chore: checkpoint web Blender migration source, tools and docs
Accumulated uncommitted work: GHOST Web backend, WebGL/GPU web layer, web workflow engine and protocol, tooling, docs and task records. Large generated evidence, user-testing archives, build snapshots and imported test assets remain untracked. Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
129
my-tools/test_wbv2_checkpoints.py
Normal file
129
my-tools/test_wbv2_checkpoints.py
Normal file
@@ -0,0 +1,129 @@
|
||||
"""Checkpoint integration tests use synthetic Main fixtures only."""
|
||||
import contextlib
|
||||
import io
|
||||
import json
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
import test_wbv2_local as local_fixtures
|
||||
from wbv2_autopilot import write_json
|
||||
|
||||
|
||||
class CheckpointTests(unittest.TestCase):
|
||||
setUp = local_fixtures.LocalWorkflowTests.setUp
|
||||
file = local_fixtures.LocalWorkflowTests.file
|
||||
ready_result = local_fixtures.LocalWorkflowTests.ready_result
|
||||
local_contract = local_fixtures.LocalWorkflowTests.local_contract
|
||||
|
||||
def prepare(self):
|
||||
contract = self.local_contract()
|
||||
self.file("build.py", "from pathlib import Path\np=Path('build-count.txt')\np.write_text(str(int(p.read_text())+1) if p.exists() else '1')\n")
|
||||
native = contract["result"]["checks"][0]
|
||||
native["kinds"].remove("source_build")
|
||||
native["cacheInputs"] = ["source.cpp", "check.py", self.native_source]
|
||||
contract["result"]["checks"].insert(0, {"id": "build", "argv": ["python3", "build.py"], "cwd": ".", "kinds": ["source_build"]})
|
||||
contract["result"]["dependencies"].append("build.py")
|
||||
write_json(self.root / "local-contract.json", contract)
|
||||
return contract
|
||||
|
||||
def attempt(self):
|
||||
with contextlib.redirect_stdout(io.StringIO()):
|
||||
return self.runner.attempt(self.context, self.job)
|
||||
|
||||
def test_native_build_stays_incremental_and_runtime_success_is_reused(self):
|
||||
self.prepare()
|
||||
self.assertTrue(self.attempt())
|
||||
first = self.runner.state["jobs"][self.job["id"]]["runDirectory"]
|
||||
self.assertTrue(self.attempt())
|
||||
self.assertEqual("2", (self.root / "build-count.txt").read_text())
|
||||
self.assertEqual("1", (self.root / "executions.txt").read_text())
|
||||
record = self.runner.state["jobs"][self.job["id"]]
|
||||
self.assertTrue(self.runner.receipt_valid(record))
|
||||
receipt = json.loads((self.root / record["receipt"]).read_text())
|
||||
cached = next(check for check in receipt["checks"] if check["id"] == "native")
|
||||
self.assertIn("reusedFrom", cached)
|
||||
self.assertTrue(all(case["receipt"].startswith(first) for case in cached["caseBindings"]))
|
||||
|
||||
def test_later_failure_preserves_success_when_only_failed_step_is_repaired(self):
|
||||
contract = self.prepare()
|
||||
self.file("failure.py", "raise SystemExit(1)\n")
|
||||
contract["result"]["dependencies"].append("failure.py")
|
||||
contract["result"]["checks"].append({"id": "failure", "argv": ["python3", "failure.py"], "cwd": ".", "kinds": ["negative"]})
|
||||
write_json(self.root / "local-contract.json", contract)
|
||||
self.assertFalse(self.attempt())
|
||||
record = self.runner.state["jobs"][self.job["id"]]
|
||||
checkpoint = json.loads((self.root / record["runDirectory"] / "step-checkpoint.json").read_text())
|
||||
self.assertEqual("failure", checkpoint["failures"][0]["checkId"])
|
||||
self.assertEqual("passed", checkpoint["outcomes"]["native"])
|
||||
self.file("failure.py", "raise SystemExit(0)\n")
|
||||
self.assertTrue(self.attempt())
|
||||
self.assertEqual("1", (self.root / "executions.txt").read_text())
|
||||
|
||||
def test_artifact_change_invalidates_cached_runtime(self):
|
||||
self.prepare()
|
||||
self.assertTrue(self.attempt())
|
||||
self.file("engine.wasm", "changed synthetic artifact\n")
|
||||
self.assertTrue(self.attempt())
|
||||
self.assertEqual("2", (self.root / "executions.txt").read_text())
|
||||
|
||||
def test_failure_continues_independent_stage_and_blocks_dependent_stage(self):
|
||||
contract = self.prepare()
|
||||
self.file("failure.py", "raise SystemExit(1)\n")
|
||||
self.file("independent.py", "from pathlib import Path\nPath('independent-ran').touch()\n")
|
||||
contract["result"]["dependencies"] += ["failure.py", "independent.py"]
|
||||
contract["result"]["checks"] += [
|
||||
{"id": "failure", "argv": ["python3", "failure.py"], "cwd": ".", "kinds": ["negative"], "continueOnFailure": True},
|
||||
{"id": "dependent", "argv": ["python3", "failure.py"], "cwd": ".", "kinds": ["negative"], "dependsOn": ["failure"]},
|
||||
{"id": "independent", "argv": ["python3", "independent.py"], "cwd": ".", "kinds": ["positive"]},
|
||||
]
|
||||
write_json(self.root / "local-contract.json", contract)
|
||||
self.assertFalse(self.attempt())
|
||||
self.assertTrue((self.root / "independent-ran").exists())
|
||||
record = self.runner.state["jobs"][self.job["id"]]
|
||||
checkpoint = json.loads((self.root / record["runDirectory"] / "step-checkpoint.json").read_text())
|
||||
self.assertEqual("blocked", checkpoint["outcomes"]["dependent"])
|
||||
self.assertEqual("passed", checkpoint["outcomes"]["independent"])
|
||||
self.assertNotIn("receipt", record)
|
||||
|
||||
def test_per_stage_timeout_overrides_global_timeout(self):
|
||||
contract = self.prepare()
|
||||
contract["result"]["checks"][1]["timeoutSeconds"] = 5
|
||||
write_json(self.root / "local-contract.json", contract)
|
||||
with patch.object(self.runner, "run_process", wraps=self.runner.run_process) as run:
|
||||
self.assertTrue(self.attempt())
|
||||
self.assertEqual(5, run.call_args_list[1].args[3])
|
||||
|
||||
def test_verification_requests_are_parent_bound_and_do_not_advance_queue(self):
|
||||
self.prepare()
|
||||
request = self.runner.directory / "requests" / "pending" / "valid.json"
|
||||
write_json(request, {"task": self.task, "parentSha256": self.context["parentSha256"], "job": self.job["id"]})
|
||||
self.assertEqual(self.job, self.runner.requested_job(self.context, [self.job]))
|
||||
self.assertEqual(request, self.runner.pending_request)
|
||||
self.assertTrue(request.is_file())
|
||||
request.unlink()
|
||||
write_json(request, {"task": self.task, "parentSha256": "0" * 64, "job": self.job["id"]})
|
||||
with contextlib.redirect_stdout(io.StringIO()):
|
||||
self.assertIsNone(self.runner.requested_job(self.context, [self.job]))
|
||||
self.assertFalse(request.exists())
|
||||
self.assertTrue((self.runner.directory / "requests" / "rejected" / "valid.json").is_file())
|
||||
|
||||
def test_process_receipt_includes_resource_observations(self):
|
||||
self.prepare()
|
||||
self.assertTrue(self.attempt())
|
||||
record = self.runner.state["jobs"][self.job["id"]]
|
||||
receipt = json.loads((self.root / record["receipt"]).read_text())
|
||||
usage = receipt["checks"][0]["resourceUsage"]
|
||||
self.assertGreaterEqual(usage["reapedChildCpuSeconds"], 0)
|
||||
self.assertGreater(usage["samples"], 0)
|
||||
|
||||
def test_repeated_cli_start_returns_existing_owner_without_traceback(self):
|
||||
import run_web_product_migration as cli
|
||||
self.runner.state.update(state="waiting_local_work", pid=123, identity="fake", executionMode="local_only")
|
||||
output = io.StringIO()
|
||||
with patch.object(cli, "main", side_effect=RuntimeError("another Python autopilot owns the project")), patch.object(cli, "Autopilot", return_value=self.runner), patch.object(cli, "alive", return_value=True), patch.object(cli, "identity", return_value="fake"), contextlib.redirect_stdout(output):
|
||||
self.assertEqual(0, cli.entrypoint())
|
||||
self.assertEqual("already_running", json.loads(output.getvalue())["state"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user