signal-desktop/ts/test-mock/messaging/retries_test.ts
2024-10-01 08:23:32 +10:00

173 lines
5 KiB
TypeScript

// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
import createDebug from 'debug';
import { EnvelopeType, StorageState } from '@signalapp/mock-server';
import type { App } from '../playwright';
import * as durations from '../../util/durations';
import { Bootstrap } from '../bootstrap';
import { sleep } from '../../util/sleep';
export const debug = createDebug('mock:test:retries');
describe('retries', function (this: Mocha.Suite) {
this.timeout(durations.MINUTE);
let bootstrap: Bootstrap;
let app: App;
beforeEach(async () => {
bootstrap = new Bootstrap();
await bootstrap.init();
app = await bootstrap.link();
const { contacts, phone } = bootstrap;
const [first] = contacts;
let state = StorageState.getEmpty();
state = state.addContact(first, {
identityKey: first.publicKey.serialize(),
profileKey: first.profileKey.serialize(),
whitelisted: true,
});
state = state.pin(first);
await phone.setStorageState(state);
});
afterEach(async function (this: Mocha.Context) {
if (!bootstrap) {
return;
}
await bootstrap.maybeSaveLogs(this.currentTest, app);
await app.close();
await bootstrap.teardown();
});
it('sends a retry request on a missing sender key error', async () => {
const { desktop, contacts } = bootstrap;
const [first] = contacts;
debug('send a sender key message without sending skdm first');
const distributionId = await first.sendSenderKey(desktop, {
timestamp: bootstrap.getTimestamp(),
skipSkdmSend: true,
});
const timestamp = bootstrap.getTimestamp();
await first.sendText(desktop, 'hello', {
distributionId,
sealed: true,
timestamp,
});
debug('waiting for the resend request');
const message = await first.waitForDecryptionError();
debug(JSON.stringify(message));
assert.equal(message.envelopeType, EnvelopeType.Plaintext);
assert.equal(message.timestamp, timestamp);
});
it('does not send a retry request if message succeeded later', async () => {
const { desktop, contacts } = bootstrap;
const [first] = contacts;
debug('send a sender key message without sending skdm first');
const firstDistributionId = await first.sendSenderKey(desktop, {
timestamp: bootstrap.getTimestamp(),
skipSkdmSend: true,
});
const content = 'how are you?';
debug('send a failing message');
const timestamp = bootstrap.getTimestamp();
await first.sendText(desktop, content, {
distributionId: firstDistributionId,
sealed: true,
timestamp,
});
debug('send second sender key out');
const secondDistributionId = await first.sendSenderKey(desktop, {
timestamp: bootstrap.getTimestamp(),
});
debug('send same hello message, this time it should work');
await first.sendText(desktop, content, {
distributionId: secondDistributionId,
sealed: true,
timestamp,
});
debug('open conversation');
const window = await app.getWindow();
const leftPane = window.locator('#LeftPane');
await leftPane.locator(`[data-testid="${first.device.aci}"]`).click();
const conversationStack = window.locator('.Inbox__conversation-stack');
debug('verify message receipt');
await conversationStack
.locator(`.module-message--incoming >> "${content}"`)
.waitFor();
debug('verify that no resend request was sent');
const count = await first.getDecryptionErrorQueueSize();
assert.equal(count, 0);
});
it('sends only one retry request if many failures with same timestamp', async () => {
const { desktop, contacts } = bootstrap;
const [first] = contacts;
debug('send a sender key message without sending skdm first');
const firstDistributionId = await first.sendSenderKey(desktop, {
timestamp: bootstrap.getTimestamp(),
skipSkdmSend: true,
});
const content = 'how are you?';
debug('send a failing message');
const timestamp = bootstrap.getTimestamp();
await first.sendText(desktop, content, {
distributionId: firstDistributionId,
sealed: true,
timestamp,
});
debug('send a failing message a second time');
await first.sendText(desktop, content, {
distributionId: firstDistributionId,
sealed: true,
timestamp,
});
debug('send a failing message a third time');
await first.sendText(desktop, content, {
distributionId: firstDistributionId,
sealed: true,
timestamp,
});
debug('waiting for the resend request');
const message = await first.waitForDecryptionError();
debug(JSON.stringify(message));
assert.equal(message.envelopeType, EnvelopeType.Plaintext);
assert.equal(message.timestamp, timestamp);
debug('wait for max jitter delay');
await sleep(500);
debug('verify that no other resend requests were sent');
const count = await first.getDecryptionErrorQueueSize();
assert.equal(count, 0);
});
});