Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/conat/core/client.reconnect.test.ts
14422 views
1
/*
2
DEVELOPMENT:
3
4
pnpm test ./client.reconnect.test.ts
5
*/
6
7
function mockSocketIO({ emitWithAck = jest.fn() } = {}) {
8
const socket = {
9
on: jest.fn(),
10
emit: jest.fn(),
11
disconnect: jest.fn(),
12
close: jest.fn(),
13
timeout: jest.fn(() => ({ emitWithAck })),
14
io: {
15
on: jest.fn(),
16
connect: jest.fn(),
17
disconnect: jest.fn(),
18
},
19
};
20
const connectToSocketIO = jest.fn(() => socket);
21
22
jest.doMock("socket.io-client", () => ({
23
connect: connectToSocketIO,
24
}));
25
26
return { socket, connectToSocketIO, emitWithAck };
27
}
28
29
describe("core client socket.io reconnect policy", () => {
30
it("respects reconnection false passed by callers", async () => {
31
jest.resetModules();
32
33
const { connectToSocketIO } = mockSocketIO();
34
35
const { connect } = require("./client");
36
const client = connect({
37
address: "http://example.com",
38
reconnection: false,
39
});
40
41
expect(connectToSocketIO).toHaveBeenCalledWith(
42
expect.any(String),
43
expect.objectContaining({
44
reconnection: false,
45
}),
46
);
47
48
client.close();
49
});
50
51
it("does not auto-connect when callers pass autoConnect false", async () => {
52
jest.resetModules();
53
54
const { connectToSocketIO, socket } = mockSocketIO();
55
56
const { connect } = require("./client");
57
const client = connect({
58
address: "http://example.com",
59
autoConnect: false,
60
noCache: true,
61
});
62
63
expect(connectToSocketIO).toHaveBeenCalledWith(
64
expect.any(String),
65
expect.objectContaining({
66
autoConnect: false,
67
}),
68
);
69
expect(socket.io.connect).not.toHaveBeenCalled();
70
71
client.connect();
72
expect(socket.io.connect).toHaveBeenCalledTimes(1);
73
74
client.close();
75
});
76
});
77
78
describe("core client subscription resync on reconnect", () => {
79
it("does not unsubscribe subjects the client still wants during resync", async () => {
80
jest.resetModules();
81
82
const emitWithAck = jest
83
.fn()
84
.mockResolvedValueOnce(["wanted.subject"])
85
.mockResolvedValueOnce([]);
86
mockSocketIO({ emitWithAck });
87
88
const { Client } = require("./client");
89
const client = new Client({
90
address: "http://example.com",
91
autoConnect: false,
92
noCache: true,
93
});
94
const anyClient = client as any;
95
anyClient.info = { user: { hub_id: "hub" } };
96
anyClient.state = "connected";
97
anyClient.queueGroups = { "wanted.subject": "0" };
98
99
const stable = await anyClient.syncSubscriptions0(1000);
100
101
expect(stable).toBe(true);
102
expect(emitWithAck).toHaveBeenCalledTimes(1);
103
expect(emitWithAck).toHaveBeenCalledWith("subscriptions", null);
104
105
client.close();
106
});
107
108
it("unsubscribes only server-side extras during resync", async () => {
109
jest.resetModules();
110
111
const emitWithAck = jest
112
.fn()
113
.mockResolvedValueOnce(["wanted.subject", "stale.subject"])
114
.mockResolvedValueOnce([]);
115
mockSocketIO({ emitWithAck });
116
117
const { Client } = require("./client");
118
const client = new Client({
119
address: "http://example.com",
120
autoConnect: false,
121
noCache: true,
122
});
123
const anyClient = client as any;
124
anyClient.info = { user: { hub_id: "hub" } };
125
anyClient.state = "connected";
126
anyClient.queueGroups = { "wanted.subject": "0" };
127
128
const stable = await anyClient.syncSubscriptions0(1000);
129
130
expect(stable).toBe(false);
131
expect(emitWithAck).toHaveBeenNthCalledWith(1, "subscriptions", null);
132
expect(emitWithAck).toHaveBeenNthCalledWith(2, "unsubscribe", [
133
{ subject: "stale.subject" },
134
]);
135
136
client.close();
137
});
138
});
139
140