
























@@ -0,0 +1,114 @@
1+import { afterEach, describe, expect, it, vi } from "vitest";
2+import { GatewayHeartbeatTimers } from "./gateway-lifecycle.js";
3+4+describe("GatewayHeartbeatTimers", () => {
5+afterEach(() => {
6+vi.restoreAllMocks();
7+vi.useRealTimers();
8+});
9+10+it("does not false-timeout when the first heartbeat fires near the interval boundary", () => {
11+vi.useFakeTimers();
12+13+const onHeartbeat = vi.fn();
14+const onAckTimeout = vi.fn();
15+const isAcked = vi.fn().mockReturnValue(false);
16+const timers = new GatewayHeartbeatTimers();
17+18+timers.start({
19+intervalMs: 45_000,
20+ isAcked,
21+ onAckTimeout,
22+ onHeartbeat,
23+random: () => 0.95,
24+});
25+26+vi.advanceTimersByTime(42_750);
27+expect(onHeartbeat).toHaveBeenCalledTimes(1);
28+expect(onAckTimeout).not.toHaveBeenCalled();
29+30+vi.advanceTimersByTime(2_250);
31+expect(onAckTimeout).not.toHaveBeenCalled();
32+33+isAcked.mockReturnValue(true);
34+vi.advanceTimersByTime(42_750);
35+expect(onHeartbeat).toHaveBeenCalledTimes(2);
36+expect(onAckTimeout).not.toHaveBeenCalled();
37+38+timers.stop();
39+});
40+41+it("fires an ACK timeout when a heartbeat is genuinely not acknowledged", () => {
42+vi.useFakeTimers();
43+44+const timers = new GatewayHeartbeatTimers();
45+const onHeartbeat = vi.fn();
46+const onAckTimeout = vi.fn();
47+48+timers.start({
49+intervalMs: 45_000,
50+isAcked: () => false,
51+ onAckTimeout,
52+ onHeartbeat,
53+random: () => 0,
54+});
55+56+vi.advanceTimersByTime(0);
57+expect(onHeartbeat).toHaveBeenCalledTimes(1);
58+59+vi.advanceTimersByTime(45_000);
60+expect(onAckTimeout).toHaveBeenCalledTimes(1);
61+62+timers.stop();
63+});
64+65+it("sends heartbeats at regular intervals after the initial random delay", () => {
66+vi.useFakeTimers();
67+68+const timers = new GatewayHeartbeatTimers();
69+const onHeartbeat = vi.fn();
70+const onAckTimeout = vi.fn();
71+72+timers.start({
73+intervalMs: 10_000,
74+isAcked: () => true,
75+ onAckTimeout,
76+ onHeartbeat,
77+random: () => 0.5,
78+});
79+80+vi.advanceTimersByTime(5_000);
81+expect(onHeartbeat).toHaveBeenCalledTimes(1);
82+83+vi.advanceTimersByTime(10_000);
84+expect(onHeartbeat).toHaveBeenCalledTimes(2);
85+86+vi.advanceTimersByTime(10_000);
87+expect(onHeartbeat).toHaveBeenCalledTimes(3);
88+expect(onAckTimeout).not.toHaveBeenCalled();
89+90+timers.stop();
91+});
92+93+it("stop cancels all pending timers", () => {
94+vi.useFakeTimers();
95+96+const timers = new GatewayHeartbeatTimers();
97+const onHeartbeat = vi.fn();
98+const onAckTimeout = vi.fn();
99+100+timers.start({
101+intervalMs: 10_000,
102+isAcked: () => true,
103+ onAckTimeout,
104+ onHeartbeat,
105+random: () => 0.5,
106+});
107+108+timers.stop();
109+vi.advanceTimersByTime(100_000);
110+111+expect(onHeartbeat).not.toHaveBeenCalled();
112+expect(onAckTimeout).not.toHaveBeenCalled();
113+});
114+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。