UNPKG

reliable-zeromq

Version:

A collection of reliable zeromq messaging constructs

206 lines 18.1 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const ava_1 = __importDefault(require("ava")); const sinon = __importStar(require("sinon")); const ts_mock_imports_1 = require("ts-mock-imports"); const zmq = __importStar(require("zeromq")); const Config_1 = __importDefault(require("../../Src/Config")); const JSONBigInt_1 = __importDefault(require("../../Src/Utils/JSONBigInt")); const ZMQRequest_1 = require("../../Src/ZMQRequest"); const ZMQResponse_1 = require("../../Src/ZMQResponse"); const AsyncTools_1 = require("../Helpers/AsyncTools"); const test = ava_1.default; test.beforeEach((t) => { const lResolvers = []; function FakeIterator() { return { async next() { return new Promise((aResolve) => { lResolvers.push(aResolve); }); }, }; } const lMockManager = ts_mock_imports_1.ImportMock.mockClass(zmq, "Dealer"); // @ts-ignore const lAsyncIteratorMock = lMockManager.mock(Symbol.asyncIterator); lAsyncIteratorMock.callsFake(FakeIterator); t.context = { ResponderEndpoint: "tcp://127.0.0.1:3000", TestData: [ { a: 100n, b: 20n, c: 0.5, d: [ 5n, "myFunc()", ], }, ], DealerMock: lMockManager, SendToReceiver: (aIndex, aMessage) => { lResolvers[aIndex]({ value: aMessage, done: false }); }, }; }); test.afterEach((t) => { sinon.restore(); ts_mock_imports_1.ImportMock.restore(); }); test.serial("Start, Send, Receive, Close", async (t) => { const lDealerStub = t.context.DealerMock; const lRequester = new ZMQRequest_1.ZMQRequest(t.context.ResponderEndpoint); t.is(lRequester.Endpoint, t.context.ResponderEndpoint); lDealerStub.mock("connect", undefined); const lSendMock = lDealerStub.mock("send", Promise.resolve()); const lRequestPromise = lRequester.Send(JSONBigInt_1.default.Stringify(t.context.TestData)); await AsyncTools_1.YieldToEventLoop(); let lCallCount = 0; t.is(lSendMock.callCount, ++lCallCount); t.deepEqual(lSendMock.getCall(lCallCount - 1).args[0], [ lRequester["mOurUniqueId"], "0", JSONBigInt_1.default.Stringify(t.context.TestData), ]); const lResponse = [ "0", "dummy message", ]; t.context.SendToReceiver(0, lResponse); const lPromiseResult = await lRequestPromise; t.deepEqual(lPromiseResult.Response, lResponse[1]); lRequester.Close(); }); test.serial("Degraded Connection", async (t) => { const clock = sinon.useFakeTimers(); const lDealerStub = t.context.DealerMock; const lRequester = new ZMQRequest_1.ZMQRequest(t.context.ResponderEndpoint); t.is(lRequester.Endpoint, t.context.ResponderEndpoint); lDealerStub.mock("connect", undefined); lDealerStub.mock("send", Promise.resolve()); const lRequestPromise = lRequester.Send(JSONBigInt_1.default.Stringify(t.context.TestData)); const lResponse = [ "0", "dummy message", ]; // Send response with 500ms delay await AsyncTools_1.YieldToEventLoop(); // Sinon timers don't seem super reliable at triggering timeouts clock.tick(501); await AsyncTools_1.YieldToEventLoop(); t.context.SendToReceiver(0, lResponse); const lPromiseResult = await lRequestPromise; t.is(lPromiseResult.Response, lResponse[1]); const lSecondRequest = lRequester.Send("MyTestDelayedResponse"); const lSecondResponse = [ "1", "another response", ]; // Send 3 responses (2 duplicates) with 2200ms delay await AsyncTools_1.YieldToEventLoop(); clock.tick(501); await AsyncTools_1.YieldToEventLoop(); t.context.SendToReceiver(1, lSecondResponse); await AsyncTools_1.YieldToEventLoop(); t.context.SendToReceiver(2, lSecondResponse); await AsyncTools_1.YieldToEventLoop(); t.context.SendToReceiver(3, lSecondResponse); await AsyncTools_1.YieldToEventLoop(); t.is((await lSecondRequest).Response, lSecondResponse[1]); lRequester.Close(); }); test.serial("Errors & Warns", async (t) => { const clock = sinon.useFakeTimers(); const lDealerStub = t.context.DealerMock; const lEndpoint = t.context.ResponderEndpoint; const lHighWaterMarkWarnings = []; const lRequester = new ZMQRequest_1.ZMQRequest(lEndpoint); const lRequesterCustom = new ZMQRequest_1.ZMQRequest(lEndpoint, { HighWaterMarkWarning: (aWarning) => { lHighWaterMarkWarnings.push(aWarning); }, }); lDealerStub.mock("send", Promise.resolve()); lDealerStub.mock("connect", undefined); const lFirstResponsePromise = lRequester.Send(JSONBigInt_1.default.Stringify("hello")); t.context.SendToReceiver(0, [JSONBigInt_1.default.Stringify(0), "world"]); clock.tick(500); t.is((await lFirstResponsePromise).Response, "world"); const lFailedRequest = lRequester.Send(JSONBigInt_1.default.Stringify("hello")); await AsyncTools_1.YieldToEventLoop(); clock.tick(Config_1.default.MaximumLatency * 2 + 600); // 500ms represents the polling interval in ZMQRequest await AsyncTools_1.YieldToEventLoop(); const lFailedResult = await lFailedRequest; if (lFailedResult.ResponseType === ZMQRequest_1.ERequestResponse.TIMEOUT) { t.is(lFailedResult.MessageNonce, 1); t.is(lFailedResult.RequestBody[ZMQRequest_1.ERequestBody.Nonce], "1"); t.is(lFailedResult.RequestBody[ZMQRequest_1.ERequestBody.Message], "\"hello\""); } else { t.fail("lFailedRequest should have resolved to TRequestTimeOut"); } lDealerStub.mock("send", Promise.reject({ code: "EAGAIN", })); t.is(lHighWaterMarkWarnings.length, 0); const lDefaultWarnPromise = lRequester.Send("THIS SHOULD BE SUPPRESSED"); const lCustomWarnPromise = lRequesterCustom.Send("THIS SHOULD PUSH TO ARRAY"); await AsyncTools_1.YieldToEventLoop(); t.is(lHighWaterMarkWarnings.length, 1); t.deepEqual(lHighWaterMarkWarnings[0], { Requester: lRequesterCustom["mOurUniqueId"], Nonce: 0, Message: "THIS SHOULD PUSH TO ARRAY", }); lDealerStub.mock("send", Promise.resolve()); t.context.SendToReceiver(2, ["2", "default errors response"]); await AsyncTools_1.YieldToEventLoop(); t.context.SendToReceiver(1, ["0", "custom errors response"]); await AsyncTools_1.YieldToEventLoop(); t.deepEqual(await lDefaultWarnPromise, { ResponseType: ZMQRequest_1.ERequestResponse.SUCCESS, Response: "default errors response", }); t.deepEqual(await lCustomWarnPromise, { ResponseType: ZMQRequest_1.ERequestResponse.SUCCESS, Response: "custom errors response", }); const lCacheError = lRequester.Send("THIS SHOULD TRIGGER A CACHE ERROR"); await AsyncTools_1.YieldToEventLoop(); t.context.SendToReceiver(3, ["3", ZMQResponse_1.RESPONSE_CACHE_EXPIRED]); await AsyncTools_1.YieldToEventLoop(); t.deepEqual(await lCacheError, { ResponseType: ZMQRequest_1.ERequestResponse.CACHE_ERROR, Endpoint: lEndpoint, MessageNonce: 3, }); lRequester.Close(); lRequesterCustom.Close(); await AsyncTools_1.YieldToEventLoop(); t.context.SendToReceiver(4, ["-10", "custom handler suppress"]); t.context.SendToReceiver(5, ["-10", "default handler suppress"]); await AsyncTools_1.YieldToEventLoop(); }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiWk1RUmVxdWVzdC50ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vVGVzdC9TcmMvWk1RUmVxdWVzdC50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUVBLDhDQUFnRDtBQUNoRCw2Q0FBK0I7QUFDL0IscURBQTBEO0FBQzFELDRDQUE4QjtBQUM5Qiw4REFBc0M7QUFFdEMsNEVBQW9EO0FBQ3BELHFEQUF3SDtBQUN4SCx1REFBK0Q7QUFDL0Qsc0RBQXlEO0FBV3pELE1BQU0sSUFBSSxHQUFnQyxhQUFzQyxDQUFDO0FBRWpGLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFpQyxFQUFRLEVBQUU7SUFFeEQsTUFBTSxVQUFVLEdBQWtELEVBQUUsQ0FBQztJQUNyRSxTQUFTLFlBQVk7UUFFakIsT0FBTztZQUNILEtBQUssQ0FBQyxJQUFJO2dCQUVOLE9BQU8sSUFBSSxPQUFPLENBQUMsQ0FBQyxRQUFnRCxFQUFRLEVBQUU7b0JBRTFFLFVBQVUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7Z0JBQzlCLENBQUMsQ0FBQyxDQUFDO1lBQ1AsQ0FBQztTQUNKLENBQUM7SUFDTixDQUFDO0lBRUQsTUFBTSxZQUFZLEdBQTRCLDRCQUFVLENBQUMsU0FBUyxDQUFhLEdBQUcsRUFBRSxRQUFRLENBQUMsQ0FBQztJQUM5RixhQUFhO0lBQ2IsTUFBTSxrQkFBa0IsR0FBb0IsWUFBWSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLENBQUM7SUFDcEYsa0JBQWtCLENBQUMsU0FBUyxDQUFDLFlBQVksQ0FBQyxDQUFDO0lBRTNDLENBQUMsQ0FBQyxPQUFPLEdBQUc7UUFDUixpQkFBaUIsRUFBRSxzQkFBc0I7UUFDekMsUUFBUSxFQUFFO1lBQ047Z0JBQ0ksQ0FBQyxFQUFFLElBQUk7Z0JBQ1AsQ0FBQyxFQUFFLEdBQUc7Z0JBQ04sQ0FBQyxFQUFFLEdBQUc7Z0JBQ04s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