A send hands its frame to the card and returns, as in Java; the frames travel while the clock advances. Swift's send ran the network until every frame had arrived; the option swiftSends keeps that for the Swift comparison. Waiting calls (TCP connect, acknowledgement) now run event by event until the answer instead of to the timeout. UDP and TCP send through a thread per node and protocol (Java's TransportProtokoll): one segment after the other; while IP waits for ARP, the next send blocks and a segment from an event queues behind it. Senders that wait take their turns in the order they came (a fair lock; Java's leaves the order to chance). All four ArpRun stories now match Java FILIUS, including when each call returns. Tests let frames arrive explicitly with letFramesArrive. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
65 lines
2.2 KiB
TypeScript
65 lines
2.2 KiB
TypeScript
// Test fixtures, ported from the private helpers of
|
|
// filius-ipad ios/FiliusPadTests/TopologyNetworkRuntimeEngineTests.swift.
|
|
|
|
import {
|
|
deviceConfiguration,
|
|
NetworkRuntimeEngine,
|
|
portSnapshot,
|
|
topologySnapshot,
|
|
type DeviceConfiguration,
|
|
type Id,
|
|
type LinkSnapshot,
|
|
type NodeSnapshot,
|
|
type TopologySnapshotInput,
|
|
} from '../src/index.js';
|
|
|
|
let linkCounter = 0;
|
|
|
|
/** Swift uses a fresh `UUID()` per link; a counter keeps runs reproducible. */
|
|
export function link(sourceNodeId: Id, sourcePortId: Id, targetNodeId: Id, targetPortId: Id): LinkSnapshot {
|
|
linkCounter += 1;
|
|
return {
|
|
id: `ffffffff-0000-0000-0000-${linkCounter.toString(16).padStart(12, '0')}`,
|
|
sourceNodeId,
|
|
sourcePortId,
|
|
targetNodeId,
|
|
targetPortId,
|
|
};
|
|
}
|
|
|
|
export function pc(nodeId: Id, portId: Id): NodeSnapshot {
|
|
return { id: nodeId, kind: 'pc', ports: [portSnapshot(portId, 'eth0')] };
|
|
}
|
|
|
|
export function device(ipAddress: string, options: { mask?: string; gateway?: string } = {}): DeviceConfiguration {
|
|
return deviceConfiguration(ipAddress, options.mask ?? '255.255.255.0', options.gateway ?? '');
|
|
}
|
|
|
|
export function startedEngine(
|
|
input: TopologySnapshotInput,
|
|
seed: number = 14,
|
|
): NetworkRuntimeEngine {
|
|
const engine = new NetworkRuntimeEngine(seed);
|
|
engine.handle({ type: 'start', snapshot: topologySnapshot(input), seed, initialTimeMilliseconds: 0 });
|
|
return engine;
|
|
}
|
|
|
|
/** `00000000-0000-0000-0000-` followed by twelve hex digits. */
|
|
export function uuid(suffix: number): Id {
|
|
return `00000000-0000-0000-0000-${suffix.toString(16).toUpperCase().padStart(12, '0')}`;
|
|
}
|
|
|
|
const FRAME_EVENTS = new Set(['ethernetLinkDeparture', 'ethernetLinkDelivery', 'remoteLinkDelivery', 'arpAnswered']);
|
|
|
|
/**
|
|
* Advances until every frame in flight has arrived — what Swift's send did
|
|
* by itself; the engine's send returns at once, as Java's.
|
|
*/
|
|
export function letFramesArrive(engine: NetworkRuntimeEngine): void {
|
|
const inFlight = () =>
|
|
engine.state.pendingEvents.filter((event) => FRAME_EVENTS.has(event.kind.kind)).map((event) => event.deadlineMilliseconds);
|
|
for (let deadlines = inFlight(); deadlines.length > 0; deadlines = inFlight()) {
|
|
engine.handle({ type: 'advance', toMilliseconds: Math.min(...deadlines) });
|
|
}
|
|
}
|