mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
Signed-off-by: Tyler Longwell <tlongwell@block.xyz> Co-authored-by: npub17jjz49l9jjmhhk7cac63j8yt9z555n9cw8vk7v5jz4vzw4ppld5qgj57cc <f4a42a97e594b77bdbd8ee35191c8b28a94a4cb871d96f32921558275421fb68@sprout-oss.stage.blox.sqprod.co> Co-authored-by: Tyler Longwell <tlongwell@block.xyz> Co-authored-by: npub12gtutshhh76rx0jx697f32f9tffd4hhp3hx58fp4x6u4uemkm7sqf8f757 <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@sprout-oss.stage.blox.sqprod.co> Co-authored-by: npub1cc3ha7z055mu0rwwu7806t2wt8mj3pvu0uv5mfp2c50dahaqhczshdalg6 <c6237ef84fa537c78dcee78efd2d4e59f728859c7f194da42ac51ededfa0be05@sprout-oss.stage.blox.sqprod.co> Co-authored-by: npub1jh9wn95s0472h86ahapupaf7m6kx4v9sx2n0atj2hltcfer8k06s5n3pyf <95cae996907d7cab9f5dbf43c0f53edeac6ab0b032a6feae4abfd784e467b3f5@sprout-oss.stage.blox.sqprod.co> Co-authored-by: npub1t2tgm7d8f995uqvmnm8h88sg3wnpp9a5xysjf6dg3tjmgt3ltulqdp8ehr <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@sprout-oss.stage.blox.sqprod.co> Co-authored-by: npub1jmc9dt2lyvzu3h0kxlwxt5zg4fxp9476awyxw6gwxn72g6cw7exqs64whm <96f056ad5f2305c8ddf637dc65d048aa4c12d7daeb8867690e34fca46b0ef64c@sprout-oss.stage.blox.sqprod.co> Co-authored-by: npub1mprnacetjua2xx3p5eddmhxyk6wv929ymm5py8kd2xfxurxahspqqlgyta <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@sprout-oss.stage.blox.sqprod.co>
253 lines
5.3 KiB
JavaScript
253 lines
5.3 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
|
|
import {
|
|
buildReconnectReplayFilter,
|
|
replayLiveSubscriptions,
|
|
} from "./relayReconnectReplay.ts";
|
|
import { buildChannelFilter } from "./relayChannelFilters.ts";
|
|
|
|
function replayFilter(filter, since, until) {
|
|
return buildReconnectReplayFilter(filter, since, until);
|
|
}
|
|
|
|
function event(id, createdAt) {
|
|
return {
|
|
id,
|
|
pubkey: "pubkey",
|
|
created_at: createdAt,
|
|
kind: 9,
|
|
tags: [],
|
|
content: "",
|
|
sig: "sig",
|
|
};
|
|
}
|
|
|
|
function eventRange(prefix, start, count) {
|
|
return Array.from({ length: count }, (_, index) =>
|
|
event(`${prefix}-${index}`, start + index),
|
|
);
|
|
}
|
|
|
|
test("reconnect replay preserves small steady-state limits when adding since", () => {
|
|
const filter = {
|
|
kinds: [9, 40002],
|
|
"#h": ["channel-1"],
|
|
limit: 50,
|
|
};
|
|
|
|
assert.deepEqual(replayFilter(filter, 123), {
|
|
kinds: [9, 40002],
|
|
"#h": ["channel-1"],
|
|
limit: 50,
|
|
since: 123,
|
|
});
|
|
});
|
|
|
|
test("reconnect replay caps large steady-state limits", () => {
|
|
const filter = {
|
|
kinds: [9],
|
|
"#h": ["channel-1"],
|
|
limit: 1000,
|
|
};
|
|
|
|
assert.deepEqual(replayFilter(filter, 123), {
|
|
kinds: [9],
|
|
"#h": ["channel-1"],
|
|
limit: 500,
|
|
since: 123,
|
|
});
|
|
});
|
|
|
|
test("reconnect replay keeps the stricter existing since window", () => {
|
|
const filter = {
|
|
kinds: [9],
|
|
"#h": ["channel-1"],
|
|
limit: 50,
|
|
since: 200,
|
|
};
|
|
|
|
assert.deepEqual(replayFilter(filter, 123), {
|
|
kinds: [9],
|
|
"#h": ["channel-1"],
|
|
limit: 50,
|
|
since: 200,
|
|
});
|
|
});
|
|
|
|
test("reconnect replay applies the stricter until window", () => {
|
|
const filter = {
|
|
kinds: [9],
|
|
"#h": ["channel-1"],
|
|
limit: 50,
|
|
until: 300,
|
|
};
|
|
|
|
assert.deepEqual(replayFilter(filter, 123, 400), {
|
|
kinds: [9],
|
|
"#h": ["channel-1"],
|
|
limit: 50,
|
|
since: 123,
|
|
until: 300,
|
|
});
|
|
});
|
|
|
|
test("initial subscription replay preserves the original filter", () => {
|
|
const filter = {
|
|
kinds: [9],
|
|
"#h": ["channel-1"],
|
|
limit: 50,
|
|
};
|
|
|
|
assert.equal(replayFilter(filter, undefined), filter);
|
|
});
|
|
|
|
test("channel reconnect replay pages the missed window until a short page", async () => {
|
|
const delivered = [];
|
|
const historyFilters = [];
|
|
const sentPayloads = [];
|
|
const pages = [
|
|
eventRange("newest", 1501, 500),
|
|
eventRange("middle", 1002, 500),
|
|
eventRange("oldest", 995, 8),
|
|
];
|
|
const filter = buildChannelFilter("channel-1", 50);
|
|
const subscriptions = new Map([
|
|
[
|
|
"live-1",
|
|
{
|
|
mode: "live",
|
|
filter,
|
|
onEvent: (event) => delivered.push(event),
|
|
lastSeenCreatedAt: 1000,
|
|
},
|
|
],
|
|
]);
|
|
|
|
await replayLiveSubscriptions({
|
|
subscriptions,
|
|
now: 2000,
|
|
sendRaw: async (payload) => {
|
|
sentPayloads.push(payload);
|
|
},
|
|
requestHistory: async (filter) => {
|
|
historyFilters.push(filter);
|
|
return pages.shift() ?? [];
|
|
},
|
|
});
|
|
|
|
assert.deepEqual(sentPayloads, [
|
|
[
|
|
"REQ",
|
|
"live-1",
|
|
{
|
|
kinds: filter.kinds,
|
|
"#h": ["channel-1"],
|
|
limit: 50,
|
|
},
|
|
],
|
|
]);
|
|
assert.deepEqual(historyFilters, [
|
|
{
|
|
kinds: filter.kinds,
|
|
"#h": ["channel-1"],
|
|
limit: 500,
|
|
since: 995,
|
|
until: 2000,
|
|
},
|
|
{
|
|
kinds: filter.kinds,
|
|
"#h": ["channel-1"],
|
|
limit: 500,
|
|
since: 995,
|
|
until: 1501,
|
|
},
|
|
{
|
|
kinds: filter.kinds,
|
|
"#h": ["channel-1"],
|
|
limit: 500,
|
|
since: 995,
|
|
until: 1002,
|
|
},
|
|
]);
|
|
assert.equal(delivered.length, 1008);
|
|
});
|
|
|
|
test("reconnect replay starts live REQs in parallel and preserves per-sub page order", async () => {
|
|
const sentPayloads = [];
|
|
const sendResolvers = [];
|
|
const historyFiltersByChannel = {
|
|
"channel-1": [],
|
|
"channel-2": [],
|
|
};
|
|
const pagesByChannel = {
|
|
"channel-1": [
|
|
eventRange("c1-full", 1501, 500),
|
|
eventRange("c1-short", 1490, 2),
|
|
],
|
|
"channel-2": [
|
|
eventRange("c2-full", 1701, 500),
|
|
eventRange("c2-short", 1690, 2),
|
|
],
|
|
};
|
|
const subscriptions = new Map([
|
|
[
|
|
"live-1",
|
|
{
|
|
mode: "live",
|
|
filter: buildChannelFilter("channel-1", 50),
|
|
onEvent: () => {},
|
|
lastSeenCreatedAt: 1000,
|
|
},
|
|
],
|
|
[
|
|
"live-2",
|
|
{
|
|
mode: "live",
|
|
filter: buildChannelFilter("channel-2", 50),
|
|
onEvent: () => {},
|
|
lastSeenCreatedAt: 1000,
|
|
},
|
|
],
|
|
]);
|
|
|
|
const replayPromise = replayLiveSubscriptions({
|
|
subscriptions,
|
|
now: 2000,
|
|
pageReplayConcurrency: 2,
|
|
sendRaw: (payload) => {
|
|
sentPayloads.push(payload);
|
|
return new Promise((resolve) => {
|
|
sendResolvers.push(resolve);
|
|
});
|
|
},
|
|
requestHistory: async (filter) => {
|
|
const channelId = filter["#h"]?.[0];
|
|
historyFiltersByChannel[channelId].push(filter.until);
|
|
return pagesByChannel[channelId].shift() ?? [];
|
|
},
|
|
});
|
|
|
|
await Promise.resolve();
|
|
|
|
assert.deepEqual(
|
|
sentPayloads.map((payload) => payload[1]),
|
|
["live-1", "live-2"],
|
|
);
|
|
assert.equal(sendResolvers.length, 2);
|
|
assert.deepEqual(historyFiltersByChannel, {
|
|
"channel-1": [],
|
|
"channel-2": [],
|
|
});
|
|
|
|
for (const resolve of sendResolvers) {
|
|
resolve();
|
|
}
|
|
await replayPromise;
|
|
|
|
assert.deepEqual(historyFiltersByChannel, {
|
|
"channel-1": [2000, 1501],
|
|
"channel-2": [2000, 1701],
|
|
});
|
|
});
|