SettingsStore: Change feature_rust_crypto to default true (#12203)
* Set default crypto stack to rust * Update test for default to rust crypto * Fix labs settings tests * Fix test not working with rust crypto
This commit is contained in:
parent
f36b6035f4
commit
cb7fd5118e
6 changed files with 225 additions and 68 deletions
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
import { test, expect } from "../../element-web-test";
|
import { test, expect } from "../../element-web-test";
|
||||||
import { logIntoElement } from "./utils";
|
import { logIntoElement } from "./utils";
|
||||||
|
|
||||||
test.describe("Migration of existing logins", () => {
|
test.describe("Adoption of rust stack", () => {
|
||||||
test("Test migration of existing logins when rollout is 100%", async ({
|
test("Test migration of existing logins when rollout is 100%", async ({
|
||||||
page,
|
page,
|
||||||
context,
|
context,
|
||||||
|
@ -25,23 +25,36 @@ test.describe("Migration of existing logins", () => {
|
||||||
credentials,
|
credentials,
|
||||||
homeserver,
|
homeserver,
|
||||||
}, workerInfo) => {
|
}, workerInfo) => {
|
||||||
test.skip(workerInfo.project.name === "Rust Crypto", "This test only works with Rust crypto.");
|
test.skip(
|
||||||
|
workerInfo.project.name === "Rust Crypto",
|
||||||
|
"No need to test this on Rust Crypto as we override the config manually",
|
||||||
|
);
|
||||||
await page.goto("/#/login");
|
await page.goto("/#/login");
|
||||||
|
|
||||||
let featureRustCrypto = false;
|
let featureRustCrypto = false;
|
||||||
let stagedRolloutPercent = 0;
|
let stagedRolloutPercent = 0;
|
||||||
|
|
||||||
await context.route(`http://localhost:8080/config.json*`, async (route) => {
|
await context.route(`http://localhost:8080/config.json*`, async (route) => {
|
||||||
const json = {};
|
const json = {
|
||||||
|
default_server_config: {
|
||||||
|
"m.homeserver": {
|
||||||
|
base_url: "https://server.invalid",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
json["features"] = {
|
json["features"] = {
|
||||||
feature_rust_crypto: featureRustCrypto,
|
feature_rust_crypto: featureRustCrypto,
|
||||||
};
|
};
|
||||||
json["setting_defaults"] = {
|
json["setting_defaults"] = {
|
||||||
|
"language": "en-GB",
|
||||||
"RustCrypto.staged_rollout_percent": stagedRolloutPercent,
|
"RustCrypto.staged_rollout_percent": stagedRolloutPercent,
|
||||||
};
|
};
|
||||||
await route.fulfill({ json });
|
await route.fulfill({ json });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// reload to ensure we read the config
|
||||||
|
await page.reload();
|
||||||
|
|
||||||
await logIntoElement(page, homeserver, credentials);
|
await logIntoElement(page, homeserver, credentials);
|
||||||
|
|
||||||
await app.settings.openUserSettings("Help & About");
|
await app.settings.openUserSettings("Help & About");
|
||||||
|
@ -61,4 +74,80 @@ test.describe("Migration of existing logins", () => {
|
||||||
await app.settings.openUserSettings("Help & About");
|
await app.settings.openUserSettings("Help & About");
|
||||||
await expect(page.getByText("Crypto version: Rust SDK")).toBeVisible();
|
await expect(page.getByText("Crypto version: Rust SDK")).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("Test new logins by default on rust stack", async ({
|
||||||
|
page,
|
||||||
|
context,
|
||||||
|
app,
|
||||||
|
credentials,
|
||||||
|
homeserver,
|
||||||
|
}, workerInfo) => {
|
||||||
|
test.skip(
|
||||||
|
workerInfo.project.name === "Rust Crypto",
|
||||||
|
"No need to test this on Rust Crypto as we override the config manually",
|
||||||
|
);
|
||||||
|
await page.goto("/#/login");
|
||||||
|
|
||||||
|
await context.route(`http://localhost:8080/config.json*`, async (route) => {
|
||||||
|
const json = {
|
||||||
|
default_server_config: {
|
||||||
|
"m.homeserver": {
|
||||||
|
base_url: "https://server.invalid",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
// we only want to test the default
|
||||||
|
json["features"] = {};
|
||||||
|
json["setting_defaults"] = {
|
||||||
|
language: "en-GB",
|
||||||
|
};
|
||||||
|
await route.fulfill({ json });
|
||||||
|
});
|
||||||
|
|
||||||
|
// reload to get the new config
|
||||||
|
await page.reload();
|
||||||
|
await logIntoElement(page, homeserver, credentials);
|
||||||
|
|
||||||
|
await app.settings.openUserSettings("Help & About");
|
||||||
|
await expect(page.getByText("Crypto version: Rust SDK")).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Test default is to not rollout existing logins", async ({
|
||||||
|
page,
|
||||||
|
context,
|
||||||
|
app,
|
||||||
|
credentials,
|
||||||
|
homeserver,
|
||||||
|
}, workerInfo) => {
|
||||||
|
test.skip(
|
||||||
|
workerInfo.project.name === "Rust Crypto",
|
||||||
|
"No need to test this on Rust Crypto as we override the config manually",
|
||||||
|
);
|
||||||
|
|
||||||
|
await page.goto("/#/login");
|
||||||
|
|
||||||
|
// In the project.name = "Legacy crypto" it will be olm crypto
|
||||||
|
await logIntoElement(page, homeserver, credentials);
|
||||||
|
|
||||||
|
await app.settings.openUserSettings("Help & About");
|
||||||
|
await expect(page.getByText("Crypto version: Olm")).toBeVisible();
|
||||||
|
|
||||||
|
// Now simulate a refresh with `feature_rust_crypto` enabled but ensure we use the default rollout
|
||||||
|
await context.route(`http://localhost:8080/config.json*`, async (route) => {
|
||||||
|
const json = {};
|
||||||
|
json["features"] = {
|
||||||
|
feature_rust_crypto: true,
|
||||||
|
};
|
||||||
|
json["setting_defaults"] = {
|
||||||
|
// We want to test the default so we don't set this
|
||||||
|
// "RustCrypto.staged_rollout_percent": 0,
|
||||||
|
};
|
||||||
|
await route.fulfill({ json });
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.reload();
|
||||||
|
|
||||||
|
await app.settings.openUserSettings("Help & About");
|
||||||
|
await expect(page.getByText("Crypto version: Olm")).toBeVisible();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -111,8 +111,9 @@ export const test = base.extend<
|
||||||
return obj;
|
return obj;
|
||||||
}, {}),
|
}, {}),
|
||||||
};
|
};
|
||||||
if (cryptoBackend === "rust") {
|
// the default is to use rust now, so set to `false` if on legacy backend
|
||||||
json.features.feature_rust_crypto = true;
|
if (cryptoBackend === "legacy") {
|
||||||
|
json.features.feature_rust_crypto = false;
|
||||||
}
|
}
|
||||||
await route.fulfill({ json });
|
await route.fulfill({ json });
|
||||||
});
|
});
|
||||||
|
|
|
@ -501,7 +501,7 @@ export const SETTINGS: { [setting: string]: ISetting } = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
shouldWarn: true,
|
shouldWarn: true,
|
||||||
default: false,
|
default: true,
|
||||||
controller: new RustCryptoSdkController(),
|
controller: new RustCryptoSdkController(),
|
||||||
},
|
},
|
||||||
// Must be set under `setting_defaults` in config.json.
|
// Must be set under `setting_defaults` in config.json.
|
||||||
|
|
|
@ -24,6 +24,7 @@ import SettingsStore from "../src/settings/SettingsStore";
|
||||||
import Modal from "../src/Modal";
|
import Modal from "../src/Modal";
|
||||||
import PlatformPeg from "../src/PlatformPeg";
|
import PlatformPeg from "../src/PlatformPeg";
|
||||||
import { SettingLevel } from "../src/settings/SettingLevel";
|
import { SettingLevel } from "../src/settings/SettingLevel";
|
||||||
|
import { Features } from "../src/settings/Settings";
|
||||||
|
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
|
|
||||||
|
@ -91,6 +92,19 @@ describe("MatrixClientPeg", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("legacy crypto", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const originalGetValue = SettingsStore.getValue;
|
||||||
|
jest.spyOn(SettingsStore, "getValue").mockImplementation(
|
||||||
|
(settingName: string, roomId: string | null = null, excludeDefault = false) => {
|
||||||
|
if (settingName === "feature_rust_crypto") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return originalGetValue(settingName, roomId, excludeDefault);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it("should initialise client crypto", async () => {
|
it("should initialise client crypto", async () => {
|
||||||
const mockInitCrypto = jest.spyOn(testPeg.safeGet(), "initCrypto").mockResolvedValue(undefined);
|
const mockInitCrypto = jest.spyOn(testPeg.safeGet(), "initCrypto").mockResolvedValue(undefined);
|
||||||
const mockSetTrustCrossSignedDevices = jest
|
const mockSetTrustCrossSignedDevices = jest
|
||||||
|
@ -120,16 +134,32 @@ describe("MatrixClientPeg", () => {
|
||||||
expect(mockWarning).toHaveBeenCalledWith(expect.stringMatching("Unable to initialise e2e"), e2eError);
|
expect(mockWarning).toHaveBeenCalledWith(expect.stringMatching("Unable to initialise e2e"), e2eError);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should initialise the rust crypto library, if enabled", async () => {
|
it("should reload when store database closes for a guest user", async () => {
|
||||||
const originalGetValue = SettingsStore.getValue;
|
testPeg.safeGet().isGuest = () => true;
|
||||||
jest.spyOn(SettingsStore, "getValue").mockImplementation(
|
const emitter = new EventEmitter();
|
||||||
(settingName: string, roomId: string | null = null, excludeDefault = false) => {
|
testPeg.safeGet().store.on = emitter.on.bind(emitter);
|
||||||
if (settingName === "feature_rust_crypto") {
|
const platform: any = { reload: jest.fn() };
|
||||||
return true;
|
PlatformPeg.set(platform);
|
||||||
}
|
await testPeg.assign();
|
||||||
return originalGetValue(settingName, roomId, excludeDefault);
|
emitter.emit("closed" as any);
|
||||||
},
|
expect(platform.reload).toHaveBeenCalled();
|
||||||
);
|
});
|
||||||
|
|
||||||
|
it("should show error modal when store database closes", async () => {
|
||||||
|
testPeg.safeGet().isGuest = () => false;
|
||||||
|
const emitter = new EventEmitter();
|
||||||
|
const platform: any = { getHumanReadableName: jest.fn() };
|
||||||
|
PlatformPeg.set(platform);
|
||||||
|
testPeg.safeGet().store.on = emitter.on.bind(emitter);
|
||||||
|
const spy = jest.spyOn(Modal, "createDialog");
|
||||||
|
await testPeg.assign();
|
||||||
|
emitter.emit("closed" as any);
|
||||||
|
expect(spy).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should initialise the rust crypto library by default", async () => {
|
||||||
|
await SettingsStore.setValue(Features.RustCrypto, null, SettingLevel.DEVICE, null);
|
||||||
|
|
||||||
const mockSetValue = jest.spyOn(SettingsStore, "setValue").mockResolvedValue(undefined);
|
const mockSetValue = jest.spyOn(SettingsStore, "setValue").mockResolvedValue(undefined);
|
||||||
|
|
||||||
|
@ -144,6 +174,32 @@ describe("MatrixClientPeg", () => {
|
||||||
expect(mockSetValue).toHaveBeenCalledWith("feature_rust_crypto", null, SettingLevel.DEVICE, true);
|
expect(mockSetValue).toHaveBeenCalledWith("feature_rust_crypto", null, SettingLevel.DEVICE, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should initialise the legacy crypto library if set", async () => {
|
||||||
|
await SettingsStore.setValue(Features.RustCrypto, null, SettingLevel.DEVICE, null);
|
||||||
|
|
||||||
|
const originalGetValue = SettingsStore.getValue;
|
||||||
|
jest.spyOn(SettingsStore, "getValue").mockImplementation(
|
||||||
|
(settingName: string, roomId: string | null = null, excludeDefault = false) => {
|
||||||
|
if (settingName === "feature_rust_crypto") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return originalGetValue(settingName, roomId, excludeDefault);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const mockSetValue = jest.spyOn(SettingsStore, "setValue").mockResolvedValue(undefined);
|
||||||
|
|
||||||
|
const mockInitCrypto = jest.spyOn(testPeg.safeGet(), "initCrypto").mockResolvedValue(undefined);
|
||||||
|
const mockInitRustCrypto = jest.spyOn(testPeg.safeGet(), "initRustCrypto").mockResolvedValue(undefined);
|
||||||
|
|
||||||
|
await testPeg.start();
|
||||||
|
expect(mockInitCrypto).toHaveBeenCalled();
|
||||||
|
expect(mockInitRustCrypto).not.toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
// we should have stashed the setting in the settings store
|
||||||
|
expect(mockSetValue).toHaveBeenCalledWith("feature_rust_crypto", null, SettingLevel.DEVICE, false);
|
||||||
|
});
|
||||||
|
|
||||||
describe("Rust staged rollout", () => {
|
describe("Rust staged rollout", () => {
|
||||||
function mockSettingStore(
|
function mockSettingStore(
|
||||||
userIsUsingRust: boolean,
|
userIsUsingRust: boolean,
|
||||||
|
@ -178,10 +234,12 @@ describe("MatrixClientPeg", () => {
|
||||||
let mockInitCrypto: jest.SpyInstance;
|
let mockInitCrypto: jest.SpyInstance;
|
||||||
let mockInitRustCrypto: jest.SpyInstance;
|
let mockInitRustCrypto: jest.SpyInstance;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(async () => {
|
||||||
mockSetValue = jest.spyOn(SettingsStore, "setValue").mockResolvedValue(undefined);
|
mockSetValue = jest.spyOn(SettingsStore, "setValue").mockResolvedValue(undefined);
|
||||||
mockInitCrypto = jest.spyOn(testPeg.safeGet(), "initCrypto").mockResolvedValue(undefined);
|
mockInitCrypto = jest.spyOn(testPeg.safeGet(), "initCrypto").mockResolvedValue(undefined);
|
||||||
mockInitRustCrypto = jest.spyOn(testPeg.safeGet(), "initRustCrypto").mockResolvedValue(undefined);
|
mockInitRustCrypto = jest.spyOn(testPeg.safeGet(), "initRustCrypto").mockResolvedValue(undefined);
|
||||||
|
|
||||||
|
await SettingsStore.setValue(Features.RustCrypto, null, SettingLevel.DEVICE, null);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should not migrate existing login if rollout is 0", async () => {
|
it("Should not migrate existing login if rollout is 0", async () => {
|
||||||
|
@ -254,28 +312,5 @@ describe("MatrixClientPeg", () => {
|
||||||
expect(mockSetValue).toHaveBeenCalledWith("feature_rust_crypto", null, SettingLevel.DEVICE, false);
|
expect(mockSetValue).toHaveBeenCalledWith("feature_rust_crypto", null, SettingLevel.DEVICE, false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should reload when store database closes for a guest user", async () => {
|
|
||||||
testPeg.safeGet().isGuest = () => true;
|
|
||||||
const emitter = new EventEmitter();
|
|
||||||
testPeg.safeGet().store.on = emitter.on.bind(emitter);
|
|
||||||
const platform: any = { reload: jest.fn() };
|
|
||||||
PlatformPeg.set(platform);
|
|
||||||
await testPeg.assign();
|
|
||||||
emitter.emit("closed" as any);
|
|
||||||
expect(platform.reload).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should show error modal when store database closes", async () => {
|
|
||||||
testPeg.safeGet().isGuest = () => false;
|
|
||||||
const emitter = new EventEmitter();
|
|
||||||
const platform: any = { getHumanReadableName: jest.fn() };
|
|
||||||
PlatformPeg.set(platform);
|
|
||||||
testPeg.safeGet().store.on = emitter.on.bind(emitter);
|
|
||||||
const spy = jest.spyOn(Modal, "createDialog");
|
|
||||||
await testPeg.assign();
|
|
||||||
emitter.emit("closed" as any);
|
|
||||||
expect(spy).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -57,6 +57,7 @@ import * as Lifecycle from "../../../src/Lifecycle";
|
||||||
import { SSO_HOMESERVER_URL_KEY, SSO_ID_SERVER_URL_KEY } from "../../../src/BasePlatform";
|
import { SSO_HOMESERVER_URL_KEY, SSO_ID_SERVER_URL_KEY } from "../../../src/BasePlatform";
|
||||||
import SettingsStore from "../../../src/settings/SettingsStore";
|
import SettingsStore from "../../../src/settings/SettingsStore";
|
||||||
import { SettingLevel } from "../../../src/settings/SettingLevel";
|
import { SettingLevel } from "../../../src/settings/SettingLevel";
|
||||||
|
import { MatrixClientPeg as peg } from "../../../src/MatrixClientPeg";
|
||||||
|
|
||||||
jest.mock("matrix-js-sdk/src/oidc/authorize", () => ({
|
jest.mock("matrix-js-sdk/src/oidc/authorize", () => ({
|
||||||
completeAuthorizationCodeGrant: jest.fn(),
|
completeAuthorizationCodeGrant: jest.fn(),
|
||||||
|
@ -84,6 +85,7 @@ describe("<MatrixChat />", () => {
|
||||||
getClientWellKnown: jest.fn().mockReturnValue({}),
|
getClientWellKnown: jest.fn().mockReturnValue({}),
|
||||||
isVersionSupported: jest.fn().mockResolvedValue(false),
|
isVersionSupported: jest.fn().mockResolvedValue(false),
|
||||||
isCryptoEnabled: jest.fn().mockReturnValue(false),
|
isCryptoEnabled: jest.fn().mockReturnValue(false),
|
||||||
|
initRustCrypto: jest.fn(),
|
||||||
getRoom: jest.fn(),
|
getRoom: jest.fn(),
|
||||||
getMediaHandler: jest.fn().mockReturnValue({
|
getMediaHandler: jest.fn().mockReturnValue({
|
||||||
setVideoInput: jest.fn(),
|
setVideoInput: jest.fn(),
|
||||||
|
@ -835,10 +837,22 @@ describe("<MatrixChat />", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the soft-logout page", async () => {
|
it("should show the soft-logout page", async () => {
|
||||||
|
// XXX This test is strange, it was working with legacy crypto
|
||||||
|
// without mocking the following but the initCrypto call was failing
|
||||||
|
// but as the exception was swallowed, the test was passing (see in `initClientCrypto`).
|
||||||
|
// There are several uses of the peg in the app, so during all these tests you might end-up
|
||||||
|
// with a real client instead of the mocked one. Not sure how reliable all these tests are.
|
||||||
|
const originalReplace = peg.replaceUsingCreds;
|
||||||
|
peg.replaceUsingCreds = jest.fn().mockResolvedValue(mockClient);
|
||||||
|
// @ts-ignore - need to mock this for the test
|
||||||
|
peg.matrixClient = mockClient;
|
||||||
|
|
||||||
const result = getComponent();
|
const result = getComponent();
|
||||||
|
|
||||||
await result.findByText("You're signed out");
|
await result.findByText("You're signed out");
|
||||||
expect(result.container).toMatchSnapshot();
|
expect(result.container).toMatchSnapshot();
|
||||||
|
|
||||||
|
peg.replaceUsingCreds = originalReplace;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1336,7 +1350,6 @@ describe("<MatrixChat />", () => {
|
||||||
await populateStorageForSession();
|
await populateStorageForSession();
|
||||||
|
|
||||||
const client = new MockClientWithEventEmitter({
|
const client = new MockClientWithEventEmitter({
|
||||||
initCrypto: jest.fn(),
|
|
||||||
...getMockClientMethods(),
|
...getMockClientMethods(),
|
||||||
}) as unknown as Mocked<MatrixClient>;
|
}) as unknown as Mocked<MatrixClient>;
|
||||||
jest.spyOn(MatrixJs, "createClient").mockReturnValue(client);
|
jest.spyOn(MatrixJs, "createClient").mockReturnValue(client);
|
||||||
|
@ -1344,7 +1357,7 @@ describe("<MatrixChat />", () => {
|
||||||
// intercept initCrypto and have it block until we complete the deferred
|
// intercept initCrypto and have it block until we complete the deferred
|
||||||
const initCryptoCompleteDefer = defer();
|
const initCryptoCompleteDefer = defer();
|
||||||
const initCryptoCalled = new Promise<void>((resolve) => {
|
const initCryptoCalled = new Promise<void>((resolve) => {
|
||||||
client.initCrypto.mockImplementation(() => {
|
client.initRustCrypto.mockImplementation(() => {
|
||||||
resolve();
|
resolve();
|
||||||
return initCryptoCompleteDefer.promise;
|
return initCryptoCompleteDefer.promise;
|
||||||
});
|
});
|
||||||
|
|
|
@ -71,6 +71,25 @@ describe("<LabsUserSettingsTab />", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Not enabled in config", () => {
|
describe("Not enabled in config", () => {
|
||||||
|
// these tests only works if the feature is not enabled in the config by default?
|
||||||
|
const copyOfGetValueAt = SettingsStore.getValueAt;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
SettingsStore.getValueAt = (
|
||||||
|
level: SettingLevel,
|
||||||
|
name: string,
|
||||||
|
roomId?: string,
|
||||||
|
isExplicit?: boolean,
|
||||||
|
) => {
|
||||||
|
if (level == SettingLevel.CONFIG && name === "feature_rust_crypto") return false;
|
||||||
|
return copyOfGetValueAt(level, name, roomId, isExplicit);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
SettingsStore.getValueAt = copyOfGetValueAt;
|
||||||
|
});
|
||||||
|
|
||||||
it("can be turned on if not already", async () => {
|
it("can be turned on if not already", async () => {
|
||||||
// By the time the settings panel is shown, `MatrixClientPeg.initClientCrypto` has saved the current
|
// By the time the settings panel is shown, `MatrixClientPeg.initClientCrypto` has saved the current
|
||||||
// value to the settings store.
|
// value to the settings store.
|
||||||
|
|
Loading…
Reference in a new issue