reliable-zeromq
Version:
A collection of reliable zeromq messaging constructs
220 lines • 22.5 kB
JavaScript
;
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 });
/* tslint:disable: no-string-literal */
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 ZMQResponse_1 = require("../../Src/ZMQResponse");
const AsyncTools_1 = require("../Helpers/AsyncTools");
const test = ava_1.default;
test.before((t) => {
// Unnecessary
});
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, "Router");
// @ts-ignore
const lAsyncIteratorMock = lMockManager.mock(Symbol.asyncIterator);
lAsyncIteratorMock.callsFake(FakeIterator);
t.context = {
ResponderEndpoint: "tcp://127.0.0.1:3001",
RouterMock: lMockManager,
SendToReceiver: (aIndex, aMessage) => {
lResolvers[aIndex]({ value: aMessage, done: false });
},
};
});
test.afterEach((t) => {
sinon.restore();
ts_mock_imports_1.ImportMock.restore();
});
test.serial("Start, Receive, Close", async (t) => {
let lResponder = async (aMsg) => "world";
const lResponderRouter = (aMsg) => {
return lResponder(aMsg); // Necessary so we can update lResponder throughout
};
const lSendMock = t.context.RouterMock.mock("send", Promise.resolve());
const lBindMock = t.context.RouterMock.mock("bind", Promise.resolve());
const lResponse = new ZMQResponse_1.ZMQResponse(t.context.ResponderEndpoint, lResponderRouter);
await AsyncTools_1.YieldToEventLoop(); // Listening to asyncIterator occurs asynchronously, so we need to yield
t.is(lResponse.Endpoint, t.context.ResponderEndpoint);
t.is(lBindMock.callCount, 1);
// Send first message to ZMQResponse
t.context.SendToReceiver(0, [
"sender",
"unique_sender_id",
"0",
"hello",
]);
await AsyncTools_1.YieldToEventLoop();
let lRouterSendCalls = 0;
t.is(lSendMock.callCount, ++lRouterSendCalls);
t.is(lResponse["mCachedRequests"].size, 1);
t.deepEqual(lSendMock.getCall(lRouterSendCalls - 1).args[0], ["sender", "0", "world"]);
lResponder = async (aMsg) => aMsg + " response";
t.context.SendToReceiver(1, [
"sender",
"unique_sender_id",
"1",
"this should not throw",
]);
await AsyncTools_1.YieldToEventLoop();
t.is(lSendMock.callCount, ++lRouterSendCalls);
t.is(lResponse["mCachedRequests"].size, 2);
t.deepEqual(lSendMock.getCall(lRouterSendCalls - 1).args[0], ["sender", "1", "this should not throw response"]);
t.context.SendToReceiver(2, [
"sender",
"unique_sender_id",
"1",
"this should not throw",
]);
await AsyncTools_1.YieldToEventLoop();
t.is(lSendMock.callCount, ++lRouterSendCalls);
t.is(lResponse["mCachedRequests"].size, 2);
t.deepEqual(lSendMock.getCall(lRouterSendCalls - 1).args[0], ["sender", "1", "this should not throw response"]);
t.context.SendToReceiver(3, [
"sender",
"unique_sender_id",
"1",
"this should not throw",
]);
await AsyncTools_1.YieldToEventLoop();
t.is(lSendMock.callCount, ++lRouterSendCalls);
t.is(lResponse["mCachedRequests"].size, 2);
t.deepEqual(lSendMock.getCall(lRouterSendCalls - 1).args[0], ["sender", "1", "this should not throw response"]);
t.context.SendToReceiver(4, [
"sender",
"unique_sender_id",
"3",
"this should not throw",
]);
await AsyncTools_1.YieldToEventLoop();
t.is(lSendMock.callCount, ++lRouterSendCalls);
t.is(lResponse["mCachedRequests"].size, 3);
t.deepEqual(lSendMock.getCall(lRouterSendCalls - 1).args[0], ["sender", "3", "this should not throw response"]);
t.context.SendToReceiver(5, [
"sender",
"unique_sender_id",
"2",
"this should not throw",
]);
await AsyncTools_1.YieldToEventLoop();
t.is(lSendMock.callCount, ++lRouterSendCalls);
t.is(lResponse["mCachedRequests"].size, 4);
t.deepEqual(lSendMock.getCall(lRouterSendCalls - 1).args[0], ["sender", "2", "this should not throw response"]);
// Test LowestUnseenNonce garbage cleaning
t.is(lResponse["mSeenMessages"].get("unique_sender_id").Has(0), true);
t.is(lResponse["mSeenMessages"].get("unique_sender_id").Has(1), true);
t.is(lResponse["mSeenMessages"].get("unique_sender_id").Has(2), true);
t.is(lResponse["mSeenMessages"].get("unique_sender_id").Has(3), true);
t.is(lResponse["mSeenMessages"].get("unique_sender_id").Has(4), false);
lResponse.Close();
});
test.serial("Errors & Warns", async (t) => {
const clock = sinon.useFakeTimers();
let lResponder = (aMsg) => Promise.resolve(aMsg + " RES");
const lResponderRouter = (aMsg) => {
return lResponder(aMsg); // Necessary so we can update lResponder throughout
};
const lEndpoint = t.context.ResponderEndpoint;
const lSendMock = t.context.RouterMock.mock("send", Promise.resolve());
t.context.RouterMock.mock("bind", Promise.resolve());
const lWarnings = [];
const lResponse = new ZMQResponse_1.ZMQResponse(lEndpoint, lResponderRouter);
const lCustomResponse = new ZMQResponse_1.ZMQResponse(lEndpoint, lResponderRouter, {
HighWaterMarkWarning: (aWarning) => {
lWarnings.push(aWarning);
},
});
await AsyncTools_1.YieldToEventLoop(); // Listening to asyncIterator occurs asynchronously, so we need to yield
t.context.SendToReceiver(0, ["sender", "uid", "0", "hello"]);
await AsyncTools_1.YieldToEventLoop();
let lCallsToSend = 0;
t.deepEqual(lSendMock.getCall(lCallsToSend++).args[0], ["sender", "0", "hello RES"]);
clock.tick(3 * Config_1.default.MaximumLatency);
t.context.SendToReceiver(2, ["sender", "uid", "0", "hello again"]);
await AsyncTools_1.YieldToEventLoop();
t.deepEqual(lSendMock.getCall(lCallsToSend++).args[0], ["sender", "0", "hello RES"]);
clock.tick(500); // 500ms is the buffer added on by ExpiryMap
t.context.SendToReceiver(3, ["sender", "uid", "0", "hello again"]);
await AsyncTools_1.YieldToEventLoop();
t.deepEqual(lSendMock.getCall(lCallsToSend++).args[0], ["sender", "0", ZMQResponse_1.RESPONSE_CACHE_EXPIRED]);
lSendMock
.onCall(lCallsToSend).returns(Promise.reject({
code: "EAGAIN",
}))
.onCall(lCallsToSend + 1).returns(Promise.reject({
code: "EAGAIN",
}));
t.context.SendToReceiver(4, ["sender", "uid", "1", "warning suppress"]);
await AsyncTools_1.YieldToEventLoop();
t.context.SendToReceiver(1, ["custom_sender", "uid", "0", "warning handler"]);
await AsyncTools_1.YieldToEventLoop();
// UPDATE RESPONDER FOR NEXT STAGE
let lCallCount = 0;
lResponder = () => {
++lCallCount;
return new Promise((aResolve) => {
setTimeout(() => aResolve("DELAY DONE"), 50);
});
};
t.context.SendToReceiver(5, ["sender", "uid", "0", "this will be another cache error"]);
await AsyncTools_1.YieldToEventLoop();
t.deepEqual(lSendMock.getCall(lCallsToSend++).args[0], ["sender", "1", "warning suppress RES"]);
t.deepEqual(lSendMock.getCall(lCallsToSend++).args[0], ["custom_sender", "0", "warning handler RES"]);
t.deepEqual(lSendMock.getCall(lCallsToSend++).args[0], ["sender", "0", ZMQResponse_1.RESPONSE_CACHE_EXPIRED]);
t.is(lWarnings.length, 1);
t.deepEqual(lWarnings[0], { Requester: "uid", Nonce: 0, Message: "warning handler RES" });
t.is(lCallCount, 0);
t.context.SendToReceiver(7, ["sender", "uid", "2", "START DELAY"]);
await AsyncTools_1.YieldToEventLoop();
t.is(lCallCount, 1);
t.context.SendToReceiver(8, ["sender", "uid", "2", "START DELAY"]);
await AsyncTools_1.YieldToEventLoop();
t.is(lCallCount, 1);
t.is(lSendMock.callCount, lCallsToSend);
clock.tick(50);
await AsyncTools_1.YieldToEventLoop();
t.is(lSendMock.callCount, lCallsToSend + 1);
t.deepEqual(lSendMock.getCall(lCallsToSend++).args[0], ["sender", "2", "DELAY DONE"]);
lResponse.Close();
lCustomResponse.Close();
t.context.SendToReceiver(9, [undefined, "SUPPRESS THIS"]);
await AsyncTools_1.YieldToEventLoop();
t.context.SendToReceiver(9, [undefined, "SUPPRESS THIS"]);
await AsyncTools_1.YieldToEventLoop();
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiWk1RUmVzcG9uc2UudGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL1Rlc3QvU3JjL1pNUVJlc3BvbnNlLnRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsdUNBQXVDO0FBQ3ZDLDhDQUFnRDtBQUVoRCw2Q0FBK0I7QUFFL0IscURBQTBEO0FBQzFELDRDQUE4QjtBQUM5Qiw4REFBc0M7QUFFdEMsdURBQTRFO0FBQzVFLHNEQUF5RDtBQVV6RCxNQUFNLElBQUksR0FBZ0MsYUFBc0MsQ0FBRTtBQUVsRixJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBaUMsRUFBUSxFQUFFO0lBRXBELGNBQWM7QUFDbEIsQ0FBQyxDQUFDLENBQUM7QUFFSCxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBaUMsRUFBUSxFQUFFO0lBRXhELE1BQU0sVUFBVSxHQUFrRCxFQUFFLENBQUM7SUFDckUsU0FBUyxZQUFZO1FBRWpCLE9BQU87WUFDSCxLQUFLLENBQUMsSUFBSTtnQkFFTixPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsUUFBZ0QsRUFBUSxFQUFFO29CQUUxRSxVQUFVLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO2dCQUM5QixDQUFDLENBQUMsQ0FBQztZQUNQLENBQUM7U0FDSixDQUFDO0lBQ04sQ0FBQztJQUVELE1BQU0sWUFBWSxHQUE0Qiw0QkFBVSxDQUFDLFNBQVMsQ0FBYSxHQUFHLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDOUYsYUFBYTtJQUNiLE1BQU0sa0JBQWtCLEdBQW9CLFlBQVksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDO0lBQ3BGLGtCQUFrQixDQUFDLFNBQVMsQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUUzQyxDQUFDLENBQUMsT0FBTyxHQUFHO1FBQ1IsaUJBQWlCLEVBQUUsc0JBQXNCO1FBQ3pDLFVBQVUsRUFBRSxZQUFZO1FB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