| from __future__ import annotations |
|
|
| import json |
| import shutil |
| import threading |
| from pathlib import Path |
|
|
| import pytest |
|
|
| from adam.executor import ToolExecutionError, ToolExecutor |
| from adam.logging_setup import configure_logging |
| from adam.registry import RegistryError, ToolRegistry |
|
|
|
|
| ROOT = Path(__file__).resolve().parents[1] |
|
|
|
|
| def make_root(tmp_path: Path) -> Path: |
| (tmp_path / "config").mkdir() |
| shutil.copy2(ROOT / "config" / "tools.json", tmp_path / "config" / "tools.json") |
| return tmp_path |
|
|
|
|
| def execute( |
| executor: ToolExecutor, |
| tool_id: str, |
| arguments: dict, |
| ) -> dict: |
| run_event = threading.Event() |
| run_event.set() |
| return executor.execute( |
| tool_id, |
| arguments, |
| job_id="TEST0001", |
| cancel_event=threading.Event(), |
| run_event=run_event, |
| progress_callback=lambda _percent, _message: None, |
| log_callback=lambda _message: None, |
| ) |
|
|
|
|
| def test_registry_exposes_enabled_trainers(tmp_path: Path) -> None: |
| registry = ToolRegistry(make_root(tmp_path)) |
|
|
| assert registry.get("lora_trainer").demo is False |
| assert "resume_training" in registry.get("lora_trainer").capabilities |
| assert registry.get("flow_trainer").demo is False |
| assert "fresh_training" in registry.get("flow_trainer").capabilities |
|
|
|
|
| def test_executor_rejects_unregistered_arguments(tmp_path: Path) -> None: |
| project = make_root(tmp_path) |
| executor = ToolExecutor( |
| project, |
| ToolRegistry(project), |
| configure_logging(project), |
| step_delay=0, |
| ) |
|
|
| with pytest.raises(ToolExecutionError, match="unsupported arguments"): |
| execute( |
| executor, |
| "preview_generator", |
| { |
| "subject": "test", |
| "project_name": "test", |
| "preview_count": 1, |
| "shell_command": "dangerous", |
| }, |
| ) |
|
|
|
|
| def test_demo_pipeline_creates_truthful_reviewable_artifacts(tmp_path: Path) -> None: |
| project = make_root(tmp_path) |
| registry_path = project / "config" / "tools.json" |
| registry_payload = json.loads(registry_path.read_text(encoding="utf-8")) |
| collector = next( |
| tool |
| for tool in registry_payload["tools"] |
| if tool["id"] == "dataset_collector" |
| ) |
| collector["demo"] = True |
| collector["backend"] = { |
| "type": "python", |
| "module": "adam.tools.demo_backends", |
| "function": "collect_dataset", |
| } |
| lora = next( |
| tool for tool in registry_payload["tools"] if tool["id"] == "lora_trainer" |
| ) |
| lora["demo"] = True |
| lora["arguments"] = ["subject", "project_name", "epochs"] |
| lora["required_arguments"] = ["subject", "project_name", "epochs"] |
| lora["backend"] = { |
| "type": "python", |
| "module": "adam.tools.demo_backends", |
| "function": "train_lora", |
| } |
| registry_path.write_text( |
| json.dumps(registry_payload), |
| encoding="utf-8", |
| ) |
| executor = ToolExecutor( |
| project, |
| ToolRegistry(project), |
| configure_logging(project), |
| step_delay=0, |
| ) |
| common = {"subject": "Test Subject", "project_name": "Test Subject LoRA"} |
| steps = [ |
| ("dataset_collector", {**common, "image_count": 12}), |
| ("dataset_preparer", {"project_name": common["project_name"]}), |
| ("caption_generator", common), |
| ("lora_trainer", {**common, "epochs": 2}), |
| ("preview_generator", {**common, "preview_count": 2}), |
| ("completion_notifier", {"project_name": common["project_name"]}), |
| ] |
| result = {} |
| for tool_id, arguments in steps: |
| result = execute(executor, tool_id, arguments) |
|
|
| output = Path(result["output_folder"]) |
| assert output.is_relative_to(project / "data" / "projects") |
| summary = json.loads( |
| (output / "training" / "training_summary.json").read_text(encoding="utf-8") |
| ) |
| assert summary["mode"] == "demo" |
| assert summary["model_created"] is False |
| assert len(list((output / "previews").glob("preview_*.svg"))) == 2 |
| assert (output / "completion.json").exists() |
|
|