reliable-zeromq
Version:
A collection of reliable zeromq messaging constructs
182 lines (140 loc) • 6.58 kB
text/typescript
/* tslint:disable: no-string-literal */
import anyTest, { ExecutionContext } from "ava";
import type { TestInterface } from "ava";
import * as sinon from "sinon";
import ExpiryMap from "../../../Src/Utils/ExpiryMap";
type TTestContext =
{
ExpiryBuffer: number;
ExpiryMap: ExpiryMap<string, string>;
DummyValues: [string, string][];
FilledMap: ExpiryMap<string, string>;
};
const test: TestInterface<TTestContext> = anyTest as TestInterface<TTestContext> ;
test.before(async(t: ExecutionContext<TTestContext>): Promise<void> =>
{
// No setup necessary
});
test.beforeEach((t: ExecutionContext<TTestContext>): void =>
{
t.context.ExpiryBuffer = 500;
t.context.ExpiryMap = new ExpiryMap(0);
t.context.DummyValues = [
["0", "myFunc()"],
["1", "d"],
["2", "200n"],
["3", "[ { \"_id\": \"5ef6d0a87fe78748b57ea948\", \"index\": 0, \"guid\": \"4332a763-53e5-4e3d-a978-d22ab6fe976c\", \"isActive\": false, \"balance\": \"$2,443.19\", \"tags\": [ \"pariatur\", \"duis\", \"commodo\", \"velit\", \"eiusmod\", \"minim\", \"eu\" ], \"greeting\": \"Hello, undefined! You have 7 unread messages.\" }, { \"_id\": \"5ef6d0a8e260872db7a55744\", \"index\": 1, \"guid\": \"c1ad2a72-2550-4a85-8556-d591af31041f\", \"isActive\": false, \"balance\": \"$3,257.61\", \"tags\": [ \"eu\", \"laborum\", \"aliquip\", \"tempor\", \"id\", \"ut\", \"consectetur\" ], \"greeting\": \"Hello, undefined! You have 2 unread messages.\" }, { \"_id\": \"5ef6d0a8a64a4201ebe17add\", \"index\": 2, \"guid\": \"ece7aabc-79dc-4286-abc1-25473a2a830e\", \"isActive\": false, \"balance\": \"$3,869.75\", \"tags\": [ \"fugiat\", \"qui\", \"irure\", \"esse\", \"ut\", \"ut\", \"consectetur\" ], \"greeting\": \"Hello, undefined! You have 3 unread messages.\" }, { \"_id\": \"5ef6d0a85fe8e68ca3af8b52\", \"index\": 3, \"guid\": \"0e9fc60a-a75b-4bd6-95f7-bed9fd514a69\", \"isActive\": true, \"balance\": \"$2,195.14\", \"tags\": [ \"aute\", \"ad\", \"irure\", \"et\", \"ea\", \"exercitation\", \"ipsum\" ], \"greeting\": \"Hello, undefined! You have 8 unread messages.\" }, { \"_id\": \"5ef6d0a86c98c87f8447bc85\", \"index\": 4, \"guid\": \"ae607bec-4a42-4884-b801-13fd04712b2e\", \"isActive\": false, \"balance\": \"$1,837.78\", \"tags\": [ \"irure\", \"occaecat\", \"nulla\", \"amet\", \"ut\", \"pariatur\", \"dolor\" ], \"greeting\": \"Hello, undefined! You have 10 unread messages.\" } ]"],
["4", "cat"],
];
});
test.afterEach((t: ExecutionContext<TTestContext>): void =>
{
sinon.restore();
});
test("Constructor", (t: ExecutionContext<TTestContext>): void =>
{
const lNewMap: ExpiryMap<string, string> = new ExpiryMap<string, string>(0);
t.is(lNewMap["mExpiryMS"], 0);
t.is(lNewMap["mNextExpiry"], undefined);
t.is(lNewMap.size, 0);
});
test("Constructor with Entries", (t: ExecutionContext<TTestContext>): void =>
{
const lDummyEntries: [string, string][] = t.context.DummyValues;
const lNewMap: ExpiryMap<string, string> = new ExpiryMap<string, string>(0, lDummyEntries);
t.is(lNewMap["mExpiryMS"], 0);
t.not(lNewMap["mNextExpiry"], undefined);
t.is(lNewMap.size, t.context.DummyValues.length);
});
test("Set, Get, and Clear", async(t: ExecutionContext<TTestContext>): Promise<void> =>
{
const clock: sinon.SinonFakeTimers = sinon.useFakeTimers();
const lMap: ExpiryMap<string, string> = t.context.ExpiryMap;
const lDummyValues: [string, string][] = t.context.DummyValues;
lMap.set(lDummyValues[0][0], lDummyValues[0][1]);
t.is(lMap.get(lDummyValues[0][0]), lDummyValues[0][1]);
lMap.set(lDummyValues[1][0], lDummyValues[1][1]);
lMap.set(lDummyValues[2][0], lDummyValues[2][1]);
lMap.set(lDummyValues[3][0], lDummyValues[3][1]);
lMap.set(lDummyValues[4][0], lDummyValues[4][1]);
t.is(lMap.size, t.context.DummyValues.length);
t.is(lMap.get(lDummyValues[1][0]), lDummyValues[1][1]);
t.is(lMap.get(lDummyValues[2][0]), lDummyValues[2][1]);
t.is(lMap.get(lDummyValues[3][0]), lDummyValues[3][1]);
t.is(lMap.get(lDummyValues[4][0]), lDummyValues[4][1]);
clock.tick(t.context.ExpiryBuffer);
t.is(lMap.size, 0);
});
test("5s Expiry", (t: ExecutionContext<TTestContext>): void =>
{
const clock: sinon.SinonFakeTimers = sinon.useFakeTimers();
const lMap: Map<string, string> = new ExpiryMap(5000, t.context.DummyValues);
clock.tick(5000 + t.context.ExpiryBuffer - 1);
t.is(lMap.size, t.context.DummyValues.length);
clock.tick(1);
t.is(lMap.size, 0);
});
test("Staggered Insertion & Pruning", (t: ExecutionContext<TTestContext>): void =>
{
const clock: sinon.SinonFakeTimers = sinon.useFakeTimers();
const lMap: ExpiryMap<bigint, number> = new ExpiryMap<bigint, number>(2000);
lMap.set(0n, 0); // 0,1,2 at 0s. Expire 2s, Timer 2.5s
lMap.set(1n, 1);
lMap.set(2n, 2);
clock.tick(1000); // 3,4,5 at 1s. Expire 3s
lMap.set(3n, 3);
lMap.set(4n, 4);
lMap.set(5n, 5);
clock.tick(900); // 6,7,8 at 1.9s. Expire 3.9s
lMap.set(6n, 6);
lMap.set(7n, 7);
lMap.set(8n, 8);
t.is(lMap.size, 9);
clock.tick(600); // 2.5s, timer triggered, first 3 cleared
t.is(lMap.size, 6);
clock.tick(1000); // 3.5s, 2nd timer triggered, next 3 cleared
t.is(lMap.size, 3);
clock.tick(900); // 4.4s 3rd timer triggered, final 3 cleared
t.is(lMap.size, 0);
t.is(lMap.size, 0);
t.is(lMap["mNextExpiry"], undefined);
lMap.clear();
lMap.set(10n, 10);
lMap.set(11n, 11);
lMap.set(12n, 12);
t.is(lMap.size, 3);
clock.tick(100); // Cleared timeout theoretical expiry
t.is(lMap.size, 3);
clock.tick(1900); // 2s into new timeout
t.is(lMap.size, 3);
clock.tick(1000); // 2.5s New timeout expiry
t.is(lMap.size, 0);
});
test("Staggered Insertion, Batched Pruning", (t: ExecutionContext<TTestContext>): void =>
{
const clock: sinon.SinonFakeTimers = sinon.useFakeTimers();
const lMap: ExpiryMap<number, boolean> = new ExpiryMap<number, boolean>(2000);
lMap.set(0, true);
lMap.set(1, true);
clock.tick(100);
lMap.set(2, true);
lMap.set(3, true);
clock.tick(200);
lMap.set(4, true);
lMap.set(5, true);
clock.tick(200);
lMap.set(6, true);
lMap.set(7, true);
clock.tick(100);
lMap.set(8, true);
lMap.set(9, true);
t.is(lMap.size, 10);
clock.tick(1899);
t.is(lMap.size, 10);
clock.tick(1);
t.is(lMap.size, 2);
clock.tick(599);
t.is(lMap.size, 2);
clock.tick(1);
t.is(lMap.size, 0);
});