Skip to content

Commit 9c6d5a6

Browse files
authored
Element-R: wait for OlmMachine on startup (#3487)
* Element-R: wait for OlmMachine on startup Previously, if you called `CryptoApi.getUserDeviceInfo()` before the first `/sync` request happened, it would return an empty list, which made a bunch of the tests racy. Add a hack to get the OlmMachine to think about its device lists during startup. * add a test
1 parent b77fe46 commit 9c6d5a6

File tree

2 files changed

+52
-1
lines changed

2 files changed

+52
-1
lines changed

spec/unit/rust-crypto/rust-crypto.spec.ts

+41-1
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,19 @@ import { IDBFactory } from "fake-indexeddb";
1919
import * as RustSdkCryptoJs from "@matrix-org/matrix-sdk-crypto-js";
2020
import { KeysQueryRequest, OlmMachine } from "@matrix-org/matrix-sdk-crypto-js";
2121
import { Mocked } from "jest-mock";
22+
import fetchMock from "fetch-mock-jest";
2223

2324
import { RustCrypto } from "../../../src/rust-crypto/rust-crypto";
2425
import { initRustCrypto } from "../../../src/rust-crypto";
25-
import { IHttpOpts, IToDeviceEvent, MatrixClient, MatrixHttpApi } from "../../../src";
26+
import {
27+
HttpApiEvent,
28+
HttpApiEventHandlerMap,
29+
IHttpOpts,
30+
IToDeviceEvent,
31+
MatrixClient,
32+
MatrixHttpApi,
33+
TypedEventEmitter,
34+
} from "../../../src";
2635
import { mkEvent } from "../../test-utils/test-utils";
2736
import { CryptoBackend } from "../../../src/common-crypto/CryptoBackend";
2837
import { IEventDecryptionResult } from "../../../src/@types/crypto";
@@ -421,6 +430,37 @@ describe("RustCrypto", () => {
421430
expect(recoveryKey.keyInfo?.passphrase?.iterations).toBe(500000);
422431
});
423432
});
433+
434+
it("should wait for a keys/query before returning devices", async () => {
435+
jest.useFakeTimers();
436+
437+
const mockHttpApi = new MatrixHttpApi(new TypedEventEmitter<HttpApiEvent, HttpApiEventHandlerMap>(), {
438+
baseUrl: "http://server/",
439+
prefix: "",
440+
onlyData: true,
441+
});
442+
fetchMock.post("path:/_matrix/client/v3/keys/upload", { one_time_key_counts: {} });
443+
fetchMock.post("path:/_matrix/client/v3/keys/query", {
444+
device_keys: {
445+
[testData.TEST_USER_ID]: {
446+
[testData.TEST_DEVICE_ID]: testData.SIGNED_TEST_DEVICE_DATA,
447+
},
448+
},
449+
});
450+
451+
const rustCrypto = await makeTestRustCrypto(mockHttpApi, testData.TEST_USER_ID);
452+
453+
// an attempt to fetch the device list should block
454+
const devicesPromise = rustCrypto.getUserDeviceInfo([testData.TEST_USER_ID]);
455+
456+
// ... until a /sync completes, and we trigger the outgoingRequests.
457+
rustCrypto.onSyncCompleted({});
458+
459+
const deviceMap = (await devicesPromise).get(testData.TEST_USER_ID)!;
460+
expect(deviceMap.has(TEST_DEVICE_ID)).toBe(true);
461+
expect(deviceMap.has(testData.TEST_DEVICE_ID)).toBe(true);
462+
rustCrypto.stop();
463+
});
424464
});
425465

426466
/** build a basic RustCrypto instance for testing

src/rust-crypto/index.ts

+11
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,17 @@ export async function initRustCrypto(
5757
rustCrypto.onRoomKeysUpdated(sessions),
5858
);
5959

60+
// Tell the OlmMachine to think about its outgoing requests before we hand control back to the application.
61+
//
62+
// This is primarily a fudge to get it to correctly populate the `users_for_key_query` list, so that future
63+
// calls to getIdentity (etc) block until the key queries are performed.
64+
//
65+
// Note that we don't actually need to *make* any requests here; it is sufficient to tell the Rust side to think
66+
// about them.
67+
//
68+
// XXX: find a less hacky way to do this.
69+
await olmMachine.outgoingRequests();
70+
6071
logger.info("Completed rust crypto-sdk setup");
6172
return rustCrypto;
6273
}

0 commit comments

Comments
 (0)