1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-14 23:33:31 +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:
Matt Gibson
2023-08-30 12:57:20 -05:00
committed by GitHub
parent b444eed0b5
commit 3340af8084
51 changed files with 1538 additions and 980 deletions

View File

@@ -0,0 +1,67 @@
import { mock, MockProxy } from "jest-mock-extended";
// eslint-disable-next-line import/no-restricted-paths -- Needed to print log messages
import { LogService } from "../platform/abstractions/log.service";
// eslint-disable-next-line import/no-restricted-paths -- Needed to interface with storage locations
import { AbstractStorageService } from "../platform/abstractions/storage.service";
import { CURRENT_VERSION, currentVersion, migrate } from "./migrate";
import { MigrationBuilder } from "./migration-builder";
jest.mock("./migration-builder", () => {
return {
MigrationBuilder: {
create: jest.fn().mockReturnThis(),
},
};
});
describe("migrate", () => {
it("should not run migrations if state is empty", async () => {
const storage = mock<AbstractStorageService>();
const logService = mock<LogService>();
storage.get.mockReturnValueOnce(null);
await migrate(storage, logService);
expect(MigrationBuilder.create).not.toHaveBeenCalled();
});
it("should set to current version if state is empty", async () => {
const storage = mock<AbstractStorageService>();
const logService = mock<LogService>();
storage.get.mockReturnValueOnce(null);
await migrate(storage, logService);
expect(storage.save).toHaveBeenCalledWith("stateVersion", CURRENT_VERSION);
});
});
describe("currentVersion", () => {
let storage: MockProxy<AbstractStorageService>;
let logService: MockProxy<LogService>;
beforeEach(() => {
storage = mock();
logService = mock();
});
it("should return -1 if no version", async () => {
storage.get.mockReturnValueOnce(null);
expect(await currentVersion(storage, logService)).toEqual(-1);
});
it("should return version", async () => {
storage.get.calledWith("stateVersion").mockReturnValueOnce(1 as any);
expect(await currentVersion(storage, logService)).toEqual(1);
});
it("should return version from global", async () => {
storage.get.calledWith("stateVersion").mockReturnValueOnce(null);
storage.get.calledWith("global").mockReturnValueOnce({ stateVersion: 1 } as any);
expect(await currentVersion(storage, logService)).toEqual(1);
});
it("should prefer root version to global", async () => {
storage.get.calledWith("stateVersion").mockReturnValue(1 as any);
storage.get.calledWith("global").mockReturnValue({ stateVersion: 2 } as any);
expect(await currentVersion(storage, logService)).toEqual(1);
});
});