CultLib/packages/cultnet-ts/test/rudp-ordered-delivery.test.ts
Meta Vens 43d7e53efd Ack Cut 1 tests: three held frames, the Rust byte bound, reset reseeds
A gap now holds three ordered frames so a watermark that advances one step
per call fails; the reset test follows a second handshake at a different
sequence so a watermark that survives the reset fails; Rust gains the
4 MiB hold bound in bytes.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 00:20:04 +02:00

110 lines
4.9 KiB
TypeScript

// Ordered delivery has one owner: the contiguous received-through watermark. A
// frame is held for exactly one reason, a reliable sequence below it has not
// arrived, and it is delivered in the call that fills the last such gap,
// whichever channel the gap belonged to.
import assert from "node:assert/strict";
import test from "node:test";
import { CultNetRudpSession } from "../src";
const enc = (text: string) => new TextEncoder().encode(text);
const dec = (bytes: Uint8Array) => new TextDecoder().decode(bytes);
function handshake(): { client: CultNetRudpSession; server: CultNetRudpSession } {
const client = new CultNetRudpSession({ connectionId: 410, initialSequence: 1 });
const server = new CultNetRudpSession({ connectionId: 410, initialSequence: 500 });
const accept = server.acceptConnect(client.createConnect(0), 0);
client.receive(accept, 0);
return { client, server };
}
const names = (result: { delivered: { payload: Uint8Array }[] }) => result.delivered.map((frame) => dec(frame.payload));
const send = (session: CultNetRudpSession, channel: string, payload: string, ordered: boolean) =>
session.send(channel, enc(payload), { reliable: true, ordered });
test("an ordered frame waits for a gap filled by another channel", () => {
const { client: sender, server: receiver } = handshake();
const o1 = send(sender, "schema", "o1", true);
const u = send(sender, "rel", "u", false);
const o2 = send(sender, "schema", "o2", true);
const o3 = send(sender, "schema", "o3", true);
const o4 = send(sender, "schema", "o4", true);
assert.deepEqual(names(receiver.receive(o1, 1)), ["o1"]);
assert.deepEqual(names(receiver.receive(o2, 2)), [], "u is missing");
assert.deepEqual(names(receiver.receive(o3, 3)), [], "u is missing");
assert.deepEqual(names(receiver.receive(o4, 4)), [], "u is missing");
assert.deepEqual(names(receiver.receive(u, 5)), ["u", "o2", "o3", "o4"]);
});
test("two ordered channels release each other in sequence order", () => {
const { client: sender, server: receiver } = handshake();
const a1 = send(sender, "schema", "A1", true);
const b1 = send(sender, "other", "B1", true);
const a2 = send(sender, "schema", "A2", true);
const a3 = send(sender, "schema", "A3", true);
const delivered = [
...names(receiver.receive(a1, 1)),
...names(receiver.receive(a2, 2)),
...names(receiver.receive(a3, 3)),
];
assert.deepEqual(delivered, ["A1"], "B1 is missing, so A2 and A3 wait");
assert.deepEqual(names(receiver.receive(b1, 4)), ["B1", "A2", "A3"]);
});
test("a channel first used after other traffic loses nothing", () => {
const { client: sender, server: receiver } = handshake();
const c1 = send(sender, "late", "C1", true);
const c2 = send(sender, "late", "C2", true);
const x = send(sender, "schema", "X", true);
assert.deepEqual(names(receiver.receive(x, 1)), [], "C1 is missing");
assert.deepEqual(names(receiver.receive(c2, 2)), [], "C1 is missing");
assert.deepEqual(names(receiver.receive(c1, 3)), ["C1", "C2", "X"]);
});
test("Accept seeds the watermark of the connecting side", () => {
const { client, server } = handshake();
const s1 = send(server, "schema", "s1", true);
const s2 = send(server, "schema", "s2", true);
assert.deepEqual(names(client.receive(s2, 1)), []);
assert.deepEqual(names(client.receive(s1, 2)), ["s1", "s2"]);
});
test("Connect seeds the watermark of the accepting side", () => {
const { client, server } = handshake();
const first = send(client, "schema", "first", true);
const second = send(client, "schema", "second", true);
assert.deepEqual(names(server.receive(second, 1)), []);
assert.deepEqual(names(server.receive(first, 2)), ["first", "second"]);
});
test("a duplicate of a held frame is not delivered twice", () => {
const { client: sender, server: receiver } = handshake();
const s1 = send(sender, "schema", "s1", true);
const s2 = send(sender, "schema", "s2", true);
assert.deepEqual(names(receiver.receive(s2, 1)), []);
assert.deepEqual(names(receiver.receive(s2, 2)), []);
assert.deepEqual(names(receiver.receive(s1, 3)), ["s1", "s2"]);
assert.deepEqual(names(receiver.receive(s2, 4)), []);
});
test("resetting peer state forgets held frames and reseeds the watermark from the next handshake", () => {
const { client: sender, server: receiver } = handshake();
send(sender, "schema", "s1", true);
const s2 = send(sender, "schema", "s2", true);
assert.deepEqual(names(receiver.receive(s2, 1)), []);
receiver.resetPeerState();
const next = new CultNetRudpSession({ connectionId: 410, initialSequence: 100 });
next.receive(receiver.acceptConnect(next.createConnect(0), 2), 2);
const d1 = send(next, "schema", "d1", true);
const d2 = send(next, "schema", "d2", true);
// The held s2 died with the reset, and the watermark follows the new peer.
assert.deepEqual(names(receiver.receive(d2, 3)), []);
assert.deepEqual(names(receiver.receive(d1, 4)), ["d1", "d2"]);
});