1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-12-21 16:18:28 +01:00

Ps/allow state provider migrations from v 9 (#7263)

* Provide missing spec helpers and fakers

* We need to be able to migrate v9 stuff to state providers
This commit is contained in:
Matt Gibson 2023-12-18 07:50:04 -05:00 committed by GitHub
parent bc1f93d098
commit 69657a5ab5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 60 additions and 24 deletions

View File

@ -4,6 +4,9 @@ import {
KeyDefinition,
ActiveUserState,
SingleUserState,
SingleUserStateProvider,
StateProvider,
ActiveUserStateProvider,
} from "../src/platform/state";
import { UserId } from "../src/types/guid";
@ -26,7 +29,7 @@ export class FakeGlobalStateProvider implements GlobalStateProvider {
}
}
export class FakeSingleUserStateProvider {
export class FakeSingleUserStateProvider implements SingleUserStateProvider {
states: Map<string, SingleUserState<unknown>> = new Map();
get<T>(userId: UserId, keyDefinition: KeyDefinition<T>): SingleUserState<T> {
let result = this.states.get(keyDefinition.buildCacheKey("user", userId)) as SingleUserState<T>;
@ -43,7 +46,7 @@ export class FakeSingleUserStateProvider {
}
}
export class FakeActiveUserStateProvider {
export class FakeActiveUserStateProvider implements ActiveUserStateProvider {
states: Map<string, ActiveUserState<unknown>> = new Map();
get<T>(keyDefinition: KeyDefinition<T>): ActiveUserState<T> {
let result = this.states.get(
@ -61,3 +64,21 @@ export class FakeActiveUserStateProvider {
return this.get(keyDefinition) as FakeActiveUserState<T>;
}
}
export class FakeStateProvider implements StateProvider {
getActive<T>(keyDefinition: KeyDefinition<T>): ActiveUserState<T> {
return this.activeUser.get(keyDefinition);
}
getGlobal<T>(keyDefinition: KeyDefinition<T>): GlobalState<T> {
return this.global.get(keyDefinition);
}
getUser<T>(userId: UserId, keyDefinition: KeyDefinition<T>): SingleUserState<T> {
return this.singleUser.get(userId, keyDefinition);
}
global: FakeGlobalStateProvider = new FakeGlobalStateProvider();
singleUser: FakeSingleUserStateProvider = new FakeSingleUserStateProvider();
activeUser: FakeActiveUserStateProvider = new FakeActiveUserStateProvider();
}

View File

@ -69,7 +69,7 @@ describe("RemoveLegacyEtmKeyMigrator", () => {
describe("getFromGlobal", () => {
it("should return the correct value", async () => {
sut.currentVersion = 10;
sut.currentVersion = 9;
const value = await sut.getFromGlobal({
stateDefinition: { name: "serviceName" },
key: "key",
@ -77,33 +77,33 @@ describe("RemoveLegacyEtmKeyMigrator", () => {
expect(value).toEqual("global_serviceName_key");
});
it("should throw if the current version is less than 10", () => {
it("should throw if the current version is less than 9", () => {
expect(() =>
sut.getFromGlobal({ stateDefinition: { name: "serviceName" }, key: "key" }),
).toThrowError("No key builder should be used for versions prior to 10.");
).toThrowError("No key builder should be used for versions prior to 9.");
});
});
describe("setToGlobal", () => {
it("should set the correct value", async () => {
sut.currentVersion = 10;
sut.currentVersion = 9;
await sut.setToGlobal({ stateDefinition: { name: "serviceName" }, key: "key" }, "new_value");
expect(storage.save).toHaveBeenCalledWith("global_serviceName_key", "new_value");
});
it("should throw if the current version is less than 10", () => {
it("should throw if the current version is less than 9", () => {
expect(() =>
sut.setToGlobal(
{ stateDefinition: { name: "serviceName" }, key: "key" },
"global_serviceName_key",
),
).toThrowError("No key builder should be used for versions prior to 10.");
).toThrowError("No key builder should be used for versions prior to 9.");
});
});
describe("getFromUser", () => {
it("should return the correct value", async () => {
sut.currentVersion = 10;
sut.currentVersion = 9;
const value = await sut.getFromUser("userId", {
stateDefinition: { name: "serviceName" },
key: "key",
@ -111,16 +111,16 @@ describe("RemoveLegacyEtmKeyMigrator", () => {
expect(value).toEqual("user_userId_serviceName_key");
});
it("should throw if the current version is less than 10", () => {
it("should throw if the current version is less than 9", () => {
expect(() =>
sut.getFromUser("userId", { stateDefinition: { name: "serviceName" }, key: "key" }),
).toThrowError("No key builder should be used for versions prior to 10.");
).toThrowError("No key builder should be used for versions prior to 9.");
});
});
describe("setToUser", () => {
it("should set the correct value", async () => {
sut.currentVersion = 10;
sut.currentVersion = 9;
await sut.setToUser(
"userId",
{ stateDefinition: { name: "serviceName" }, key: "key" },
@ -129,31 +129,46 @@ describe("RemoveLegacyEtmKeyMigrator", () => {
expect(storage.save).toHaveBeenCalledWith("user_userId_serviceName_key", "new_value");
});
it("should throw if the current version is less than 10", () => {
it("should throw if the current version is less than 9", () => {
expect(() =>
sut.setToUser(
"userId",
{ stateDefinition: { name: "serviceName" }, key: "key" },
"new_value",
),
).toThrowError("No key builder should be used for versions prior to 10.");
).toThrowError("No key builder should be used for versions prior to 9.");
});
});
});
/** Helper to create well-mocked migration helpers in migration tests */
export function mockMigrationHelper(storageJson: any): MockProxy<MigrationHelper> {
export function mockMigrationHelper(
storageJson: any,
stateVersion = 0,
): MockProxy<MigrationHelper> {
const logService: MockProxy<LogService> = mock();
const storage: MockProxy<AbstractStorageService> = mock();
storage.get.mockImplementation((key) => (storageJson as any)[key]);
storage.save.mockImplementation(async (key, value) => {
(storageJson as any)[key] = value;
});
const helper = new MigrationHelper(0, storage, logService);
const helper = new MigrationHelper(stateVersion, storage, logService);
const mockHelper = mock<MigrationHelper>();
mockHelper.get.mockImplementation((key) => helper.get(key));
mockHelper.set.mockImplementation((key, value) => helper.set(key, value));
mockHelper.getFromGlobal.mockImplementation((keyDefinition) =>
helper.getFromGlobal(keyDefinition),
);
mockHelper.setToGlobal.mockImplementation((keyDefinition, value) =>
helper.setToGlobal(keyDefinition, value),
);
mockHelper.getFromUser.mockImplementation((userId, keyDefinition) =>
helper.getFromUser(userId, keyDefinition),
);
mockHelper.setToUser.mockImplementation((userId, keyDefinition, value) =>
helper.setToUser(userId, keyDefinition, value),
);
mockHelper.getAccounts.mockImplementation(() => helper.getAccounts());
return mockHelper;
}

View File

@ -123,8 +123,8 @@ export class MigrationHelper {
* @returns
*/
private getUserKey(userId: string, keyDefinition: KeyDefinitionLike): string {
if (this.currentVersion < 10) {
return userKeyBuilderPre10();
if (this.currentVersion < 9) {
return userKeyBuilderPre9();
} else {
return userKeyBuilder(userId, keyDefinition);
}
@ -137,8 +137,8 @@ export class MigrationHelper {
* @returns
*/
private getGlobalKey(keyDefinition: KeyDefinitionLike): string {
if (this.currentVersion < 10) {
return globalKeyBuilderPre10();
if (this.currentVersion < 9) {
return globalKeyBuilderPre9();
} else {
return globalKeyBuilder(keyDefinition);
}
@ -158,8 +158,8 @@ function userKeyBuilder(userId: string, keyDefinition: KeyDefinitionLike): strin
return `user_${userId}_${keyDefinition.stateDefinition.name}_${keyDefinition.key}`;
}
function userKeyBuilderPre10(): string {
throw Error("No key builder should be used for versions prior to 10.");
function userKeyBuilderPre9(): string {
throw Error("No key builder should be used for versions prior to 9.");
}
/**
@ -174,6 +174,6 @@ function globalKeyBuilder(keyDefinition: KeyDefinitionLike): string {
return `global_${keyDefinition.stateDefinition.name}_${keyDefinition.key}`;
}
function globalKeyBuilderPre10(): string {
throw Error("No key builder should be used for versions prior to 10.");
function globalKeyBuilderPre9(): string {
throw Error("No key builder should be used for versions prior to 9.");
}