Path: blob/master/src/packages/backend/conat/test/cluster/node-discovery.test.ts
1712 views
import {1before,2after,3delay,4wait,5waitForConsistentState,6} from "@cocalc/backend/conat/test/setup";7import { createClusterNode } from "./util";8import { isEqual } from "lodash";910beforeAll(before);1112jest.setTimeout(30000);13describe("test automatic node discovery (and forgetting)", () => {14const nodes: { client; server }[] = [];15const clusterName = "auto";16const create = async (id) => {17nodes.push(18await createClusterNode({19id,20clusterName,21autoscanInterval: 50,22longAutoscanInterval: 6000,23forgetClusterNodeInterval: 500, // make automatic forgetting short so we can test.24}),25);26};2728it("create two servers with cluster support enabled", async () => {29await create("node0");30await create("node1");31});3233it("connect 0 -> 1 and see other link get automatically added", async () => {34expect(nodes[0].server.clusterAddresses(clusterName).length).toBe(1);35await nodes[0].server.join(nodes[1].server.address());36expect(nodes[0].server.clusterAddresses(clusterName).length).toBe(2);37expect(nodes[1].server.clusterAddresses(clusterName).length).toBe(1);38await wait({39until: () => {40return nodes[1].server.clusterAddresses(clusterName).length == 2;41},42});43});4445it("make a new node and a connection 2 -> 1 and observe cluster gets completed automatically", async () => {46await create("node2");47await nodes[2].server.join(nodes[1].server.address());48// node0 and node1 don't instantly know node249expect(nodes[0].server.clusterAddresses(clusterName).length).toBe(2);50expect(nodes[1].server.clusterAddresses(clusterName).length).toBe(2);51expect(nodes[2].server.clusterAddresses(clusterName).length).toBe(2);52// but soon they will all know each other53await wait({54until: () => {55return (56nodes[0].server.clusterAddresses(clusterName).length == 3 &&57nodes[1].server.clusterAddresses(clusterName).length == 3 &&58nodes[2].server.clusterAddresses(clusterName).length == 359);60},61});62});6364// WORRY -- with count bigger, e.g., 5, sometimes this doesn't work.65// It might be an indicator of an issue.66const count = 3;67it(`check state is consistent -- before adding more ${count} nodes`, async () => {68await waitForConsistentState(nodes.map((x) => x.server));69});7071it(`add ${count} more nodes`, async () => {72for (let i = 3; i < 3 + count; i++) {73await create(`node${i}`);74await nodes[i].server.join(nodes[i - 1].server.address());75}76});7778it("wait until every node knows about every other node", async () => {79const total = nodes.length;80const all = new Set(nodes.map((x) => x.server.address()));81await wait({82until: () => {83for (let i = 0; i < total; i++) {84if (85!isEqual(86all,87new Set(nodes[i].server.clusterAddresses(clusterName)),88)89) {90return false;91}92}93return true;94},95});96});9798it(`wait for cluster to have consistent state -- after adding ${count} nodes`, async () => {99await waitForConsistentState(nodes.map((x) => x.server));100});101102it("close nodes[1], run scan, and observe that nodes[1] is forgotten", async () => {103const numNodes = () => {104return Object.keys(105nodes[0].server.clusterLinks[nodes[0].server.clusterName],106).length;107};108const n = numNodes();109nodes[1].server.close();110expect(nodes[1].server.isHealthy()).toBe(false);111// not instantly gone112expect(numNodes()).toBe(n);113await nodes[0].server.scan();114// still not gone115expect(numNodes()).toBe(n);116// wait a second and scan, and it must be gone (because we set the interval very short)117await delay(1000);118await nodes[0].server.scan();119expect(numNodes()).toBe(n - 1);120});121});122123afterAll(after);124125126