Make messaging/relink mock test more reliable

Co-authored-by: Fedor Indutny <indutny@signal.org>
This commit is contained in:
Scott Nonnenberg 2024-08-15 10:13:48 +10:00 committed by GitHub
parent 3914216f5c
commit c040cb2d6c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 63 additions and 19 deletions

8
package-lock.json generated
View file

@ -128,7 +128,7 @@
"@indutny/parallel-prettier": "3.0.0", "@indutny/parallel-prettier": "3.0.0",
"@indutny/rezip-electron": "1.3.1", "@indutny/rezip-electron": "1.3.1",
"@indutny/symbolicate-mac": "2.3.0", "@indutny/symbolicate-mac": "2.3.0",
"@signalapp/mock-server": "6.7.0", "@signalapp/mock-server": "6.8.1",
"@storybook/addon-a11y": "8.1.11", "@storybook/addon-a11y": "8.1.11",
"@storybook/addon-actions": "8.1.11", "@storybook/addon-actions": "8.1.11",
"@storybook/addon-controls": "8.1.11", "@storybook/addon-controls": "8.1.11",
@ -7253,9 +7253,9 @@
} }
}, },
"node_modules/@signalapp/mock-server": { "node_modules/@signalapp/mock-server": {
"version": "6.7.0", "version": "6.8.1",
"resolved": "https://registry.npmjs.org/@signalapp/mock-server/-/mock-server-6.7.0.tgz", "resolved": "https://registry.npmjs.org/@signalapp/mock-server/-/mock-server-6.8.1.tgz",
"integrity": "sha512-ueF3RTp07Y3kxdIg3un3dyE87VdA3y+E37wNxG9HbAb8fk5WP4LYlRwa7VvJBRuI28IU8LbrrC0d7ItXGdN3sA==", "integrity": "sha512-RYAaNoCMuIPoMTAuvgEwMh8D12pdvpjOA/qfEOnwXRRLJU1XWXKuAHBc0uJ7deZWLM6qbC/egST/hXImLcsV7Q==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@signalapp/libsignal-client": "^0.45.0", "@signalapp/libsignal-client": "^0.45.0",

View file

@ -210,7 +210,7 @@
"@indutny/parallel-prettier": "3.0.0", "@indutny/parallel-prettier": "3.0.0",
"@indutny/rezip-electron": "1.3.1", "@indutny/rezip-electron": "1.3.1",
"@indutny/symbolicate-mac": "2.3.0", "@indutny/symbolicate-mac": "2.3.0",
"@signalapp/mock-server": "6.7.0", "@signalapp/mock-server": "6.8.1",
"@storybook/addon-a11y": "8.1.11", "@storybook/addon-a11y": "8.1.11",
"@storybook/addon-actions": "8.1.11", "@storybook/addon-actions": "8.1.11",
"@storybook/addon-controls": "8.1.11", "@storybook/addon-controls": "8.1.11",

View file

@ -35,6 +35,7 @@ import { ChallengeHandler } from './challenge';
import * as durations from './util/durations'; import * as durations from './util/durations';
import { drop } from './util/drop'; import { drop } from './util/drop';
import { explodePromise } from './util/explodePromise'; import { explodePromise } from './util/explodePromise';
import type { ExplodePromiseResultType } from './util/explodePromise';
import { isWindowDragElement } from './util/isWindowDragElement'; import { isWindowDragElement } from './util/isWindowDragElement';
import { assertDev, strictAssert } from './util/assert'; import { assertDev, strictAssert } from './util/assert';
import { filter } from './util/iterables'; import { filter } from './util/iterables';
@ -1462,7 +1463,7 @@ export async function startApp(): Promise<void> {
log.info(`Startup/syncTasks: Queueing ${syncTasks.length} sync tasks`); log.info(`Startup/syncTasks: Queueing ${syncTasks.length} sync tasks`);
await queueSyncTasks(syncTasks, DataWriter.removeSyncTaskById); await queueSyncTasks(syncTasks, DataWriter.removeSyncTaskById);
log.info('`Startup/syncTasks: Done'); log.info('Startup/syncTasks: Done');
} }
log.info('listening for registration events'); log.info('listening for registration events');
@ -1708,16 +1709,31 @@ export async function startApp(): Promise<void> {
} }
let connectCount = 0; let connectCount = 0;
let connecting = false; let connectPromise: ExplodePromiseResultType<void> | undefined;
let remotelyExpired = false; let remotelyExpired = false;
async function connect(firstRun?: boolean) { async function connect(firstRun?: boolean) {
if (connecting) { if (connectPromise && !firstRun) {
log.warn('background: connect already running', { log.warn('background: connect already running', {
connectCount, connectCount,
firstRun, firstRun,
}); });
return; return;
} }
if (connectPromise && firstRun) {
while (connectPromise) {
log.warn(
'background: connect already running; waiting for previous run',
{
connectCount,
firstRun,
}
);
// eslint-disable-next-line no-await-in-loop
await connectPromise.promise;
}
await connect(firstRun);
return;
}
if (remotelyExpired) { if (remotelyExpired) {
log.warn('background: remotely expired, not reconnecting'); log.warn('background: remotely expired, not reconnecting');
@ -1727,8 +1743,7 @@ export async function startApp(): Promise<void> {
strictAssert(server !== undefined, 'WebAPI not connected'); strictAssert(server !== undefined, 'WebAPI not connected');
try { try {
connecting = true; connectPromise = explodePromise();
// Reset the flag and update it below if needed // Reset the flag and update it below if needed
setIsInitialSync(false); setIsInitialSync(false);
@ -1804,12 +1819,13 @@ export async function startApp(): Promise<void> {
window.textsecure.storage.user.getDeviceId() !== 1 window.textsecure.storage.user.getDeviceId() !== 1
) { ) {
log.info('Boot after upgrading. Requesting contact sync'); log.info('Boot after upgrading. Requesting contact sync');
window.getSyncRequest();
void StorageService.reprocessUnknownFields();
void runStorageService();
try { try {
window.getSyncRequest();
void StorageService.reprocessUnknownFields();
void runStorageService();
const manager = window.getAccountManager(); const manager = window.getAccountManager();
await Promise.all([ await Promise.all([
manager.maybeUpdateDeviceName(), manager.maybeUpdateDeviceName(),
@ -1817,7 +1833,7 @@ export async function startApp(): Promise<void> {
]); ]);
} catch (e) { } catch (e) {
log.error( log.error(
'Problem with account manager updates after starting new version: ', "Problem with 'boot after upgrade' tasks: ",
Errors.toLogFormat(e) Errors.toLogFormat(e)
); );
} }
@ -1982,7 +1998,15 @@ export async function startApp(): Promise<void> {
reconnectBackOff.reset(); reconnectBackOff.reset();
} finally { } finally {
connecting = false; if (connectPromise) {
connectPromise.resolve();
connectPromise = undefined;
} else {
log.warn('background connect: in finally, no connectPromise!', {
connectCount,
firstRun,
});
}
} }
} }
@ -3082,6 +3106,10 @@ export async function startApp(): Promise<void> {
); );
} finally { } finally {
await Registration.markEverDone(); await Registration.markEverDone();
if (window.SignalCI) {
window.SignalCI.handleEvent('unlinkCleanupComplete', null);
}
} }
} }

View file

@ -305,6 +305,8 @@ export class Bootstrap {
const app = await this.startApp(extraConfig); const app = await this.startApp(extraConfig);
const window = await app.getWindow(); const window = await app.getWindow();
debug('looking for QR code or relink button');
const qrCode = window.locator( const qrCode = window.locator(
'.module-InstallScreenQrCodeNotScannedStep__qr-code__code' '.module-InstallScreenQrCodeNotScannedStep__qr-code__code'
); );
@ -316,10 +318,13 @@ export class Bootstrap {
await qrCode.waitFor(); await qrCode.waitFor();
} }
debug('waiting for provision');
const provision = await this.server.waitForProvision(); const provision = await this.server.waitForProvision();
debug('waiting for provision URL');
const provisionURL = await app.waitForProvisionURL(); const provisionURL = await app.waitForProvisionURL();
debug('completing provision');
this.privDesktop = await provision.complete({ this.privDesktop = await provision.complete({
provisionURL, provisionURL,
primaryDevice: this.phone, primaryDevice: this.phone,

View file

@ -9,7 +9,7 @@ import type { App } from '../playwright';
import { Bootstrap } from '../bootstrap'; import { Bootstrap } from '../bootstrap';
import { expectSystemMessages } from '../helpers'; import { expectSystemMessages } from '../helpers';
export const debug = createDebug('mock:test:stories'); export const debug = createDebug('mock:test:relink');
describe('messaging/relink', function (this: Mocha.Suite) { describe('messaging/relink', function (this: Mocha.Suite) {
this.timeout(durations.MINUTE); this.timeout(durations.MINUTE);
@ -70,9 +70,10 @@ describe('messaging/relink', function (this: Mocha.Suite) {
it('updates pin state on relink', async () => { it('updates pin state on relink', async () => {
const { const {
phone,
desktop,
contacts: [first, second], contacts: [first, second],
desktop,
phone,
server,
} = bootstrap; } = bootstrap;
{ {
@ -88,7 +89,10 @@ describe('messaging/relink', function (this: Mocha.Suite) {
.waitFor(); .waitFor();
await app.unlink(); await app.unlink();
await app.waitForUnlink();
await phone.unlink(desktop); await phone.unlink(desktop);
await server.removeDevice(desktop.number, desktop.deviceId);
await app.close(); await app.close();
debug('change pinned contact, identity key'); debug('change pinned contact, identity key');
@ -133,6 +137,9 @@ describe('messaging/relink', function (this: Mocha.Suite) {
timestamp: bootstrap.getTimestamp(), timestamp: bootstrap.getTimestamp(),
}); });
// Wait for that storage service version to be processed
await app.waitForManifestVersion(state.version);
debug('open old pinned contact'); debug('open old pinned contact');
await leftPane await leftPane
.locator( .locator(

View file

@ -180,6 +180,10 @@ export class App extends EventEmitter {
return window.evaluate('window.SignalCI.unlink()'); return window.evaluate('window.SignalCI.unlink()');
} }
public async waitForUnlink(): Promise<void> {
return this.waitForEvent('unlinkCleanupComplete');
}
// EventEmitter types // EventEmitter types
public override on(type: 'close', callback: () => void): this; public override on(type: 'close', callback: () => void): this;