NODEDC_PLATFORM/infra/deploy-runner/test_engine_mcp_registered_...

317 lines
12 KiB
Python

import hashlib
import importlib.machinery
import importlib.util
import io
import json
import os
from pathlib import Path
import subprocess
import tarfile
import tempfile
import unittest
from contextlib import redirect_stdout
from unittest import mock
SCRIPT_DIR = Path(__file__).resolve().parent
RUNNER_PATH = SCRIPT_DIR / "nodedc-deploy"
BUILDER_PATH = (
SCRIPT_DIR
/ "build-engine-mcp-registered-execution-profiles-artifact.mjs"
)
ENGINE_ROOT = SCRIPT_DIR.parent.parent.parent / "NODEDC_ENGINE_INFRA"
PATCH_ID = "engine-mcp-registered-execution-profiles-20991231-999"
def load_runner():
loader = importlib.machinery.SourceFileLoader(
"nodedc_engine_mcp_registered_execution_profiles",
str(RUNNER_PATH),
)
spec = importlib.util.spec_from_loader(loader.name, loader)
module = importlib.util.module_from_spec(spec)
loader.exec_module(module)
return module
RUNNER = load_runner()
class EngineMcpRegisteredExecutionProfilesTest(unittest.TestCase):
def require_current_target_source(self):
for relative_path, expected in (
RUNNER.ENGINE_MCP_REGISTERED_EXECUTION_PROFILES_TARGET_SHA256.items()
):
path = ENGINE_ROOT / relative_path
if (
not path.is_file()
or hashlib.sha256(path.read_bytes()).hexdigest() != expected
):
self.skipTest("Registered execution profiles source advanced")
def build(self, artifact_dir):
environment = os.environ.copy()
environment["NODEDC_ENGINE_SOURCE_ROOT"] = str(ENGINE_ROOT)
environment["NODEDC_DEPLOY_ARTIFACT_DIR"] = str(artifact_dir)
completed = subprocess.run(
["node", str(BUILDER_PATH), PATCH_ID],
check=True,
capture_output=True,
text=True,
env=environment,
)
return json.loads(completed.stdout)
def test_builder_emits_exact_deterministic_backend_slice(self):
self.require_current_target_source()
with tempfile.TemporaryDirectory(
prefix="nodedc-engine-registered-profiles-builder-"
) as directory:
root = Path(directory)
first = self.build(root / "first")
second = self.build(root / "second")
first_artifact = Path(first["artifact"])
second_artifact = Path(second["artifact"])
self.assertEqual(
first_artifact.read_bytes(),
second_artifact.read_bytes(),
)
self.assertEqual(
first["sha256"],
hashlib.sha256(first_artifact.read_bytes()).hexdigest(),
)
self.assertEqual(first["services"], ["nodedc-backend"])
self.assertEqual(first["mcpVersion"], "0.12.0")
self.assertEqual(first["registeredProfiles"], 6)
self.assertEqual(first["existingMaterializerReused"], True)
self.assertEqual(
first["nodeIntelligenceAttestationChanged"],
True,
)
self.assertEqual(first["nodeIntelligenceImageChanged"], False)
self.assertEqual(first["nodeIntelligenceSourceChanged"], False)
self.assertEqual(first["n8nCoreChanged"], False)
self.assertEqual(first["l2GraphChanged"], False)
extract = root / "extract"
with tarfile.open(first_artifact, "r:gz") as archive:
archive.extractall(extract, filter="data")
entries = tuple(
(extract / "files.txt").read_text(encoding="utf-8").splitlines()
)
self.assertEqual(
entries,
RUNNER.ENGINE_MCP_REGISTERED_EXECUTION_PROFILES_ARTIFACT_ENTRIES,
)
self.assertTrue(
RUNNER.is_engine_mcp_registered_execution_profiles_slice(
"engine",
entries,
)
)
self.assertEqual(
RUNNER.component_services("engine", entries),
("nodedc-backend",),
)
RUNNER.validate_engine_mcp_registered_execution_profiles_slice(
extract / "payload",
entries,
)
def test_preflight_requires_exact_046_predecessor_and_absent_new_paths(self):
with tempfile.TemporaryDirectory(
prefix="nodedc-engine-registered-profiles-preflight-"
) as directory:
root = Path(directory)
all_live = {
**RUNNER.ENGINE_MCP_REGISTERED_EXECUTION_PROFILES_PREDECESSOR_SHA256,
**RUNNER.ENGINE_MCP_REGISTERED_EXECUTION_PROFILES_FOUNDATION_SHA256,
}
for relative_path in all_live:
path = root / relative_path
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text("live\n", encoding="utf-8")
def exact_hash(path):
relative_path = Path(path).relative_to(root).as_posix()
return all_live[relative_path]
with (
mock.patch.object(RUNNER, "component_root", return_value=root),
mock.patch.object(RUNNER, "sha256_file", side_effect=exact_hash),
mock.patch.object(
RUNNER,
"preflight_engine_credential_backend_runtime",
return_value={"mode": "verified-derived-retry"},
),
):
result = (
RUNNER
.preflight_engine_mcp_registered_execution_profiles_predecessor()
)
self.assertEqual(
result["mode"],
"gelios-items-envelope-v12-to-registered-profiles-v2-attested",
)
self.assertEqual(
result["new_paths"],
RUNNER.ENGINE_MCP_REGISTERED_EXECUTION_PROFILES_NEW_PATHS,
)
new_path = (
root
/ RUNNER.ENGINE_MCP_REGISTERED_EXECUTION_PROFILES_NEW_PATHS[0]
)
new_path.parent.mkdir(parents=True, exist_ok=True)
new_path.write_text("unexpected\n", encoding="utf-8")
with (
mock.patch.object(RUNNER, "component_root", return_value=root),
mock.patch.object(RUNNER, "sha256_file", side_effect=exact_hash),
):
with self.assertRaises(RUNNER.DeployError):
(
RUNNER
.preflight_engine_mcp_registered_execution_profiles_predecessor()
)
def test_plan_renders_exact_server_side_planning_boundary(self):
self.require_current_target_source()
with tempfile.TemporaryDirectory(
prefix="nodedc-engine-registered-profiles-plan-"
) as directory:
root = Path(directory)
built = self.build(root / "artifacts")
artifact = Path(built["artifact"])
live_root = root / "live"
live_root.mkdir()
preflight = {
"mode":
"gelios-items-envelope-v12-to-registered-profiles-v2-attested",
"predecessor_sha256": dict(
RUNNER
.ENGINE_MCP_REGISTERED_EXECUTION_PROFILES_PREDECESSOR_SHA256
),
"foundation_sha256": dict(
RUNNER
.ENGINE_MCP_REGISTERED_EXECUTION_PROFILES_FOUNDATION_SHA256
),
"target_sha256": dict(
RUNNER
.ENGINE_MCP_REGISTERED_EXECUTION_PROFILES_TARGET_SHA256
),
"new_paths": (
RUNNER
.ENGINE_MCP_REGISTERED_EXECUTION_PROFILES_NEW_PATHS
),
"backend_mode": "verified-derived-retry",
}
output = io.StringIO()
with (
mock.patch.object(RUNNER, "validate_artifact_location"),
mock.patch.object(RUNNER, "ensure_layout"),
mock.patch.object(RUNNER, "TMP_DIR", root),
mock.patch.object(
RUNNER,
"component_root",
return_value=live_root,
),
mock.patch.object(
RUNNER,
"component_compose_root",
return_value=live_root,
),
mock.patch.object(
RUNNER,
"preflight_engine_mcp_registered_execution_profiles_predecessor",
return_value=preflight,
),
mock.patch.object(
RUNNER,
"preflight_engine_credential_backend_runtime",
return_value={"mode": "verified-derived-retry"},
),
mock.patch.object(RUNNER, "state_has_sha", return_value=False),
mock.patch.object(
RUNNER,
"state_has_patch_id",
return_value=False,
),
redirect_stdout(output),
):
RUNNER.plan_artifact(artifact)
plan = output.getvalue()
self.assertIn("services=nodedc-backend", plan)
self.assertIn("engine_mcp_version=0.12.0", plan)
self.assertIn("engine_mcp_registered_profiles=6", plan)
self.assertIn("engine_mcp_target_scope=server-derived", plan)
self.assertIn("engine_mcp_existing_materializer=reused", plan)
self.assertIn("engine_mcp_provider_endpoints_included=no", plan)
self.assertIn(
"engine_node_intelligence_attestation=updated",
plan,
)
self.assertIn("engine_node_intelligence_image=untouched", plan)
self.assertIn("l2_graph=untouched", plan)
self.assertIn("n8n_core=untouched", plan)
self.assertIn("foundry=untouched", plan)
self.assertIn("state=new", plan)
def test_live_acceptance_probes_tools_catalog_and_target_rebinding(self):
self.require_current_target_source()
expected_live = (
"engine-mcp-registered-execution-profiles:"
"0.12.0:profiles-6:target-scope:existing-materializer"
)
with (
mock.patch.object(RUNNER, "component_root", return_value=ENGINE_ROOT),
mock.patch.object(
RUNNER,
"engine_backend_container_id",
return_value="backend",
),
mock.patch.object(
RUNNER,
"run_engine_backend_probe",
return_value=expected_live,
) as backend_probe,
):
result = (
RUNNER.accept_engine_mcp_registered_execution_profiles_runtime()
)
self.assertEqual(result["live"], expected_live)
probe_source = backend_probe.call_args.args[0][-1]
self.assertIn("engine_list_l2_execution_profiles", probe_source)
self.assertIn("engine_plan_registered_l2_execution", probe_source)
self.assertIn("tenant-probe", probe_source)
self.assertIn("ndc-credref:engine-target-", probe_source)
def test_target_gateway_matches_node_intelligence_attestation(self):
descriptor_path = (
ENGINE_ROOT
/ RUNNER.ENGINE_NODE_INTELLIGENCE_DESCRIPTOR_REL
)
descriptor = RUNNER.read_engine_node_intelligence_descriptor(
descriptor_path,
"registered profiles target node-intelligence descriptor",
)
with mock.patch.object(
RUNNER,
"component_root",
return_value=ENGINE_ROOT,
):
gateway_sha256 = (
RUNNER.validate_installed_engine_node_intelligence_source(
descriptor,
)
)
self.assertEqual(
gateway_sha256,
RUNNER.ENGINE_MCP_REGISTERED_EXECUTION_PROFILES_TARGET_SHA256[
RUNNER.ENGINE_NODE_INTELLIGENCE_GATEWAY_REL
],
)
if __name__ == "__main__":
unittest.main(verbosity=2)