Test fixtures: the Rust owner's Idunn runtime records, and one fake Idunn RUDP endpoint
tests/fixtures/idunn-runtime holds expected.cc, activation.cc, the activation seed, the presence identity credential and the machine-id it is bound to, copied from CultLib 217a9480 (Rust-written; test keys only). fake-idunn-rudp.ts is the accept server idunn-rudp-health.test.ts built inline, now keeping a session per remote and every delivered frame, so a boot test can receive several pulses. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
e8548614c8
commit
c0d30e8081
9 changed files with 83 additions and 36 deletions
64
tests/fixtures/fake-idunn-rudp.ts
vendored
Normal file
64
tests/fixtures/fake-idunn-rudp.ts
vendored
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
* A stand-in for Idunn's health endpoint: it accepts each RUDP connect, acks
|
||||
* the frame that follows and keeps every delivered frame. Heimdall opens a
|
||||
* fresh socket and session per publication, so sessions are kept per remote.
|
||||
*/
|
||||
import dgram from "node:dgram";
|
||||
import {
|
||||
CultNetRudpSession,
|
||||
decodeRudpPacket,
|
||||
encodeRudpPacket,
|
||||
type CultNetTransportFrame,
|
||||
} from "cultnet-ts";
|
||||
|
||||
export interface FakeIdunnRudp {
|
||||
port: number;
|
||||
frames: CultNetTransportFrame[];
|
||||
/** Resolves with the nth delivered frame (0-based) once it has arrived. */
|
||||
frame(index: number): Promise<CultNetTransportFrame>;
|
||||
close(): void;
|
||||
}
|
||||
|
||||
export async function startFakeIdunnRudp(): Promise<FakeIdunnRudp> {
|
||||
const server = dgram.createSocket("udp4");
|
||||
const sessions = new Map<string, CultNetRudpSession>();
|
||||
const frames: CultNetTransportFrame[] = [];
|
||||
const waiting: Array<{ index: number; resolve: (frame: CultNetTransportFrame) => void }> = [];
|
||||
|
||||
server.on("message", (wire, remote) => {
|
||||
const packet = decodeRudpPacket(wire);
|
||||
const key = `${remote.address}:${remote.port}`;
|
||||
if (packet.packetType === "connect") {
|
||||
const session = new CultNetRudpSession({
|
||||
connectionId: 0x1d0d0001,
|
||||
initialSequence: 1,
|
||||
resendDelayMs: 100,
|
||||
});
|
||||
sessions.set(key, session);
|
||||
server.send(encodeRudpPacket(session.acceptConnect(packet, Date.now())), remote.port, remote.address);
|
||||
return;
|
||||
}
|
||||
const session = sessions.get(key);
|
||||
if (!session) return;
|
||||
const result = session.receive(packet, Date.now());
|
||||
if (result.reply) server.send(encodeRudpPacket(result.reply), remote.port, remote.address);
|
||||
for (const frame of result.delivered) {
|
||||
frames.push(frame);
|
||||
for (const waiter of waiting.filter((entry) => entry.index === frames.length - 1)) waiter.resolve(frame);
|
||||
}
|
||||
if (result.delivered.length > 0) {
|
||||
server.send(encodeRudpPacket(session.createAck()), remote.port, remote.address);
|
||||
}
|
||||
});
|
||||
await new Promise<void>((resolve) => server.bind(0, "127.0.0.1", resolve));
|
||||
|
||||
return {
|
||||
port: server.address().port,
|
||||
frames,
|
||||
frame: (index) =>
|
||||
frames[index]
|
||||
? Promise.resolve(frames[index]!)
|
||||
: new Promise((resolve) => waiting.push({ index, resolve })),
|
||||
close: () => server.close(),
|
||||
};
|
||||
}
|
||||
1
tests/fixtures/idunn-runtime/.gitattributes
vendored
Normal file
1
tests/fixtures/idunn-runtime/.gitattributes
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
* -text
|
||||
11
tests/fixtures/idunn-runtime/README.md
vendored
Normal file
11
tests/fixtures/idunn-runtime/README.md
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# Idunn runtime fixtures
|
||||
|
||||
Written by the Rust owner, not by Heimdall's tests. Copied byte for byte from CultLib
|
||||
`217a9480`, `packages/cultnet-ts/test/fixtures/idunn-runtime/web` (`expected.cc`,
|
||||
`activation.cc`, `activation-key.seed`, `provider-identity.credential`) and that directory's
|
||||
`machine-id`. CultLib regenerates them with `packages/cultnet-rs/examples/idunn_runtime_fixture.rs`
|
||||
(its own README has the Yggdrasil command); the provider identity is bound to `machine-id`, so a
|
||||
test that decodes it supplies that machine id instead of `/etc/machine-id`.
|
||||
|
||||
Every key here is a test key. `provider-identity.credential` is the shape Idunn passes on the
|
||||
presence-identity descriptor: key fields are 32-integer arrays, which only the Rust owner writes.
|
||||
1
tests/fixtures/idunn-runtime/activation-key.seed
vendored
Normal file
1
tests/fixtures/idunn-runtime/activation-key.seed
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
¯ÂOd×f¯l*oµ‘ÀFªv‰n<E280B0>hLûÑpšS´p
|
||||
BIN
tests/fixtures/idunn-runtime/activation.cc
vendored
Normal file
BIN
tests/fixtures/idunn-runtime/activation.cc
vendored
Normal file
Binary file not shown.
BIN
tests/fixtures/idunn-runtime/expected.cc
vendored
Normal file
BIN
tests/fixtures/idunn-runtime/expected.cc
vendored
Normal file
Binary file not shown.
1
tests/fixtures/idunn-runtime/machine-id
vendored
Normal file
1
tests/fixtures/idunn-runtime/machine-id
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1
|
||||
BIN
tests/fixtures/idunn-runtime/provider-identity.credential
vendored
Normal file
BIN
tests/fixtures/idunn-runtime/provider-identity.credential
vendored
Normal file
Binary file not shown.
|
|
@ -1,18 +1,12 @@
|
|||
import dgram from "node:dgram";
|
||||
import { mkdtemp } from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { decode } from "@msgpack/msgpack";
|
||||
import {
|
||||
CultNetRudpSession,
|
||||
decodeRudpPacket,
|
||||
encodeRudpPacket,
|
||||
parseCultNetMessage,
|
||||
type CultNetTransportFrame,
|
||||
} from "cultnet-ts";
|
||||
import { parseCultNetMessage } from "cultnet-ts";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { loadConfig } from "../src/config.js";
|
||||
import { publishIdunnRudpHealth } from "../src/idunn-rudp-health.js";
|
||||
import { startFakeIdunnRudp } from "./fixtures/fake-idunn-rudp.js";
|
||||
|
||||
vi.mock("node:fs/promises", async (importOriginal) => {
|
||||
const original = await importOriginal<typeof import("node:fs/promises")>();
|
||||
|
|
@ -27,37 +21,12 @@ vi.mock("node:fs/promises", async (importOriginal) => {
|
|||
|
||||
describe("Heimdall Idunn health publication", () => {
|
||||
it("completes the canonical RUDP handshake before publishing its signed frame", async () => {
|
||||
const server = dgram.createSocket("udp4");
|
||||
const session = new CultNetRudpSession({
|
||||
connectionId: 0x1d0d0001,
|
||||
initialSequence: 1,
|
||||
resendDelayMs: 100,
|
||||
});
|
||||
let resolveFrame!: (frame: CultNetTransportFrame) => void;
|
||||
const frameReceived = new Promise<CultNetTransportFrame>((resolve) => {
|
||||
resolveFrame = resolve;
|
||||
});
|
||||
|
||||
server.on("message", (wire, remote) => {
|
||||
const packet = decodeRudpPacket(wire);
|
||||
if (packet.packetType === "connect") {
|
||||
server.send(encodeRudpPacket(session.acceptConnect(packet, Date.now())), remote.port, remote.address);
|
||||
return;
|
||||
}
|
||||
const result = session.receive(packet, Date.now());
|
||||
if (result.reply) server.send(encodeRudpPacket(result.reply), remote.port, remote.address);
|
||||
for (const frame of result.delivered) resolveFrame(frame);
|
||||
if (result.delivered.length > 0) {
|
||||
server.send(encodeRudpPacket(session.createAck()), remote.port, remote.address);
|
||||
}
|
||||
});
|
||||
await new Promise<void>((resolve) => server.bind(0, "127.0.0.1", resolve));
|
||||
const server = await startFakeIdunnRudp();
|
||||
|
||||
try {
|
||||
const tmp = await mkdtemp(path.join(os.tmpdir(), "heimdall-idunn-rudp-"));
|
||||
const address = server.address();
|
||||
const config = loadConfig({
|
||||
GC_ACCESS_IDUNN_RUDP_HEALTH: `127.0.0.1:${address.port}`,
|
||||
GC_ACCESS_IDUNN_RUDP_HEALTH: `127.0.0.1:${server.port}`,
|
||||
GC_ACCESS_PROVIDER_HEALTH_IDENTITY_PATH: path.join(tmp, "provider-health-identity.cc"),
|
||||
});
|
||||
const observedAt = "2026-08-22T00:45:00.000Z";
|
||||
|
|
@ -78,7 +47,7 @@ describe("Heimdall Idunn health publication", () => {
|
|||
observedAt,
|
||||
presence,
|
||||
});
|
||||
const frame = await frameReceived;
|
||||
const frame = await server.frame(0);
|
||||
const message = parseCultNetMessage(decode(frame.payload), "cultnet.schema.v0");
|
||||
|
||||
expect(frame.channelId).toBe("schema");
|
||||
|
|
|
|||
Loading…
Reference in a new issue