[PM-7766] Add `clientType` to MigrationHelper (#8945)

* Add `clientType` to MigrationHelper

* PM-7766 - Fix migration builder tests to take new clientType into account.

Co-authored-by: Justin Baur <19896123+justindbaur@users.noreply.github.com>

* PM-7766 - Add client type to migration builder tests.

* PM-7766 - Fix migration-helper.spec tests.

* PM-7766 - Fix migrator.spec.ts

---------

Co-authored-by: Jared Snider <jsnider@bitwarden.com>
This commit is contained in:
Justin Baur 2024-04-29 07:28:58 -04:00 committed by GitHub
parent 42f1f965af
commit 3caa6cb635
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 295 additions and 210 deletions

View File

@ -71,6 +71,7 @@ import {
} from "@bitwarden/common/autofill/services/user-notification-settings.service"; } from "@bitwarden/common/autofill/services/user-notification-settings.service";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { DefaultBillingAccountProfileStateService } from "@bitwarden/common/billing/services/account/billing-account-profile-state.service"; import { DefaultBillingAccountProfileStateService } from "@bitwarden/common/billing/services/account/billing-account-profile-state.service";
import { ClientType } from "@bitwarden/common/enums";
import { AppIdService as AppIdServiceAbstraction } from "@bitwarden/common/platform/abstractions/app-id.service"; import { AppIdService as AppIdServiceAbstraction } from "@bitwarden/common/platform/abstractions/app-id.service";
import { ConfigApiServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config-api.service.abstraction"; import { ConfigApiServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config-api.service.abstraction";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
@ -520,6 +521,7 @@ export default class MainBackground {
this.storageService, this.storageService,
this.logService, this.logService,
new MigrationBuilderService(), new MigrationBuilderService(),
ClientType.Browser,
); );
this.stateService = new DefaultBrowserStateService( this.stateService = new DefaultBrowserStateService(

View File

@ -1,3 +1,4 @@
import { ClientType } from "@bitwarden/common/enums";
import { MigrationBuilderService } from "@bitwarden/common/platform/services/migration-builder.service"; import { MigrationBuilderService } from "@bitwarden/common/platform/services/migration-builder.service";
import { MigrationRunner } from "@bitwarden/common/platform/services/migration-runner"; import { MigrationRunner } from "@bitwarden/common/platform/services/migration-runner";
@ -27,6 +28,7 @@ export async function migrationRunnerFactory(
await diskStorageServiceFactory(cache, opts), await diskStorageServiceFactory(cache, opts),
await logServiceFactory(cache, opts), await logServiceFactory(cache, opts),
new MigrationBuilderService(), new MigrationBuilderService(),
ClientType.Browser,
), ),
); );
} }

View File

@ -13,6 +13,7 @@ import {
SYSTEM_THEME_OBSERVABLE, SYSTEM_THEME_OBSERVABLE,
SafeInjectionToken, SafeInjectionToken,
INTRAPROCESS_MESSAGING_SUBJECT, INTRAPROCESS_MESSAGING_SUBJECT,
CLIENT_TYPE,
} from "@bitwarden/angular/services/injection-tokens"; } from "@bitwarden/angular/services/injection-tokens";
import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module"; import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module";
import { AuthRequestServiceAbstraction } from "@bitwarden/auth/common"; import { AuthRequestServiceAbstraction } from "@bitwarden/auth/common";
@ -45,6 +46,7 @@ import {
UserNotificationSettingsServiceAbstraction, UserNotificationSettingsServiceAbstraction,
} from "@bitwarden/common/autofill/services/user-notification-settings.service"; } from "@bitwarden/common/autofill/services/user-notification-settings.service";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { ClientType } from "@bitwarden/common/enums";
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
@ -558,6 +560,10 @@ const safeProviders: SafeProvider[] = [
OBSERVABLE_LARGE_OBJECT_MEMORY_STORAGE, OBSERVABLE_LARGE_OBJECT_MEMORY_STORAGE,
], ],
}), }),
safeProvider({
provide: CLIENT_TYPE,
useValue: ClientType.Browser,
}),
]; ];
@NgModule({ @NgModule({

View File

@ -344,6 +344,7 @@ export class Main {
this.storageService, this.storageService,
this.logService, this.logService,
new MigrationBuilderService(), new MigrationBuilderService(),
ClientType.Cli,
); );
this.stateService = new StateService( this.stateService = new StateService(

View File

@ -15,6 +15,7 @@ import {
SafeInjectionToken, SafeInjectionToken,
STATE_FACTORY, STATE_FACTORY,
INTRAPROCESS_MESSAGING_SUBJECT, INTRAPROCESS_MESSAGING_SUBJECT,
CLIENT_TYPE,
} from "@bitwarden/angular/services/injection-tokens"; } from "@bitwarden/angular/services/injection-tokens";
import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module"; import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module";
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
@ -25,6 +26,7 @@ import { KdfConfigService as KdfConfigServiceAbstraction } from "@bitwarden/comm
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service"; import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
import { ClientType } from "@bitwarden/common/enums";
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto-function.service";
import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto.service"; import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
@ -275,6 +277,10 @@ const safeProviders: SafeProvider[] = [
useClass: NativeMessagingManifestService, useClass: NativeMessagingManifestService,
deps: [], deps: [],
}), }),
safeProvider({
provide: CLIENT_TYPE,
useValue: ClientType.Desktop,
}),
]; ];
@NgModule({ @NgModule({

View File

@ -6,6 +6,7 @@ import { Subject, firstValueFrom } from "rxjs";
import { TokenService as TokenServiceAbstraction } from "@bitwarden/common/auth/abstractions/token.service"; import { TokenService as TokenServiceAbstraction } from "@bitwarden/common/auth/abstractions/token.service";
import { AccountServiceImplementation } from "@bitwarden/common/auth/services/account.service"; import { AccountServiceImplementation } from "@bitwarden/common/auth/services/account.service";
import { TokenService } from "@bitwarden/common/auth/services/token.service"; import { TokenService } from "@bitwarden/common/auth/services/token.service";
import { ClientType } from "@bitwarden/common/enums";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import { KeyGenerationService as KeyGenerationServiceAbstraction } from "@bitwarden/common/platform/abstractions/key-generation.service"; import { KeyGenerationService as KeyGenerationServiceAbstraction } from "@bitwarden/common/platform/abstractions/key-generation.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
@ -190,6 +191,7 @@ export class Main {
this.storageService, this.storageService,
this.logService, this.logService,
new MigrationBuilderService(), new MigrationBuilderService(),
ClientType.Desktop,
); );
// TODO: this state service will have access to on disk storage, but not in memory storage. // TODO: this state service will have access to on disk storage, but not in memory storage.

View File

@ -13,10 +13,12 @@ import {
OBSERVABLE_DISK_LOCAL_STORAGE, OBSERVABLE_DISK_LOCAL_STORAGE,
WINDOW, WINDOW,
SafeInjectionToken, SafeInjectionToken,
CLIENT_TYPE,
} from "@bitwarden/angular/services/injection-tokens"; } from "@bitwarden/angular/services/injection-tokens";
import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module"; import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module";
import { ModalService as ModalServiceAbstraction } from "@bitwarden/angular/services/modal.service"; import { ModalService as ModalServiceAbstraction } from "@bitwarden/angular/services/modal.service";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { ClientType } from "@bitwarden/common/enums";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service"; import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/platform/abstractions/i18n.service";
@ -157,6 +159,10 @@ const safeProviders: SafeProvider[] = [
new DefaultThemeStateService(globalStateProvider, ThemeType.Light), new DefaultThemeStateService(globalStateProvider, ThemeType.Light),
deps: [GlobalStateProvider], deps: [GlobalStateProvider],
}), }),
safeProvider({
provide: CLIENT_TYPE,
useValue: ClientType.Web,
}),
]; ];
@NgModule({ @NgModule({

View File

@ -1,3 +1,4 @@
import { ClientType } from "@bitwarden/common/enums";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service"; import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service";
import { Utils } from "@bitwarden/common/platform/misc/utils"; import { Utils } from "@bitwarden/common/platform/misc/utils";
@ -14,7 +15,7 @@ export class WebMigrationRunner extends MigrationRunner {
migrationBuilderService: MigrationBuilderService, migrationBuilderService: MigrationBuilderService,
private diskLocalStorage: WindowStorageService, private diskLocalStorage: WindowStorageService,
) { ) {
super(diskStorage, logService, migrationBuilderService); super(diskStorage, logService, migrationBuilderService, ClientType.Web);
} }
override async run(): Promise<void> { override async run(): Promise<void> {
@ -46,7 +47,7 @@ class WebMigrationHelper extends MigrationHelper {
storageService: WindowStorageService, storageService: WindowStorageService,
logService: LogService, logService: LogService,
) { ) {
super(currentVersion, storageService, logService, "web-disk-local"); super(currentVersion, storageService, logService, "web-disk-local", ClientType.Web);
this.diskLocalStorageService = storageService; this.diskLocalStorageService = storageService;
} }

View File

@ -1,6 +1,7 @@
import { InjectionToken } from "@angular/core"; import { InjectionToken } from "@angular/core";
import { Observable, Subject } from "rxjs"; import { Observable, Subject } from "rxjs";
import { ClientType } from "@bitwarden/common/enums";
import { import {
AbstractMemoryStorageService, AbstractMemoryStorageService,
AbstractStorageService, AbstractStorageService,
@ -52,3 +53,4 @@ export const SYSTEM_THEME_OBSERVABLE = new SafeInjectionToken<Observable<ThemeTy
export const INTRAPROCESS_MESSAGING_SUBJECT = new SafeInjectionToken<Subject<Message<object>>>( export const INTRAPROCESS_MESSAGING_SUBJECT = new SafeInjectionToken<Subject<Message<object>>>(
"INTRAPROCESS_MESSAGING_SUBJECT", "INTRAPROCESS_MESSAGING_SUBJECT",
); );
export const CLIENT_TYPE = new SafeInjectionToken<ClientType>("CLIENT_TYPE");

View File

@ -276,6 +276,7 @@ import {
SYSTEM_THEME_OBSERVABLE, SYSTEM_THEME_OBSERVABLE,
WINDOW, WINDOW,
INTRAPROCESS_MESSAGING_SUBJECT, INTRAPROCESS_MESSAGING_SUBJECT,
CLIENT_TYPE,
} from "./injection-tokens"; } from "./injection-tokens";
import { ModalService } from "./modal.service"; import { ModalService } from "./modal.service";
@ -1099,7 +1100,7 @@ const safeProviders: SafeProvider[] = [
safeProvider({ safeProvider({
provide: MigrationRunner, provide: MigrationRunner,
useClass: MigrationRunner, useClass: MigrationRunner,
deps: [AbstractStorageService, LogService, MigrationBuilderService], deps: [AbstractStorageService, LogService, MigrationBuilderService, CLIENT_TYPE],
}), }),
safeProvider({ safeProvider({
provide: MigrationBuilderService, provide: MigrationBuilderService,

View File

@ -1,6 +1,7 @@
import { mock } from "jest-mock-extended"; import { mock } from "jest-mock-extended";
import { FakeStorageService } from "../../../spec/fake-storage.service"; import { FakeStorageService } from "../../../spec/fake-storage.service";
import { ClientType } from "../../enums";
import { MigrationHelper } from "../../state-migrations/migration-helper"; import { MigrationHelper } from "../../state-migrations/migration-helper";
import { MigrationBuilderService } from "./migration-builder.service"; import { MigrationBuilderService } from "./migration-builder.service";
@ -66,16 +67,27 @@ describe("MigrationBuilderService", () => {
global: {}, global: {},
}; };
it.each([ const startingStates = [
noAccounts, { data: noAccounts, description: "No Accounts" },
nullAndUndefinedAccounts, { data: nullAndUndefinedAccounts, description: "Null and Undefined Accounts" },
emptyAccountObject, { data: emptyAccountObject, description: "Empty Account Object" },
nullCommonAccountProperties, { data: nullCommonAccountProperties, description: "Null Common Account Properties" },
emptyCommonAccountProperties, { data: emptyCommonAccountProperties, description: "Empty Common Account Properties" },
nullGlobal, { data: nullGlobal, description: "Null Global" },
undefinedGlobal, { data: undefinedGlobal, description: "Undefined Global" },
emptyGlobalObject, { data: emptyGlobalObject, description: "Empty Global Object" },
])("should not produce migrations that throw when given data: %s", async (startingState) => { ];
const clientTypes = Object.values(ClientType);
// Generate all possible test cases
const testCases = startingStates.flatMap((startingState) =>
clientTypes.map((clientType) => ({ startingState, clientType })),
);
it.each(testCases)(
"should not produce migrations that throw when given $startingState.description for client $clientType",
async ({ startingState, clientType }) => {
const sut = new MigrationBuilderService(); const sut = new MigrationBuilderService();
const helper = new MigrationHelper( const helper = new MigrationHelper(
@ -83,8 +95,10 @@ describe("MigrationBuilderService", () => {
new FakeStorageService(startingState), new FakeStorageService(startingState),
mock(), mock(),
"general", "general",
clientType,
); );
await sut.build().migrate(helper); await sut.build().migrate(helper);
}); },
);
}); });

View File

@ -1,6 +1,7 @@
import { mock } from "jest-mock-extended"; import { mock } from "jest-mock-extended";
import { awaitAsync } from "../../../spec"; import { awaitAsync } from "../../../spec";
import { ClientType } from "../../enums";
import { CURRENT_VERSION } from "../../state-migrations"; import { CURRENT_VERSION } from "../../state-migrations";
import { MigrationBuilder } from "../../state-migrations/migration-builder"; import { MigrationBuilder } from "../../state-migrations/migration-builder";
import { LogService } from "../abstractions/log.service"; import { LogService } from "../abstractions/log.service";
@ -17,7 +18,7 @@ describe("MigrationRunner", () => {
migrationBuilderService.build.mockReturnValue(mockMigrationBuilder); migrationBuilderService.build.mockReturnValue(mockMigrationBuilder);
const sut = new MigrationRunner(storage, logService, migrationBuilderService); const sut = new MigrationRunner(storage, logService, migrationBuilderService, ClientType.Web);
describe("migrate", () => { describe("migrate", () => {
it("should not run migrations if state is empty", async () => { it("should not run migrations if state is empty", async () => {

View File

@ -1,3 +1,4 @@
import { ClientType } from "../../enums";
import { waitForMigrations } from "../../state-migrations"; import { waitForMigrations } from "../../state-migrations";
import { CURRENT_VERSION, currentVersion } from "../../state-migrations/migrate"; import { CURRENT_VERSION, currentVersion } from "../../state-migrations/migrate";
import { MigrationHelper } from "../../state-migrations/migration-helper"; import { MigrationHelper } from "../../state-migrations/migration-helper";
@ -11,6 +12,7 @@ export class MigrationRunner {
protected diskStorage: AbstractStorageService, protected diskStorage: AbstractStorageService,
protected logService: LogService, protected logService: LogService,
protected migrationBuilderService: MigrationBuilderService, protected migrationBuilderService: MigrationBuilderService,
private clientType: ClientType,
) {} ) {}
async run(): Promise<void> { async run(): Promise<void> {
@ -19,6 +21,7 @@ export class MigrationRunner {
this.diskStorage, this.diskStorage,
this.logService, this.logService,
"general", "general",
this.clientType,
); );
if (migrationHelper.currentVersion < 0) { if (migrationHelper.currentVersion < 0) {

View File

@ -1,5 +1,8 @@
import { mock } from "jest-mock-extended"; import { mock } from "jest-mock-extended";
// eslint-disable-next-line import/no-restricted-paths
import { ClientType } from "../enums";
import { MigrationBuilder } from "./migration-builder"; import { MigrationBuilder } from "./migration-builder";
import { MigrationHelper } from "./migration-helper"; import { MigrationHelper } from "./migration-helper";
import { Migrator } from "./migrator"; import { Migrator } from "./migrator";
@ -72,6 +75,9 @@ describe("MigrationBuilder", () => {
expect(migrations[1]).toMatchObject({ migrator: expect.any(TestMigrator), direction: "down" }); expect(migrations[1]).toMatchObject({ migrator: expect.any(TestMigrator), direction: "down" });
}); });
const clientTypes = Object.values(ClientType);
describe.each(clientTypes)("for client %s", (clientType) => {
describe("migrate", () => { describe("migrate", () => {
let migrator: TestMigrator; let migrator: TestMigrator;
let rollback_migrator: TestMigrator; let rollback_migrator: TestMigrator;
@ -83,35 +89,35 @@ describe("MigrationBuilder", () => {
}); });
it("should migrate", async () => { it("should migrate", async () => {
const helper = new MigrationHelper(0, mock(), mock(), "general"); const helper = new MigrationHelper(0, mock(), mock(), "general", clientType);
const spy = jest.spyOn(migrator, "migrate"); const spy = jest.spyOn(migrator, "migrate");
await sut.migrate(helper); await sut.migrate(helper);
expect(spy).toBeCalledWith(helper); expect(spy).toBeCalledWith(helper);
}); });
it("should rollback", async () => { it("should rollback", async () => {
const helper = new MigrationHelper(1, mock(), mock(), "general"); const helper = new MigrationHelper(1, mock(), mock(), "general", clientType);
const spy = jest.spyOn(rollback_migrator, "rollback"); const spy = jest.spyOn(rollback_migrator, "rollback");
await sut.migrate(helper); await sut.migrate(helper);
expect(spy).toBeCalledWith(helper); expect(spy).toBeCalledWith(helper);
}); });
it("should update version on migrate", async () => { it("should update version on migrate", async () => {
const helper = new MigrationHelper(0, mock(), mock(), "general"); const helper = new MigrationHelper(0, mock(), mock(), "general", clientType);
const spy = jest.spyOn(migrator, "updateVersion"); const spy = jest.spyOn(migrator, "updateVersion");
await sut.migrate(helper); await sut.migrate(helper);
expect(spy).toBeCalledWith(helper, "up"); expect(spy).toBeCalledWith(helper, "up");
}); });
it("should update version on rollback", async () => { it("should update version on rollback", async () => {
const helper = new MigrationHelper(1, mock(), mock(), "general"); const helper = new MigrationHelper(1, mock(), mock(), "general", clientType);
const spy = jest.spyOn(rollback_migrator, "updateVersion"); const spy = jest.spyOn(rollback_migrator, "updateVersion");
await sut.migrate(helper); await sut.migrate(helper);
expect(spy).toBeCalledWith(helper, "down"); expect(spy).toBeCalledWith(helper, "down");
}); });
it("should not run the migrator if the current version does not match the from version", async () => { it("should not run the migrator if the current version does not match the from version", async () => {
const helper = new MigrationHelper(3, mock(), mock(), "general"); const helper = new MigrationHelper(3, mock(), mock(), "general", clientType);
const migrate = jest.spyOn(migrator, "migrate"); const migrate = jest.spyOn(migrator, "migrate");
const rollback = jest.spyOn(rollback_migrator, "rollback"); const rollback = jest.spyOn(rollback_migrator, "rollback");
await sut.migrate(helper); await sut.migrate(helper);
@ -120,7 +126,7 @@ describe("MigrationBuilder", () => {
}); });
it("should not update version if the current version does not match the from version", async () => { it("should not update version if the current version does not match the from version", async () => {
const helper = new MigrationHelper(3, mock(), mock(), "general"); const helper = new MigrationHelper(3, mock(), mock(), "general", clientType);
const migrate = jest.spyOn(migrator, "updateVersion"); const migrate = jest.spyOn(migrator, "updateVersion");
const rollback = jest.spyOn(rollback_migrator, "updateVersion"); const rollback = jest.spyOn(rollback_migrator, "updateVersion");
await sut.migrate(helper); await sut.migrate(helper);
@ -130,7 +136,8 @@ describe("MigrationBuilder", () => {
}); });
it("should be able to call instance methods", async () => { it("should be able to call instance methods", async () => {
const helper = new MigrationHelper(0, mock(), mock(), "general"); const helper = new MigrationHelper(0, mock(), mock(), "general", clientType);
await sut.with(TestMigratorWithInstanceMethod, 0, 1).migrate(helper); await sut.with(TestMigratorWithInstanceMethod, 0, 1).migrate(helper);
}); });
});
}); });

View File

@ -2,6 +2,8 @@ import { MockProxy, mock } from "jest-mock-extended";
// eslint-disable-next-line import/no-restricted-paths -- Needed to print log messages // eslint-disable-next-line import/no-restricted-paths -- Needed to print log messages
import { FakeStorageService } from "../../spec/fake-storage.service"; import { FakeStorageService } from "../../spec/fake-storage.service";
// eslint-disable-next-line import/no-restricted-paths -- Needed client type enum
import { ClientType } from "../enums";
// eslint-disable-next-line import/no-restricted-paths -- Needed to print log messages // eslint-disable-next-line import/no-restricted-paths -- Needed to print log messages
import { LogService } from "../platform/abstractions/log.service"; import { LogService } from "../platform/abstractions/log.service";
// eslint-disable-next-line import/no-restricted-paths -- Needed to interface with storage locations // eslint-disable-next-line import/no-restricted-paths -- Needed to interface with storage locations
@ -32,12 +34,15 @@ describe("RemoveLegacyEtmKeyMigrator", () => {
let logService: MockProxy<LogService>; let logService: MockProxy<LogService>;
let sut: MigrationHelper; let sut: MigrationHelper;
const clientTypes = Object.values(ClientType);
describe.each(clientTypes)("for client %s", (clientType) => {
beforeEach(() => { beforeEach(() => {
logService = mock(); logService = mock();
storage = mock(); storage = mock();
storage.get.mockImplementation((key) => (exampleJSON as any)[key]); storage.get.mockImplementation((key) => (exampleJSON as any)[key]);
sut = new MigrationHelper(0, storage, logService, "general"); sut = new MigrationHelper(0, storage, logService, "general", clientType);
}); });
describe("get", () => { describe("get", () => {
@ -58,8 +63,14 @@ describe("RemoveLegacyEtmKeyMigrator", () => {
it("should return all accounts", async () => { it("should return all accounts", async () => {
const accounts = await sut.getAccounts(); const accounts = await sut.getAccounts();
expect(accounts).toEqual([ expect(accounts).toEqual([
{ userId: "c493ed01-4e08-4e88-abc7-332f380ca760", account: { otherStuff: "otherStuff1" } }, {
{ userId: "23e61a5f-2ece-4f5e-b499-f0bc489482a9", account: { otherStuff: "otherStuff2" } }, userId: "c493ed01-4e08-4e88-abc7-332f380ca760",
account: { otherStuff: "otherStuff1" },
},
{
userId: "23e61a5f-2ece-4f5e-b499-f0bc489482a9",
account: { otherStuff: "otherStuff2" },
},
]); ]);
}); });
@ -92,7 +103,10 @@ describe("RemoveLegacyEtmKeyMigrator", () => {
describe("setToGlobal", () => { describe("setToGlobal", () => {
it("should set the correct value", async () => { it("should set the correct value", async () => {
sut.currentVersion = 9; sut.currentVersion = 9;
await sut.setToGlobal({ stateDefinition: { name: "serviceName" }, key: "key" }, "new_value"); await sut.setToGlobal(
{ stateDefinition: { name: "serviceName" }, key: "key" },
"new_value",
);
expect(storage.save).toHaveBeenCalledWith("global_serviceName_key", "new_value"); expect(storage.save).toHaveBeenCalledWith("global_serviceName_key", "new_value");
}); });
@ -144,6 +158,7 @@ describe("RemoveLegacyEtmKeyMigrator", () => {
).toThrowError("No key builder should be used for versions prior to 9."); ).toThrowError("No key builder should be used for versions prior to 9.");
}); });
}); });
});
}); });
/** Helper to create well-mocked migration helpers in migration tests */ /** Helper to create well-mocked migration helpers in migration tests */
@ -151,6 +166,7 @@ export function mockMigrationHelper(
storageJson: any, storageJson: any,
stateVersion = 0, stateVersion = 0,
type: MigrationHelperType = "general", type: MigrationHelperType = "general",
clientType: ClientType = ClientType.Web,
): MockProxy<MigrationHelper> { ): MockProxy<MigrationHelper> {
const logService: MockProxy<LogService> = mock(); const logService: MockProxy<LogService> = mock();
const storage: MockProxy<AbstractStorageService> = mock(); const storage: MockProxy<AbstractStorageService> = mock();
@ -158,7 +174,7 @@ export function mockMigrationHelper(
storage.save.mockImplementation(async (key, value) => { storage.save.mockImplementation(async (key, value) => {
(storageJson as any)[key] = value; (storageJson as any)[key] = value;
}); });
const helper = new MigrationHelper(stateVersion, storage, logService, type); const helper = new MigrationHelper(stateVersion, storage, logService, type, clientType);
const mockHelper = mock<MigrationHelper>(); const mockHelper = mock<MigrationHelper>();
mockHelper.get.mockImplementation((key) => helper.get(key)); mockHelper.get.mockImplementation((key) => helper.get(key));
@ -295,7 +311,13 @@ export async function runMigrator<
const allInjectedData = injectData(initalData, []); const allInjectedData = injectData(initalData, []);
const fakeStorageService = new FakeStorageService(initalData); const fakeStorageService = new FakeStorageService(initalData);
const helper = new MigrationHelper(migrator.fromVersion, fakeStorageService, mock(), "general"); const helper = new MigrationHelper(
migrator.fromVersion,
fakeStorageService,
mock(),
"general",
ClientType.Web,
);
// Run their migrations // Run their migrations
if (direction === "rollback") { if (direction === "rollback") {

View File

@ -1,3 +1,5 @@
// eslint-disable-next-line import/no-restricted-paths -- Needed to provide client type to migrations
import { ClientType } from "../enums";
// eslint-disable-next-line import/no-restricted-paths -- Needed to print log messages // eslint-disable-next-line import/no-restricted-paths -- Needed to print log messages
import { LogService } from "../platform/abstractions/log.service"; import { LogService } from "../platform/abstractions/log.service";
// eslint-disable-next-line import/no-restricted-paths -- Needed to interface with storage locations // eslint-disable-next-line import/no-restricted-paths -- Needed to interface with storage locations
@ -17,6 +19,7 @@ export class MigrationHelper {
private storageService: AbstractStorageService, private storageService: AbstractStorageService,
public logService: LogService, public logService: LogService,
type: MigrationHelperType, type: MigrationHelperType,
public clientType: ClientType,
) { ) {
this.type = type; this.type = type;
} }

View File

@ -1,5 +1,7 @@
import { mock, MockProxy } from "jest-mock-extended"; import { mock, MockProxy } from "jest-mock-extended";
// eslint-disable-next-line import/no-restricted-paths -- Needed client type enum
import { ClientType } from "../enums";
// eslint-disable-next-line import/no-restricted-paths -- Needed to print log messages // eslint-disable-next-line import/no-restricted-paths -- Needed to print log messages
import { LogService } from "../platform/abstractions/log.service"; import { LogService } from "../platform/abstractions/log.service";
// eslint-disable-next-line import/no-restricted-paths -- Needed to interface with storage locations // eslint-disable-next-line import/no-restricted-paths -- Needed to interface with storage locations
@ -23,10 +25,13 @@ describe("migrator default methods", () => {
let helper: MigrationHelper; let helper: MigrationHelper;
let sut: TestMigrator; let sut: TestMigrator;
const clientTypes = Object.values(ClientType);
describe.each(clientTypes)("for client %s", (clientType) => {
beforeEach(() => { beforeEach(() => {
storage = mock(); storage = mock();
logService = mock(); logService = mock();
helper = new MigrationHelper(0, storage, logService, "general"); helper = new MigrationHelper(0, storage, logService, "general", clientType);
sut = new TestMigrator(0, 1); sut = new TestMigrator(0, 1);
}); });
@ -72,4 +77,5 @@ describe("migrator default methods", () => {
}); });
}); });
}); });
});
}); });