157 lines
5.2 KiB
Python
157 lines
5.2 KiB
Python
#!/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
|
|
|
|
|
|
SCRIPT_DIR = Path(__file__).resolve().parent
|
|
BUILDER = SCRIPT_DIR / "build-device-plane-artifact.mjs"
|
|
RUNNER_PATH = SCRIPT_DIR / "nodedc-deploy"
|
|
EXPECTED_ENTRIES = [
|
|
".dockerignore",
|
|
"package.json",
|
|
"package-lock.json",
|
|
"docker-compose.device-plane.yml",
|
|
"packages/device-protocol-contract",
|
|
"packages/arusnavi-b2-adapter",
|
|
"services/device-control-core",
|
|
"services/device-gateway",
|
|
]
|
|
|
|
|
|
def load_runner():
|
|
loader = importlib.machinery.SourceFileLoader(
|
|
"nodedc_device_plane_artifact_runner_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 DevicePlaneArtifactTest(unittest.TestCase):
|
|
def build(self, artifact_dir, patch_id):
|
|
environment = os.environ.copy()
|
|
environment["NODEDC_DEPLOY_ARTIFACT_DIR"] = str(artifact_dir)
|
|
result = subprocess.run(
|
|
["node", str(BUILDER), patch_id],
|
|
check=True,
|
|
capture_output=True,
|
|
text=True,
|
|
env=environment,
|
|
)
|
|
return json.loads(result.stdout)
|
|
|
|
def test_artifact_is_narrow_safe_and_deterministic(self):
|
|
with tempfile.TemporaryDirectory(
|
|
prefix="nodedc-device-plane-artifact-",
|
|
) as directory:
|
|
artifact_dir = Path(directory)
|
|
first = self.build(
|
|
artifact_dir,
|
|
"device-plane-foundation-unit-001",
|
|
)
|
|
artifact = Path(first["artifact"])
|
|
first_bytes = artifact.read_bytes()
|
|
second = self.build(
|
|
artifact_dir,
|
|
"device-plane-foundation-unit-001",
|
|
)
|
|
second_bytes = Path(second["artifact"]).read_bytes()
|
|
|
|
self.assertEqual(first["component"], "device-plane")
|
|
self.assertEqual(first["entries"], EXPECTED_ENTRIES)
|
|
self.assertEqual(
|
|
first["services"],
|
|
["device-control-core", "device-gateway"],
|
|
)
|
|
self.assertEqual(
|
|
first["sha256"],
|
|
hashlib.sha256(first_bytes).hexdigest(),
|
|
)
|
|
self.assertEqual(first["sha256"], second["sha256"])
|
|
self.assertEqual(first_bytes, second_bytes)
|
|
|
|
with tarfile.open(artifact, "r:gz") as archive:
|
|
members = archive.getmembers()
|
|
names = {member.name for member in members}
|
|
files = (
|
|
archive.extractfile("files.txt")
|
|
.read()
|
|
.decode("utf-8")
|
|
.splitlines()
|
|
)
|
|
manifest = (
|
|
archive.extractfile("manifest.env")
|
|
.read()
|
|
.decode("utf-8")
|
|
)
|
|
compose = (
|
|
archive.extractfile(
|
|
"payload/docker-compose.device-plane.yml",
|
|
)
|
|
.read()
|
|
.decode("utf-8")
|
|
)
|
|
regular_payloads = [
|
|
archive.extractfile(member).read()
|
|
for member in members
|
|
if member.isfile()
|
|
]
|
|
|
|
self.assertEqual(files, EXPECTED_ENTRIES)
|
|
self.assertEqual(
|
|
manifest,
|
|
"id=device-plane-foundation-unit-001\n"
|
|
"component=device-plane\n"
|
|
"type=app-overlay\n",
|
|
)
|
|
self.assertIn(
|
|
"payload/services/device-control-core/Dockerfile",
|
|
names,
|
|
)
|
|
self.assertIn(
|
|
"payload/services/device-gateway/Dockerfile",
|
|
names,
|
|
)
|
|
self.assertFalse(any(
|
|
"/test/" in name
|
|
or "/node_modules/" in name
|
|
or Path(name).name.startswith(".env")
|
|
or name.startswith("payload/docs/")
|
|
or name.startswith("payload/runtime/")
|
|
or name.startswith("payload/secrets/")
|
|
for name in names
|
|
))
|
|
self.assertNotIn("9921:9921", compose)
|
|
self.assertIn('DEVICE_GATEWAY_LISTEN_ENABLED: "false"', compose)
|
|
self.assertIn('DEVICE_DISCOVERY_INGEST_ENABLED: "false"', compose)
|
|
self.assertNotIn(b"-----BEGIN PRIVATE KEY-----", b"\n".join(
|
|
regular_payloads,
|
|
))
|
|
|
|
with tempfile.TemporaryDirectory(
|
|
prefix="nodedc-device-plane-runner-load-",
|
|
) as work_directory:
|
|
manifest_loaded, entries_loaded, payload_loaded = (
|
|
RUNNER.load_artifact(artifact, Path(work_directory))
|
|
)
|
|
self.assertEqual(manifest_loaded["component"], "device-plane")
|
|
self.assertEqual(entries_loaded, EXPECTED_ENTRIES)
|
|
self.assertEqual(payload_loaded.name, "payload")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main(verbosity=2)
|