mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-13 15:14:52 +09:00
Test suite mostly ready
This commit is contained in:
3 files changed
+473
-132
No files matched your search
@@ -82,6 +82,9 @@ export class SubscriptionRequest {
|
||||
public channels: Array<string | number> = [],
|
||||
public lastRequestTime: number = 0,
|
||||
) {
|
||||
if (!Link._eventsByName.has(eventName)) {
|
||||
throw new Error(`Unregistered Event class ${eventName}`);
|
||||
}
|
||||
}
|
||||
|
||||
static jsonSchema = Type.Tuple([
|
||||
@@ -114,7 +117,7 @@ export class SubscriptionController {
|
||||
constructor(
|
||||
private controller: any, // Controller | Link
|
||||
) {
|
||||
this.controller.handle(SubscriptionRequest, this._handleEvent.bind(this));
|
||||
this.controller.handle(SubscriptionRequest, this._handleRequest.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,7 +151,7 @@ export class SubscriptionController {
|
||||
broadcast(event: Event<unknown>) {
|
||||
const entry = Link._eventsByClass.get(event.constructor);
|
||||
if (!entry) {
|
||||
throw new Error(`Unregistered Event class ${Event.name}`);
|
||||
throw new Error(`Unregistered Event class ${event.constructor.name}`);
|
||||
}
|
||||
const eventData = this._events.get(entry.name);
|
||||
if (!eventData) {
|
||||
@@ -164,7 +167,7 @@ export class SubscriptionController {
|
||||
}
|
||||
}
|
||||
|
||||
async _handleEvent(event: SubscriptionRequest, src: Address, dst: Address) {
|
||||
async _handleRequest(event: SubscriptionRequest, src: Address, dst: Address) {
|
||||
if (!Link._eventsByName.has(event.eventName)) {
|
||||
throw new Error(`Event ${event.eventName} is not a registered event`);
|
||||
}
|
||||
@@ -199,18 +202,19 @@ export class EventSubscriber<T, V=T> {
|
||||
_channelCallbacks = new Map<string | number, Array<EventSubscriberCallback<V>>>()
|
||||
lastResponse: T | null = null; // Does not work with Event<T>
|
||||
lastResponseTime = 0;
|
||||
control?: Link
|
||||
|
||||
constructor(
|
||||
private event: EventClass<T>,
|
||||
private prehandler?: (event: T) => V,
|
||||
private control?: Link
|
||||
control?: Link
|
||||
) {
|
||||
const entry = Link._eventsByClass.get(this.event);
|
||||
if (!entry) {
|
||||
throw new Error(`Unregistered Event class ${this.event.name}`);
|
||||
}
|
||||
if (this.control) {
|
||||
this.control.handle(this.event, this._handle.bind(this));
|
||||
if (control) {
|
||||
this.connectControl(control);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,7 +241,7 @@ export class EventSubscriber<T, V=T> {
|
||||
|
||||
subscribe(handler: EventSubscriberCallback<V>) {
|
||||
this._callbacks.push(handler);
|
||||
this._updateSubscription();
|
||||
return this._updateSubscription();
|
||||
}
|
||||
|
||||
subscribeToChannel(channel: string | number, handler: EventSubscriberCallback<V>) {
|
||||
@@ -245,7 +249,7 @@ export class EventSubscriber<T, V=T> {
|
||||
this._channelCallbacks.set(channel, []);
|
||||
}
|
||||
this._channelCallbacks.get(channel)!.push(handler);
|
||||
this._updateSubscription();
|
||||
return this._updateSubscription();
|
||||
}
|
||||
|
||||
unsubscribe(handler: EventSubscriberCallback<V>) {
|
||||
@@ -255,7 +259,7 @@ export class EventSubscriber<T, V=T> {
|
||||
}
|
||||
|
||||
this._callbacks.splice(index, 1);
|
||||
this._updateSubscription();
|
||||
return this._updateSubscription();
|
||||
}
|
||||
|
||||
unsubscribeFromChannel(channel: string | number, handler: EventSubscriberCallback<V>) {
|
||||
@@ -274,7 +278,7 @@ export class EventSubscriber<T, V=T> {
|
||||
} else {
|
||||
channelCallbacks.splice(index, 1);
|
||||
}
|
||||
this._updateSubscription();
|
||||
return this._updateSubscription();
|
||||
}
|
||||
|
||||
async _updateSubscription() {
|
||||
|
||||
+456
-121
@@ -1,231 +1,566 @@
|
||||
"use strict";
|
||||
const events = require("events");
|
||||
const assert = require("assert").strict;
|
||||
const lib = require("@clusterio/lib");
|
||||
const { MockController, MockConnector, MockControl } = require("../mock");
|
||||
|
||||
const addr = lib.Address.fromShorthand;
|
||||
|
||||
describe("lib/subscriptions", function() {
|
||||
class UnregisteredEvent {
|
||||
static type = "event";
|
||||
static src = ["controller", "control"];
|
||||
static dst = ["controller", "control"];
|
||||
static permission = null;
|
||||
}
|
||||
|
||||
class RegisteredEvent {
|
||||
static type = "event";
|
||||
static src = ["controller", "control"];
|
||||
static dst = ["controller", "control"];
|
||||
static permission = null;
|
||||
}
|
||||
lib.Link.register(RegisteredEvent);
|
||||
|
||||
class ChannelEvent {
|
||||
static type = "event";
|
||||
static src = ["controller", "control"];
|
||||
static dst = ["controller", "control"];
|
||||
static permission = null;
|
||||
}
|
||||
lib.Link.register(ChannelEvent);
|
||||
|
||||
class StringPermissionEvent {
|
||||
static type = "event";
|
||||
static src = ["controller", "control"];
|
||||
static dst = ["controller", "control"];
|
||||
static permission = "StringPermission";
|
||||
}
|
||||
lib.Link.register(StringPermissionEvent);
|
||||
|
||||
class FunctionPermissionEvent {
|
||||
static type = "event";
|
||||
static src = ["controller", "control"];
|
||||
static dst = ["controller", "control"];
|
||||
static permission(user, message) {
|
||||
user.checkPermission("FunctionPermission");
|
||||
};
|
||||
}
|
||||
lib.Link.register(FunctionPermissionEvent);
|
||||
|
||||
class MockUser {
|
||||
checkPermission(permission) {
|
||||
this.lastPermissionCheck = permission;
|
||||
}
|
||||
}
|
||||
|
||||
describe("class SubscriptionResponse", function() {
|
||||
describe("constructor()", function() {
|
||||
it("should be constructable without an event replay", function() {
|
||||
assert(false);
|
||||
});
|
||||
it("should be constructable with an event replay", function() {
|
||||
assert(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("toJSON()", function() {
|
||||
it("should be serialisable to json without an event replay", function() {
|
||||
assert(false);
|
||||
});
|
||||
it("should be serialisable to json with an event replay", function() {
|
||||
assert(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("fromJSON()", function() {
|
||||
it("should be deserialisable from json without an event replay", function() {
|
||||
assert(false);
|
||||
});
|
||||
it("should be deserialisable from json with an event replay", function() {
|
||||
assert(false);
|
||||
});
|
||||
});
|
||||
|
||||
it("should be round trip json serialisable without an event replay", function() {
|
||||
assert(false);
|
||||
const response = new lib.SubscriptionResponse();
|
||||
const json = JSON.stringify(response);
|
||||
assert.equal(typeof json, "string");
|
||||
const reconstructed = lib.SubscriptionResponse.fromJSON(JSON.parse(json));
|
||||
assert.deepEqual(reconstructed, response);
|
||||
});
|
||||
|
||||
it("should be round trip json serialisable with an event replay", function() {
|
||||
assert(false);
|
||||
const response = new lib.SubscriptionResponse(new RegisteredEvent());
|
||||
const json = JSON.stringify(response);
|
||||
assert.equal(typeof json, "string");
|
||||
const reconstructed = lib.SubscriptionResponse.fromJSON(JSON.parse(json));
|
||||
assert.deepEqual(reconstructed, response);
|
||||
});
|
||||
|
||||
it("should be round trip json serialisable with a null event replay", function() {
|
||||
const response = new lib.SubscriptionResponse(null);
|
||||
const json = JSON.stringify(response);
|
||||
assert.equal(typeof json, "string");
|
||||
const reconstructed = lib.SubscriptionResponse.fromJSON(JSON.parse(json));
|
||||
assert.deepEqual(reconstructed, response);
|
||||
});
|
||||
|
||||
it("should be throw when given an unregistered event", function() {
|
||||
assert.throws(
|
||||
() => new lib.SubscriptionResponse(new UnregisteredEvent()),
|
||||
new Error(`Unregistered Event class ${UnregisteredEvent.name}`)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("class SubscriptionRequest", function() {
|
||||
describe("constructor()", function() {
|
||||
it("should be constructable with only an allChannels argument", function() {
|
||||
assert(false);
|
||||
});
|
||||
it("should be constructable with without a lastRequestTime", function() {
|
||||
assert(false);
|
||||
});
|
||||
it("should be constructable with with a lastRequestTime", function() {
|
||||
assert(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("permission()", function() {
|
||||
it("should do nothing when the event has no permission property", function() {
|
||||
assert(false);
|
||||
const mockUser = new MockUser();
|
||||
const request = new lib.SubscriptionRequest(RegisteredEvent.name, true);
|
||||
lib.SubscriptionRequest.permission(mockUser, new lib.MessageRequest(
|
||||
0,
|
||||
addr({ controlId: 0 }),
|
||||
addr("controller"),
|
||||
lib.SubscriptionRequest.name,
|
||||
JSON.stringify(request)
|
||||
));
|
||||
assert.equal(mockUser.lastPermissionCheck, undefined);
|
||||
});
|
||||
it("should check user permission when the permission property is a string", function() {
|
||||
assert(false);
|
||||
const mockUser = new MockUser();
|
||||
const request = new lib.SubscriptionRequest(StringPermissionEvent.name, true);
|
||||
lib.SubscriptionRequest.permission(mockUser, new lib.MessageRequest(
|
||||
0,
|
||||
addr({ controlId: 0 }),
|
||||
addr("controller"),
|
||||
lib.SubscriptionRequest.name,
|
||||
request.toJSON()
|
||||
));
|
||||
assert.equal(mockUser.lastPermissionCheck, "StringPermission");
|
||||
});
|
||||
it("should call the permission property when it is a function", function() {
|
||||
assert(false);
|
||||
const mockUser = new MockUser();
|
||||
const request = new lib.SubscriptionRequest(FunctionPermissionEvent.name, true);
|
||||
lib.SubscriptionRequest.permission(mockUser, new lib.MessageRequest(
|
||||
0,
|
||||
addr({ controlId: 0 }),
|
||||
addr("controller"),
|
||||
lib.SubscriptionRequest.name,
|
||||
request.toJSON()
|
||||
));
|
||||
assert.equal(mockUser.lastPermissionCheck, "FunctionPermission");
|
||||
});
|
||||
});
|
||||
|
||||
it("should be serialisable to json", function() {
|
||||
assert(false);
|
||||
});
|
||||
|
||||
it("should be deserialisable from json", function() {
|
||||
assert(false);
|
||||
});
|
||||
|
||||
it("should be round trip json serialisable", function() {
|
||||
assert(false);
|
||||
const request = new lib.SubscriptionRequest(RegisteredEvent.name, true, ["channelOne"], 123);
|
||||
const json = JSON.stringify(request);
|
||||
assert.equal(typeof json, "string");
|
||||
const reconstructed = lib.SubscriptionRequest.fromJSON(JSON.parse(json));
|
||||
assert.deepEqual(reconstructed, request);
|
||||
});
|
||||
|
||||
it("should be throw when given an unregistered event", function() {
|
||||
assert.throws(
|
||||
() => new lib.SubscriptionRequest(UnregisteredEvent.name, true),
|
||||
new Error(`Unregistered Event class ${UnregisteredEvent.name}`)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("class SubscriptionController", function() {
|
||||
let mockController, subscriptions;
|
||||
const connectorSetupDate = [{
|
||||
id: 1,
|
||||
request: new lib.SubscriptionRequest(RegisteredEvent.name, true),
|
||||
src: addr({ controlId: 1 }),
|
||||
dst: addr("controller"),
|
||||
}, {
|
||||
id: 2,
|
||||
request: new lib.SubscriptionRequest(RegisteredEvent.name, true),
|
||||
src: addr({ controlId: 2 }),
|
||||
dst: addr("controller"),
|
||||
}, {
|
||||
id: 3,
|
||||
request: new lib.SubscriptionRequest(ChannelEvent.name, true),
|
||||
src: addr({ controlId: 3 }),
|
||||
dst: addr("controller"),
|
||||
}, {
|
||||
id: 4,
|
||||
request: new lib.SubscriptionRequest(ChannelEvent.name, false, ["channelOne"]),
|
||||
src: addr({ controlId: 4 }),
|
||||
dst: addr("controller"),
|
||||
}, {
|
||||
id: 5,
|
||||
request: new lib.SubscriptionRequest(ChannelEvent.name, false, ["channelTwo"]),
|
||||
src: addr({ controlId: 5 }),
|
||||
dst: addr("controller"),
|
||||
}];
|
||||
|
||||
function awaitMessages(ids) {
|
||||
return Promise.all(ids.map(function(id) {
|
||||
const link = mockController.wsServer.controlConnections.get(id);
|
||||
return events.once(link.connector, "send");
|
||||
}));
|
||||
}
|
||||
|
||||
function assertLastEvent(connectorId, Event) {
|
||||
const link = mockController.wsServer.controlConnections.get(connectorId);
|
||||
const lastMessage = link.connector.sentMessages.at(-1);
|
||||
const name = Event.plugin ? `${Event.plugin}:${Event.name}` : Event.name;
|
||||
assert.equal(lastMessage.name, name);
|
||||
}
|
||||
|
||||
function assertNoEvent(connectorId) {
|
||||
const link = mockController.wsServer.controlConnections.get(connectorId);
|
||||
assert.equal(link.connector.sentMessages.length, 0);
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
mockController = new MockController();
|
||||
mockController.wsServer = {
|
||||
controlConnections: new Map(connectorSetupDate.map(function (connectorData) {
|
||||
return [connectorData.id, new lib.Link(new MockConnector(connectorData.src, connectorData.dst))];
|
||||
})),
|
||||
};
|
||||
subscriptions = new lib.SubscriptionController(mockController);
|
||||
});
|
||||
|
||||
it("should handle the SubscriptionRequest event", function() {
|
||||
assert(false);
|
||||
assert.equal(mockController.handles.has(lib.SubscriptionRequest), true);
|
||||
});
|
||||
|
||||
describe("handle()", function() {
|
||||
it("should accept registered events", function() {
|
||||
assert(false);
|
||||
subscriptions.handle(RegisteredEvent);
|
||||
});
|
||||
it("should not accept unregistered events", function() {
|
||||
assert(false);
|
||||
assert.throws(
|
||||
() => subscriptions.handle(UnregisteredEvent),
|
||||
new Error(`Unregistered Event class ${UnregisteredEvent.name}`)
|
||||
);
|
||||
});
|
||||
it("should not accept events already handled by the class", function() {
|
||||
assert(false);
|
||||
subscriptions.handle(RegisteredEvent);
|
||||
assert.throws(
|
||||
() => subscriptions.handle(RegisteredEvent),
|
||||
new Error(`Event ${RegisteredEvent.name} is already registered`)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("broadcast()", function() {
|
||||
beforeEach(function() {
|
||||
subscriptions.handle(RegisteredEvent);
|
||||
subscriptions.handle(ChannelEvent, () => "channelOne");
|
||||
for (let connectorData of connectorSetupDate) {
|
||||
subscriptions._handleRequest(connectorData.request, connectorData.src, connectorData.dst);
|
||||
}
|
||||
});
|
||||
|
||||
it("should not accept unregistered events", function() {
|
||||
assert(false);
|
||||
assert.throws(
|
||||
() => subscriptions.broadcast(new UnregisteredEvent()),
|
||||
new Error(`Unregistered Event class ${UnregisteredEvent.name}`)
|
||||
);
|
||||
});
|
||||
it("should not accept events not handled by the class", function() {
|
||||
assert(false);
|
||||
assert.throws(
|
||||
() => subscriptions.broadcast(new StringPermissionEvent()),
|
||||
new Error(`Event ${StringPermissionEvent.name} is not a registered as subscribable`)
|
||||
);
|
||||
});
|
||||
it("should notify all links who subscribed all notifications, when channels are disabled", function() {
|
||||
assert(false);
|
||||
it("should notify all links who subscribed to all channels", async function() {
|
||||
const messages = awaitMessages([1, 2]);
|
||||
subscriptions.broadcast(new RegisteredEvent());
|
||||
await messages;
|
||||
assertLastEvent(1, RegisteredEvent); // RegisteredEvent: All
|
||||
assertLastEvent(2, RegisteredEvent); // RegisteredEvent: All
|
||||
assertNoEvent(3); // ChannelEvent: All
|
||||
assertNoEvent(4); // ChannelEvent: channelOne
|
||||
assertNoEvent(5); // ChannelEvent: channelTwo
|
||||
});
|
||||
it("should notify all links who subscribed all notifications, when channels are enabled", function() {
|
||||
assert(false);
|
||||
it("should not notify a link who unsubscribed from all all channels", async function() {
|
||||
const messages = awaitMessages([2]);
|
||||
const connectorData = connectorSetupDate[1];
|
||||
const request = new lib.SubscriptionRequest(RegisteredEvent.name, false);
|
||||
await subscriptions._handleRequest(request, connectorData.src, connectorData.dst);
|
||||
subscriptions.broadcast(new RegisteredEvent());
|
||||
await messages;
|
||||
assertNoEvent(1);
|
||||
assertLastEvent(2, RegisteredEvent);
|
||||
assertNoEvent(3);
|
||||
assertNoEvent(4);
|
||||
assertNoEvent(5);
|
||||
});
|
||||
it("should not notify a link who unsubscribed from all notifications", function() {
|
||||
assert(false);
|
||||
it("should notify all links who subscribed the specific channel", async function() {
|
||||
const messages = awaitMessages([3, 4]);
|
||||
subscriptions.broadcast(new ChannelEvent());
|
||||
await messages;
|
||||
assertNoEvent(1);
|
||||
assertNoEvent(2);
|
||||
assertLastEvent(3, ChannelEvent);
|
||||
assertNoEvent(4, ChannelEvent);
|
||||
assertNoEvent(5);
|
||||
});
|
||||
it("should notify all links who subscribed the specific channel", function() {
|
||||
assert(false);
|
||||
it("should not notify a link who unsubscribed from the specific channel", async function() {
|
||||
const messages = awaitMessages([3]);
|
||||
const connectorData = connectorSetupDate[4];
|
||||
const request = new lib.SubscriptionRequest(ChannelEvent.name, false, []);
|
||||
await subscriptions._handleRequest(request, connectorData.src, connectorData.dst);
|
||||
subscriptions.broadcast(new ChannelEvent());
|
||||
await messages;
|
||||
assertNoEvent(1);
|
||||
assertNoEvent(2);
|
||||
assertLastEvent(3, ChannelEvent);
|
||||
assertNoEvent(4);
|
||||
assertNoEvent(5);
|
||||
});
|
||||
it("should not notify a link who did subscribe the specific channel", function() {
|
||||
assert(false);
|
||||
});
|
||||
it("should not notify a link who unsubscribed from the specific channel", function() {
|
||||
assert(false);
|
||||
});
|
||||
it("should not notify links which are closed or closing", function() {
|
||||
assert(false);
|
||||
it("should not notify links which are closed or closing", async function() {
|
||||
const messages = awaitMessages([2]);
|
||||
const link = mockController.wsServer.controlConnections.get(1);
|
||||
link.connector.closing = true;
|
||||
subscriptions.broadcast(new RegisteredEvent());
|
||||
await messages;
|
||||
assertNoEvent(1);
|
||||
assertLastEvent(2, RegisteredEvent);
|
||||
assertNoEvent(3);
|
||||
assertNoEvent(4);
|
||||
assertNoEvent(5);
|
||||
});
|
||||
});
|
||||
|
||||
describe("_handleEvent()", function() {
|
||||
describe("_handleRequest()", function() {
|
||||
beforeEach(function() {
|
||||
subscriptions.handle(RegisteredEvent);
|
||||
subscriptions.handle(ChannelEvent, () => "channelOne");
|
||||
});
|
||||
|
||||
it("should not accept subscriptions to unregistered events", function() {
|
||||
assert(false);
|
||||
const request = new lib.SubscriptionRequest(RegisteredEvent.name, true);
|
||||
request.eventName = UnregisteredEvent.name;
|
||||
assert.throws(
|
||||
() => subscriptions._handleRequest(request, connectorSetupDate[0].src, connectorSetupDate[0].dst),
|
||||
new Error(`Unregistered Event class ${UnregisteredEvent.name}`)
|
||||
);
|
||||
});
|
||||
it("should not accept subscriptions to events not handled by the class", function() {
|
||||
assert(false);
|
||||
const request = new lib.SubscriptionRequest(RegisteredEvent.name, true);
|
||||
request.eventName = StringPermissionEvent.name;
|
||||
assert.throws(
|
||||
() => subscriptions._handleRequest(request, connectorSetupDate[0].src, connectorSetupDate[0].dst),
|
||||
new Error(`Unregistered Event class ${StringPermissionEvent.name}`)
|
||||
);
|
||||
});
|
||||
it("should accept a subscription to all notifications for an event", function() {
|
||||
assert(false);
|
||||
it("should accept a subscription to all channels", async function() {
|
||||
const messages = awaitMessages([1]);
|
||||
const request = new lib.SubscriptionRequest(RegisteredEvent.name, true);
|
||||
await subscriptions._handleRequest(request, connectorSetupDate[0].src, connectorSetupDate[0].dst);
|
||||
subscriptions.broadcast(new RegisteredEvent());
|
||||
await messages;
|
||||
assertLastEvent(1, RegisteredEvent);
|
||||
});
|
||||
it("should accept a unsubscription from all notifications for an event", function() {
|
||||
assert(false);
|
||||
it("should accept a unsubscription from all channels", async function() {
|
||||
const messages = awaitMessages([1]);
|
||||
const request = new lib.SubscriptionRequest(RegisteredEvent.name, true);
|
||||
await subscriptions._handleRequest(request, connectorSetupDate[0].src, connectorSetupDate[0].dst);
|
||||
subscriptions.broadcast(new RegisteredEvent());
|
||||
await messages;
|
||||
assertLastEvent(1, RegisteredEvent);
|
||||
|
||||
const link = mockController.wsServer.controlConnections.get(1);
|
||||
link.connector.sentMessages.pop();
|
||||
|
||||
const unsubRequest = new lib.SubscriptionRequest(RegisteredEvent.name, false);
|
||||
await subscriptions._handleRequest(unsubRequest, connectorSetupDate[0].src, connectorSetupDate[0].dst);
|
||||
subscriptions.broadcast(new RegisteredEvent());
|
||||
assertNoEvent(1);
|
||||
});
|
||||
it("should accept a subscription to a specific channel for an event", function() {
|
||||
assert(false);
|
||||
it("should accept a subscription to a specific channel", async function() {
|
||||
const messages = awaitMessages([1]);
|
||||
const request = new lib.SubscriptionRequest(ChannelEvent.name, false, ["channelOne"]);
|
||||
await subscriptions._handleRequest(request, connectorSetupDate[0].src, connectorSetupDate[0].dst);
|
||||
subscriptions.broadcast(new ChannelEvent());
|
||||
await messages;
|
||||
assertLastEvent(1, ChannelEvent);
|
||||
});
|
||||
it("should accept a unsubscription from a specific channel for an event", function() {
|
||||
assert(false);
|
||||
it("should accept a unsubscription from a specific channel", async function() {
|
||||
const messages = awaitMessages([1]);
|
||||
const request = new lib.SubscriptionRequest(ChannelEvent.name, false, ["channelOne"]);
|
||||
await subscriptions._handleRequest(request, connectorSetupDate[0].src, connectorSetupDate[0].dst);
|
||||
subscriptions.broadcast(new ChannelEvent());
|
||||
await messages;
|
||||
assertLastEvent(1, ChannelEvent);
|
||||
|
||||
const link = mockController.wsServer.controlConnections.get(1);
|
||||
link.connector.sentMessages.pop();
|
||||
|
||||
const unsubRequest = new lib.SubscriptionRequest(ChannelEvent.name, false, []);
|
||||
await subscriptions._handleRequest(unsubRequest, connectorSetupDate[0].src, connectorSetupDate[0].dst);
|
||||
subscriptions.broadcast(new ChannelEvent());
|
||||
assertNoEvent(1);
|
||||
});
|
||||
it("should accept a respond with an event replay when returned by the handler", function() {
|
||||
assert(false);
|
||||
it("should accept a respond with an event replay when returned by the handler", async function() {
|
||||
const messages = awaitMessages([1]);
|
||||
subscriptions.handle(StringPermissionEvent, undefined, async function() {
|
||||
return new StringPermissionEvent();
|
||||
});
|
||||
|
||||
const request = new lib.SubscriptionRequest(StringPermissionEvent.name, true);
|
||||
await subscriptions._handleRequest(request, connectorSetupDate[0].src, connectorSetupDate[0].dst);
|
||||
subscriptions.broadcast(new StringPermissionEvent());
|
||||
await messages;
|
||||
assertLastEvent(1, StringPermissionEvent);
|
||||
|
||||
const link = mockController.wsServer.controlConnections.get(1);
|
||||
const lastMessage = link.connector.sentMessages.pop();
|
||||
const response = lib.SubscriptionResponse.fromJSON(lastMessage.data);
|
||||
assert.deepEqual(response, new lib.SubscriptionResponse(new StringPermissionEvent()));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("class EventSubscriber", function() {
|
||||
let channelEvent, mockControl, registeredEvent;
|
||||
beforeEach(function() {
|
||||
mockControl = new MockControl(new MockConnector(
|
||||
addr({ controlId: 1 }),
|
||||
addr("controller"),
|
||||
));
|
||||
registeredEvent = new lib.EventSubscriber(RegisteredEvent, undefined, mockControl);
|
||||
channelEvent = new lib.EventSubscriber(ChannelEvent, undefined, mockControl);
|
||||
});
|
||||
|
||||
function assertLastRequest(request) {
|
||||
const Request = request.constructor;
|
||||
const lastMessage = mockControl.connector.sentMessages.at(-1);
|
||||
const name = Request.plugin ? `${Request.plugin}:${Request.name}` : Request.name;
|
||||
assert.equal(lastMessage.name, name);
|
||||
assert.deepEqual(lastMessage.data, request);
|
||||
}
|
||||
|
||||
describe("constructor()", function() {
|
||||
it("should not accept unregistered events", function() {
|
||||
assert(false);
|
||||
assert.throws(
|
||||
() => new lib.EventSubscriber(UnregisteredEvent),
|
||||
new Error(`Unregistered Event class ${UnregisteredEvent.name}`)
|
||||
);
|
||||
});
|
||||
it("should handle the provided event if a control link is given", function() {
|
||||
assert(false);
|
||||
it("should handle the provided event, if a control link is provided", function() {
|
||||
assert.equal(mockControl._eventHandlers.has(RegisteredEvent), true);
|
||||
assert.equal(mockControl._eventHandlers.has(ChannelEvent), true);
|
||||
});
|
||||
it("should call and use the return of a pre-handler if provided", function() {
|
||||
assert(false);
|
||||
it("should call and use the return of a pre-handler, if provided", function() {
|
||||
let calledWith = null;
|
||||
function prehandler() { return "PreHandlerReturn"; }
|
||||
const eventSubscriber = new lib.EventSubscriber(StringPermissionEvent, prehandler, mockControl);
|
||||
eventSubscriber.subscribe(function(value) { calledWith = value; });
|
||||
eventSubscriber._handle(new StringPermissionEvent());
|
||||
assert.equal(calledWith, "PreHandlerReturn");
|
||||
});
|
||||
});
|
||||
|
||||
describe("connectControl()", function() {
|
||||
it("should handle the provided event", function() {
|
||||
assert(false);
|
||||
const control = new MockControl(new MockConnector(
|
||||
addr({ controlId: 1 }),
|
||||
addr("controller"),
|
||||
));
|
||||
registeredEvent.connectControl(control);
|
||||
assert.equal(control._eventHandlers.has(RegisteredEvent), true);
|
||||
});
|
||||
it("should do nothing if the control is already connected", function() {
|
||||
assert(false);
|
||||
assert.equal(mockControl._eventHandlers.has(RegisteredEvent), true);
|
||||
registeredEvent.connectControl(mockControl);
|
||||
assert.equal(mockControl._eventHandlers.has(RegisteredEvent), true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("subscribe()", function() {
|
||||
it("should allow subscriptions to an event", function() {
|
||||
assert(false);
|
||||
});
|
||||
it("should call all handlers who subscripted, when channels are disabled", function() {
|
||||
assert(false);
|
||||
});
|
||||
it("should call all handlers who subscripted, when channels are enabled", function() {
|
||||
assert(false);
|
||||
let calledWith = null;
|
||||
let calledWithTwo = null;
|
||||
const event = new RegisteredEvent();
|
||||
registeredEvent.subscribe(function(value) { calledWith = value; });
|
||||
registeredEvent.subscribe(function(value) { calledWithTwo = value; });
|
||||
registeredEvent._handle(event);
|
||||
assert.deepEqual(calledWith, event);
|
||||
assert.deepEqual(calledWithTwo, event);
|
||||
});
|
||||
});
|
||||
|
||||
describe("subscribeToChannel()", function() {
|
||||
it("should allow subscriptions to a channel for an event", function() {
|
||||
assert(false);
|
||||
});
|
||||
it("should call all handlers who subscripted to the specific channel", function() {
|
||||
assert(false);
|
||||
});
|
||||
it("should not call a handler who did not subscribe to the specific channel", function() {
|
||||
assert(false);
|
||||
let calledWith = null;
|
||||
let calledWithTwo = null;
|
||||
const event = new ChannelEvent();
|
||||
channelEvent.subscribeToChannel("channelOne", function(value) { calledWith = value; });
|
||||
channelEvent.subscribeToChannel("channelTwo", function(value) { calledWithTwo = value; });
|
||||
channelEvent._handle(event);
|
||||
assert.deepEqual(calledWith, event);
|
||||
assert.deepEqual(calledWithTwo, null);
|
||||
});
|
||||
});
|
||||
|
||||
describe("unsubscribe()", function() {
|
||||
it("should allow unsubscribing from an event", function() {
|
||||
assert(false);
|
||||
let calledWith = null;
|
||||
let event = new RegisteredEvent();
|
||||
function callback(value) { calledWith = value; }
|
||||
registeredEvent.subscribe(callback);
|
||||
registeredEvent._handle(event);
|
||||
assert.deepEqual(calledWith, event);
|
||||
|
||||
calledWith = null;
|
||||
event = new RegisteredEvent();
|
||||
registeredEvent.unsubscribe(callback);
|
||||
registeredEvent._handle(event);
|
||||
assert.equal(calledWith, null);
|
||||
});
|
||||
it("should throw an error if the handler was not subscribed", function() {
|
||||
assert(false);
|
||||
function callback(value) { calledWith = value; }
|
||||
assert.throws(
|
||||
() => registeredEvent.unsubscribe(callback),
|
||||
new Error("handler is not registered")
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("unsubscribeFromChannel()", function() {
|
||||
it("should allow unsubscribing from a channel for an event", function() {
|
||||
assert(false);
|
||||
let calledWith = null;
|
||||
let event = new ChannelEvent();
|
||||
function callback(value) { calledWith = value; }
|
||||
channelEvent.subscribeToChannel("channelOne", callback);
|
||||
channelEvent._handle(event);
|
||||
assert.deepEqual(calledWith, event);
|
||||
|
||||
calledWith = null;
|
||||
event = new ChannelEvent();
|
||||
channelEvent.unsubscribeFromChannel("channelOne", callback);
|
||||
channelEvent._handle(event);
|
||||
assert.equal(calledWith, null);
|
||||
});
|
||||
it("should throw an error if the handler was not subscribed", function() {
|
||||
assert(false);
|
||||
function callback(value) { calledWith = value; }
|
||||
assert.throws(
|
||||
() => channelEvent.unsubscribeFromChannel("channelOne", callback),
|
||||
new Error("handler is not registered")
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("_updateSubscription()", function() {
|
||||
it("should correctly request a subscription for all channels", function() {
|
||||
assert(false);
|
||||
it("should correctly request a subscription for all channels", async function() {
|
||||
const expected = new lib.SubscriptionRequest(RegisteredEvent.name, true);
|
||||
registeredEvent.subscribe(() => true);
|
||||
await events.once(mockControl.connector, "send");
|
||||
assertLastRequest(expected);
|
||||
});
|
||||
it("should correctly request a subscription for some channels", function() {
|
||||
assert(false);
|
||||
it("should correctly request a subscription for some channels", async function() {
|
||||
const expected = new lib.SubscriptionRequest(ChannelEvent.name, false, ["channelOne"]);
|
||||
channelEvent.subscribeToChannel("channelOne", () => true);
|
||||
await events.once(mockControl.connector, "send");
|
||||
assertLastRequest(expected);
|
||||
});
|
||||
it("should correctly request a subscription for no channels", function() {
|
||||
assert(false);
|
||||
it("should correctly request a subscription for no channels", async function() {
|
||||
const expected = new lib.SubscriptionRequest(RegisteredEvent.name, false);
|
||||
function callback() {}
|
||||
registeredEvent.subscribe(callback);
|
||||
await events.once(mockControl.connector, "send");
|
||||
registeredEvent.unsubscribe(callback);
|
||||
await events.once(mockControl.connector, "send");
|
||||
assertLastRequest(expected);
|
||||
});
|
||||
it("should call handlers when a replay event is returned", function() {
|
||||
assert(false);
|
||||
it("should call handlers when a replay event is returned", async function() {
|
||||
let calledWith = null;
|
||||
const event = new RegisteredEvent();
|
||||
const request = registeredEvent.subscribe(function(value) { calledWith = value; });
|
||||
await events.once(mockControl.connector, "send");
|
||||
|
||||
const responseMessage = new lib.MessageResponse(
|
||||
1,
|
||||
mockControl.connector.dst,
|
||||
mockControl.connector.src,
|
||||
new lib.SubscriptionResponse(event)
|
||||
);
|
||||
mockControl.connector.emit("message", responseMessage);
|
||||
assert.deepEqual(await request, event);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+3
-1
@@ -178,9 +178,11 @@ class MockController {
|
||||
]);
|
||||
this.instances = new Map();
|
||||
this.hosts = new Map();
|
||||
this.handles = new Map();
|
||||
}
|
||||
|
||||
handle() {
|
||||
handle(eventClass, handler) {
|
||||
this.handles.set(eventClass, handler);
|
||||
}
|
||||
|
||||
getControllerUrl() {
|
||||
|
||||
Reference in new issue
Block a user