import assert from "node:assert/strict"; import { after, before, test } from "node:test"; import { createServer } from "vite"; let server; let parseDevicePluginManifest; let createDevicePluginRegistry; let xgridsK1Manifest; let xgridsK1Actions; let xgridsK1Api; let lifecycle; before(async () => { server = await createServer({ appType: "custom", logLevel: "silent", server: { middlewareMode: true }, }); ({ parseDevicePluginManifest } = await server.ssrLoadModule( "/src/core/device-plugins/manifestParser.ts", )); ({ createDevicePluginRegistry } = await server.ssrLoadModule( "/src/core/device-plugins/registry.ts", )); ({ xgridsK1Manifest, xgridsK1Actions } = await server.ssrLoadModule( "/src/device-plugins/xgrids-k1/manifest.ts", )); lifecycle = await server.ssrLoadModule( "/src/device-plugins/xgrids-k1/lifecycle.ts", ); ({ xgridsK1Api } = await server.ssrLoadModule( "/src/device-plugins/xgrids-k1/api.ts", )); }); after(async () => { await server?.close(); }); function manifestDocument({ apiVersion = "missioncore.nodedc/v1alpha1", pluginId = "test.device.plugin", modelId = "test.device.model", } = {}) { const v1alpha2 = apiVersion === "missioncore.nodedc/v1alpha2"; return { apiVersion, kind: "DevicePlugin", metadata: { id: pluginId, version: "1.0.0", displayName: "Test device", }, spec: { hostApiRange: v1alpha2 ? "v1alpha2" : "v1alpha1", runtime: { backendEntrypoint: "test.plugin:build", isolation: "transitional-in-process", }, ...(v1alpha2 ? { compatibilityProfiles: [ { profileId: `${modelId}.fw-1.v1`, path: "profiles/fw-1/profile.v1.json", modelId, }, ], } : {}), permissions: ["device.read"], actions: [{ id: "state.read", mutating: false, secretFields: [] }], models: [ { id: modelId, vendor: "Test", displayName: "Test model", category: "Sensor", description: "Fixture model", verified: true, capabilities: [{ id: "device.read", label: "Read" }], ui: { slot: "device.connection", componentKey: "test.connection" }, }, ], }, }; } function uiPlugin(manifest) { return { manifest, RuntimeProvider: ({ children }) => children, connectionViews: { "test.connection": () => null }, }; } test("parser accepts reviewed v1alpha1 and v1alpha2 shapes", () => { const legacy = parseDevicePluginManifest(manifestDocument()); const current = parseDevicePluginManifest( manifestDocument({ apiVersion: "missioncore.nodedc/v1alpha2" }), ); assert.equal(legacy.apiVersion, "missioncore.nodedc/v1alpha1"); assert.equal(legacy.spec.hostApiRange, "v1alpha1"); assert.equal(current.apiVersion, "missioncore.nodedc/v1alpha2"); assert.equal(current.spec.hostApiRange, "v1alpha2"); assert.deepEqual(current.spec.compatibilityProfiles, [ { profileId: "test.device.model.fw-1.v1", path: "profiles/fw-1/profile.v1.json", modelId: "test.device.model", }, ]); }); test("v1alpha1 keeps the original nonblank identifier compatibility", () => { const legacyDocument = manifestDocument({ pluginId: "legacy plugin id", modelId: "legacy model id", }); legacyDocument.spec.permissions = ["legacy permission"]; legacyDocument.spec.actions[0].secretFields = ["legacy secret field"]; legacyDocument.spec.models[0].capabilities = [ { id: "legacy capability", label: "Legacy" }, ]; const legacy = parseDevicePluginManifest(legacyDocument); assert.equal(legacy.metadata.id, "legacy plugin id"); assert.equal(legacy.spec.models[0].id, "legacy model id"); assert.deepEqual(legacy.spec.permissions, ["legacy permission"]); }); test("v1alpha2 applies strict identifiers without redefining v1alpha1", () => { const current = manifestDocument({ apiVersion: "missioncore.nodedc/v1alpha2", pluginId: "current plugin id", }); assert.throws( () => parseDevicePluginManifest(current), /не является идентификатором/, ); }); test("v1alpha2 parser and registry accept multiple independently profiled models", () => { const document = manifestDocument({ apiVersion: "missioncore.nodedc/v1alpha2", pluginId: "test.family", modelId: "test.family.model-a", }); document.spec.models.push({ ...document.spec.models[0], id: "test.family.model-b", displayName: "Test model B", }); document.spec.compatibilityProfiles.push({ profileId: "test.family.model-b.fw-1.v1", path: "profiles/fw-1/model-b.v1.json", modelId: "test.family.model-b", }); const manifest = parseDevicePluginManifest(document); const plugin = { ...uiPlugin(manifest), connectionViews: { "test.connection": () => null }, }; const registry = createDevicePluginRegistry([plugin]); assert.deepEqual(registry.models.map(({ model }) => model.id), [ "test.family.model-a", "test.family.model-b", ]); }); test("installed XGRIDS frontend manifest exposes the semantic v1alpha2 actions", () => { assert.equal(xgridsK1Manifest.apiVersion, "missioncore.nodedc/v1alpha2"); assert.deepEqual(xgridsK1Manifest.spec.compatibilityProfiles, [ { profileId: "xgrids.lixelkity-k1.fw-3.0.2.direct-lan.v1", path: "profiles/fw-3.0.2/direct-lan.v1.json", modelId: "xgrids.lixelkity-k1", }, ]); assert.equal(xgridsK1Actions.acquisitionPrepare, "acquisition.prepare"); assert.equal(xgridsK1Actions.acquisitionStart, "acquisition.start"); assert.equal(xgridsK1Actions.acquisitionStop, "acquisition.stop"); }); test("v1alpha2 compatibility profile is exact-key and rejects duplicated profile status", () => { const document = manifestDocument({ apiVersion: "missioncore.nodedc/v1alpha2" }); document.spec.compatibilityProfiles[0].status = "verified"; assert.throws( () => parseDevicePluginManifest(document), /неизвестные поля status/, ); }); test("v1alpha2 compatibility profile fails closed on unsafe paths", () => { const document = manifestDocument({ apiVersion: "missioncore.nodedc/v1alpha2" }); document.spec.compatibilityProfiles[0].path = "../private/profile.json"; assert.throws( () => parseDevicePluginManifest(document), /безопасным относительным JSON-путём/, ); }); test("v1alpha2 compatibility profile cannot reference an unknown model", () => { const document = manifestDocument({ apiVersion: "missioncore.nodedc/v1alpha2" }); document.spec.compatibilityProfiles[0].modelId = "missing.model"; assert.throws( () => parseDevicePluginManifest(document), /ссылается на неизвестную модель missing\.model/, ); }); test("registry accepts v1alpha1 and v1alpha2 plugins together", () => { const legacy = parseDevicePluginManifest( manifestDocument({ pluginId: "test.legacy", modelId: "test.legacy.model" }), ); const current = parseDevicePluginManifest( manifestDocument({ apiVersion: "missioncore.nodedc/v1alpha2", pluginId: "test.current", modelId: "test.current.model", }), ); const registry = createDevicePluginRegistry([uiPlugin(legacy), uiPlugin(current)]); assert.equal(registry.plugins.length, 2); assert.equal(registry.models.length, 2); assert.equal(registry.resolveModel("test.current.model")?.plugin.manifest.metadata.id, "test.current"); }); test("registry independently rejects an uncovered v1alpha2 model", () => { const current = parseDevicePluginManifest( manifestDocument({ apiVersion: "missioncore.nodedc/v1alpha2" }), ); current.spec.compatibilityProfiles[0].modelId = "missing.model"; assert.throws( () => createDevicePluginRegistry([uiPlugin(current)]), /ссылается на неизвестную модель missing\.model/, ); }); test("live source is confirmed only by an acquiring acquisition", () => { const waiting = { source_mode: "live", phase: "live", acquisition: { state: "awaiting_external_start" }, }; const acquiring = { ...waiting, acquisition: { state: "acquiring" }, }; assert.equal(lifecycle.isConfirmedLiveState(waiting), false); assert.equal(lifecycle.confirmedRuntimeSourceMode(waiting), "idle"); assert.equal(lifecycle.sourceStatusLabel(waiting), "Ожидание реальных данных"); assert.equal(lifecycle.isConfirmedLiveState(acquiring), true); assert.equal(lifecycle.confirmedRuntimeSourceMode(acquiring), "live"); }); test("prepared acquisition resumes without another prepare and remains recoverable", () => { const prepared = { source_mode: "idle", acquisition: { acquisition_id: "acq-1", state: "prepared", }, }; assert.equal(lifecycle.liveStartPlan(prepared), "resume-prepared"); assert.equal(lifecycle.recoverableAcquisition(prepared)?.acquisition_id, "acq-1"); }); test("replay ignores a stale failed live acquisition", () => { const replay = { source_mode: "replay", phase: "replay", rerun_grpc_url: "rerun+http://127.0.0.1:9876/proxy", acquisition: { acquisition_id: "old-live-acquisition", state: "failed", }, }; assert.equal(lifecycle.normalizeRuntimePhase(replay), "replaying"); assert.equal(lifecycle.effectiveAcquisition(replay), null); assert.equal( lifecycle.spatialSourceId(replay, replay.rerun_grpc_url), `replay:${replay.rerun_grpc_url}`, ); }); test("provisioning intent keeps one idempotency key and exposes unsafe outcomes", () => { let created = 0; const createUuid = () => { created += 1; return "11111111-1111-4111-8111-111111111111"; }; const first = lifecycle.provisioningIntentKey(null, createUuid); const repeated = lifecycle.provisioningIntentKey(first, createUuid); const failedOperation = { status: "failed", error: { safe_to_retry: false }, }; assert.equal(first, "network-provision:11111111-1111-4111-8111-111111111111"); assert.equal(repeated, first); assert.equal(created, 1); assert.equal(lifecycle.operationNeedsReconciliation(failedOperation), true); }); test("device mutations send explicit nested compatibility attestation", async () => { const originalFetch = globalThis.fetch; const calls = []; const syntheticCredential = "x".repeat(32); globalThis.fetch = async (path, init) => { calls.push({ path, init }); return new Response(JSON.stringify({ state: { source_mode: "idle" } }), { status: 200, headers: { "Content-Type": "application/json" }, }); }; const attestation = { firmware_version: "3.0.2", topology: "direct-lan", operator_confirmed: true, }; try { await xgridsK1Api.connect({ device_id: "ble-device", ssid: "lab-network", password: syntheticCredential, compatibility_attestation: attestation, idempotency_key: "network-provision:test", }); await xgridsK1Api.prepareAcquisition({ compatibility_attestation: attestation, }); } finally { globalThis.fetch = originalFetch; } assert.equal(calls.length, 2); const provisioning = JSON.parse(calls[0].init.body); const prepare = JSON.parse(calls[1].init.body); assert.deepEqual(provisioning.input.compatibility_attestation, attestation); assert.equal(provisioning.input.idempotency_key, "network-provision:test"); assert.deepEqual(prepare.input.compatibility_attestation, attestation); });