Path: blob/master/src/packages/backend/conat/test/socket/restarts.test.ts
1451 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: 750, publish: 750 });18});1920jest.setTimeout(15000);2122describe("create a client and server and socket, verify it works, restart conat server, then confirm that socket still works", () => {23const SUBJECT = "reconnect.one";2425let client,26server,27cn1,28cn2,29sockets: any[] = [];3031it("creates the client and server and confirms it works", async () => {32cn1 = connect();33server = cn1.socket.listen(SUBJECT);34server.on("connection", (socket) => {35sockets.push(socket);36socket.on("data", (data) => {37socket.write(`${data}`.repeat(2));38});39socket.on("request", (mesg) => {40mesg.respond("hello");41});42});43cn2 = connect();44client = cn2.socket.connect(SUBJECT);4546const iter = client.iter();47client.write("cocalc");48const { value } = await iter.next();49expect(value[0]).toBe("cocalccocalc");5051expect((await client.request(null)).data).toBe("hello");52});5354async function waitForClientsToReconnect() {55await Promise.all([once(cn1, "connected"), once(cn2, "connected")]);56}5758it("restarts the conat socketio server, wait for clients to reconnect, and test sending data over socket", async () => {59await restartServer();60await waitForClientsToReconnect();61// sending data over socket62const iter = client.iter();63client.write("test");64const { value, done } = await iter.next();65expect(done).toBe(false);66expect(value[0]).toBe("testtest");67});6869let socketDisconnects: string[] = [];70it("also request/respond immediately works", async () => {71expect((await client.request(null)).data).toBe("hello");72});7374it("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 () => {75expect(socketDisconnects.length).toBe(0);76});7778// this test should take several seconds due to having to missed-packet detection logic79it("restart connection right when message is being sent; dropped message eventually gets through automatically without waiting for reconnect", async () => {80const iter = client.iter();81client.write("conat ");82await restartServer();83const { value } = await iter.next();84expect(value[0]).toBe("conat conat ");85});8687it("cleans up", () => {88cn1.close();89cn2.close();90});91});9293describe("test of socket and restarting server -- restart while sending data from server to the client", () => {94const SUBJECT = "reconnect.two";9596let client,97server,98cn1,99cn2,100sockets: any[] = [];101102it("creates the client and server and confirms it works", async () => {103cn1 = connect();104server = cn1.socket.listen(SUBJECT);105server.on("connection", (socket) => {106sockets.push(socket);107socket.on("data", (data) => {108socket.write(`${data}`.repeat(2));109});110});111cn2 = connect();112client = cn2.socket.connect(SUBJECT);113const iter = client.iter();114client.write("cocalc");115const { value } = await iter.next();116expect(value[0]).toBe("cocalccocalc");117});118119// this test should take several seconds due to having to missed-packet detection logic120it("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 () => {121const socket = sockets[0];122const iter = client.iter();123socket.write("sneaky");124await restartServer();125const { value } = await iter.next();126expect(value[0]).toBe("sneaky");127});128129it("cleans up", () => {130cn1.close();131cn2.close();132});133});134135describe("another restart test: sending data while reconnecting to try to screw with order of arrival of messages", () => {136const SUBJECT = "reconnect.three";137138let client,139server,140cn1,141cn2,142sockets: any[] = [],143iter;144it("creates the client and server and confirms it works", async () => {145cn1 = connect();146server = cn1.socket.listen(SUBJECT);147server.on("connection", (socket) => {148sockets.push(socket);149socket.on("data", (data) => {150socket.write(`${data}`.repeat(2));151});152});153cn2 = connect();154client = cn2.socket.connect(SUBJECT);155iter = client.iter();156client.write("one ");157const { value } = await iter.next();158expect(value[0]).toBe("one one ");159});160161it("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 () => {162client.write("four ");163await restartServer();164165// write another message to socket to cause out of order message deliver166// to the other end167client.write("five ");168const { value } = await iter.next();169expect(value[0]).toBe("four four ");170171// also checking ordering is correct too -- we next172// next get the foofoo response;173const { value: value1 } = await iter.next();174expect(value1[0]).toBe("five five ");175});176177it("cleans up", () => {178cn1.close();179cn2.close();180});181});182183afterAll(after);184185186