mirror of
https://github.com/bringout/oca-ocb-core.git
synced 2026-04-21 04:52:00 +02:00
563 lines
22 KiB
JavaScript
563 lines
22 KiB
JavaScript
import {
|
|
addBusServiceListeners,
|
|
defineBusModels,
|
|
startBusService,
|
|
stepWorkerActions,
|
|
waitForChannels,
|
|
waitNotifications,
|
|
} from "@bus/../tests/bus_test_helpers";
|
|
import {
|
|
WEBSOCKET_CLOSE_CODES,
|
|
WebsocketWorker,
|
|
WORKER_STATE,
|
|
} from "@bus/workers/websocket_worker";
|
|
import { describe, expect, test } from "@odoo/hoot";
|
|
import { Deferred, manuallyDispatchProgrammaticEvent, runAllTimers, waitFor } from "@odoo/hoot-dom";
|
|
import { mockWebSocket } from "@odoo/hoot-mock";
|
|
import {
|
|
asyncStep,
|
|
contains,
|
|
getService,
|
|
makeMockEnv,
|
|
makeMockServer,
|
|
MockServer,
|
|
mockService,
|
|
mountWithCleanup,
|
|
patchWithCleanup,
|
|
restoreRegistry,
|
|
waitForSteps,
|
|
} from "@web/../tests/web_test_helpers";
|
|
import { getWebSocketWorker, onWebsocketEvent } from "./mock_websocket";
|
|
|
|
import { browser } from "@web/core/browser/browser";
|
|
import { registry } from "@web/core/registry";
|
|
import { user } from "@web/core/user";
|
|
import { session } from "@web/session";
|
|
import { WebClient } from "@web/webclient/webclient";
|
|
|
|
defineBusModels();
|
|
describe.current.tags("desktop");
|
|
|
|
test("notifications not received after stoping the service", async () => {
|
|
const firstTabEnv = await makeMockEnv();
|
|
stepWorkerActions("BUS:LEAVE");
|
|
restoreRegistry(registry);
|
|
const secondTabEnv = await makeMockEnv(null, { makeNew: true });
|
|
startBusService(firstTabEnv);
|
|
startBusService(secondTabEnv);
|
|
firstTabEnv.services.bus_service.addChannel("lambda");
|
|
await waitForChannels(["lambda"]);
|
|
MockServer.env["bus.bus"]._sendone("lambda", "notifType", "beta");
|
|
await waitNotifications(
|
|
[firstTabEnv, "notifType", "beta"],
|
|
[secondTabEnv, "notifType", "beta"]
|
|
);
|
|
secondTabEnv.services.bus_service.stop();
|
|
await waitForSteps(["BUS:LEAVE"]);
|
|
MockServer.env["bus.bus"]._sendone("lambda", "notifType", "epsilon");
|
|
await waitNotifications(
|
|
[firstTabEnv, "notifType", "epsilon"],
|
|
[secondTabEnv, "notifType", "epsilon", { received: false }]
|
|
);
|
|
});
|
|
|
|
test("notifications still received after disconnect/reconnect", async () => {
|
|
addBusServiceListeners(
|
|
["BUS:DISCONNECT", () => asyncStep("BUS:DISCONNECT")],
|
|
["BUS:RECONNECT", () => asyncStep("BUS:RECONNECT")]
|
|
);
|
|
await makeMockEnv();
|
|
getService("bus_service").addChannel("lambda");
|
|
await waitForChannels(["lambda"]);
|
|
MockServer.env["bus.bus"]._sendone("lambda", "notifType", "beta");
|
|
await waitNotifications(["notifType", "beta"]);
|
|
MockServer.env["bus.bus"]._simulateDisconnection(WEBSOCKET_CLOSE_CODES.ABNORMAL_CLOSURE);
|
|
await waitForSteps(["BUS:DISCONNECT"]);
|
|
await runAllTimers();
|
|
await waitForSteps(["BUS:RECONNECT"]);
|
|
MockServer.env["bus.bus"]._sendone("lambda", "notifType", "gamma");
|
|
await waitNotifications(["notifType", "gamma"]);
|
|
});
|
|
|
|
test("notifications are received by each tab", async () => {
|
|
const firstTabEnv = await makeMockEnv();
|
|
restoreRegistry(registry);
|
|
const secondTabEnv = await makeMockEnv(null, { makeNew: true });
|
|
firstTabEnv.services.bus_service.addChannel("lambda");
|
|
secondTabEnv.services.bus_service.addChannel("lambda");
|
|
await waitForChannels(["lambda"]);
|
|
MockServer.env["bus.bus"]._sendone("lambda", "notifType", "beta");
|
|
await waitNotifications(
|
|
[firstTabEnv, "notifType", "beta"],
|
|
[secondTabEnv, "notifType", "beta"]
|
|
);
|
|
});
|
|
|
|
test("second tab still receives notifications after main pagehide", async () => {
|
|
const mainEnv = await makeMockEnv();
|
|
stepWorkerActions("BUS:LEAVE");
|
|
mainEnv.services.bus_service.addChannel("lambda");
|
|
// Prevent second tab from receiving pagehide event.
|
|
patchWithCleanup(browser, {
|
|
addEventListener(eventName, callback) {
|
|
if (eventName !== "pagehide") {
|
|
super.addEventListener(eventName, callback);
|
|
}
|
|
},
|
|
});
|
|
const worker = getWebSocketWorker();
|
|
patchWithCleanup(worker, {
|
|
_unregisterClient(client) {
|
|
// Ensure that the worker does not receive any messages from the main tab
|
|
// after pagehide, mimicking real-world behavior.
|
|
client.onmessage = null;
|
|
super._unregisterClient(client);
|
|
},
|
|
});
|
|
restoreRegistry(registry);
|
|
const secondEnv = await makeMockEnv(null, { makeNew: true });
|
|
secondEnv.services.bus_service.addChannel("lambda");
|
|
await waitForChannels(["lambda"]);
|
|
MockServer.env["bus.bus"]._sendone("lambda", "notifType", "beta");
|
|
await waitNotifications([mainEnv, "notifType", "beta"], [secondEnv, "notifType", "beta"]);
|
|
// simulate unloading main
|
|
await manuallyDispatchProgrammaticEvent(window, "pagehide");
|
|
await waitForSteps(["BUS:LEAVE"]);
|
|
MockServer.env["bus.bus"]._sendone("lambda", "notifType", "gamma");
|
|
await waitNotifications(
|
|
[mainEnv, "notifType", "gamma", { received: false }],
|
|
[secondEnv, "notifType", "gamma"]
|
|
);
|
|
});
|
|
|
|
test("add two different channels from different tabs", async () => {
|
|
const firstTabEnv = await makeMockEnv();
|
|
restoreRegistry(registry);
|
|
const secondTabEnv = await makeMockEnv(null, { makeNew: true });
|
|
firstTabEnv.services.bus_service.addChannel("alpha");
|
|
secondTabEnv.services.bus_service.addChannel("beta");
|
|
await waitForChannels(["alpha", "beta"]);
|
|
MockServer.env["bus.bus"]._sendmany([
|
|
["alpha", "notifType", "alpha"],
|
|
["beta", "notifType", "beta"],
|
|
]);
|
|
await waitNotifications(
|
|
[firstTabEnv, "notifType", "alpha"],
|
|
[secondTabEnv, "notifType", "alpha"],
|
|
[firstTabEnv, "notifType", "beta"],
|
|
[secondTabEnv, "notifType", "beta"]
|
|
);
|
|
});
|
|
|
|
test("channel management from multiple tabs", async () => {
|
|
onWebsocketEvent("subscribe", (data) => asyncStep(`subscribe - [${data.channels.toString()}]`));
|
|
const firstTabEnv = await makeMockEnv();
|
|
restoreRegistry(registry);
|
|
const secondTabEnv = await makeMockEnv(null, { makeNew: true });
|
|
firstTabEnv.services.bus_service.addChannel("channel1");
|
|
await waitForSteps(["subscribe - [channel1]"]);
|
|
// Already known: no subscription.
|
|
secondTabEnv.services.bus_service.addChannel("channel1");
|
|
// Remove from tab1, but tab2 still listens: no subscription.
|
|
firstTabEnv.services.bus_service.deleteChannel("channel1");
|
|
// New channel: subscription.
|
|
secondTabEnv.services.bus_service.addChannel("channel2");
|
|
await waitForSteps(["subscribe - [channel1,channel2]"]);
|
|
// Removing last listener of channel1: subscription.
|
|
secondTabEnv.services.bus_service.deleteChannel("channel1");
|
|
await waitForSteps(["subscribe - [channel2]"]);
|
|
});
|
|
|
|
test("re-subscribe on reconnect", async () => {
|
|
onWebsocketEvent("subscribe", (data) => asyncStep(`subscribe - [${data.channels.toString()}]`));
|
|
addBusServiceListeners(["BUS:RECONNECT", () => asyncStep("BUS:RECONNECT")]);
|
|
await makeMockEnv();
|
|
startBusService();
|
|
await waitForSteps(["subscribe - []"]);
|
|
MockServer.env["bus.bus"]._simulateDisconnection(WEBSOCKET_CLOSE_CODES.KEEP_ALIVE_TIMEOUT);
|
|
await runAllTimers();
|
|
await waitForSteps(["BUS:RECONNECT", "subscribe - []"]);
|
|
});
|
|
|
|
test("pass last notification id on initialization", async () => {
|
|
patchWithCleanup(WebsocketWorker.prototype, {
|
|
_onClientMessage(_client, { action, data }) {
|
|
if (action === "BUS:INITIALIZE_CONNECTION") {
|
|
asyncStep(`${action} - ${data["lastNotificationId"]}`);
|
|
}
|
|
return super._onClientMessage(...arguments);
|
|
},
|
|
});
|
|
const firstEnv = await makeMockEnv();
|
|
startBusService(firstEnv);
|
|
await waitForSteps(["BUS:INITIALIZE_CONNECTION - 0"]);
|
|
firstEnv.services.bus_service.addChannel("lambda");
|
|
await waitForChannels(["lambda"]);
|
|
MockServer.env["bus.bus"]._sendone("lambda", "notifType", "beta");
|
|
await waitNotifications([firstEnv, "notifType", "beta"]);
|
|
restoreRegistry(registry);
|
|
const secondEnv = await makeMockEnv(null, { makeNew: true });
|
|
startBusService(secondEnv);
|
|
await waitForSteps([`BUS:INITIALIZE_CONNECTION - 1`]);
|
|
});
|
|
|
|
test("websocket disconnects when user logs out", async () => {
|
|
addBusServiceListeners(
|
|
["BUS:CONNECT", () => asyncStep("BUS:CONNECT")],
|
|
["BUS:RECONNECT", () => asyncStep("BUS:CONNECT")],
|
|
["BUS:DISCONNECT", () => asyncStep("BUS:DISCONNECT")]
|
|
);
|
|
patchWithCleanup(session, { user_id: null, db: "openerp" });
|
|
patchWithCleanup(user, { userId: 1 });
|
|
const firstTabEnv = await makeMockEnv();
|
|
await startBusService(firstTabEnv);
|
|
await waitForSteps(["BUS:CONNECT"]);
|
|
// second tab connects to the worker, omitting the DB name. Consider same DB.
|
|
patchWithCleanup(session, { db: undefined });
|
|
restoreRegistry(registry);
|
|
const env2 = await makeMockEnv(null, { makeNew: true });
|
|
await startBusService(env2);
|
|
await waitForSteps([]);
|
|
// third tab connects to the worker after disconnection: userId is now false.
|
|
patchWithCleanup(user, { userId: false });
|
|
restoreRegistry(registry);
|
|
const env3 = await makeMockEnv(null, { makeNew: true });
|
|
await startBusService(env3);
|
|
await waitForSteps(["BUS:DISCONNECT", "BUS:CONNECT"]);
|
|
});
|
|
|
|
test("websocket reconnects upon user log in", async () => {
|
|
addBusServiceListeners(
|
|
["BUS:CONNECT", () => asyncStep("BUS:CONNECT")],
|
|
["BUS:DISCONNECT", () => asyncStep("BUS:DISCONNECT")]
|
|
);
|
|
patchWithCleanup(session, { user_id: null });
|
|
patchWithCleanup(user, { userId: false });
|
|
await makeMockEnv();
|
|
startBusService();
|
|
await waitForSteps(["BUS:CONNECT"]);
|
|
patchWithCleanup(user, { userId: 1 });
|
|
restoreRegistry(registry);
|
|
const secondTabEnv = await makeMockEnv(null, { makeNew: true });
|
|
startBusService(secondTabEnv);
|
|
await waitForSteps(["BUS:DISCONNECT", "BUS:CONNECT"]);
|
|
});
|
|
|
|
test("websocket connects with URL corresponding to given serverURL", async () => {
|
|
const serverURL = "http://random-website.com";
|
|
mockService("bus.parameters", { serverURL });
|
|
await makeMockEnv();
|
|
mockWebSocket((ws) => asyncStep(ws.url));
|
|
startBusService();
|
|
await waitForSteps([
|
|
`${serverURL.replace("http", "ws")}/websocket?version=${session.websocket_worker_version}`,
|
|
]);
|
|
});
|
|
|
|
test("disconnect on offline, re-connect on online", async () => {
|
|
browser.addEventListener("online", () => asyncStep("online"));
|
|
addBusServiceListeners(
|
|
["BUS:CONNECT", () => asyncStep("BUS:CONNECT")],
|
|
["BUS:DISCONNECT", () => asyncStep("BUS:DISCONNECT")]
|
|
);
|
|
await makeMockEnv();
|
|
startBusService();
|
|
await waitForSteps(["BUS:CONNECT"]);
|
|
manuallyDispatchProgrammaticEvent(window, "offline");
|
|
await waitForSteps(["BUS:DISCONNECT"]);
|
|
manuallyDispatchProgrammaticEvent(window, "online");
|
|
await waitForSteps(["online"]);
|
|
await runAllTimers();
|
|
await waitForSteps(["BUS:CONNECT"]);
|
|
});
|
|
|
|
test("no disconnect on offline/online when bus is inactive", async () => {
|
|
browser.addEventListener("online", () => asyncStep("online"));
|
|
browser.addEventListener("offline", () => asyncStep("offline"));
|
|
addBusServiceListeners(
|
|
["BUS:CONNECT", () => asyncStep("BUS:CONNECT")],
|
|
["BUS:DISCONNECT", () => asyncStep("BUS:DISCONNECT")]
|
|
);
|
|
mockService("bus_service", {
|
|
addChannel() {},
|
|
});
|
|
await makeMockEnv();
|
|
expect(getService("bus_service").isActive).toBe(false);
|
|
manuallyDispatchProgrammaticEvent(window, "offline");
|
|
await waitForSteps(["offline"]);
|
|
manuallyDispatchProgrammaticEvent(window, "online");
|
|
await waitForSteps(["online"]);
|
|
});
|
|
|
|
test("can reconnect after late close event", async () => {
|
|
browser.addEventListener("online", () => asyncStep("online"));
|
|
addBusServiceListeners(
|
|
["BUS:CONNECT", () => asyncStep("BUS:CONNECT")],
|
|
["BUS:DISCONNECT", () => asyncStep("BUS:DISCONNECT")],
|
|
["BUS:RECONNECT", () => asyncStep("BUS:RECONNECT")],
|
|
["BUS:RECONNECTING", () => asyncStep("BUS:RECONNECTING")]
|
|
);
|
|
const closeDeferred = new Deferred();
|
|
await makeMockEnv();
|
|
startBusService();
|
|
await waitForSteps(["BUS:CONNECT"]);
|
|
patchWithCleanup(getWebSocketWorker().websocket, {
|
|
async close(code = WEBSOCKET_CLOSE_CODES.CLEAN, reason) {
|
|
this._readyState = 2; // WebSocket.CLOSING
|
|
if (code === WEBSOCKET_CLOSE_CODES.CLEAN) {
|
|
// Simulate that the connection could not be closed cleanly.
|
|
await closeDeferred;
|
|
code = WEBSOCKET_CLOSE_CODES.ABNORMAL_CLOSURE;
|
|
}
|
|
return super.close(code, reason);
|
|
},
|
|
});
|
|
// Connection will be closed when passing offline. But the close event will
|
|
// be delayed to come after the next open event. The connection will thus be
|
|
// in the closing state in the meantime (Simulates pending TCP closing
|
|
// handshake).
|
|
manuallyDispatchProgrammaticEvent(window, "offline");
|
|
// Worker reconnects upon the reception of the online event.
|
|
manuallyDispatchProgrammaticEvent(window, "online");
|
|
await waitForSteps(["online"]);
|
|
await runAllTimers();
|
|
await waitForSteps(["BUS:DISCONNECT", "BUS:CONNECT"]);
|
|
// Trigger the close event, it shouldn't have any effect since it is
|
|
// related to an old connection that is no longer in use.
|
|
closeDeferred.resolve();
|
|
await waitForSteps([]);
|
|
// Server closes the connection, the worker should reconnect.
|
|
MockServer.env["bus.bus"]._simulateDisconnection(WEBSOCKET_CLOSE_CODES.KEEP_ALIVE_TIMEOUT);
|
|
await waitForSteps(["BUS:DISCONNECT", "BUS:RECONNECTING", "BUS:RECONNECT"]);
|
|
});
|
|
|
|
test("fallback on simple worker when shared worker failed to initialize", async () => {
|
|
addBusServiceListeners(["BUS:CONNECT", () => asyncStep("BUS:CONNECT")]);
|
|
// Starting the server first, the following patch would be overwritten otherwise.
|
|
await makeMockServer();
|
|
patchWithCleanup(browser, {
|
|
SharedWorker: class extends browser.SharedWorker {
|
|
constructor() {
|
|
super(...arguments);
|
|
asyncStep("shared-worker-creation");
|
|
setTimeout(() => this.dispatchEvent(new Event("error")));
|
|
}
|
|
},
|
|
Worker: class extends browser.Worker {
|
|
constructor() {
|
|
super(...arguments);
|
|
|
|
asyncStep("worker-creation");
|
|
}
|
|
},
|
|
});
|
|
patchWithCleanup(console, {
|
|
warn: (message) => asyncStep(message),
|
|
});
|
|
await makeMockEnv();
|
|
startBusService();
|
|
await waitForSteps([
|
|
"shared-worker-creation",
|
|
"Error while loading SharedWorker, fallback on Worker: ",
|
|
"worker-creation",
|
|
"BUS:CONNECT",
|
|
]);
|
|
});
|
|
|
|
test("subscribe to single notification", async () => {
|
|
await makeMockEnv();
|
|
startBusService();
|
|
getService("bus_service").addChannel("my_channel");
|
|
await waitForChannels(["my_channel"]);
|
|
getService("bus_service").subscribe("message_type", (payload) =>
|
|
asyncStep(`message - ${JSON.stringify(payload)}`)
|
|
);
|
|
MockServer.env["bus.bus"]._sendone("my_channel", "message_type", { body: "hello", id: 1 });
|
|
await waitForSteps(['message - {"body":"hello","id":1}']);
|
|
});
|
|
|
|
test("do not reconnect when worker version is outdated", async () => {
|
|
addBusServiceListeners(
|
|
["BUS:CONNECT", () => asyncStep("BUS:CONNECT")],
|
|
["BUS:DISCONNECT", () => asyncStep("BUS:DISCONNECT")],
|
|
["BUS:RECONNECT", () => asyncStep("BUS:RECONNECT")]
|
|
);
|
|
await makeMockEnv();
|
|
startBusService();
|
|
await runAllTimers();
|
|
await waitForSteps(["BUS:CONNECT"]);
|
|
const worker = getWebSocketWorker();
|
|
expect(worker.state).toBe(WORKER_STATE.CONNECTED);
|
|
MockServer.env["bus.bus"]._simulateDisconnection(WEBSOCKET_CLOSE_CODES.ABNORMAL_CLOSURE);
|
|
await waitForSteps(["BUS:DISCONNECT"]);
|
|
await runAllTimers();
|
|
await waitForSteps(["BUS:RECONNECT"]);
|
|
expect(worker.state).toBe(WORKER_STATE.CONNECTED);
|
|
patchWithCleanup(console, { warn: (message) => asyncStep(message) });
|
|
MockServer.env["bus.bus"]._simulateDisconnection(
|
|
WEBSOCKET_CLOSE_CODES.CLEAN,
|
|
"OUTDATED_VERSION"
|
|
);
|
|
await waitForSteps(["Worker deactivated due to an outdated version.", "BUS:DISCONNECT"]);
|
|
await runAllTimers();
|
|
stepWorkerActions("BUS:START");
|
|
startBusService();
|
|
await runAllTimers();
|
|
await waitForSteps(["BUS:START"]);
|
|
// Verify the worker state instead of the steps as the connect event is
|
|
// asynchronous and may not be fired at this point.
|
|
expect(worker.state).toBe(WORKER_STATE.DISCONNECTED);
|
|
});
|
|
|
|
test("reconnect on demande after clean close code", async () => {
|
|
addBusServiceListeners(
|
|
["BUS:CONNECT", () => asyncStep("BUS:CONNECT")],
|
|
["BUS:DISCONNECT", () => asyncStep("BUS:DISCONNECT")],
|
|
["BUS:RECONNECT", () => asyncStep("BUS:RECONNECT")]
|
|
);
|
|
await makeMockEnv();
|
|
startBusService();
|
|
await runAllTimers();
|
|
await waitForSteps(["BUS:CONNECT"]);
|
|
MockServer.env["bus.bus"]._simulateDisconnection(WEBSOCKET_CLOSE_CODES.ABNORMAL_CLOSURE);
|
|
await waitForSteps(["BUS:DISCONNECT"]);
|
|
await runAllTimers();
|
|
await waitForSteps(["BUS:RECONNECT"]);
|
|
MockServer.env["bus.bus"]._simulateDisconnection(WEBSOCKET_CLOSE_CODES.CLEAN);
|
|
await waitForSteps(["BUS:DISCONNECT"]);
|
|
await runAllTimers();
|
|
startBusService();
|
|
await waitForSteps(["BUS:CONNECT"]);
|
|
});
|
|
|
|
test("remove from main tab candidates when version is outdated", async () => {
|
|
addBusServiceListeners(
|
|
["BUS:CONNECT", () => asyncStep("BUS:CONNECT")],
|
|
["BUS:DISCONNECT", () => asyncStep("BUS:DISCONNECT")]
|
|
);
|
|
await makeMockEnv();
|
|
patchWithCleanup(console, { warn: (message) => asyncStep(message) });
|
|
getService("multi_tab").bus.addEventListener("no_longer_main_tab", () =>
|
|
asyncStep("no_longer_main_tab")
|
|
);
|
|
startBusService();
|
|
await waitForSteps(["BUS:CONNECT"]);
|
|
expect(await getService("multi_tab").isOnMainTab()).toBe(true);
|
|
MockServer.env["bus.bus"]._simulateDisconnection(
|
|
WEBSOCKET_CLOSE_CODES.CLEAN,
|
|
"OUTDATED_VERSION"
|
|
);
|
|
await waitForSteps([
|
|
"Worker deactivated due to an outdated version.",
|
|
"BUS:DISCONNECT",
|
|
"no_longer_main_tab",
|
|
]);
|
|
});
|
|
|
|
test("show notification when version is outdated", async () => {
|
|
browser.location.addEventListener("reload", () => asyncStep("reload"));
|
|
addBusServiceListeners(
|
|
["BUS:CONNECT", () => asyncStep("BUS:CONNECT")],
|
|
["BUS:DISCONNECT", () => asyncStep("BUS:DISCONNECT")]
|
|
);
|
|
patchWithCleanup(console, { warn: (message) => asyncStep(message) });
|
|
await mountWithCleanup(WebClient);
|
|
await waitForSteps(["BUS:CONNECT"]);
|
|
MockServer.env["bus.bus"]._simulateDisconnection(
|
|
WEBSOCKET_CLOSE_CODES.CLEAN,
|
|
"OUTDATED_VERSION"
|
|
);
|
|
await waitForSteps(["Worker deactivated due to an outdated version.", "BUS:DISCONNECT"]);
|
|
await runAllTimers();
|
|
await waitFor(".o_notification", {
|
|
contains:
|
|
"Save your work and refresh to get the latest updates and avoid potential issues.",
|
|
});
|
|
await contains(".o_notification button:contains(Refresh)").click();
|
|
await waitForSteps(["reload"]);
|
|
});
|
|
|
|
test("subscribe message is sent first", async () => {
|
|
addBusServiceListeners(["BUS:DISCONNECT", () => asyncStep("BUS:DISCONNECT")]);
|
|
// Starting the server first, the following patch would be overwritten otherwise.
|
|
await makeMockServer();
|
|
const ogSocket = window.WebSocket;
|
|
patchWithCleanup(window, {
|
|
WebSocket: function () {
|
|
const ws = new ogSocket(...arguments);
|
|
ws.send = (message) => {
|
|
const evName = JSON.parse(message).event_name;
|
|
if (["subscribe", "some_event", "some_other_event"].includes(evName)) {
|
|
asyncStep(evName);
|
|
}
|
|
};
|
|
return ws;
|
|
},
|
|
});
|
|
await makeMockEnv();
|
|
startBusService();
|
|
await runAllTimers();
|
|
await waitForSteps(["subscribe"]);
|
|
getService("bus_service").send("some_event");
|
|
await waitForSteps(["some_event"]);
|
|
MockServer.env["bus.bus"]._simulateDisconnection(WEBSOCKET_CLOSE_CODES.CLEAN);
|
|
await waitForSteps(["BUS:DISCONNECT"]);
|
|
getService("bus_service").send("some_event");
|
|
getService("bus_service").send("some_other_event");
|
|
getService("bus_service").addChannel("channel_1");
|
|
await runAllTimers();
|
|
await waitForSteps([]);
|
|
startBusService();
|
|
await runAllTimers();
|
|
await waitForSteps(["subscribe", "some_event", "some_other_event"]);
|
|
});
|
|
|
|
test("worker state is available from the bus service", async () => {
|
|
addBusServiceListeners(
|
|
["BUS:CONNECT", () => asyncStep("BUS:CONNECT")],
|
|
["BUS:DISCONNECT", () => asyncStep("BUS:DISCONNECT")]
|
|
);
|
|
await makeMockEnv();
|
|
startBusService();
|
|
await waitForSteps(["BUS:CONNECT"]);
|
|
expect(getService("bus_service").workerState).toBe(WORKER_STATE.CONNECTED);
|
|
MockServer.env["bus.bus"]._simulateDisconnection(WEBSOCKET_CLOSE_CODES.CLEAN);
|
|
await waitForSteps(["BUS:DISCONNECT"]);
|
|
await runAllTimers();
|
|
expect(getService("bus_service").workerState).toBe(WORKER_STATE.DISCONNECTED);
|
|
startBusService();
|
|
await waitForSteps(["BUS:CONNECT"]);
|
|
expect(getService("bus_service").workerState).toBe(WORKER_STATE.CONNECTED);
|
|
});
|
|
|
|
test("channel is kept until deleted as many times as added", async () => {
|
|
onWebsocketEvent("subscribe", (data) =>
|
|
expect.step(`subscribe - [${data.channels.toString()}]`)
|
|
);
|
|
await makeMockEnv();
|
|
const worker = getWebSocketWorker();
|
|
patchWithCleanup(worker, {
|
|
_deleteChannel() {
|
|
super._deleteChannel(...arguments);
|
|
expect.step("delete channel");
|
|
},
|
|
_addChannel(client, channel) {
|
|
super._addChannel(client, channel);
|
|
expect.step(`add channel - ${channel}`);
|
|
},
|
|
});
|
|
startBusService();
|
|
const busService = getService("bus_service");
|
|
await expect.waitForSteps(["subscribe - []"]);
|
|
busService.addChannel("foo");
|
|
await expect.waitForSteps(["add channel - foo", "subscribe - [foo]"]);
|
|
busService.addChannel("foo");
|
|
await expect.waitForSteps(["add channel - foo"]);
|
|
await runAllTimers();
|
|
busService.deleteChannel("foo");
|
|
await expect.waitForSteps(["delete channel"]);
|
|
await runAllTimers();
|
|
await expect.waitForSteps([]);
|
|
busService.deleteChannel("foo");
|
|
await expect.waitForSteps(["delete channel", "subscribe - []"]);
|
|
});
|