mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 16:02:26 +00:00
214 lines
6.0 KiB
JavaScript
214 lines
6.0 KiB
JavaScript
// Run with: node tests/nostr-count-fallback.test.mjs
|
|
|
|
import "./test-helpers/setup-localstorage.mjs";
|
|
import assert from "node:assert/strict";
|
|
|
|
if (typeof globalThis.window === "undefined") {
|
|
globalThis.window = {};
|
|
}
|
|
|
|
if (!globalThis.window.NostrTools) {
|
|
globalThis.window.NostrTools = {};
|
|
}
|
|
|
|
const { VIEW_COUNT_BACKFILL_MAX_DAYS } = await import("../js/config.js");
|
|
const { NostrClient } = await import("../js/nostr/client.js");
|
|
|
|
async function withFrozenTime(timestampSeconds, callback) {
|
|
const originalNow = Date.now;
|
|
Date.now = () => timestampSeconds * 1000;
|
|
try {
|
|
return await callback();
|
|
} finally {
|
|
Date.now = originalNow;
|
|
}
|
|
}
|
|
|
|
function getConfiguredHorizonDays() {
|
|
const horizonDaysRaw = Number(VIEW_COUNT_BACKFILL_MAX_DAYS);
|
|
return Number.isFinite(horizonDaysRaw)
|
|
? Math.max(0, Math.floor(horizonDaysRaw))
|
|
: 0;
|
|
}
|
|
|
|
async function testFallbackAddsDefaultSinceWhenPoolMissing() {
|
|
const client = new NostrClient();
|
|
client.pool = null;
|
|
|
|
const pointer = { type: "e", value: "count-fallback-default" };
|
|
const calls = [];
|
|
client.listVideoViewEvents = async (_, options = {}) => {
|
|
calls.push({ ...options });
|
|
return [];
|
|
};
|
|
|
|
const horizonDays = getConfiguredHorizonDays();
|
|
|
|
const nowSeconds = 1_700_000_000;
|
|
await withFrozenTime(nowSeconds, async () => {
|
|
const result = await client.countVideoViewEvents(pointer, {});
|
|
assert.equal(calls.length, 1, "fallback should issue a single list query");
|
|
const [{ since }] = calls;
|
|
if (horizonDays > 0) {
|
|
const expectedSince = Math.max(0, nowSeconds - horizonDays * 86_400);
|
|
assert.equal(
|
|
since,
|
|
expectedSince,
|
|
"fallback list should clamp history to the configured horizon"
|
|
);
|
|
} else {
|
|
assert.equal(
|
|
Object.prototype.hasOwnProperty.call(calls[0], "since"),
|
|
false,
|
|
"without a configured horizon the fallback should avoid forcing a since filter"
|
|
);
|
|
}
|
|
assert.equal(result.fallback, true, "fallback branch should be flagged");
|
|
});
|
|
}
|
|
|
|
async function testFallbackHonorsCallerOverrides() {
|
|
const client = new NostrClient();
|
|
client.pool = null;
|
|
|
|
const pointer = { type: "e", value: "count-fallback-overrides" };
|
|
let receivedOptions = null;
|
|
client.listVideoViewEvents = async (_, options = {}) => {
|
|
receivedOptions = { ...options };
|
|
return [];
|
|
};
|
|
|
|
const overrides = {
|
|
since: 1_234_567,
|
|
until: 1_235_000,
|
|
limit: 42,
|
|
};
|
|
|
|
await client.countVideoViewEvents(pointer, overrides);
|
|
|
|
assert.ok(receivedOptions, "fallback should forward overrides to list");
|
|
assert.equal(
|
|
receivedOptions.since,
|
|
Math.floor(overrides.since),
|
|
"caller supplied since should be preserved"
|
|
);
|
|
assert.equal(
|
|
receivedOptions.until,
|
|
Math.floor(overrides.until),
|
|
"caller supplied until should be preserved"
|
|
);
|
|
assert.equal(
|
|
receivedOptions.limit,
|
|
Math.floor(overrides.limit),
|
|
"caller supplied limit should be preserved"
|
|
);
|
|
}
|
|
|
|
async function testFallbackAfterCountFailureUsesDefaultWindow() {
|
|
const client = new NostrClient();
|
|
client.pool = {};
|
|
client.countEventsAcrossRelays = async () => {
|
|
throw new Error("count failed");
|
|
};
|
|
|
|
const pointer = { type: "e", value: "count-fallback-error" };
|
|
let receivedOptions = null;
|
|
client.listVideoViewEvents = async (_, options = {}) => {
|
|
receivedOptions = { ...options };
|
|
return [];
|
|
};
|
|
|
|
const horizonDays = getConfiguredHorizonDays();
|
|
|
|
const nowSeconds = 1_800_000_000;
|
|
await withFrozenTime(nowSeconds, async () => {
|
|
await client.countVideoViewEvents(pointer, {});
|
|
});
|
|
|
|
assert.ok(receivedOptions, "fallback should invoke the list helper");
|
|
if (horizonDays > 0) {
|
|
const expectedSince = Math.max(0, nowSeconds - horizonDays * 86_400);
|
|
assert.equal(
|
|
receivedOptions.since,
|
|
expectedSince,
|
|
"COUNT fallback should restrict scans to the configured horizon"
|
|
);
|
|
} else {
|
|
assert.equal(
|
|
Object.prototype.hasOwnProperty.call(receivedOptions, "since"),
|
|
false,
|
|
"COUNT fallback should avoid forcing a since filter when no horizon is set"
|
|
);
|
|
}
|
|
}
|
|
|
|
async function testUnsupportedRelaySkipsWarningsAndFallsBack() {
|
|
const client = new NostrClient();
|
|
const unsupportedRelay = "wss://unsupported.example";
|
|
client.relays = [unsupportedRelay];
|
|
|
|
let ensureRelayCalls = 0;
|
|
client.pool = {
|
|
ensureRelay: async (url) => {
|
|
ensureRelayCalls += 1;
|
|
assert.equal(
|
|
url,
|
|
unsupportedRelay,
|
|
"COUNT helper should target the configured relay"
|
|
);
|
|
return {};
|
|
},
|
|
};
|
|
|
|
let listCalls = 0;
|
|
client.listVideoViewEvents = async () => {
|
|
listCalls += 1;
|
|
return [];
|
|
};
|
|
|
|
const originalWarn = console.warn;
|
|
const warnCalls = [];
|
|
console.warn = (...args) => {
|
|
warnCalls.push(args);
|
|
};
|
|
|
|
try {
|
|
const pointer = { type: "e", value: "unsupported-relay" };
|
|
const result = await client.countVideoViewEvents(pointer, {});
|
|
|
|
assert.equal(listCalls, 1, "fallback should query list once when COUNT fails");
|
|
assert.equal(result?.fallback, true, "unsupported relay should trigger fallback");
|
|
assert.ok(
|
|
client.countUnsupportedRelays.has(unsupportedRelay),
|
|
"unsupported relay should be remembered for future requests"
|
|
);
|
|
assert.equal(
|
|
warnCalls.length,
|
|
0,
|
|
"unsupported relay error should not emit console warnings"
|
|
);
|
|
|
|
// Subsequent calls should skip the unsupported relay entirely.
|
|
await client.countVideoViewEvents(pointer, {});
|
|
assert.equal(
|
|
ensureRelayCalls,
|
|
1,
|
|
"unsupported relays should be skipped after the first failure"
|
|
);
|
|
assert.equal(
|
|
warnCalls.length,
|
|
0,
|
|
"no warnings should be emitted for cached unsupported relays"
|
|
);
|
|
} finally {
|
|
console.warn = originalWarn;
|
|
}
|
|
}
|
|
|
|
await testFallbackAddsDefaultSinceWhenPoolMissing();
|
|
await testFallbackHonorsCallerOverrides();
|
|
await testFallbackAfterCountFailureUsesDefaultWindow();
|
|
await testUnsupportedRelaySkipsWarningsAndFallsBack();
|
|
|
|
console.log("nostr COUNT fallback tests completed successfully.");
|