mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-11 23:04:52 +09:00
Implement proper session tracking and resume on reconnect for the WebSocket server.
177 lines
5.9 KiB
JavaScript
177 lines
5.9 KiB
JavaScript
const assert = require('assert').strict;
|
|
const events = require('events');
|
|
|
|
const link = require("lib/link");
|
|
const errors = require("lib/errors");
|
|
const schema = require("lib/schema");
|
|
const mock = require("../../mock");
|
|
|
|
|
|
describe("lib/link/link", function() {
|
|
describe("class Link", function() {
|
|
let testConnector;
|
|
let testLink;
|
|
|
|
before(function() {
|
|
testConnector = new mock.MockConnector();
|
|
testLink = new link.Link('source', 'target', testConnector);
|
|
testLink.setValidator('simple', schema.compile({
|
|
properties: {
|
|
"data": {
|
|
type: 'object',
|
|
properties: {
|
|
"string": { type: 'string' },
|
|
},
|
|
},
|
|
},
|
|
}));
|
|
});
|
|
|
|
it("should emitt error processing message to connector", async function() {
|
|
testLink.setHandler('throws', () => { throw new Error("Handler error"); }, () => true);
|
|
let result = events.once(testConnector, 'message');
|
|
testConnector.emit('message', { seq: 1, type: 'throws', data: {}});
|
|
await assert.rejects(result, new Error("Handler error"));
|
|
});
|
|
|
|
describe(".setValidator()", function() {
|
|
it("should set the validator", function() {
|
|
testLink.setValidator('test', () => true);
|
|
assert(testLink._validators.has('test'), "validator was not added");
|
|
});
|
|
it("should throw on duplicated validator", function() {
|
|
assert.throws(
|
|
() => testLink.setValidator('test', () => true),
|
|
new Error("test already has a validator")
|
|
);
|
|
});
|
|
});
|
|
|
|
describe(".setHandler()", function() {
|
|
it("should throw if validator is not passed", function() {
|
|
assert.throws(
|
|
() => testLink.setHandler('no_validator_test', (message) => {}),
|
|
new Error("validator is required")
|
|
);
|
|
});
|
|
it("should set the handler", function() {
|
|
let handler = (message) => {};
|
|
testLink.setHandler('handler_test', handler, (message) => true);
|
|
assert.equal(testLink._handlers.get('handler_test'), handler);
|
|
});
|
|
it("should throw on duplicated handler", function() {
|
|
assert.throws(
|
|
() => testLink.setHandler('handler_test', (message) => {}),
|
|
new Error("handler_test already has a handler")
|
|
);
|
|
});
|
|
});
|
|
|
|
describe(".processMessage()", function() {
|
|
it("should throw on invalid message", function() {
|
|
assert.throws(
|
|
() => testLink.processMessage({ data: "invalid message" }),
|
|
{ message: "Malformed" }
|
|
);
|
|
});
|
|
it("should throw on message without validator", function() {
|
|
assert.throws(
|
|
() => testLink.processMessage({ seq: 1, type: 'no_validator', data: {} }),
|
|
new errors.InvalidMessage("No validator for no_validator on source-target")
|
|
);
|
|
});
|
|
it("should throw on message failing validation", function() {
|
|
assert.throws(
|
|
() => testLink.processMessage({ seq: 1, type: 'simple', data: { string: 1 }}),
|
|
{ message: "Validation failed for simple" }
|
|
);
|
|
});
|
|
it("should throw on unhandled message", function() {
|
|
assert.throws(
|
|
() => testLink.processMessage({ seq: 1, type: 'simple', data: { string: "a" }}),
|
|
new errors.InvalidMessage("Unhandled message simple")
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("._processHandler()", function() {
|
|
it("should call the handler", function() {
|
|
let handled = [];
|
|
testLink.setHandler('handled', (message) => handled.push(message), (message) => true)
|
|
testLink._processHandler({ seq: 1, type: 'handled', data: { test: "foo" } });
|
|
assert.deepEqual(handled, [{ seq: 1, type: 'handled', data: { test: "foo" } }]);
|
|
});
|
|
it("should return true if handled", function() {
|
|
let result = testLink._processHandler({ seq: 1, type: 'handled', data: {} });
|
|
assert.equal(result, true);
|
|
});
|
|
it("should return false if not handled", function() {
|
|
let result = testLink._processHandler({ seq: 1, type: 'not_handled', data: {} });
|
|
assert.equal(result, false);
|
|
});
|
|
});
|
|
|
|
describe("._processWaiters()", function() {
|
|
it("should call waiters", async function() {
|
|
let waiter = new Promise(resolve => {
|
|
testLink._waiters.set('test', [{ resolve, data: {} }]);
|
|
});
|
|
assert(
|
|
testLink._processWaiters({ type: 'test', seq: 4, data: {} }),
|
|
"Waiter was not processed"
|
|
);
|
|
assert.deepEqual(await waiter, { type: 'test', seq: 4, data: {} });
|
|
});
|
|
it("should filter on data", async function() {
|
|
let waiter = new Promise(resolve => {
|
|
testLink._waiters.set('test', [{ resolve, data: { a: 1, b: 2 } }]);
|
|
});
|
|
assert(
|
|
!testLink._processWaiters({ type: 'test', seq: 4, data: {} }),
|
|
"Incorrectly matched empty message"
|
|
);
|
|
assert(
|
|
!testLink._processWaiters({ type: 'test', seq: 4, data: { a: 1, b: 0 } }),
|
|
"Incorrectly matched message with wrong data"
|
|
);
|
|
assert(
|
|
testLink._processWaiters({ type: 'test', seq: 4, data: { a: 1, b: 2, c: 3 } }),
|
|
"Did not match correct message"
|
|
);
|
|
assert.deepEqual(await waiter, { type: 'test', seq: 4, data: { a: 1, b: 2, c: 3 } });
|
|
});
|
|
});
|
|
|
|
describe(".waitFor()", function() {
|
|
before(function() {
|
|
testLink.setValidator('waiter', (message) => true);
|
|
});
|
|
|
|
it("should throw on missing validator", async function() {
|
|
await assert.rejects(
|
|
testLink.waitFor('no_validator', {}),
|
|
new Error("No validator for no_validator on source-target")
|
|
);
|
|
});
|
|
it("should wait for a given message", async function() {
|
|
let result = testLink.waitFor('waiter', {});
|
|
assert(
|
|
testLink._processWaiters({ type: 'waiter', seq: 5, data: {} }),
|
|
"Did not proccess waiter"
|
|
);
|
|
assert.deepEqual(await result, { type: 'waiter', seq: 5, data: {} });
|
|
});
|
|
it("should handle multiple waiters", async function() {
|
|
let result1 = testLink.waitFor('waiter', {});
|
|
let result2 = testLink.waitFor('waiter', {});
|
|
assert(
|
|
testLink._processWaiters({ type: 'waiter', seq: 5, data: {} }),
|
|
"Did not proccess waiter"
|
|
);
|
|
assert.deepEqual(await result1, { type: 'waiter', seq: 5, data: {} });
|
|
assert.deepEqual(await result2, { type: 'waiter', seq: 5, data: {} });
|
|
});
|
|
});
|
|
});
|
|
});
|