104 lines
3.4 KiB
JavaScript
104 lines
3.4 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
|
|
import {
|
|
createDeviceCoreClient,
|
|
createLocalPreviewDeviceCore,
|
|
} from "./device-core-client.mjs";
|
|
|
|
const token = "device-core-test-token-that-is-never-exposed";
|
|
const actor = Object.freeze({
|
|
userRef: "user:device-admin",
|
|
hubRole: "admin",
|
|
groupRefs: ["group:device-engineers"],
|
|
ownerScopes: [{ scopeKind: "personal", ownerRef: "user:device-admin" }],
|
|
});
|
|
|
|
test("Device Core client creates trusted actor headers and keeps its token server-side", async () => {
|
|
const calls = [];
|
|
const client = createDeviceCoreClient({
|
|
baseUrl: "http://device-control-core:3210",
|
|
token,
|
|
fetchImpl: async (url, init) => {
|
|
calls.push({ url: String(url), init });
|
|
return jsonResponse(200, { ok: true, projects: [] });
|
|
},
|
|
});
|
|
|
|
assert.deepEqual(await client.listProjects(actor), []);
|
|
assert.equal(calls.length, 1);
|
|
assert.equal(calls[0].init.headers.Authorization, `Bearer ${token}`);
|
|
assert.equal(calls[0].init.headers["X-NODEDC-User-Ref"], actor.userRef);
|
|
assert.equal(calls[0].init.headers["X-NODEDC-Hub-Role"], "admin");
|
|
assert.equal(calls[0].init.headers["X-NODEDC-Group-Refs"], "group:device-engineers");
|
|
assert.equal(
|
|
calls[0].init.headers["X-NODEDC-Owner-Scopes"],
|
|
"personal=user:device-admin",
|
|
);
|
|
assert.equal(JSON.stringify(await client.listProjects(actor)).includes(token), false);
|
|
});
|
|
|
|
test("Device Core client accepts only canonical commands and entity refs", async () => {
|
|
const client = createDeviceCoreClient({
|
|
baseUrl: "http://127.0.0.1:3210",
|
|
token,
|
|
fetchImpl: async () => jsonResponse(200, { ok: true, replayed: false, result: {} }),
|
|
});
|
|
|
|
await assert.rejects(
|
|
client.execute("raw:proxy", actor, {}, "device-manager-12345678"),
|
|
/device_manager_command_invalid/,
|
|
);
|
|
await assert.rejects(
|
|
client.getWorkspace(actor, "project:not-a-uuid"),
|
|
/device_project_ref_invalid/,
|
|
);
|
|
await assert.rejects(
|
|
client.execute("projects:ensure", actor, {}, "short"),
|
|
/device_idempotency_key_invalid/,
|
|
);
|
|
});
|
|
|
|
test("local preview is empty and creates resources only through canonical commands", async () => {
|
|
const client = createLocalPreviewDeviceCore();
|
|
assert.deepEqual(await client.listProjects(actor), []);
|
|
|
|
const owner = await client.execute("owner-scopes:ensure", actor, {
|
|
scopeKind: "personal",
|
|
ownerRef: actor.userRef,
|
|
displayName: "Device Admin",
|
|
});
|
|
assert.equal(owner.result.created, true);
|
|
|
|
const created = await client.execute("projects:ensure", actor, {
|
|
scopeKind: "personal",
|
|
ownerRef: actor.userRef,
|
|
projectKey: "sandbox",
|
|
name: "Device sandbox",
|
|
description: null,
|
|
});
|
|
assert.equal(created.result.created, true);
|
|
const projectRef = created.result.project.projectRef;
|
|
|
|
await client.execute("collections:ensure", actor, {
|
|
projectRef,
|
|
collectionKey: "field-devices",
|
|
name: "Field devices",
|
|
description: null,
|
|
});
|
|
|
|
const projects = await client.listProjects(actor);
|
|
assert.equal(projects.length, 1);
|
|
assert.equal(projects[0].counts.collections, 1);
|
|
const workspace = await client.getWorkspace(actor, projectRef);
|
|
assert.equal(workspace.collections[0].collectionKey, "field-devices");
|
|
assert.deepEqual(workspace.devices, []);
|
|
});
|
|
|
|
function jsonResponse(status, body) {
|
|
return new Response(JSON.stringify(body), {
|
|
status,
|
|
headers: { "content-type": "application/json" },
|
|
});
|
|
}
|