Initial Commit
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
import { Mulberry32Rng } from "@suaveplan/pseudo-random";
|
||||
import { describe, expect, it } from "@suaveplan/testing/runner";
|
||||
import {
|
||||
applyNetworkConditions,
|
||||
shouldDropPacket,
|
||||
simulateLatency,
|
||||
} from "./index.js";
|
||||
|
||||
const seededRng = (): Mulberry32Rng => new Mulberry32Rng(0xc0ffee);
|
||||
|
||||
describe("network legacy helpers", () => {
|
||||
it("simulates latency within range", () => {
|
||||
const latency = simulateLatency(
|
||||
{
|
||||
latencyMs: 100,
|
||||
jitterMs: 20,
|
||||
packetLossRate: 0,
|
||||
},
|
||||
seededRng()
|
||||
);
|
||||
expect(latency).toBeGreaterThanOrEqual(80);
|
||||
expect(latency).toBeLessThanOrEqual(120);
|
||||
});
|
||||
|
||||
it("never drops with zero loss rate", () => {
|
||||
const rng = seededRng();
|
||||
for (let i = 0; i < 100; i++) {
|
||||
expect(
|
||||
shouldDropPacket(
|
||||
{
|
||||
latencyMs: 50,
|
||||
jitterMs: 0,
|
||||
packetLossRate: 0,
|
||||
},
|
||||
rng
|
||||
)
|
||||
).toBe(false);
|
||||
}
|
||||
});
|
||||
|
||||
it("passes payload through network", () => {
|
||||
const payload = new Uint8Array([1, 2, 3]);
|
||||
const result = applyNetworkConditions(
|
||||
payload,
|
||||
{
|
||||
latencyMs: 50,
|
||||
jitterMs: 0,
|
||||
packetLossRate: 0,
|
||||
},
|
||||
seededRng()
|
||||
);
|
||||
expect(result).toEqual(payload);
|
||||
});
|
||||
|
||||
it("drops packet with 100% loss rate", () => {
|
||||
const payload = new Uint8Array([1, 2, 3]);
|
||||
const result = applyNetworkConditions(
|
||||
payload,
|
||||
{
|
||||
latencyMs: 50,
|
||||
jitterMs: 0,
|
||||
packetLossRate: 1,
|
||||
},
|
||||
seededRng()
|
||||
);
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it("uses default conditions when none provided", () => {
|
||||
const latency = simulateLatency(undefined, seededRng());
|
||||
expect(latency).toBeGreaterThanOrEqual(40);
|
||||
expect(latency).toBeLessThanOrEqual(60);
|
||||
expect(shouldDropPacket(undefined, seededRng())).toBe(false);
|
||||
const payload = new Uint8Array([1]);
|
||||
expect(applyNetworkConditions(payload, undefined, seededRng())).toEqual(
|
||||
payload
|
||||
);
|
||||
});
|
||||
|
||||
it("falls back to defaultRng when no Rng supplied", () => {
|
||||
// In this test env the host lacks crypto.getRandomValues, so the
|
||||
// default RNG factory throws RandomError. The genesis determinism
|
||||
// rule forbids silent Math.random fallback; either crypto is
|
||||
// available (function returns) or it isn't (function throws).
|
||||
// Both outcomes exercise the fallback branch.
|
||||
try {
|
||||
simulateLatency();
|
||||
// If it didn't throw, the host has crypto.getRandomValues.
|
||||
expect(true).toBe(true);
|
||||
} catch (e) {
|
||||
expect(e).toBeInstanceOf(Error);
|
||||
expect((e as Error).message).toMatch(
|
||||
/random\.source\.unavailable|getRandomValues|crypto/i
|
||||
);
|
||||
}
|
||||
try {
|
||||
shouldDropPacket();
|
||||
} catch (e) {
|
||||
expect(e).toBeInstanceOf(Error);
|
||||
}
|
||||
try {
|
||||
applyNetworkConditions(new Uint8Array([1]));
|
||||
} catch (e) {
|
||||
expect(e).toBeInstanceOf(Error);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user