feat(device-plane): add canonical Device Manager runtime
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
#!/usr/bin/env python3
|
||||
import hashlib
|
||||
import importlib.machinery
|
||||
import importlib.util
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import tarfile
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from unittest import mock
|
||||
|
||||
|
||||
SCRIPT_DIR = Path(__file__).resolve().parent
|
||||
PLATFORM_ROOT = SCRIPT_DIR.parent.parent
|
||||
RUNNER_PATH = SCRIPT_DIR / "nodedc-deploy"
|
||||
|
||||
|
||||
def load_runner():
|
||||
loader = importlib.machinery.SourceFileLoader(
|
||||
"nodedc_device_manager_deploy_under_test",
|
||||
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 DeviceManagerControlPlaneArtifactsTest(unittest.TestCase):
|
||||
def build(self, script, patch_id, artifact_dir):
|
||||
environment = os.environ.copy()
|
||||
environment["NODEDC_DEPLOY_ARTIFACT_DIR"] = str(artifact_dir)
|
||||
completed = subprocess.run(
|
||||
["node", str(SCRIPT_DIR / script), patch_id],
|
||||
cwd=PLATFORM_ROOT,
|
||||
env=environment,
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
return json.loads(completed.stdout)
|
||||
|
||||
def assert_deterministic_artifact(self, script, patch_id, expected_entries):
|
||||
with tempfile.TemporaryDirectory(prefix="nodedc-device-manager-artifact-") as directory:
|
||||
root = Path(directory)
|
||||
first = self.build(script, patch_id, root / "first")
|
||||
second = self.build(script, patch_id, 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(tuple(first["entries"]), tuple(expected_entries))
|
||||
extracted = root / "extracted"
|
||||
extracted.mkdir()
|
||||
manifest, entries, payload = RUNNER.load_artifact(first_artifact, extracted)
|
||||
self.assertEqual(tuple(entries), tuple(expected_entries))
|
||||
with tarfile.open(first_artifact, "r:gz") as archive:
|
||||
members = archive.getmembers()
|
||||
names = [member.name for member in members]
|
||||
bytes_joined = b"\n".join(
|
||||
archive.extractfile(member).read()
|
||||
for member in members
|
||||
if member.isfile()
|
||||
)
|
||||
self.assertFalse(any(Path(name).name.startswith("._") for name in names))
|
||||
self.assertFalse(any("/node_modules/" in name or "/.git/" in name for name in names))
|
||||
self.assertNotIn(b"-----BEGIN PRIVATE KEY-----", bytes_joined)
|
||||
return manifest, entries, names, first
|
||||
|
||||
def test_platform_hub_trust_artifact_is_exact_and_build_free(self):
|
||||
manifest, entries, _names, result = self.assert_deterministic_artifact(
|
||||
"build-platform-device-core-hub-trust-artifact.mjs",
|
||||
"platform-device-core-hub-trust-unit-001",
|
||||
RUNNER.PLATFORM_DEVICE_CORE_HUB_TRUST_ENTRIES,
|
||||
)
|
||||
self.assertEqual(manifest["component"], "platform")
|
||||
self.assertEqual(RUNNER.component_services("platform", entries), ("launcher",))
|
||||
self.assertEqual(RUNNER.component_builds("platform", entries), ())
|
||||
self.assertEqual(result["services"], ["launcher"])
|
||||
|
||||
def test_launcher_session_artifact_is_exact(self):
|
||||
manifest, entries, _names, result = self.assert_deterministic_artifact(
|
||||
"build-launcher-device-core-artifact.mjs",
|
||||
"launcher-device-core-session-unit-001",
|
||||
RUNNER.LAUNCHER_DEVICE_CORE_SESSION_ENTRIES,
|
||||
)
|
||||
self.assertEqual(manifest["component"], "launcher")
|
||||
self.assertEqual(RUNNER.component_services("launcher", entries), ("launcher",))
|
||||
self.assertEqual(len(RUNNER.component_builds("launcher", entries)), 1)
|
||||
self.assertEqual(result["services"], ["launcher"])
|
||||
|
||||
def test_device_manager_artifact_selects_only_core_and_manager(self):
|
||||
manifest, entries, names, result = self.assert_deterministic_artifact(
|
||||
"build-device-manager-control-plane-artifact.mjs",
|
||||
"device-manager-control-plane-unit-001",
|
||||
RUNNER.DEVICE_PLANE_MANAGER_CONTROL_PLANE_ENTRIES,
|
||||
)
|
||||
self.assertEqual(manifest["component"], "device-plane")
|
||||
self.assertEqual(
|
||||
RUNNER.component_services("device-plane", entries),
|
||||
("device-control-core", "device-manager"),
|
||||
)
|
||||
builds = RUNNER.component_builds("device-plane", entries)
|
||||
self.assertEqual(len(builds), 2)
|
||||
self.assertIn(RUNNER.DEVICE_PLANE_CONTROL_CORE_IMAGE, builds[0][1])
|
||||
self.assertIn(RUNNER.DEVICE_PLANE_MANAGER_IMAGE, builds[1][1])
|
||||
self.assertIn("payload/services/device-manager/dist/index.html", names)
|
||||
self.assertIn(
|
||||
"payload/services/device-manager/server/device-manager-server.mjs",
|
||||
names,
|
||||
)
|
||||
self.assertFalse(any(name.endswith(".test.mjs") for name in names))
|
||||
self.assertEqual(result["services"], ["device-control-core", "device-manager"])
|
||||
self.assertNotIn("device-postgres", result["services"])
|
||||
self.assertIn("docker-compose.device-manager.yml", entries)
|
||||
self.assertNotIn("docker-compose.device-plane.yml", entries)
|
||||
checks = RUNNER.component_healthchecks("device-plane", entries, tuple(result["services"]))
|
||||
self.assertEqual(checks[0]["expected_json"]["managementApi"], "enabled")
|
||||
self.assertEqual(checks[0]["expected_json"]["discoveryIngest"], "enabled")
|
||||
|
||||
def test_public_route_artifact_is_last_and_proxy_only(self):
|
||||
manifest, entries, _names, result = self.assert_deterministic_artifact(
|
||||
"build-platform-device-manager-route-artifact.mjs",
|
||||
"platform-device-manager-route-unit-001",
|
||||
RUNNER.PLATFORM_DEVICE_MANAGER_PUBLIC_ROUTE_ENTRIES,
|
||||
)
|
||||
self.assertEqual(manifest["component"], "platform")
|
||||
self.assertEqual(RUNNER.component_services("platform", entries), ("reverse-proxy",))
|
||||
self.assertEqual(RUNNER.component_builds("platform", entries), ())
|
||||
self.assertEqual(result["services"], ["reverse-proxy"])
|
||||
|
||||
def test_runner_creates_only_file_backed_runtime_secrets(self):
|
||||
with mock.patch.object(RUNNER, "ensure_platform_runtime_secret") as ensure:
|
||||
RUNNER.prepare_component_runtime(
|
||||
"platform",
|
||||
RUNNER.PLATFORM_DEVICE_CORE_HUB_TRUST_ENTRIES,
|
||||
)
|
||||
self.assertEqual(
|
||||
[call.args[0] for call in ensure.call_args_list],
|
||||
[RUNNER.PLATFORM_DEVICE_CORE_INTERNAL_TOKEN_FILE],
|
||||
)
|
||||
|
||||
with mock.patch.object(RUNNER, "ensure_platform_runtime_secret") as ensure:
|
||||
RUNNER.prepare_component_runtime(
|
||||
"device-plane",
|
||||
RUNNER.DEVICE_PLANE_MANAGER_CONTROL_PLANE_ENTRIES,
|
||||
)
|
||||
self.assertEqual(
|
||||
[call.args[0] for call in ensure.call_args_list],
|
||||
[
|
||||
RUNNER.DEVICE_PLANE_POSTGRES_PASSWORD_FILE,
|
||||
RUNNER.DEVICE_PLANE_GATEWAY_CORE_TOKEN_FILE,
|
||||
RUNNER.DEVICE_PLANE_IDENTIFIER_PEPPER_FILE,
|
||||
RUNNER.DEVICE_PLANE_MANAGEMENT_CORE_TOKEN_FILE,
|
||||
RUNNER.PLATFORM_DEVICE_CORE_INTERNAL_TOKEN_FILE,
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(verbosity=2)
|
||||
Reference in New Issue
Block a user