"""Settings: parsed once at startup, and refused there rather than mid-motion.""" import pytest from dora_teleop.config import Config def test_the_defaults_need_no_environment(): config = Config.from_env() assert config.speed_mm_s == 60.0 assert config.speed_deg_s == 30.0 def test_the_deadman_is_shorter_than_the_arms_own_expiry(): # The arm node's VELOCITY_COMMAND_TTL_S defaults to 0.5 s and is the # backstop. Ours has to fire first, or the backstop backs up nothing. assert Config.from_env().deadman.jog_ttl_s < 0.5 def test_the_layers_fire_innermost_first(): # A stale pad reading has to be noticed before the jog deadline it feeds. deadman = Config.from_env().deadman assert deadman.joy_ttl_s < deadman.jog_ttl_s def test_a_blank_variable_falls_back_to_the_default(monkeypatch): monkeypatch.setenv("SPEED_MM_S", " ") assert Config.from_env().speed_mm_s == 60.0 def test_a_speed_that_is_not_a_number_names_itself(monkeypatch): monkeypatch.setenv("SPEED_MM_S", "brisk") with pytest.raises(ValueError, match="SPEED_MM_S"): Config.from_env() def test_a_joy_ttl_at_or_above_the_jog_ttl_is_refused_at_startup(monkeypatch): # Layers out of order means a backstop firing before the thing it backs up, # which is invisible until the day something actually goes wrong. monkeypatch.setenv("JOY_TTL_S", "0.4") with pytest.raises(ValueError, match="JOY_TTL_S"): Config.from_env() def test_a_keepalive_at_or_above_the_jog_ttl_is_refused_at_startup(monkeypatch): # The repeat has to outpace the arm's own velocity expiry. It cannot be read # from here, but JOG_TTL_S already sits below it, so a repeat slower than # JOG_TTL_S is a repeat the arm stops between — an arm that stutters under a # held stick, with nothing in the logs to say why. monkeypatch.setenv("JOG_KEEPALIVE_S", "0.4") with pytest.raises(ValueError, match="JOG_KEEPALIVE_S"): Config.from_env() def test_a_keepalive_of_zero_is_refused_at_startup(monkeypatch): # Zero would mean repeating every tick, which is the behaviour the keepalive # exists to replace. monkeypatch.setenv("JOG_KEEPALIVE_S", "0") with pytest.raises(ValueError, match="JOG_KEEPALIVE_S"): Config.from_env() @pytest.mark.parametrize("value", ["1.0", "-0.1", "2"]) def test_a_deadzone_outside_the_stick_is_refused_at_startup(monkeypatch, value): # A deadzone of 1 would silently make the pad inert; catching it here beats # finding out when somebody picks it up. monkeypatch.setenv("DEADZONE", value) with pytest.raises(ValueError, match="DEADZONE"): Config.from_env() @pytest.mark.parametrize("value", ["-0.1", "1.1"]) def test_an_expo_outside_the_curve_is_refused_at_startup(monkeypatch, value): monkeypatch.setenv("EXPO", value) with pytest.raises(ValueError, match="EXPO"): Config.from_env() def test_the_timings_can_be_tuned_without_touching_the_speeds(monkeypatch): monkeypatch.setenv("JOG_TTL_S", "0.25") monkeypatch.setenv("JOY_TTL_S", "0.1") monkeypatch.setenv("GAMEPAD_IDLE_RELEASE_S", "5") config = Config.from_env() assert config.deadman.jog_ttl_s == 0.25 assert config.deadman.joy_ttl_s == 0.1 assert config.deadman.gamepad_idle_release_s == 5.0