Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
"""E2E for the canonical-loader migration (managed-scope/env-expansion drift fix).
|
||||
|
||||
Runs a real subprocess with a temp HERMES_HOME whose config.yaml contains a
|
||||
``${ENV_VAR}`` reference, plus a managed-scope overlay dir (HERMES_MANAGED_DIR).
|
||||
|
||||
Asserts the two halves of the contract:
|
||||
|
||||
1. A migrated BEHAVIORAL site (``tui_gateway.server._load_cfg``) resolves the
|
||||
env-expanded AND managed-overlaid values — the drift bug this branch fixes.
|
||||
2. A WRITE-BACK site round-trips the raw user file without leaking managed
|
||||
values, expanded literals, or merged defaults into it.
|
||||
|
||||
Subprocess (not in-process monkeypatching) so module-level ``_hermes_home``
|
||||
globals, managed-scope caches, and ``_under_pytest`` guards behave like
|
||||
production: ``HERMES_MANAGED_DIR`` is set explicitly, which bypasses the
|
||||
pytest suppression in ``get_managed_dir``.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
import textwrap
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent.parent
|
||||
|
||||
|
||||
def _run_py(code: str, env_extra: dict[str, str], tmp_path: Path) -> dict:
|
||||
"""Run ``code`` in a subprocess; results come back via a JSON file.
|
||||
|
||||
A file (not stdout) because importing ``tui_gateway.server`` re-routes
|
||||
the real stdout into its JSON-RPC transport.
|
||||
"""
|
||||
import os
|
||||
|
||||
out_file = tmp_path / "e2e_result.json"
|
||||
env = dict(os.environ)
|
||||
env.pop("PYTEST_CURRENT_TEST", None)
|
||||
env["PYTHONPATH"] = str(REPO_ROOT)
|
||||
env["E2E_OUT_FILE"] = str(out_file)
|
||||
env.update(env_extra)
|
||||
proc = subprocess.run(
|
||||
[sys.executable, "-c", code],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env=env,
|
||||
cwd=str(tmp_path),
|
||||
timeout=120,
|
||||
)
|
||||
assert proc.returncode == 0, f"subprocess failed:\n{proc.stdout}\n{proc.stderr}"
|
||||
assert out_file.exists(), f"no result file:\n{proc.stdout}\n{proc.stderr}"
|
||||
return json.loads(out_file.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def test_behavioral_read_gets_expansion_and_overlay_while_writeback_stays_raw(
|
||||
tmp_path,
|
||||
):
|
||||
home = tmp_path / "hermes_home"
|
||||
home.mkdir()
|
||||
user_yaml = (
|
||||
"custom_prompt: 'hello ${E2E_PROMPT_SUFFIX}'\n"
|
||||
"agent:\n"
|
||||
" reasoning_effort: low\n"
|
||||
"display:\n"
|
||||
" skin: usertheme\n"
|
||||
)
|
||||
(home / "config.yaml").write_text(user_yaml, encoding="utf-8")
|
||||
|
||||
managed_dir = tmp_path / "managed"
|
||||
managed_dir.mkdir()
|
||||
# Administrator pins reasoning_effort — must win over the user's "low".
|
||||
(managed_dir / "config.yaml").write_text(
|
||||
"agent:\n reasoning_effort: high\n", encoding="utf-8"
|
||||
)
|
||||
|
||||
code = textwrap.dedent(
|
||||
"""
|
||||
import json
|
||||
from tui_gateway import server
|
||||
|
||||
cfg = server._load_cfg()
|
||||
raw = server._load_cfg_raw()
|
||||
|
||||
# Write-back round-trip through the real save path.
|
||||
rt = server._load_cfg_raw()
|
||||
rt.setdefault("display", {})["battery"] = True
|
||||
server._save_cfg(rt)
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
saved = Path(server._hermes_home, "config.yaml").read_text(encoding="utf-8")
|
||||
Path(os.environ["E2E_OUT_FILE"]).write_text(json.dumps({
|
||||
"behavioral_prompt": cfg.get("custom_prompt"),
|
||||
"behavioral_effort": (cfg.get("agent") or {}).get("reasoning_effort"),
|
||||
"raw_prompt": raw.get("custom_prompt"),
|
||||
"raw_effort": (raw.get("agent") or {}).get("reasoning_effort"),
|
||||
"saved": saved,
|
||||
}), encoding="utf-8")
|
||||
"""
|
||||
)
|
||||
out = _run_py(
|
||||
code,
|
||||
{
|
||||
"HERMES_HOME": str(home),
|
||||
"HERMES_MANAGED_DIR": str(managed_dir),
|
||||
"E2E_PROMPT_SUFFIX": "world",
|
||||
},
|
||||
tmp_path,
|
||||
)
|
||||
|
||||
# 1. Behavioral read: ${VAR} expanded + managed overlay applied.
|
||||
assert out["behavioral_prompt"] == "hello world"
|
||||
assert out["behavioral_effort"] == "high"
|
||||
|
||||
# 2. Raw primitive: byte-faithful view of the user's file.
|
||||
assert out["raw_prompt"] == "hello ${E2E_PROMPT_SUFFIX}"
|
||||
assert out["raw_effort"] == "low"
|
||||
|
||||
# 3. Write-back: user values round-trip; no managed/expanded/default leak.
|
||||
saved = out["saved"]
|
||||
assert "hello ${E2E_PROMPT_SUFFIX}" in saved # template preserved
|
||||
assert "hello world" not in saved # no expansion persisted
|
||||
assert "reasoning_effort: low" in saved # user value preserved
|
||||
assert "high" not in saved # managed value NOT persisted
|
||||
assert "battery: true" in saved # the actual edit landed
|
||||
assert "max_turns" not in saved # no DEFAULT_CONFIG pollution
|
||||
|
||||
|
||||
def test_writeback_roundtrip_byte_identical_when_unchanged(tmp_path):
|
||||
"""read_user_config_raw → save with no mutation must not alter content
|
||||
semantics (yaml re-dump may reorder nothing here: flat mapping)."""
|
||||
home = tmp_path / "hermes_home"
|
||||
home.mkdir()
|
||||
original = "custom_prompt: keep ${NOT_SET_VAR}\ndisplay:\n skin: usertheme\n"
|
||||
(home / "config.yaml").write_text(original, encoding="utf-8")
|
||||
|
||||
code = textwrap.dedent(
|
||||
"""
|
||||
import json
|
||||
from pathlib import Path
|
||||
from hermes_cli.config import read_user_config_raw
|
||||
import yaml
|
||||
|
||||
p = Path(__import__('os').environ['HERMES_HOME']) / 'config.yaml'
|
||||
before = p.read_text(encoding='utf-8')
|
||||
data = read_user_config_raw(p)
|
||||
# No mutation, no save — the primitive itself must be read-only.
|
||||
after = p.read_text(encoding='utf-8')
|
||||
import os
|
||||
Path(os.environ["E2E_OUT_FILE"]).write_text(json.dumps({
|
||||
"identical": before == after,
|
||||
"parsed": data,
|
||||
}), encoding="utf-8")
|
||||
"""
|
||||
)
|
||||
out = _run_py(code, {"HERMES_HOME": str(home)}, tmp_path)
|
||||
assert out["identical"] is True
|
||||
assert out["parsed"]["custom_prompt"] == "keep ${NOT_SET_VAR}"
|
||||
Reference in New Issue
Block a user