115 lines
4.8 KiB
Python
115 lines
4.8 KiB
Python
"""Per-task archive quality overrides outrank JSON and saved environment defaults."""
|
|
|
|
import json
|
|
from types import SimpleNamespace
|
|
|
|
import pytest
|
|
|
|
from apps.admin_console.services.task_import import TaskCase, TaskOptions
|
|
from artemis.config.agent import AgentGlobalConfig, load_agent_config
|
|
from artemis.config.settings import settings
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def recording_defaults(monkeypatch):
|
|
monkeypatch.setattr(settings, "ARTEMIS_RECORDING_CONFIG", {"fps": 10, "h264_kbps": 900})
|
|
monkeypatch.setattr(settings, "ARTEMIS_TASK_RECORDING_CONFIG", {})
|
|
|
|
|
|
def test_json_recording_defaults_override_saved_defaults(tmp_path):
|
|
config = tmp_path / "artemis.jsonc"
|
|
config.write_text(json.dumps({"agent": {"recording": {"fps": 20}}}), encoding="utf-8")
|
|
result = load_agent_config(config).recording
|
|
assert result.fps == 20
|
|
assert result.h264_kbps == 900
|
|
assert result.max_long_edge == 1280
|
|
|
|
|
|
def test_task_recording_override_has_highest_priority_and_is_partial(tmp_path, monkeypatch):
|
|
monkeypatch.setattr(settings, "ARTEMIS_TASK_RECORDING_CONFIG", {"fps": 30})
|
|
config = tmp_path / "artemis.jsonc"
|
|
config.write_text(
|
|
json.dumps({"agent": {"recording": {"fps": 20, "max_long_edge": 1920}}}), encoding="utf-8"
|
|
)
|
|
result = load_agent_config(config).recording
|
|
assert result.fps == 30
|
|
assert result.max_long_edge == 1920
|
|
assert result.h264_kbps == 900
|
|
|
|
|
|
def test_task_recording_override_applies_without_json_recording_block(monkeypatch):
|
|
monkeypatch.setattr(settings, "ARTEMIS_TASK_RECORDING_CONFIG", {"fps": 30})
|
|
assert AgentGlobalConfig().recording.fps == 30
|
|
|
|
|
|
def test_invalid_task_recording_override_is_rejected(monkeypatch):
|
|
monkeypatch.setattr(settings, "ARTEMIS_TASK_RECORDING_CONFIG", {"fps": 500})
|
|
with pytest.raises(ValueError, match="fps"):
|
|
AgentGlobalConfig.model_validate({"recording": {"fps": 20}})
|
|
|
|
|
|
def test_task_and_batch_serialization_do_not_inject_unset_recording_defaults():
|
|
options = TaskOptions.model_validate({"recording": {"fps": 30}})
|
|
assert options.model_dump(exclude_none=True)["recording"] == {"fps": 30}
|
|
case = TaskCase(name="fixture", goal="fixture", task_config=options)
|
|
assert case.model_dump()["task_config"]["recording"] == {"fps": 30}
|
|
# Round trips through stored batches preserve the partial override.
|
|
restored = TaskCase.model_validate(case.model_dump())
|
|
assert restored.model_dump()["task_config"]["recording"] == {"fps": 30}
|
|
|
|
|
|
def test_worker_env_keeps_task_quality_separate_from_saved_defaults(monkeypatch):
|
|
from apps.admin_console.services.task_queue_service import TaskQueueService
|
|
from artemis.runtime.adb_endpoint import AdbEndpoint, AdbTarget
|
|
|
|
monkeypatch.setenv("ARTEMIS_RECORDING_CONFIG", '{"fps":10}')
|
|
monkeypatch.setenv("ARTEMIS_TASK_RECORDING_CONFIG", '{"fps":60}')
|
|
_, environment = TaskQueueService._build_worker_invocation(
|
|
{"runtime_overrides": {"recording": {"fps": 30}}},
|
|
"test-run",
|
|
None,
|
|
"fixture",
|
|
"flash",
|
|
AdbTarget(AdbEndpoint.local()),
|
|
)
|
|
assert json.loads(environment["ARTEMIS_RECORDING_CONFIG"]) == {"fps": 10}
|
|
assert json.loads(environment["ARTEMIS_TASK_RECORDING_CONFIG"]) == {"fps": 30}
|
|
_, clean_environment = TaskQueueService._build_worker_invocation(
|
|
{}, "test-run", None, "fixture", "flash", AdbTarget(AdbEndpoint.local())
|
|
)
|
|
assert "ARTEMIS_TASK_RECORDING_CONFIG" not in clean_environment
|
|
|
|
|
|
def test_sdk_preserves_task_recording_scope_through_recorder(tmp_path, monkeypatch):
|
|
from artemis.plugins.models import EvidenceSource
|
|
from artemis.plugins.recording import PluginRecordings, capture_rectangle
|
|
from artemis.sdk.builders.agent_config_builder import AgentConfigBuilder
|
|
|
|
monkeypatch.setattr(
|
|
settings,
|
|
"ARTEMIS_TASK_RECORDING_CONFIG",
|
|
{"computer_scope": "window", "codec": "h264", "fps": 7, "max_long_edge": 960},
|
|
)
|
|
builder = AgentConfigBuilder()
|
|
config = builder.build()
|
|
ctx = SimpleNamespace(
|
|
agent_config=config,
|
|
data_engine=SimpleNamespace(base_dir=tmp_path, session_start_time=100),
|
|
execution_setup=SimpleNamespace(record_video_enabled=True),
|
|
)
|
|
recorder = PluginRecordings(ctx)
|
|
source = EvidenceSource(
|
|
kind="computer",
|
|
target_id="fixture",
|
|
window={"left": 40, "top": 50, "width": 800, "height": 600},
|
|
screen={"left": 0, "top": 0, "width": 1920, "height": 1080},
|
|
)
|
|
assert recorder.config.computer_scope == "window"
|
|
assert capture_rectangle(source, recorder.config.computer_scope) == source.window
|
|
assert recorder.config.codec == "h264"
|
|
assert recorder.config.fps == 7
|
|
assert recorder.config.max_long_edge == 960
|
|
# Building another task must not share a mutable recording configuration.
|
|
config.recording.fps = 12
|
|
assert builder.build().recording.fps == 7
|