Path: blob/master/src/packages/backend/conat/test/socket/restarts.test.ts
1712 views
/*12pnpm test `pwd`/restarts.test.ts34*/56import {7before,8after,9connect,10restartServer,11setDefaultTimeouts,12} from "@cocalc/backend/conat/test/setup";13import { once } from "@cocalc/util/async-utils";1415beforeAll(async () => {16await before();17setDefaultTimeouts({ request: 500, publish: 500 });18});1920describe("create a client and server and socket, verify it works, restart conat server, then confirm that socket still works", () => {21const SUBJECT = "reconnect.one";2223let client,24server,25cn1,26cn2,27sockets: any[] = [];2829it("creates the client and server and confirms it works", async () => {30cn1 = connect();31server = cn1.socket.listen(SUBJECT);32server.on("connection", (socket) => {33sockets.push(socket);34socket.on("data", (data) => {35socket.write(`${data}`.repeat(2));36});37socket.on("request", (mesg) => {38mesg.respond("hello");39});40});41cn2 = connect();42client = cn2.socket.connect(SUBJECT);4344const iter = client.iter();45client.write("cocalc");46const { value } = await iter.next();47expect(value[0]).toBe("cocalccocalc");4849expect((await client.request(null)).data).toBe("hello");50});5152async function waitForClientsToReconnect() {53for (const client of [cn1, cn2]) {54if (client.state != "connected") {55await once(client, "connected");56}57}58}5960it("restarts the conat socketio server, wait for clients to reconnect, and test sending data over socket", async () => {61await restartServer();62await waitForClientsToReconnect();63// sending data over socket64const iter = client.iter();65client.write("test");66const { value, done } = await iter.next();67expect(done).toBe(false);68expect(value[0]).toBe("testtest");69});7071let socketDisconnects: string[] = [];72it("also request/respond immediately works", async () => {73expect((await client.request(null)).data).toBe("hello");74});7576it("observes the socket did not disconnect - they never do until a timeout or being explicitly closed, which is the point of sockets -- they are robust to client connection state", async () => {77expect(socketDisconnects.length).toBe(0);78});7980// this test should take several seconds due to having to missed-packet detection logic81it("restart connection right when message is being sent; dropped message eventually gets through automatically without waiting for reconnect", async () => {82const iter = client.iter();83client.write("conat ");84await restartServer();85const { value } = await iter.next();86expect(value[0]).toBe("conat conat ");87});8889it("cleans up", () => {90cn1.close();91cn2.close();92});93});9495describe("test of socket and restarting server -- restart while sending data from server to the client", () => {96const SUBJECT = "reconnect.two";9798let client,99server,100cn1,101cn2,102sockets: any[] = [];103104it("creates the client and server and confirms it works", async () => {105cn1 = connect();106server = cn1.socket.listen(SUBJECT);107server.on("connection", (socket) => {108sockets.push(socket);109socket.on("data", (data) => {110socket.write(`${data}`.repeat(2));111});112});113cn2 = connect();114client = cn2.socket.connect(SUBJECT);115const iter = client.iter();116client.write("cocalc");117const { value } = await iter.next();118expect(value[0]).toBe("cocalccocalc");119});120121// this test should take several seconds due to having to missed-packet detection logic122it("restart connection as we are sending data from the server to the client, and see again that nothing is lost - this the server --> client direction of the tests below which was client --> server", async () => {123const socket = sockets[0];124const iter = client.iter();125socket.write("sneaky");126await restartServer();127const { value } = await iter.next();128expect(value[0]).toBe("sneaky");129});130131it("cleans up", () => {132cn1.close();133cn2.close();134});135});136137describe("another restart test: sending data while reconnecting to try to screw with order of arrival of messages", () => {138const SUBJECT = "reconnect.three";139140let client,141server,142cn1,143cn2,144sockets: any[] = [],145iter;146it("creates the client and server and confirms it works", async () => {147cn1 = connect();148server = cn1.socket.listen(SUBJECT);149server.on("connection", (socket) => {150sockets.push(socket);151socket.on("data", (data) => {152socket.write(`${data}`.repeat(2));153});154});155cn2 = connect();156client = cn2.socket.connect(SUBJECT);157iter = client.iter();158client.write("one ");159const { value } = await iter.next();160expect(value[0]).toBe("one one ");161});162163it("now the **HARD CASE**; we do the same as above, but kill the server exactly as the message is being sent, so it is dropped", async () => {164client.write("four ");165await restartServer();166167// write another message to socket to cause out of order message deliver168// to the other end169client.write("five ");170const { value } = await iter.next();171expect(value[0]).toBe("four four ");172173// also checking ordering is correct too -- we next174// next get the foofoo response;175const { value: value1 } = await iter.next();176expect(value1[0]).toBe("five five ");177});178179it("cleans up", () => {180cn1.close();181cn2.close();182});183});184185afterAll(after);186187188