mirror of
https://github.com/bitwarden/browser
synced 2026-02-22 12:24:01 +00:00
* 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>
118 lines
4.0 KiB
TypeScript
118 lines
4.0 KiB
TypeScript
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();
|
|
});
|
|
});
|
|
});
|