NODEDC_MISSION_CORE/tests/test_simulation_provider_co...

100 lines
3.2 KiB
Python

from __future__ import annotations
from dataclasses import replace
import pytest
from k1link.simulation.contracts import ControlProfile
from k1link.simulation.provider_contract import (
ProviderRole,
SimulationClockDescriptor,
SimulationProviderContractError,
SimulationProviderDescriptor,
SimulationProviderProfile,
)
from k1link.simulation.stock_rover import STOCK_ROVER_PROVIDER_PROFILE
def _unreal_profile() -> SimulationProviderProfile:
return SimulationProviderProfile(
profile_id="unreal-native-rover-v1",
providers=(
SimulationProviderDescriptor(
provider_id="unreal-native",
roles=(
ProviderRole.WORLD,
ProviderRole.PHYSICS,
ProviderRole.STATE,
ProviderRole.SENSOR,
),
capabilities=(
"clock.simulation",
"state.vehicle-pose",
"truth.ground-truth",
"sensor.virtual",
),
),
SimulationProviderDescriptor(
provider_id="unreal-direct-control",
roles=(ProviderRole.CONTROLLER,),
capabilities=("command.rover-speed-steering/v1",),
),
),
clock=SimulationClockDescriptor(
provider_id="unreal-native",
domain="unreal:fixed-step",
),
control_profiles=(ControlProfile.ROVER_SPEED_STEERING_V1,),
)
def test_stock_rover_provider_profile_round_trips_exactly() -> None:
restored = SimulationProviderProfile.from_dict(STOCK_ROVER_PROVIDER_PROFILE.to_dict())
assert restored == STOCK_ROVER_PROVIDER_PROFILE
assert restored.clock.domain == "gazebo:/clock"
assert any(ProviderRole.CONTROLLER in provider.roles for provider in restored.providers)
def test_provider_contract_accepts_unreal_without_changing_canonical_frames() -> None:
profile = SimulationProviderProfile.from_dict(_unreal_profile().to_dict())
assert profile.clock.domain == "unreal:fixed-step"
assert profile.world_frame == "map_enu"
assert profile.body_frame == "base_link_flu"
def test_provider_contract_rejects_missing_clock_capability() -> None:
profile = _unreal_profile()
world = profile.providers[0]
with pytest.raises(SimulationProviderContractError, match="clock.simulation"):
replace(
profile,
providers=(
replace(
world,
capabilities=tuple(
capability
for capability in world.capabilities
if capability != "clock.simulation"
),
),
profile.providers[1],
),
)
def test_provider_contract_rejects_undeclared_command_capability() -> None:
profile = _unreal_profile()
controller = profile.providers[1]
with pytest.raises(SimulationProviderContractError, match="control profiles"):
replace(
profile,
providers=(
profile.providers[0],
replace(controller, capabilities=("transport.custom",)),
),
)