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

Add unit tests and update injectables

Signed-off-by: Antti Lustila <antti.lustila@luotocompany.fi>
This commit is contained in:
Antti Lustila 2023-02-15 09:35:56 +02:00
parent 4849f62141
commit 1dce6b2eb8
5 changed files with 173 additions and 27 deletions

View File

@ -0,0 +1,109 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { runInAction } from "mobx";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import type { FakeExtensionOptions } from "../../renderer/components/test-utils/get-extension-fake";
import logErrorInjectable from "../../common/log-error.injectable";
import getHashInjectable from "../../extensions/extension-loader/file-system-provisioner-store/get-hash.injectable";
import fsInjectable from "../../common/fs/fs.injectable";
describe("configurable directories for extension files", () => {
let builder: ApplicationBuilder;
let logErrorMock: jest.Mock;
beforeEach(async () => {
builder = getApplicationBuilder();
builder.beforeApplicationStart(
(mainDi) => {
runInAction(() => {
mainDi.override(getHashInjectable, () => x => x);
});
logErrorMock = jest.fn();
mainDi.override(logErrorInjectable, () => logErrorMock);
},
);
await builder.startHidden();
const window = builder.applicationWindow.create("some-window-id");
await window.start();
});
describe("when extension with a specific store name is enabled", () => {
let testExtensionOptions: FakeExtensionOptions;
beforeEach(() => {
testExtensionOptions = {
id: "some-extension",
name: "some-extension-name",
mainOptions: {
manifest: {
name: "irrelevant",
storeName: "some-specific-store-name",
version: "0",
engines: {
lens: "0",
},
},
},
};
builder.extensions.enable(testExtensionOptions);
});
it("creates extension directory for specific store name", async () => {
const fs = builder.mainDi.inject(fsInjectable);
await builder.extensions.get("some-extension").main.getExtensionFileFolder();
const nonHashedExtensionDirectories = await fs.readdir("/some-directory-for-app-data/some-product-name/extension_data");
expect(nonHashedExtensionDirectories).toContain("some-specific-store-name");
});
});
describe("when extension with no specific store name is enabled", () => {
let testExtensionOptions: FakeExtensionOptions;
beforeEach(() => {
testExtensionOptions = {
id: "some-extension",
name: "some-extension-name",
mainOptions: {
manifest: {
name: "some-package-name",
storeName: undefined,
version: "0",
engines: {
lens: "0",
},
},
},
};
builder.extensions.enable(testExtensionOptions);
});
it("creates extension directory for package name", async () => {
const fs = builder.mainDi.inject(fsInjectable);
await builder.extensions.get("some-extension").main.getExtensionFileFolder();
const nonHashedExtensionDirectories = await fs.readdir("/some-directory-for-app-data/some-product-name/extension_data");
expect(nonHashedExtensionDirectories).toContain("some-package-name");
});
});
});

View File

@ -0,0 +1,43 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { ObservableMap } from "mobx";
import { getInjectable } from "@ogre-tools/injectable";
import { getOrInsertWithAsync } from "../../../common/utils";
import randomBytesInjectable from "../../../common/utils/random-bytes.injectable";
import joinPathsInjectable from "../../../common/path/join-paths.injectable";
import directoryForExtensionDataInjectable from "./directory-for-extension-data.injectable";
import ensureDirInjectable from "../../../common/fs/ensure-dir.injectable";
import getHashInjectable from "./get-hash.injectable";
export type EnsureHashedDirectoryForExtension = (extensionName: string, registeredExtensions: ObservableMap<string, string>) => Promise<string>;
const ensureHashedDirectoryForExtensionInjectable = getInjectable({
id: "ensure-hashed-directory-for-extension",
instantiate: (di): EnsureHashedDirectoryForExtension => {
const randomBytes = di.inject(randomBytesInjectable);
const joinPaths = di.inject(joinPathsInjectable);
const directoryForExtensionData = di.inject(directoryForExtensionDataInjectable);
const ensureDirectory = di.inject(ensureDirInjectable);
const getHash = di.inject(getHashInjectable);
return async (extensionName, registeredExtensions) => {
const dirPath = await getOrInsertWithAsync(registeredExtensions, extensionName, async () => {
const salt = (await randomBytes(32)).toString("hex");
const hashedName = getHash(`${extensionName}/${salt}`);
return joinPaths(directoryForExtensionData, hashedName);
});
await ensureDirectory(dirPath);
return dirPath;
};
},
});
export default ensureHashedDirectoryForExtensionInjectable;

View File

@ -4,10 +4,6 @@
*/
import { getInjectable } from "@ogre-tools/injectable";
import { FileSystemProvisionerStore } from "./file-system-provisioner-store";
import directoryForExtensionDataInjectable from "./directory-for-extension-data.injectable";
import ensureDirectoryInjectable from "../../../common/fs/ensure-dir.injectable";
import joinPathsInjectable from "../../../common/path/join-paths.injectable";
import randomBytesInjectable from "../../../common/utils/random-bytes.injectable";
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
import getConfigurationFileModelInjectable from "../../../common/get-configuration-file-model/get-configuration-file-model.injectable";
import loggerInjectable from "../../../common/logger.injectable";
@ -17,15 +13,12 @@ import { shouldBaseStoreDisableSyncInIpcListenerInjectionToken } from "../../../
import { persistStateToConfigInjectionToken } from "../../../common/base-store/save-to-file";
import getBasenameOfPathInjectable from "../../../common/path/get-basename.injectable";
import { enlistMessageChannelListenerInjectionToken } from "../../../common/utils/channel/enlist-message-channel-listener-injection-token";
import ensureHashedDirectoryForExtensionInjectable from "./ensure-hashed-directory-for-extension.injectable";
const fileSystemProvisionerStoreInjectable = getInjectable({
id: "file-system-provisioner-store",
instantiate: (di) => new FileSystemProvisionerStore({
directoryForExtensionData: di.inject(directoryForExtensionDataInjectable),
ensureDirectory: di.inject(ensureDirectoryInjectable),
joinPaths: di.inject(joinPathsInjectable),
randomBytes: di.inject(randomBytesInjectable),
directoryForUserData: di.inject(directoryForUserDataInjectable),
getConfigurationFileModel: di.inject(getConfigurationFileModelInjectable),
logger: di.inject(loggerInjectable),
@ -36,6 +29,7 @@ const fileSystemProvisionerStoreInjectable = getInjectable({
persistStateToConfig: di.inject(persistStateToConfigInjectionToken),
enlistMessageChannelListener: di.inject(enlistMessageChannelListenerInjectionToken),
shouldDisableSyncInListener: di.inject(shouldBaseStoreDisableSyncInIpcListenerInjectionToken),
ensureHashedDirectoryForExtension: di.inject(ensureHashedDirectoryForExtensionInjectable),
}),
});

View File

@ -3,25 +3,19 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { SHA256 } from "crypto-js";
import { action, makeObservable, observable } from "mobx";
import type { BaseStoreDependencies } from "../../../common/base-store/base-store";
import { BaseStore } from "../../../common/base-store/base-store";
import type { LensExtensionId } from "../../lens-extension";
import { getOrInsertWithAsync, toJS } from "../../../common/utils";
import type { EnsureDirectory } from "../../../common/fs/ensure-dir.injectable";
import type { JoinPaths } from "../../../common/path/join-paths.injectable";
import type { RandomBytes } from "../../../common/utils/random-bytes.injectable";
import { toJS } from "../../../common/utils";
import type { EnsureHashedDirectoryForExtension } from "./ensure-hashed-directory-for-extension.injectable";
interface FSProvisionModel {
extensions: Record<string, string>; // extension names to paths
}
interface Dependencies extends BaseStoreDependencies {
readonly directoryForExtensionData: string;
ensureDirectory: EnsureDirectory;
joinPaths: JoinPaths;
randomBytes: RandomBytes;
ensureHashedDirectoryForExtension: EnsureHashedDirectoryForExtension;
}
export class FileSystemProvisionerStore extends BaseStore<FSProvisionModel> {
@ -43,16 +37,7 @@ export class FileSystemProvisionerStore extends BaseStore<FSProvisionModel> {
* @returns path to the folder that the extension can safely write files to.
*/
async requestDirectory(extensionName: string): Promise<string> {
const dirPath = await getOrInsertWithAsync(this.registeredExtensions, extensionName, async () => {
const salt = (await this.dependencies.randomBytes(32)).toString("hex");
const hashedName = SHA256(`${extensionName}/${salt}`).toString();
return this.dependencies.joinPaths(this.dependencies.directoryForExtensionData, hashedName);
});
await this.dependencies.ensureDirectory(dirPath);
return dirPath;
return this.dependencies.ensureHashedDirectoryForExtension(extensionName, this.registeredExtensions);
}
@action

View File

@ -0,0 +1,15 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { SHA256 } from "crypto-js";
const getHashInjectable = getInjectable({
id: "get-hash",
instantiate: () => (text: string) => SHA256(text).toString(),
});
export default getHashInjectable;