mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-11 20:27:44 +02:00
* [haik]: ckpt, added in the test runner skelton i made in another repo -> still gotta make tweaks to fold it onto the current repo * [haik]: restructure backend test layout: move 37 test files from backend/tests/ into backend/tests/test_cases/, add backend/tests/run.sh one-command launcher that auto-provisions both runner and test venvs with stamp-based caching, update runner config.json to point test_paths at test_cases/ and fix venv_python path, revise runner README with run.sh usage and clearer setup instructions, and gitignore the .runner-venv directory * [haik]: refactor: reorganize backend/tests/test_cases from flat structure into domain subdirectories — moved 36 test files into auth/, browser/, labeling/, service/, settings/, and web_search/ for better discoverability and grouping * [haik]: overhaul test picker UI and add post-run rerun loop: replace checkbox glyphs with fzf-style row recolouring (coral=full, lighter coral=partial) and a right-pinned selection dot, add config-driven icon tiers (nerd/emoji/unicode/ascii) with per-glyph graceful degradation, replace the modal -k keyword screen with an inline live-filtering search bar that prunes the tree on every keystroke, add warm Anthropic-dark coral theme, toolbar flag chips replacing the old status line, and a floating help badge overlay; add rerun_prompt.py with inline Textual pill prompt (rerun all/failed/passed/exit) shown after each TTY run, wire it into main.py as a post-run loop; change run_tests to return (exit_code, RunSummary) tracking collected/passed/failed node IDs via new Dashboard methods; add icons field to config.py and config.json (set to nerd), document icon tiers and Nerd Font setup in README, set Hack Nerd Font in .vscode/settings.json, add .runner-venv to linter excludes
117 lines
3.7 KiB
Python
117 lines
3.7 KiB
Python
import json
|
|
import os
|
|
|
|
import pytest
|
|
|
|
from backend.apps.settings import store
|
|
from backend.apps.settings.models import AppSettings
|
|
from backend.apps.tools_lib import tools_lib
|
|
from backend.apps.tools_lib.models import ToolDefinition
|
|
|
|
|
|
@pytest.fixture
|
|
def settings_tmp(tmp_path, monkeypatch):
|
|
f = tmp_path / "settings.json"
|
|
monkeypatch.setattr(store, "DATA_DIR", str(tmp_path))
|
|
monkeypatch.setattr(store, "SETTINGS_FILE", str(f))
|
|
monkeypatch.setattr(store, "_cached_settings", None)
|
|
monkeypatch.setattr(store, "_cached_sig", None)
|
|
return f
|
|
|
|
|
|
@pytest.fixture
|
|
def tools_tmp(tmp_path, monkeypatch):
|
|
d = tmp_path / "tools"
|
|
d.mkdir()
|
|
monkeypatch.setattr(tools_lib, "DATA_DIR", str(d))
|
|
monkeypatch.setattr(tools_lib, "_tools_cache", None)
|
|
monkeypatch.setattr(tools_lib, "_tools_cache_sig", None)
|
|
return d
|
|
|
|
|
|
def bump_mtime(path):
|
|
# FAT32-style coarse clocks could hide a same-size rewrite; force a distinct mtime.
|
|
st = os.stat(path)
|
|
os.utime(path, ns=(st.st_atime_ns, st.st_mtime_ns + 1_000_000))
|
|
|
|
|
|
@pytest.mark.usefixtures("settings_tmp")
|
|
def test_settings_write_through_is_fresh():
|
|
s = store.load_settings()
|
|
s.theme = "light"
|
|
store.save_settings(s)
|
|
assert store.load_settings().theme == "light"
|
|
s2 = store.load_settings()
|
|
s2.theme = "dark"
|
|
store.save_settings(s2)
|
|
assert store.load_settings().theme == "dark"
|
|
|
|
|
|
def test_settings_external_edit_detected(settings_tmp):
|
|
store.save_settings(AppSettings(theme="dark"))
|
|
assert store.load_settings().theme == "dark"
|
|
raw = json.loads(settings_tmp.read_text())
|
|
raw["theme"] = "light"
|
|
settings_tmp.write_text(json.dumps(raw))
|
|
bump_mtime(settings_tmp)
|
|
assert store.load_settings().theme == "light"
|
|
|
|
|
|
@pytest.mark.usefixtures("settings_tmp")
|
|
def test_settings_cache_returns_isolated_copies():
|
|
store.save_settings(AppSettings(theme="dark"))
|
|
a = store.load_settings()
|
|
a.theme = "light"
|
|
assert store.load_settings().theme == "dark"
|
|
|
|
|
|
def test_settings_file_deleted_falls_back_to_defaults(settings_tmp):
|
|
store.save_settings(AppSettings(theme="light"))
|
|
os.remove(settings_tmp)
|
|
assert store.load_settings().theme == AppSettings().theme
|
|
|
|
|
|
def test_tools_write_then_list_is_fresh(tools_tmp):
|
|
assert tools_lib._load_all() == []
|
|
t = ToolDefinition(name="Alpha", description="a")
|
|
tools_lib._save(t)
|
|
bump_mtime(tools_tmp / f"{t.id}.json")
|
|
names = [x.name for x in tools_lib._load_all()]
|
|
assert names == ["Alpha"]
|
|
|
|
t2 = ToolDefinition(name="Beta", description="b")
|
|
tools_lib._save(t2)
|
|
assert sorted(x.name for x in tools_lib._load_all()) == ["Alpha", "Beta"]
|
|
|
|
|
|
def test_tools_delete_detected(tools_tmp):
|
|
t = ToolDefinition(name="Gone", description="g")
|
|
tools_lib._save(t)
|
|
assert [x.name for x in tools_lib._load_all()] == ["Gone"]
|
|
os.remove(tools_tmp / f"{t.id}.json")
|
|
assert tools_lib._load_all() == []
|
|
|
|
|
|
def test_tools_in_place_rewrite_detected(tools_tmp):
|
|
t = ToolDefinition(name="Old", description="x")
|
|
tools_lib._save(t)
|
|
assert [x.name for x in tools_lib._load_all()] == ["Old"]
|
|
t.name = "New"
|
|
tools_lib._save(t)
|
|
bump_mtime(tools_tmp / f"{t.id}.json")
|
|
assert [x.name for x in tools_lib._load_all()] == ["New"]
|
|
|
|
|
|
@pytest.mark.usefixtures("tools_tmp")
|
|
def test_tools_cached_hit_skips_reparse(monkeypatch):
|
|
tools_lib._save(ToolDefinition(name="Once", description="o"))
|
|
tools_lib._load_all()
|
|
real_load = json.load
|
|
loads = {"n": 0}
|
|
def counting_load(*a, **k):
|
|
loads["n"] += 1
|
|
return real_load(*a, **k)
|
|
monkeypatch.setattr(json, "load", counting_load)
|
|
assert [x.name for x in tools_lib._load_all()] == ["Once"]
|
|
assert loads["n"] == 0, "disk re-parse on unchanged dir"
|