@nostr-dev-kit/ndk
Version:
NDK - Nostr Development Kit. Includes AI Guardrails to catch common mistakes during development.
113 lines (92 loc) • 4.9 kB
text/typescript
import { describe, expect, it } from "bun:test";
describe("Reconnection Integration", () => {
describe("Backoff calculations", () => {
it("should use correct standard exponential backoff", () => {
const calculateStandardBackoff = (attempt: number) => {
return Math.min(1000 * 2 ** attempt, 30000);
};
expect(calculateStandardBackoff(0)).toBe(1000); // 1s
expect(calculateStandardBackoff(1)).toBe(2000); // 2s
expect(calculateStandardBackoff(2)).toBe(4000); // 4s
expect(calculateStandardBackoff(3)).toBe(8000); // 8s
expect(calculateStandardBackoff(4)).toBe(16000); // 16s
expect(calculateStandardBackoff(5)).toBe(30000); // 30s (capped)
expect(calculateStandardBackoff(6)).toBe(30000); // 30s (remains capped)
});
it("should use aggressive backoff for idle/wake scenarios", () => {
const aggressiveDelays = [0, 1000, 2000, 5000, 10000, 30000];
const getAggressiveDelay = (attempt: number) => {
return aggressiveDelays[Math.min(attempt, aggressiveDelays.length - 1)];
};
expect(getAggressiveDelay(0)).toBe(0); // Immediate
expect(getAggressiveDelay(1)).toBe(1000); // 1s
expect(getAggressiveDelay(2)).toBe(2000); // 2s
expect(getAggressiveDelay(3)).toBe(5000); // 5s
expect(getAggressiveDelay(4)).toBe(10000); // 10s
expect(getAggressiveDelay(5)).toBe(30000); // 30s
expect(getAggressiveDelay(10)).toBe(30000); // Still 30s for any higher attempt
});
it("should be much faster than old broken implementation", () => {
// Old broken calculation
const oldBrokenDelay = (attempt: number) => {
return (1000 * (attempt + 1)) ** 2;
};
// New correct calculation
const newDelay = (attempt: number) => {
return Math.min(1000 * 2 ** attempt, 30000);
};
// Compare first attempt
const oldFirst = oldBrokenDelay(0); // 1,000,000ms (16.7 minutes)
const newFirst = newDelay(0); // 1,000ms (1 second)
expect(oldFirst / newFirst).toBe(1000); // 1000x improvement
// Compare second attempt
const oldSecond = oldBrokenDelay(1); // 4,000,000ms (66.7 minutes)
const newSecond = newDelay(1); // 2,000ms (2 seconds)
expect(oldSecond / newSecond).toBe(2000); // 2000x improvement
});
});
describe("Sleep detection logic", () => {
it("should detect sleep through time gaps", () => {
const checkForSleep = (lastCheck: number, now: number, threshold = 15000) => {
const elapsed = now - lastCheck;
return elapsed > threshold;
};
// Normal 10s check - no sleep
const normalCheck = checkForSleep(Date.now() - 10000, Date.now());
expect(normalCheck).toBe(false);
// 20s gap - likely sleep
const sleepCheck = checkForSleep(Date.now() - 20000, Date.now());
expect(sleepCheck).toBe(true);
});
it("should mark connection as idle after 2 minutes", () => {
const checkIfIdle = (lastMessageSent: number, idleThreshold = 120000) => {
return Date.now() - lastMessageSent > idleThreshold;
};
// Recent activity - not idle
const recentActivity = checkIfIdle(Date.now() - 60000); // 1 minute ago
expect(recentActivity).toBe(false);
// Old activity - idle
const oldActivity = checkIfIdle(Date.now() - 150000); // 2.5 minutes ago
expect(oldActivity).toBe(true);
});
});
describe("System-wide detection", () => {
it("should detect system-wide disconnection", () => {
const checkSystemWide = (disconnections: number[], totalRelays: number, threshold = 0.5) => {
const now = Date.now();
const recentDisconnections = disconnections.filter((time) => now - time < 5000);
return totalRelays > 1 && recentDisconnections.length > totalRelays * threshold;
};
const now = Date.now();
// 3 out of 5 relays disconnect within 5s - system event
const systemEvent = checkSystemWide([now - 1000, now - 2000, now - 3000], 5);
expect(systemEvent).toBe(true);
// 2 out of 5 relays - not system event
const normalEvent = checkSystemWide([now - 1000, now - 2000], 5);
expect(normalEvent).toBe(false);
// Single relay pool - never system event
const singleRelay = checkSystemWide([now], 1);
expect(singleRelay).toBe(false);
});
});
});