Files
NODEDC_MISSION_CORE/plugins/insta360-x4/tests/check_runtime.py
T
DCCONSTRUCTIONS a3c15e11e9 Add packaged Insta360 X4 integration and recover paired Node channels
Discover independent camera instances and prepare their versioned runtime
from Node or remote Core. Add isolated SDK workers, camera controls, raw
dual-fisheye WebRTC preview, and shared action/region loading states.

Recover existing Node bindings over known Tailscale addresses after a Core
LAN address change. Preserve identities and trust, pin both peers, migrate
endpoints with revision checks, and require real heartbeats for online status.
Fix the Python client certificate profile for Go X509 verification.

Pin Design Guideline 8c53f73 and retain installer/build/acceptance history.
Node 0.8.19 is installed; X4 0.1.3-3 is bundled but hardware activation is pending.

Validation: qualified DG/Node builds and Go race tests; 31 fleet tests;
Python-to-Go certificate interoperability and live tailnet recovery with five
fresh heartbeats; prior 38 X4 tests and bounded remote WebRTC acceptance.
Clean-OS, replug/power autonomy, local X4 video and long-run stability remain open.
2026-09-10 09:21:24 +03:00

350 lines
14 KiB
Python

"""Qualification on Ubuntu using a freshly extracted pinned Python runtime.
Only fake camera calls are executed. No vendor SDK import, USB or system change.
"""
import hashlib
import io
import os
import sys
import tempfile
import threading
import time
import unittest
import uuid
import zipfile
from datetime import UTC, datetime, timedelta
from fractions import Fraction
from pathlib import Path
from unittest.mock import patch
ROOT = Path(__file__).resolve().parents[1]
sys.path[:0] = [str(ROOT), str(ROOT / "packaging")]
import prepare # noqa: E402
from runtime import broker, http, identity, operations, worker # noqa: E402
from runtime.verification import Control # noqa: E402
class VideoCamera:
def __init__(self, packets, preview=0, recording=0, stop_unknown=False):
self.packets = list(packets)
self.preview, self.recording = preview, recording
self.stop_unknown = stop_unknown
self.calls = []
self.sequence = 0
def call(self, action, values):
self.calls.append(action)
if action == "details":
return {
"state": "complete",
"result": {"connected": True, "preview": self.preview, "recording": self.recording},
}
if action == "preview.start":
self.preview = 1
if action == "preview.stop":
self.preview = 0
if self.stop_unknown:
return {"state": "unknown"}
return {"state": "complete", "result": {"ok": True}}
def video(self):
if not self.packets:
return None
self.sequence += 1
return {
"stream_index": 0,
"codec": 0,
"generation": 1,
"sequence": self.sequence,
}, self.packets.pop(0)
def synthetic_video(count=4):
import av
encoder = av.CodecContext.create("libx264", "w")
encoder.width, encoder.height = 32, 16
encoder.pix_fmt = "yuv420p"
encoder.time_base = Fraction(1, 30)
encoder.options = {"preset": "ultrafast", "tune": "zerolatency"}
output = []
for number in range(count):
frame = av.VideoFrame(32, 16, "yuv420p")
frame.pts = number
for index, plane in enumerate(frame.planes):
plane.update(bytes([16 if index == 0 else 128]) * plane.buffer_size)
output.extend(bytes(packet) for packet in encoder.encode(frame))
output.extend(bytes(packet) for packet in encoder.encode(None))
return output
class Camera:
def __init__(self):
self.calls = []
def call(self, action, values):
self.calls.append((action, values))
return {"state": "complete", "result": {"ok": True}}
def command(ident, session, action="record.start"):
now = datetime.now(UTC)
operation = "op_" + uuid.uuid4().hex
return {
"api_version": "missioncore.nodedc/plugin-sdk/v0alpha2",
"kind": "OperationRequest",
"operation_id": operation,
"idempotency_key": operation,
"session": {"device_id": ident, "session_id": session},
"action_id": action,
"requested_at": now.isoformat(),
"deadline_at": (now + timedelta(seconds=60)).isoformat(),
"parameters": {},
}
class RuntimeTests(unittest.TestCase):
def setUp(self):
self.temporary = tempfile.TemporaryDirectory(dir=ROOT / "build")
self.root = Path(self.temporary.name)
def tearDown(self):
self.temporary.cleanup()
def test_verification_uses_live_source_and_deduplicates_across_preview_states(self):
value = broker.Broker()
ident, session = identity.device_id("SYNTHETIC-A"), "session_one"
current = {
"id": ident,
"session_id": session,
"online": True,
"status": {"preview": 1, "recording": 0},
}
calls = []
class Engine:
def verify(self, key):
calls.append(key)
return {"state": "complete", "result": {"verified": True}}
value.media = Engine()
sdk = []
def request(path, route, command=None, **kwargs):
if route == "/snapshot":
return current
sdk.append(command)
return {"state": "complete", "result": {"verified": True}}
first = command(ident, session, "verify")
with patch.object(broker, "STATE", self.root), patch.object(broker, "request", request):
self.assertEqual(value.verify_operation(ident, first)["state"], "complete")
current["status"]["preview"] = 0
self.assertEqual(value.verify_operation(ident, first)["state"], "complete")
self.assertEqual(len(calls), 1)
self.assertFalse(sdk)
second = command(ident, session, "verify")
self.assertEqual(value.verify_operation(ident, second)["state"], "complete")
self.assertEqual(sdk, [second])
current["status"]["recording"] = 1
refused = value.verify_operation(ident, command(ident, session, "verify"))
self.assertIn("остановите запись", refused["error"])
self.assertEqual(len(sdk), 1)
def test_error_translation_preserves_verification_reason_and_redacts_vendor_text(self):
class Failed:
error = "preview_no_decodable_image"
def call(self, action, params):
return {"state": "error", "error": self.error}
camera = Failed()
ident = identity.device_id("SYNTHETIC-A")
runtime = operations.Operations(ident, "session_one", self.root, camera)
result = runtime.execute(command(ident, "session_one", "verify"))
self.assertEqual(result["error"], "Камера не передала декодируемое изображение.")
camera.error = "PRIVATE VENDOR DEVICE IDENTIFIER"
result = runtime.execute(command(ident, "session_one", "verify"))
self.assertEqual(result["error"], "Не удалось выполнить команду камеры.")
camera.error = "unsupported_camera_parameter"
result = runtime.execute(command(ident, "session_one", "verify"))
self.assertEqual(result, operations.INVALID)
def test_receipt_deduplicates_start_after_worker_recreation(self):
camera = Camera()
ident = identity.device_id("SYNTHETIC-A")
original = operations.Operations(ident, "session_one", self.root, camera)
value = command(ident, "session_one")
self.assertEqual(original.execute(value)["state"], "complete")
resumed = operations.Operations(ident, "session_two", self.root, camera)
self.assertEqual(resumed.execute(value)["state"], "complete")
self.assertEqual(len(camera.calls), 1)
def test_two_instances_never_share_commands_or_receipts(self):
first, second = Camera(), Camera()
a, b = identity.device_id("SYNTHETIC-A"), identity.device_id("SYNTHETIC-B")
left = operations.Operations(a, "session_a", self.root / "a", first)
right = operations.Operations(b, "session_b", self.root / "b", second)
value = command(a, "session_a")
left.execute(value)
with self.assertRaises(ValueError):
right.execute(value)
self.assertEqual(len(first.calls), 1)
self.assertEqual(second.calls, [])
def test_expired_or_stale_session_has_no_sdk_effect(self):
camera = Camera()
ident = identity.device_id("SYNTHETIC-A")
runtime = operations.Operations(ident, "session_two", self.root, camera)
for value in [command(ident, "session_one"), command(ident, "session_two")]:
if value["session"]["session_id"] == "session_two":
value["requested_at"] = (datetime.now(UTC) - timedelta(seconds=90)).isoformat()
value["deadline_at"] = (datetime.now(UTC) - timedelta(seconds=10)).isoformat()
with self.assertRaises(ValueError):
runtime.execute(value)
self.assertEqual(camera.calls, [])
def test_sd_recording_and_unknown_status_block_profile_replacement(self):
binding = identity.Binding(identity.device_id("SYNTHETIC"), "1-2", 1, 2, "SYNTHETIC")
instance = worker.Worker(binding, self.root, self.root)
instance.ready = True
for recording, preview, expected in [
(0, 0, True),
(1, 0, False),
(-1, 0, False),
(0, 1, False),
]:
instance.status = {"connected": True, "recording": recording, "preview": preview}
instance.observed = time.monotonic()
self.assertEqual(instance.snapshot()["preparation_safe"], expected)
instance.observed = 0
self.assertFalse(instance.snapshot()["preparation_safe"])
def test_installer_fails_closed_when_worker_exists_but_broker_is_missing(self):
instances = self.root / "instances"
instances.mkdir()
(instances / identity.device_id("SYNTHETIC")).mkdir()
with (
patch.object(prepare, "SOCKET", self.root / "absent.sock"),
patch.object(prepare, "INSTANCES", instances),
self.assertRaises(RuntimeError),
):
prepare.assert_safe()
def test_installer_refuses_active_recording_even_if_preview_idle(self):
socket = self.root / "driver.sock"
socket.touch()
with (
patch.object(prepare, "SOCKET", socket),
patch.object(prepare, "request", return_value={"safe": False}),
self.assertRaises(RuntimeError),
):
prepare.assert_safe()
def test_runtime_integrity_rechecks_existing_install(self):
files = {"lib/synthetic.so": b"SYNTHETIC-NOT-AN-ELF", "python/example.py": b"value = 1\n"}
data = io.BytesIO()
with zipfile.ZipFile(data, "w") as archive:
for name, content in files.items():
archive.writestr(name, content)
payload = data.getvalue()
share, state = self.root / "share", self.root / "state"
share.mkdir()
state.mkdir()
(share / "payload.zip").write_bytes(payload)
bundle = {
"revision": "a" * 24,
"payload_sha256": hashlib.sha256(payload).hexdigest(),
"files": {
name: {"bytes": len(content), "sha256": hashlib.sha256(content).hexdigest()}
for name, content in files.items()
},
}
def directory(path):
path.mkdir(exist_ok=True)
with (
patch.object(prepare, "STATE", state),
patch.object(prepare, "SHARE", share),
patch.object(prepare, "trusted", side_effect=lambda path, directory=False: path),
patch.object(prepare, "directory", side_effect=directory),
):
ident = prepare.install_runtime(bundle)
self.assertEqual(prepare.install_runtime(bundle), ident)
(state / "runtime" / ident / "python/example.py").write_bytes(b"modified")
with self.assertRaises(RuntimeError):
prepare.install_runtime(bundle)
def test_payload_rejects_traversal_before_extraction(self):
data = io.BytesIO()
with zipfile.ZipFile(data, "w") as archive:
archive.writestr("../escape", b"synthetic")
info = {"bytes": 9, "sha256": hashlib.sha256(b"synthetic").hexdigest()}
with (
zipfile.ZipFile(io.BytesIO(data.getvalue())) as archive,
self.assertRaises(RuntimeError),
):
list(prepare.entries(archive, {"files": {"../escape": info}}))
self.assertFalse((self.root.parent / "escape").exists())
def test_private_socket_checks_kernel_peer_credentials(self):
# Keep the socket in owned staging through a short directory-FD alias;
# Linux sockaddr_un cannot hold the long build-source pathname.
descriptor = os.open(self.root, os.O_RDONLY)
self.addCleanup(os.close, descriptor)
for allowed, success in [({os.geteuid()}, True), ({os.geteuid() + 10000}, False)]:
path = Path(f"/proc/self/fd/{descriptor}") / ("yes.sock" if success else "no.sock")
server = http.Server(path, lambda *_: {"ok": True}, allowed)
thread = threading.Thread(target=server.serve_forever, kwargs={"poll_interval": 0.01})
thread.start()
try:
if success:
self.assertTrue(http.request(path, "/snapshot")["ok"])
else:
with self.assertRaises((OSError, http.http.client.HTTPException)):
http.request(path, "/snapshot")
finally:
server.shutdown()
server.server_close()
thread.join(2)
self.assertFalse(thread.is_alive())
def test_worker_routes_never_accept_arbitrary_device_paths(self):
for value in ("../another.sock", "/run/driver.sock", "instax4_bad", None):
with self.assertRaises(ValueError):
broker.worker_socket(value)
def test_verification_requires_decoded_images_and_only_closes_own_preview(self):
camera = VideoCamera(synthetic_video())
control = Control(camera)
result = control.verify(timeout=1)
self.assertEqual(result["state"], "complete")
self.assertTrue(control.verified)
self.assertGreaterEqual(result["result"]["streams"][0]["frames"], 2)
self.assertEqual(result["result"]["streams"][0]["width"], 32)
self.assertEqual(camera.calls, ["details", "preview.start", "preview.stop"])
existing = VideoCamera(synthetic_video(), preview=1)
self.assertEqual(Control(existing).verify(timeout=1)["state"], "complete")
self.assertEqual(existing.calls, ["details"])
def test_packets_and_unconfirmed_preview_cleanup_are_not_verified(self):
broken = VideoCamera([b"SYNTHETIC-NOT-VIDEO"])
control = Control(broken)
self.assertEqual(control.verify(timeout=0.03)["state"], "error")
self.assertFalse(control.verified)
uncertain = VideoCamera(synthetic_video(), stop_unknown=True)
control = Control(uncertain)
self.assertEqual(control.verify(timeout=1)["state"], "unknown")
self.assertFalse(control.verified)
def test_image_verification_does_not_interrupt_sd_recording(self):
camera = VideoCamera([], recording=1)
self.assertEqual(Control(camera).verify(timeout=0.03)["state"], "error")
self.assertEqual(camera.calls, ["details"])
if __name__ == "__main__":
unittest.main(verbosity=2)