UNPKG

moleculer

Version:

Fast & powerful microservices framework for Node.JS

815 lines (615 loc) 27.3 kB
const ServiceBroker = require("../../src/service-broker"); const Context = require("../../src/context"); const Transit = require("../../src/transit"); const FakeTransporter = require("../../src/transporters/fake"); const { ValidationError } = require("../../src/errors"); const P = require("../../src/packets"); //const lolex = require("lolex"); describe("Test Transporter constructor", () => { const broker = new ServiceBroker(); const transporter = new FakeTransporter(); it("create instance", () => { let transit = new Transit(broker, transporter); expect(transit).toBeDefined(); expect(transit.opts).toBeUndefined(); expect(transit.connect).toBeDefined(); expect(transit.disconnect).toBeDefined(); expect(transit.emit).toBeDefined(); expect(transit.request).toBeDefined(); expect(transit.logger).toBeDefined(); expect(transit.nodeID).toBe(broker.nodeID); expect(transit.tx).toBe(transporter); expect(transit.nodes).toBeInstanceOf(Map); expect(transit.pendingRequests).toBeInstanceOf(Map); expect(transit.stat).toEqual({ packets: { sent: 0, received: 0 } }); }); it("create instance with options", () => { let opts = { id: 5 }; let transit = new Transit(broker, transporter, opts); expect(transit).toBeDefined(); expect(transit.opts).toBe(opts); }); it("should call transporter.init", () => { transporter.init = jest.fn(); let transit = new Transit(broker, transporter); expect(transporter.init).toHaveBeenCalledTimes(1); expect(transporter.init).toHaveBeenCalledWith(transit, jasmine.any(Function), jasmine.any(Function)); }); }); describe("Test Transit.connect", () => { const broker = new ServiceBroker(); const transporter = new FakeTransporter(); const transit = new Transit(broker, transporter); transporter.connect = jest.fn(() => Promise.resolve()); it("should call transporter connect", () => { let p = transit.connect().then(() => { expect(transporter.connect).toHaveBeenCalledTimes(1); expect(transit.__connectResolve).toBeDefined(); expect(transit.heartbeatTimer).toBeDefined(); expect(transit.checkNodesTimer).toBeDefined(); }); transit.__connectResolve(); return p; }); /* not working it("should recall transporter connect if failed", () => { let clock = lolex.install(); transporter.connect = jest.fn() .mockImplementationOnce(() => Promise.reject()) .mockImplementationOnce(() => Promise.resolve()); let p = transit.connect().then(() => { expect(transporter.connect).toHaveBeenCalledTimes(2); clock.uninstall(); }); clock.runAll(); return p; }); */ }); describe("Test Transit.afterConnect", () => { const broker = new ServiceBroker(); const transporter = new FakeTransporter(); const transit = new Transit(broker, transporter); let resolver; beforeEach(() => { resolver = jest.fn(); transit.__connectResolve = resolver; transit.makeSubscriptions = jest.fn(() => Promise.resolve()); transit.discoverNodes = jest.fn(() => Promise.resolve()); }); it("should call makeSubscriptions & discoverNodes", () => { return transit.afterConnect().then(() => { expect(transit.makeSubscriptions).toHaveBeenCalledTimes(1); expect(transit.discoverNodes).toHaveBeenCalledTimes(1); expect(resolver).toHaveBeenCalledTimes(1); expect(transit.__connectResolve).toBeNull(); }); }); it("should call only discoverNodes if was reconnected", () => { return transit.afterConnect(true).then(() => { expect(transit.makeSubscriptions).toHaveBeenCalledTimes(0); expect(transit.discoverNodes).toHaveBeenCalledTimes(1); expect(resolver).toHaveBeenCalledTimes(1); expect(transit.__connectResolve).toBeNull(); }); }); }); describe("Test Transit.disconnect", () => { const broker = new ServiceBroker(); const transporter = new FakeTransporter(); const transit = new Transit(broker, transporter); transporter.disconnect = jest.fn(() => Promise.resolve()); transit.sendDisconnectPacket = jest.fn(() => Promise.resolve()); transit.connect(); it("should call transporter disconnect & sendDisconnectPacket", () => { return transit.disconnect().then(() => { expect(transporter.disconnect).toHaveBeenCalledTimes(1); expect(transit.sendDisconnectPacket).toHaveBeenCalledTimes(1); expect(transit.heartbeatTimer).toBeNull(); expect(transit.checkNodesTimer).toBeNull(); }); }); }); describe("Test Transit.sendDisconnectPacket", () => { const broker = new ServiceBroker({ nodeID: "node1", transporter: new FakeTransporter() }); const transit = broker.transit; transit.publish = jest.fn(); it("should call publish iwth correct params", () => { return transit.sendDisconnectPacket().then(() => { expect(transit.publish).toHaveBeenCalledTimes(1); expect(transit.publish).toHaveBeenCalledWith(jasmine.any(P.PacketDisconnect)); }); }); }); describe("Test Transit.makeSubscriptions", () => { const broker = new ServiceBroker({ nodeID: "node1", transporter: new FakeTransporter() }); const transit = broker.transit; transit.subscribe = jest.fn(); it("should call subscribe with all topics", () => { transit.makeSubscriptions(); expect(transit.subscribe).toHaveBeenCalledTimes(8); expect(transit.subscribe).toHaveBeenCalledWith("EVENT"); expect(transit.subscribe).toHaveBeenCalledWith("REQ", "node1"); expect(transit.subscribe).toHaveBeenCalledWith("RES", "node1"); expect(transit.subscribe).toHaveBeenCalledWith("DISCOVER"); expect(transit.subscribe).toHaveBeenCalledWith("INFO"); expect(transit.subscribe).toHaveBeenCalledWith("INFO", "node1"); expect(transit.subscribe).toHaveBeenCalledWith("DISCONNECT"); expect(transit.subscribe).toHaveBeenCalledWith("HEARTBEAT"); }); }); describe("Test Transit.emit", () => { const broker = new ServiceBroker({ nodeID: "node1", transporter: new FakeTransporter() }); const transit = broker.transit; transit.publish = jest.fn(); it("should call publish with correct params", () => { const user = { id: 5, name: "Jameson" }; transit.emit("user.created", user); expect(transit.publish).toHaveBeenCalledTimes(1); const packet = transit.publish.mock.calls[0][0]; expect(packet).toBeInstanceOf(P.PacketEvent); expect(packet.payload.event).toBe("user.created"); expect(packet.payload.data).toBe("{\"id\":5,\"name\":\"Jameson\"}"); }); }); describe("Test Transit.messageHandler", () => { let broker; let transit; // transit.subscribe = jest.fn(); beforeEach(() => { broker = new ServiceBroker({ nodeID: "node1", transporter: new FakeTransporter() }); transit = broker.transit; }); it("should throw Error if msg not valid", () => { expect(transit.stat.packets.received).toBe(0); //transit.deserialize = jest.fn(() => null); expect(() => { transit.messageHandler("EVENT"); }).toThrow("Missing packet!"); //transit.deserialize.mockReset(); }); it("should call broker.emitLocal if topic is 'EVENT' ", () => { broker.emitLocal = jest.fn(); let msg = { sender: "remote", event: "user.created", data: JSON.stringify("John Doe") }; transit.messageHandler("EVENT", JSON.stringify(msg)); expect(broker.emitLocal).toHaveBeenCalledTimes(1); expect(broker.emitLocal).toHaveBeenCalledWith(msg.event, "John Doe", "remote"); expect(transit.stat.packets.received).toBe(1); }); describe("Test 'REQ'", () => { let broker = new ServiceBroker({ nodeID: "node1", transporter: new FakeTransporter() }); let transit = broker.transit; transit.sendResponse = jest.fn(); it("should call broker.call & sendResponse with result", () => { let response = [1, 5, 8]; broker.call = jest.fn(() => Promise.resolve(response)); let msg = { sender: "remote", action: "posts.find", id: "123", params: JSON.stringify({ limit: 5 }), meta: JSON.stringify({ b: 100 }), parentID: "555", level: 5, metrics: true }; return transit.messageHandler("REQ", JSON.stringify(msg)).then(() => { expect(broker.call).toHaveBeenCalledTimes(1); expect(broker.call).toHaveBeenCalledWith(msg.action, { limit: 5 }, { ctx: jasmine.any(Context) }); // Check context props const ctx = broker.call.mock.calls[0][2].ctx; expect(ctx).toBeInstanceOf(Context); expect(ctx.id).toBe("123"); expect(ctx.parentID).toBe("555"); expect(ctx.action.name).toBe("posts.find"); expect(ctx.params).toEqual({ limit: 5 }); expect(ctx.meta).toEqual({ b: 100 }); expect(ctx.metrics).toBe(true); expect(ctx.level).toBe(5); expect(transit.sendResponse).toHaveBeenCalledTimes(1); expect(transit.sendResponse).toHaveBeenCalledWith("remote", "123", [1, 5, 8], null); }); }); it("should call broker.call & sendResponse with error", () => { transit.sendResponse.mockClear(); broker.call = jest.fn(() => Promise.reject(new ValidationError("Not valid params"))); let msg = { sender: "remote", action: "posts.create", id: "123", params: JSON.stringify({ title: "Hello" }), meta: "{}" }; return transit.messageHandler("REQ", JSON.stringify(msg)).then(() => { expect(broker.call).toHaveBeenCalledTimes(1); expect(broker.call).toHaveBeenCalledWith(msg.action, { title: "Hello" }, { ctx: jasmine.any(Context) }); // Check context props const ctx = broker.call.mock.calls[0][2].ctx; expect(ctx).toBeInstanceOf(Context); expect(ctx.id).toBe("123"); expect(ctx.params).toEqual({"title": "Hello"}); expect(ctx.meta).toEqual({}); expect(transit.sendResponse).toHaveBeenCalledTimes(1); expect(transit.sendResponse).toHaveBeenCalledWith("remote", "123", null, jasmine.any(ValidationError)); }); }); }); describe("Test 'RES'", () => { const broker = new ServiceBroker({ nodeID: "node1", transporter: new FakeTransporter() }); const transit = broker.transit; let id = "12345"; it("should not call resolve or reject if prending req is not exists", () => { let req = { resolve: jest.fn(), reject: jest.fn() }; let msg = { sender: "remote", id }; return transit.messageHandler("RES", JSON.stringify(msg)).then(() => { expect(req.resolve).toHaveBeenCalledTimes(0); expect(req.reject).toHaveBeenCalledTimes(0); }); }); it("should call resolve with data", () => { let data = { id: 5, name: "John" }; let req = { action: { name: "posts.find" }, resolve: jest.fn(() => Promise.resolve()), reject: jest.fn(() => Promise.resolve()) }; transit.pendingRequests.set(id, req); let msg = { sender: "remote", id, success: true, data: JSON.stringify(data) }; return transit.messageHandler("RES", JSON.stringify(msg)).then(() => { expect(req.resolve).toHaveBeenCalledTimes(1); expect(req.resolve).toHaveBeenCalledWith(data); expect(req.reject).toHaveBeenCalledTimes(0); expect(transit.pendingRequests.size).toBe(0); }); }); it("should call reject with error", () => { let req = { action: { name: "posts.find" }, resolve: jest.fn(), reject: jest.fn(err => Promise.reject(err)) }; transit.pendingRequests.set(id, req); let msg = { sender: "remote", id, success: false, error: { name: "ValidationError", code: 422, data: JSON.stringify({ a: 5 }) }}; return transit.messageHandler("RES", JSON.stringify(msg)).catch(err => { expect(req.reject).toHaveBeenCalledTimes(1); expect(req.reject).toHaveBeenCalledWith(err); expect(req.resolve).toHaveBeenCalledTimes(0); expect(err.name).toBe("ValidationError"); expect(err.code).toBe(422); expect(err.data).toEqual({ a: 5 }); expect(err.nodeID).toBe("remote"); expect(transit.pendingRequests.size).toBe(0); }); }); }); it("should call transit.processNodeInfo if topic is 'INFO' ", () => { transit.processNodeInfo = jest.fn(); let msg = { sender: "remote", services: JSON.stringify([]) }; transit.messageHandler("INFO", JSON.stringify(msg)); expect(transit.processNodeInfo).toHaveBeenCalledTimes(1); expect(transit.processNodeInfo).toHaveBeenCalledWith("remote", {"services": [], "sender": "remote"}); }); it("should call broker.processNodeInfo & sendNodeInfo if topic is 'DISCOVER' ", () => { transit.processNodeInfo = jest.fn(); transit.sendNodeInfo = jest.fn(); let msg = { sender: "remote", services: JSON.stringify([]) }; transit.messageHandler("DISCOVER", JSON.stringify(msg)); expect(transit.processNodeInfo).toHaveBeenCalledTimes(1); expect(transit.processNodeInfo).toHaveBeenCalledWith("remote", msg); expect(transit.sendNodeInfo).toHaveBeenCalledTimes(1); }); it("should call broker.nodeDisconnected if topic is 'DISCONNECT' ", () => { transit.nodeDisconnected = jest.fn(); let msg = { sender: "remote" }; transit.messageHandler("DISCONNECT", JSON.stringify(msg)); expect(transit.nodeDisconnected).toHaveBeenCalledTimes(1); expect(transit.nodeDisconnected).toHaveBeenCalledWith(msg.sender); }); it("should call broker.nodeHeartbeat if topic is 'HEARTBEAT' ", () => { transit.nodeHeartbeat = jest.fn(); let msg = { sender: "remote", uptime: 100 }; transit.messageHandler("HEARTBEAT", JSON.stringify(msg)); expect(transit.nodeHeartbeat).toHaveBeenCalledTimes(1); expect(transit.nodeHeartbeat).toHaveBeenCalledWith(msg.sender, msg); }); }); describe("Test Transit.request", () => { const broker = new ServiceBroker({ nodeID: "node1", transporter: new FakeTransporter() }); const transit = broker.transit; it("should create packet", () => { let ctx = new Context(broker, { name: "users.find" }); ctx.nodeID = "remote"; ctx.params = { a: 5 }; ctx.meta = { user: { id: 5, roles: [ "user" ] } }, ctx.timeout = 500; ctx.id = "12345"; transit.publish = jest.fn(() => { let req = transit.pendingRequests.get("12345"); return req.resolve(req); }); return transit.request(ctx).then(req => { expect(transit.pendingRequests.size).toBe(1); expect(transit.publish).toHaveBeenCalledTimes(1); const packet = transit.publish.mock.calls[0][0]; expect(packet).toBeInstanceOf(P.PacketRequest); expect(packet.payload.id).toBe("12345"); expect(packet.payload.action).toBe("users.find"); expect(packet.payload.params).toBe("{\"a\":5}"); expect(packet.payload.meta).toBe("{\"user\":{\"id\":5,\"roles\":[\"user\"]}}"); expect(packet.payload.timeout).toBe(500); expect(req.nodeID).toBe("remote"); //expect(req.ctx).toBe(ctx); expect(req.resolve).toBeInstanceOf(Function); expect(req.reject).toBeInstanceOf(Function); }); }); }); describe("Test Transit.sendResponse", () => { const broker = new ServiceBroker({ nodeID: "node1", transporter: new FakeTransporter() }); const transit = broker.transit; transit.publish = jest.fn(); it("should call publish with the data", () => { const data = { id: 1, name: "John Doe" }; transit.sendResponse("node2", "12345", data); expect(transit.publish).toHaveBeenCalledTimes(1); const packet = transit.publish.mock.calls[0][0]; expect(packet).toBeInstanceOf(P.PacketResponse); expect(packet.target).toBe("node2"); expect(packet.payload.id).toBe("12345"); expect(packet.payload.success).toBe(true); expect(packet.payload.data).toBe("{\"id\":1,\"name\":\"John Doe\"}"); }); it("should call publish with the error", () => { transit.publish.mockClear(); transit.sendResponse("node2", "12345", null, new ValidationError("Not valid params", "ERR_INVALID_A_PARAM", { a: "Too small" })); expect(transit.publish).toHaveBeenCalledTimes(1); const packet = transit.publish.mock.calls[0][0]; expect(packet).toBeInstanceOf(P.PacketResponse); expect(packet.target).toBe("node2"); expect(packet.payload.id).toBe("12345"); expect(packet.payload.success).toBe(false); expect(packet.payload.data).toBeNull(); expect(packet.payload.error).toBeDefined(); expect(packet.payload.error.name).toBe("ValidationError"); expect(packet.payload.error.message).toBe("Not valid params"); expect(packet.payload.error.code).toBe(422); expect(packet.payload.error.type).toBe("ERR_INVALID_A_PARAM"); expect(packet.payload.error.nodeID).toBe("node1"); expect(packet.payload.error.data).toBe("{\"a\":\"Too small\"}"); }); }); describe("Test Transit.discoverNodes", () => { const broker = new ServiceBroker({ nodeID: "node1", transporter: new FakeTransporter() }); const transit = broker.transit; transit.publish = jest.fn(); it("should call publish with correct params", () => { transit.discoverNodes(); expect(transit.publish).toHaveBeenCalledTimes(1); const packet = transit.publish.mock.calls[0][0]; expect(packet).toBeInstanceOf(P.PacketDiscover); expect(packet.payload).toEqual({ sender: "node1" }); }); }); describe("Test Transit.sendNodeInfo", () => { const broker = new ServiceBroker({ nodeID: "node1", transporter: new FakeTransporter(), internalActions: false }); const transit = broker.transit; transit.publish = jest.fn(); it("should call publish with correct params", () => { transit.sendNodeInfo("node2"); expect(transit.publish).toHaveBeenCalledTimes(1); const packet = transit.publish.mock.calls[0][0]; expect(packet).toBeInstanceOf(P.PacketInfo); expect(packet.target).toBe("node2"); expect(packet.payload.services).toBe("[]"); expect(packet.payload.ipList).toBeInstanceOf(Array); expect(packet.payload.versions).toBeDefined(); expect(packet.payload.versions.node).toBe(process.version); expect(packet.payload.versions.moleculer).toBe(broker.MOLECULER_VERSION); expect(packet.payload.uptime).toBeDefined(); }); }); describe("Test Transit.sendHeartbeat", () => { const broker = new ServiceBroker({ nodeID: "node1", transporter: new FakeTransporter() }); const transit = broker.transit; transit.publish = jest.fn(); it("should call publish with correct params", () => { transit.sendHeartbeat(); expect(transit.publish).toHaveBeenCalledTimes(1); const packet = transit.publish.mock.calls[0][0]; expect(packet).toBeInstanceOf(P.PacketHeartbeat); }); }); describe("Test Transit.subscribe", () => { const broker = new ServiceBroker({ nodeID: "node1", transporter: new FakeTransporter() }); const transit = broker.transit; const transporter = transit.tx; transporter.subscribe = jest.fn(); it("should call transporter.subscribe", () => { transit.subscribe("REQ", "node-2"); expect(transporter.subscribe).toHaveBeenCalledTimes(1); expect(transporter.subscribe).toHaveBeenCalledWith("REQ", "node-2"); }); }); describe("Test Transit.publish", () => { const broker = new ServiceBroker({ nodeID: "node1", transporter: new FakeTransporter() }); const transit = broker.transit; const transporter = transit.tx; transporter.publish = jest.fn(); broker.serializer.serialize = jest.fn(o => JSON.stringify(o)); it("should call transporter.publish", () => { expect(transit.stat.packets.sent).toBe(0); let packet = new P.PacketEvent("user.created", { a: "John Doe" }); transit.publish(packet); expect(transporter.publish).toHaveBeenCalledTimes(1); const p = transporter.publish.mock.calls[0][0]; expect(p).toBe(packet); expect(transit.stat.packets.sent).toBe(1); }); }); describe("Test Transit.serialize", () => { const broker = new ServiceBroker({ nodeID: "node1", transporter: new FakeTransporter() }); const transit = broker.transit; broker.serializer.serialize = jest.fn(); it("should call broker.serializer.serialize", () => { let payload = { a: "John Doe" }; transit.serialize(payload, P.PACKET_DISCOVER); expect(broker.serializer.serialize).toHaveBeenCalledTimes(1); expect(broker.serializer.serialize).toHaveBeenCalledWith(payload, P.PACKET_DISCOVER); }); }); describe("Test Transit.deserialize", () => { const broker = new ServiceBroker({ nodeID: "node1", transporter: new FakeTransporter() }); const transit = broker.transit; broker.serializer.deserialize = jest.fn(); it("should call broker.serializer.deserialize", () => { let payload = { a: "John Doe" }; transit.deserialize(payload, P.PACKET_DISCOVER); expect(broker.serializer.deserialize).toHaveBeenCalledTimes(1); expect(broker.serializer.deserialize).toHaveBeenCalledWith(payload, P.PACKET_DISCOVER); }); }); describe("Test Transit node & heartbeat handling", () => { describe("Test processNodeInfo", () => { const broker = new ServiceBroker({ nodeID: "node1", transporter: new FakeTransporter(), internalActions: false }); const transit = broker.transit; broker.registerRemoteService = jest.fn(); broker.emitLocal = jest.fn(); let remoteService = { name: "users", settings: {}, actions: {} }; let nodeInfo = { sender: "server-1", services: [ remoteService ] }; it("should emit a new node event & register remote actions", () => { transit.processNodeInfo("server-1", nodeInfo); let node = transit.nodes.get("server-1"); expect(node.id).toBe("server-1"); expect(node.available).toBe(true); expect(node.lastHeartbeatTime).toBeDefined(); expect(broker.emitLocal).toHaveBeenCalledTimes(1); expect(broker.emitLocal).toHaveBeenCalledWith("node.connected", node); expect(broker.registerRemoteService).toHaveBeenCalledTimes(1); expect(broker.registerRemoteService).toHaveBeenCalledWith("server-1", remoteService); }); it("should not emit event because node is exist but register remote actions again", () => { broker.emitLocal.mockClear(); broker.registerRemoteService.mockClear(); transit.processNodeInfo("server-1", nodeInfo); let node = transit.nodes.get("server-1"); expect(node.id).toBe("server-1"); expect(broker.emitLocal).toHaveBeenCalledTimes(0); expect(broker.registerRemoteService).toHaveBeenCalledTimes(1); expect(broker.registerRemoteService).toHaveBeenCalledWith("server-1", remoteService); }); it("should not process info if nodeID is null", () => { broker.emitLocal.mockClear(); broker.registerRemoteService.mockClear(); transit.processNodeInfo(null, nodeInfo); expect(broker.emitLocal).toHaveBeenCalledTimes(0); expect(broker.registerRemoteService).toHaveBeenCalledTimes(0); }); }); describe("Test isNodeAvailable", () => { let broker = new ServiceBroker({ nodeID: "node1", transporter: new FakeTransporter() }); const transit = broker.transit; it("should node is not available because is not exist", () => { expect(transit.isNodeAvailable("server-2")).toBe(false); }); it("should node is not available", () => { transit.nodes.set("server-2", { available: false }); expect(transit.isNodeAvailable("server-2")).toBe(false); }); it("should node is available", () => { transit.nodes.set("server-2", { available: true }); expect(transit.isNodeAvailable("server-2")).toBe(true); }); }); describe("Test transit.nodeHeartbeat", () => { let broker = new ServiceBroker({ nodeID: "node1", transporter: new FakeTransporter() }); const transit = broker.transit; transit.nodes.set("server-2", { available: false, lastHeartbeatTime: 1000 }); it("should node is not available because is not exist", () => { transit.nodeHeartbeat("server-2", { uptime: 123 }); expect(transit.nodes.get("server-2").available).toBe(true); expect(transit.nodes.get("server-2").lastHeartbeatTime).not.toBe(1000); expect(transit.nodes.get("server-2").uptime).toBe(123); }); }); describe("Test nodeDisconnected", () => { let broker = new ServiceBroker({ nodeID: "node1", transporter: new FakeTransporter() }); const transit = broker.transit; broker.emitLocal = jest.fn(); broker.unregisterServicesByNode = jest.fn(); transit.nodes.set("server-2", { available: true }); it("should not emit event because node is not found", () => { broker.emitLocal.mockClear(); transit.nodeDisconnected("server-1"); expect(broker.emitLocal).toHaveBeenCalledTimes(0); }); it("should set node to unavailable and emit a `disconnected` event", () => { broker.emitLocal.mockClear(); transit.nodeDisconnected("server-2"); expect(transit.nodes.get("server-2").available).toBe(false); expect(broker.emitLocal).toHaveBeenCalledTimes(1); expect(broker.emitLocal).toHaveBeenCalledWith("node.disconnected", {"available": false }); }); it("should set node to unavailable and emit a `broken` event", () => { broker.emitLocal.mockClear(); transit.nodes.set("server-2", { available: true }); transit.nodeDisconnected("server-2", true); expect(transit.nodes.get("server-2").available).toBe(false); expect(broker.emitLocal).toHaveBeenCalledTimes(1); expect(broker.emitLocal).toHaveBeenCalledWith("node.broken", {"available": false }); }); it("should set node to unavailable and emit a `broken` event", () => { broker.emitLocal.mockClear(); transit.processNodeInfo("server-2", { services: [] }); expect(transit.nodes.get("server-2").available).toBe(true); expect(broker.emitLocal).toHaveBeenCalledTimes(1); expect(broker.emitLocal).toHaveBeenCalledWith("node.reconnected", transit.nodes.get("server-2")); }); let remoteService = { name: "users", settings: {}, actions: {} }; transit.nodes.set("server-3", { id: "server-3", available: true, services: [ remoteService ] }); broker.registerRemoteService("server-3", remoteService); it("should unregister actions of disconnected node", () => { broker.unregisterServicesByNode.mockClear(); transit.nodeDisconnected("server-3"); expect(broker.unregisterServicesByNode).toHaveBeenCalledTimes(1); expect(broker.unregisterServicesByNode).toHaveBeenCalledWith("server-3"); }); }); describe("Test nodeDisconnected", () => { let broker = new ServiceBroker({ nodeID: "node1", transporter: new FakeTransporter() }); const transit = broker.transit; broker.nodeDisconnected = jest.fn(); transit.nodes.set("server-2", { id: "server-2", available: true }); it("should call 'nodeDisconnected' if the heartbeat time is too old", () => { let node = transit.nodes.get("server-2"); transit.nodeDisconnected = jest.fn(); transit.nodeHeartbeat("server-2", { uptime: 156 }); transit.checkRemoteNodes(); expect(transit.nodeDisconnected).toHaveBeenCalledTimes(0); expect(node.uptime).toBe(156); node.lastHeartbeatTime -= broker.options.heartbeatTimeout * 1.5 * 1000; transit.checkRemoteNodes(); expect(transit.nodeDisconnected).toHaveBeenCalledTimes(1); expect(transit.nodeDisconnected).toHaveBeenCalledWith("server-2", true); }); }); });