mirror of
https://github.com/bitwarden/browser
synced 2025-12-14 15:23:33 +00:00
PM-3585 Improve state migrations (#5009)
* WIP: safer state migrations Co-authored-by: Justin Baur <justindbaur@users.noreply.github.com> * Add min version check and remove old migrations Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com> * Add rollback and version checking * Add state version move migration * Expand tests and improve typing for Migrations * Remove StateMigration Service * Rewrite version 5 and 6 migrations * Add all but initial migration to supported migrations * Handle stateVersion location in migrator update versions * Move to unique migrations directory * Disallow imports outside of state-migrations * Lint and test fixes * Do not run migrations if we cannot determine state * Fix desktop background StateService build * Document Migration builder class * Add debug logging to migrations * Comment on migrator overrides * Use specific property names * `npm run prettier` 🤖 * Insert new migration * Set stateVersion when creating new globals object * PR comments * Fix migrate imports * Move migration building into `migrate` function * Export current version from migration definitions * Move file version concerns to migrator * Update migrate spec to reflect new version requirements * Fix import paths * Prefer unique state data * Remove unnecessary async * Prefer to not use `any` --------- Co-authored-by: Justin Baur <justindbaur@users.noreply.github.com> Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com>
This commit is contained in:
117
libs/common/src/state-migrations/migration-builder.spec.ts
Normal file
117
libs/common/src/state-migrations/migration-builder.spec.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import { mock } from "jest-mock-extended";
|
||||
|
||||
import { MigrationBuilder } from "./migration-builder";
|
||||
import { MigrationHelper } from "./migration-helper";
|
||||
import { Migrator } from "./migrator";
|
||||
|
||||
describe("MigrationBuilder", () => {
|
||||
class TestMigrator extends Migrator<0, 1> {
|
||||
async migrate(helper: MigrationHelper): Promise<void> {
|
||||
await helper.set("test", "test");
|
||||
return;
|
||||
}
|
||||
|
||||
async rollback(helper: MigrationHelper): Promise<void> {
|
||||
await helper.set("test", "rollback");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let sut: MigrationBuilder<number>;
|
||||
|
||||
beforeEach(() => {
|
||||
sut = MigrationBuilder.create();
|
||||
});
|
||||
|
||||
class TestBadMigrator extends Migrator<1, 0> {
|
||||
async migrate(helper: MigrationHelper): Promise<void> {
|
||||
await helper.set("test", "test");
|
||||
}
|
||||
|
||||
async rollback(helper: MigrationHelper): Promise<void> {
|
||||
await helper.set("test", "rollback");
|
||||
}
|
||||
}
|
||||
|
||||
it("should throw if instantiated incorrectly", () => {
|
||||
expect(() => MigrationBuilder.create().with(TestMigrator, null, null)).toThrow();
|
||||
expect(() =>
|
||||
MigrationBuilder.create().with(TestMigrator, 0, 1).with(TestBadMigrator, 1, 0)
|
||||
).toThrow();
|
||||
});
|
||||
|
||||
it("should be able to create a new MigrationBuilder", () => {
|
||||
expect(sut).toBeInstanceOf(MigrationBuilder);
|
||||
});
|
||||
|
||||
it("should be able to add a migrator", () => {
|
||||
const newBuilder = sut.with(TestMigrator, 0, 1);
|
||||
const migrations = newBuilder["migrations"];
|
||||
expect(migrations.length).toBe(1);
|
||||
expect(migrations[0]).toMatchObject({ migrator: expect.any(TestMigrator), direction: "up" });
|
||||
});
|
||||
|
||||
it("should be able to add a rollback", () => {
|
||||
const newBuilder = sut.with(TestMigrator, 0, 1).rollback(TestMigrator, 1, 0);
|
||||
const migrations = newBuilder["migrations"];
|
||||
expect(migrations.length).toBe(2);
|
||||
expect(migrations[1]).toMatchObject({ migrator: expect.any(TestMigrator), direction: "down" });
|
||||
});
|
||||
|
||||
describe("migrate", () => {
|
||||
let migrator: TestMigrator;
|
||||
let rollback_migrator: TestMigrator;
|
||||
|
||||
beforeEach(() => {
|
||||
sut = sut.with(TestMigrator, 0, 1).rollback(TestMigrator, 1, 0);
|
||||
migrator = (sut as any).migrations[0].migrator;
|
||||
rollback_migrator = (sut as any).migrations[1].migrator;
|
||||
});
|
||||
|
||||
it("should migrate", async () => {
|
||||
const helper = new MigrationHelper(0, mock(), mock());
|
||||
const spy = jest.spyOn(migrator, "migrate");
|
||||
await sut.migrate(helper);
|
||||
expect(spy).toBeCalledWith(helper);
|
||||
});
|
||||
|
||||
it("should rollback", async () => {
|
||||
const helper = new MigrationHelper(1, mock(), mock());
|
||||
const spy = jest.spyOn(rollback_migrator, "rollback");
|
||||
await sut.migrate(helper);
|
||||
expect(spy).toBeCalledWith(helper);
|
||||
});
|
||||
|
||||
it("should update version on migrate", async () => {
|
||||
const helper = new MigrationHelper(0, mock(), mock());
|
||||
const spy = jest.spyOn(migrator, "updateVersion");
|
||||
await sut.migrate(helper);
|
||||
expect(spy).toBeCalledWith(helper, "up");
|
||||
});
|
||||
|
||||
it("should update version on rollback", async () => {
|
||||
const helper = new MigrationHelper(1, mock(), mock());
|
||||
const spy = jest.spyOn(rollback_migrator, "updateVersion");
|
||||
await sut.migrate(helper);
|
||||
expect(spy).toBeCalledWith(helper, "down");
|
||||
});
|
||||
|
||||
it("should not run the migrator if the current version does not match the from version", async () => {
|
||||
const helper = new MigrationHelper(3, mock(), mock());
|
||||
const migrate = jest.spyOn(migrator, "migrate");
|
||||
const rollback = jest.spyOn(rollback_migrator, "rollback");
|
||||
await sut.migrate(helper);
|
||||
expect(migrate).not.toBeCalled();
|
||||
expect(rollback).not.toBeCalled();
|
||||
});
|
||||
|
||||
it("should not update version if the current version does not match the from version", async () => {
|
||||
const helper = new MigrationHelper(3, mock(), mock());
|
||||
const migrate = jest.spyOn(migrator, "updateVersion");
|
||||
const rollback = jest.spyOn(rollback_migrator, "updateVersion");
|
||||
await sut.migrate(helper);
|
||||
expect(migrate).not.toBeCalled();
|
||||
expect(rollback).not.toBeCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user