1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Fix user store tests by using override of config

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2023-01-04 13:24:46 -05:00
parent da23e44419
commit a28f60d5d3
2 changed files with 92 additions and 64 deletions

View File

@ -2,28 +2,7 @@
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import mockFs from "mock-fs";
jest.mock("electron", () => ({
app: {
getVersion: () => "99.99.99",
getName: () => "lens",
setName: jest.fn(),
setPath: jest.fn(),
getPath: () => "tmp",
getLocale: () => "en",
setLoginItemSettings: jest.fn(),
},
ipcMain: {
on: jest.fn(),
handle: jest.fn(),
},
}));
import type { UserStore } from "../user-store";
import { Console } from "console";
import { stdout, stderr } from "process";
import userStoreInjectable from "../user-store/user-store.injectable";
import type { DiContainer } from "@ogre-tools/injectable";
import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable";
@ -31,13 +10,11 @@ import type { ClusterStoreModel } from "../cluster-store/cluster-store";
import { defaultThemeId } from "../vars";
import writeFileInjectable from "../fs/write-file.injectable";
import { getDiForUnitTesting } from "../../main/getDiForUnitTesting";
import getConfigurationFileModelInjectable from "../get-configuration-file-model/get-configuration-file-model.injectable";
import storeMigrationVersionInjectable from "../vars/store-migration-version.injectable";
import releaseChannelInjectable from "../vars/release-channel.injectable";
import defaultUpdateChannelInjectable from "../../features/application-update/common/selected-update-channel/default-update-channel.injectable";
import fsInjectable from "../fs/fs.injectable";
console = new Console(stdout, stderr);
import writeJsonSyncInjectable from "../fs/write-json-sync.injectable";
import writeFileSyncInjectable from "../fs/write-file-sync.injectable";
describe("user store tests", () => {
let userStore: UserStore;
@ -46,14 +23,8 @@ describe("user store tests", () => {
beforeEach(async () => {
di = getDiForUnitTesting({ doGeneralOverrides: true });
mockFs();
di.override(writeFileInjectable, () => () => Promise.resolve());
di.override(directoryForUserDataInjectable, () => "some-directory-for-user-data");
di.permitSideEffects(getConfigurationFileModelInjectable);
di.unoverride(getConfigurationFileModelInjectable);
di.permitSideEffects(fsInjectable);
di.override(directoryForUserDataInjectable, () => "/some-directory-for-user-data");
di.override(releaseChannelInjectable, () => ({
get: () => "latest" as const,
@ -64,13 +35,12 @@ describe("user store tests", () => {
userStore = di.inject(userStoreInjectable);
});
afterEach(() => {
mockFs.restore();
});
describe("for an empty config", () => {
beforeEach(() => {
mockFs({ "some-directory-for-user-data": { "lens-user-store.json": "{}", "kube_config": "{}" }});
const writeJsonSync = di.inject(writeJsonSyncInjectable);
writeJsonSync("/some-directory-for-user-data/lens-user-store.json", {});
writeJsonSync("/some-directory-for-user-data/kube_config", {});
userStore.load();
});
@ -94,40 +64,38 @@ describe("user store tests", () => {
describe("migrations", () => {
beforeEach(() => {
mockFs({
"some-directory-for-user-data": {
"lens-user-store.json": JSON.stringify({
preferences: { colorTheme: "light" },
}),
"lens-cluster-store.json": JSON.stringify({
clusters: [
{
id: "foobar",
kubeConfigPath: "some-directory-for-user-data/extension_data/foo/bar",
},
{
id: "barfoo",
kubeConfigPath: "some/other/path",
},
],
} as ClusterStoreModel),
"extension_data": {},
},
"some": {
"other": {
"path": "is file",
},
},
const writeJsonSync = di.inject(writeJsonSyncInjectable);
const writeFileSync = di.inject(writeFileSyncInjectable);
writeJsonSync("/some-directory-for-user-data/lens-user-store.json", {
preferences: { colorTheme: "light" },
});
writeJsonSync("/some-directory-for-user-data/lens-cluster-store.json", {
clusters: [
{
id: "foobar",
kubeConfigPath: "/some-directory-for-user-data/extension_data/foo/bar",
},
{
id: "barfoo",
kubeConfigPath: "/some/other/path",
},
],
} as ClusterStoreModel);
writeJsonSync("/some-directory-for-user-data/extension_data", {});
writeFileSync("/some/other/path", "is file");
di.override(storeMigrationVersionInjectable, () => "10.0.0");
userStore.load();
});
it("skips clusters for adding to kube-sync with files under extension_data/", () => {
expect(userStore.syncKubeconfigEntries.has("some-directory-for-user-data/extension_data/foo/bar")).toBe(false);
expect(userStore.syncKubeconfigEntries.has("some/other/path")).toBe(true);
expect(userStore.syncKubeconfigEntries.has("/some-directory-for-user-data/extension_data/foo/bar")).toBe(false);
expect(userStore.syncKubeconfigEntries.has("/some/other/path")).toBe(true);
});
it("allows access to the colorTheme preference", () => {

View File

@ -10,6 +10,34 @@ import getConfigurationFileModelInjectable from "./get-configuration-file-model.
import type Config from "conf";
import readJsonSyncInjectable from "../fs/read-json-sync.injectable";
import writeJsonSyncInjectable from "../fs/write-json-sync.injectable";
import { get, set } from "lodash";
import semver from "semver";
const MIGRATION_KEY = `__internal__.migrations.version`;
const _isVersionInRangeFormat = (version: string) => {
return semver.clean(version) === null;
};
const _shouldPerformMigration = (candidateVersion: string, previousMigratedVersion: string, versionToMigrate: string) => {
if (_isVersionInRangeFormat(candidateVersion)) {
if (previousMigratedVersion !== "0.0.0" && semver.satisfies(previousMigratedVersion, candidateVersion)) {
return false;
}
return semver.satisfies(versionToMigrate, candidateVersion);
}
if (semver.lte(candidateVersion, previousMigratedVersion)) {
return false;
}
if (semver.gt(candidateVersion, versionToMigrate)) {
return false;
}
return true;
};
export default getGlobalOverride(getConfigurationFileModelInjectable, (di) => {
const readJsonSync = di.inject(readJsonSyncInjectable);
@ -18,6 +46,7 @@ export default getGlobalOverride(getConfigurationFileModelInjectable, (di) => {
return (options) => {
assert(options.cwd, "Missing options.cwd");
assert(options.configName, "Missing options.configName");
assert(options.projectVersion, "Missing options.projectVersion");
const configFilePath = path.posix.join(options.cwd, `${options.configName}.json`);
let store: object = {};
@ -28,11 +57,12 @@ export default getGlobalOverride(getConfigurationFileModelInjectable, (di) => {
// ignore
}
return {
const config = {
get store() {
return store;
},
path: configFilePath,
get: (key: string) => get(store, key),
set: (key: string, value: unknown) => {
let currentState: object;
@ -49,5 +79,35 @@ export default getGlobalOverride(getConfigurationFileModelInjectable, (di) => {
store = readJsonSync(configFilePath);
},
} as Partial<Config> as Config<any>;
// Migrate
{
const migrations = options.migrations ?? [];
const versionToMigrate = options.projectVersion;
let previousMigratedVersion = get(store, MIGRATION_KEY) || "0.0.0";
const newerVersions = Object.entries(migrations)
.filter(([candidateVersion]) => _shouldPerformMigration(candidateVersion, previousMigratedVersion, versionToMigrate));
let storeBackup = { ...store };
for (const [version, migration] of newerVersions) {
try {
migration(config);
set(store, MIGRATION_KEY, version);
previousMigratedVersion = version;
storeBackup = { ...store };
}
catch (error) {
store = storeBackup;
throw new Error(`Something went wrong during the migration! Changes applied to the store until this failed migration will be restored. ${error}`);
}
}
if (_isVersionInRangeFormat(previousMigratedVersion) || !semver.eq(previousMigratedVersion, versionToMigrate)) {
set(store, MIGRATION_KEY, versionToMigrate);
}
}
return config;
};
});