[FIX] bus: fix non-deterministic channel managment test

This commit fixes a non-deterministic error in the bus module. Testing
the bus service is difficult because it relies heavily on async code.
Until now, `nextTick` was used but there is no guarantee that this is
enough. This commit introduces the `waitForChannels` method that
awaits the channel subscriptions to be done before resolving.

fixes runbot-21942,54467

closes odoo/odoo#147616

X-original-commit: 429a0668a4bed52eff1c7b8cd0c5c66261678699
Signed-off-by: Matthieu Stockbauer (tsm) <tsm@odoo.com>
This commit is contained in:
tsm-odoo
2023-12-28 13:09:29 +00:00
parent 47852f79d2
commit be63841a6e
@@ -60,38 +60,43 @@ export function waitUntilSubscribe(...requiredChannels) {
*
* @returns {import("@web/core/utils/concurrency").Deferred} */
export function waitForChannels(channels, { operation = "add" } = {}) {
const successDeferred = makeDeferred();
const failTimeout = setTimeout(() => {
const failMessage = `Waited ${TIMEOUT}ms for ${channels.join(", ")} to be ${
operation === "add" ? "added" : "deleted"
}`;
const missingChannels = new Set(channels);
const deferred = makeDeferred();
function check({ crashOnFail = false } = {}) {
const success = missingChannels.size === 0;
if (!success && !crashOnFail) {
return;
}
unpatch();
QUnit.assert.ok(false, failMessage);
successDeferred.resolve();
}, TIMEOUT);
const channelsSeen = new Set();
clearTimeout(failTimeout);
const msg = success
? `Channel(s) [${channels.join(", ")}] ${operation === "add" ? "added" : "deleted"}.`
: `Waited ${TIMEOUT}ms for [${channels.join(", ")}] to be ${
operation === "add" ? "added" : "deleted"
}`;
QUnit.assert.ok(success, msg);
if (success) {
deferred.resolve();
} else {
deferred.reject(new Error(msg));
}
}
const failTimeout = setTimeout(() => check({ crashOnFail: true }), TIMEOUT);
registerCleanup(() => {
if (missingChannels.length > 0) {
check({ crashOnFail: true });
}
});
const worker = patchWebsocketWorkerWithCleanup();
const workerMethod = operation === "add" ? "_addChannel" : "_deleteChannel";
const unpatch = patch(worker, {
async [operation === "add" ? "_addChannel" : "_deleteChannel"](client, channel) {
await super[operation === "add" ? "_addChannel" : "_deleteChannel"](client, channel);
if (channels.includes(channel)) {
channelsSeen.add(channel);
}
if (channelsSeen.size === channels.length) {
unpatch();
QUnit.assert.ok(
true,
`Channel(s) ${channels.join(", ")} ${
operation === "add" ? "added" : "deleted"
}.`
);
successDeferred.resolve();
clearTimeout(failTimeout);
}
async [workerMethod](client, channel) {
await super[workerMethod](client, channel);
missingChannels.delete(channel);
check();
},
});
registerCleanup(unpatch);
return successDeferred;
return deferred;
}
/**