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

fix cluster.test.ts tests

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2022-04-08 10:42:29 -04:00
parent 199f142559
commit ffb840f0ed
6 changed files with 36 additions and 58 deletions

View File

@ -3,7 +3,6 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import { ipcMain } from "electron";
import { action, comparer, computed, makeObservable, observable, reaction, when } from "mobx"; import { action, comparer, computed, makeObservable, observable, reaction, when } from "mobx";
import { broadcastMessage } from "../ipc"; import { broadcastMessage } from "../ipc";
import type { ClusterContextHandler } from "../../main/context-handler/context-handler"; import type { ClusterContextHandler } from "../../main/context-handler/context-handler";
@ -14,7 +13,6 @@ import type { KubeconfigManager } from "../../main/kubeconfig-manager/kubeconfig
import { loadConfigFromFile, loadConfigFromFileSync, validateKubeConfig } from "../kube-helpers"; import { loadConfigFromFile, loadConfigFromFileSync, validateKubeConfig } from "../kube-helpers";
import type { KubeApiResource, KubeResource } from "../rbac"; import type { KubeApiResource, KubeResource } from "../rbac";
import { apiResourceRecord, apiResources } from "../rbac"; import { apiResourceRecord, apiResources } from "../rbac";
import logger from "../../main/logger";
import { VersionDetector } from "../../main/cluster-detectors/version-detector"; import { VersionDetector } from "../../main/cluster-detectors/version-detector";
import { DetectorRegistry } from "../../main/cluster-detectors/detector-registry"; import { DetectorRegistry } from "../../main/cluster-detectors/detector-registry";
import plimit from "p-limit"; import plimit from "p-limit";
@ -26,11 +24,13 @@ import { clusterListNamespaceForbiddenChannel } from "../ipc/cluster";
import type { CanI } from "./authorization-review.injectable"; import type { CanI } from "./authorization-review.injectable";
import type { ListNamespaces } from "./list-namespaces.injectable"; import type { ListNamespaces } from "./list-namespaces.injectable";
import assert from "assert"; import assert from "assert";
import type { Logger } from "../logger";
export interface ClusterDependencies { export interface ClusterDependencies {
readonly directoryForKubeConfigs: string; readonly directoryForKubeConfigs: string;
createKubeconfigManager: (cluster: Cluster) => KubeconfigManager; readonly logger: Logger;
createContextHandler: (cluster: Cluster) => ClusterContextHandler; createKubeconfigManager: (cluster: Cluster) => KubeconfigManager | undefined;
createContextHandler: (cluster: Cluster) => ClusterContextHandler | undefined;
createKubectl: (clusterVersion: string) => Kubectl; createKubectl: (clusterVersion: string) => Kubectl;
createAuthorizationReview: (config: KubeConfig) => CanI; createAuthorizationReview: (config: KubeConfig) => CanI;
createListNamespaces: (config: KubeConfig) => ListNamespaces; createListNamespaces: (config: KubeConfig) => ListNamespaces;
@ -256,17 +256,14 @@ export class Cluster implements ClusterModel, ClusterState {
this.apiUrl = cluster.server; this.apiUrl = cluster.server;
if (ipcMain) { // for the time being, until renderer gets its own cluster type
// for the time being, until renderer gets its own cluster type this._contextHandler = this.dependencies.createContextHandler(this);
this._contextHandler = this.dependencies.createContextHandler(this); this._proxyKubeconfigManager = this.dependencies.createKubeconfigManager(this);
this._proxyKubeconfigManager = this.dependencies.createKubeconfigManager(this); this.dependencies.logger.debug(`[CLUSTER]: Cluster init success`, {
id: this.id,
logger.debug(`[CLUSTER]: Cluster init success`, { context: this.contextName,
id: this.id, apiUrl: this.apiUrl,
context: this.contextName, });
apiUrl: this.apiUrl,
});
}
} }
/** /**
@ -309,7 +306,7 @@ export class Cluster implements ClusterModel, ClusterState {
* @internal * @internal
*/ */
protected bindEvents() { protected bindEvents() {
logger.info(`[CLUSTER]: bind events`, this.getMeta()); this.dependencies.logger.info(`[CLUSTER]: bind events`, this.getMeta());
const refreshTimer = setInterval(() => !this.disconnected && this.refresh(), 30000); // every 30s const refreshTimer = setInterval(() => !this.disconnected && this.refresh(), 30000); // every 30s
const refreshMetadataTimer = setInterval(() => !this.disconnected && this.refreshMetadata(), 900000); // every 15 minutes const refreshMetadataTimer = setInterval(() => !this.disconnected && this.refreshMetadata(), 900000); // every 15 minutes
@ -330,13 +327,13 @@ export class Cluster implements ClusterModel, ClusterState {
* @internal * @internal
*/ */
protected async recreateProxyKubeconfig() { protected async recreateProxyKubeconfig() {
logger.info("[CLUSTER]: Recreating proxy kubeconfig"); this.dependencies.logger.info("[CLUSTER]: Recreating proxy kubeconfig");
try { try {
await this.proxyKubeconfigManager.clear(); await this.proxyKubeconfigManager.clear();
await this.getProxyKubeconfig(); await this.getProxyKubeconfig();
} catch (error) { } catch (error) {
logger.error(`[CLUSTER]: failed to recreate proxy kubeconfig`, error); this.dependencies.logger.error(`[CLUSTER]: failed to recreate proxy kubeconfig`, error);
} }
} }
@ -350,7 +347,7 @@ export class Cluster implements ClusterModel, ClusterState {
return this.pushState(); return this.pushState();
} }
logger.info(`[CLUSTER]: activate`, this.getMeta()); this.dependencies.logger.info(`[CLUSTER]: activate`, this.getMeta());
if (!this.eventsDisposer.length) { if (!this.eventsDisposer.length) {
this.bindEvents(); this.bindEvents();
@ -368,7 +365,7 @@ export class Cluster implements ClusterModel, ClusterState {
await this.refreshAccessibility(); await this.refreshAccessibility();
// download kubectl in background, so it's not blocking dashboard // download kubectl in background, so it's not blocking dashboard
this.ensureKubectl() this.ensureKubectl()
.catch(error => logger.warn(`[CLUSTER]: failed to download kubectl for clusterId=${this.id}`, error)); .catch(error => this.dependencies.logger.warn(`[CLUSTER]: failed to download kubectl for clusterId=${this.id}`, error));
this.broadcastConnectUpdate("Connected, waiting for view to load ..."); this.broadcastConnectUpdate("Connected, waiting for view to load ...");
} }
@ -392,7 +389,7 @@ export class Cluster implements ClusterModel, ClusterState {
*/ */
@action @action
async reconnect() { async reconnect() {
logger.info(`[CLUSTER]: reconnect`, this.getMeta()); this.dependencies.logger.info(`[CLUSTER]: reconnect`, this.getMeta());
await this.contextHandler?.restartServer(); await this.contextHandler?.restartServer();
this.disconnected = false; this.disconnected = false;
} }
@ -402,10 +399,10 @@ export class Cluster implements ClusterModel, ClusterState {
*/ */
@action disconnect(): void { @action disconnect(): void {
if (this.disconnected) { if (this.disconnected) {
return void logger.debug("[CLUSTER]: already disconnected", { id: this.id }); return void this.dependencies.logger.debug("[CLUSTER]: already disconnected", { id: this.id });
} }
logger.info(`[CLUSTER]: disconnecting`, { id: this.id }); this.dependencies.logger.info(`[CLUSTER]: disconnecting`, { id: this.id });
this.eventsDisposer(); this.eventsDisposer();
this.contextHandler?.stopServer(); this.contextHandler?.stopServer();
this.disconnected = true; this.disconnected = true;
@ -416,7 +413,7 @@ export class Cluster implements ClusterModel, ClusterState {
this.allowedNamespaces = []; this.allowedNamespaces = [];
this.resourceAccessStatuses.clear(); this.resourceAccessStatuses.clear();
this.pushState(); this.pushState();
logger.info(`[CLUSTER]: disconnected`, { id: this.id }); this.dependencies.logger.info(`[CLUSTER]: disconnected`, { id: this.id });
} }
/** /**
@ -425,7 +422,7 @@ export class Cluster implements ClusterModel, ClusterState {
*/ */
@action @action
async refresh(opts: ClusterRefreshOptions = {}) { async refresh(opts: ClusterRefreshOptions = {}) {
logger.info(`[CLUSTER]: refresh`, this.getMeta()); this.dependencies.logger.info(`[CLUSTER]: refresh`, this.getMeta());
await this.refreshConnectionStatus(); await this.refreshConnectionStatus();
if (this.accessible) { if (this.accessible) {
@ -443,7 +440,7 @@ export class Cluster implements ClusterModel, ClusterState {
*/ */
@action @action
async refreshMetadata() { async refreshMetadata() {
logger.info(`[CLUSTER]: refreshMetadata`, this.getMeta()); this.dependencies.logger.info(`[CLUSTER]: refreshMetadata`, this.getMeta());
const metadata = await DetectorRegistry.getInstance().detectForCluster(this); const metadata = await DetectorRegistry.getInstance().detectForCluster(this);
const existingMetadata = this.metadata; const existingMetadata = this.metadata;
@ -514,7 +511,7 @@ export class Cluster implements ClusterModel, ClusterState {
return ClusterStatus.AccessGranted; return ClusterStatus.AccessGranted;
} catch (error) { } catch (error) {
logger.error(`[CLUSTER]: Failed to connect to "${this.contextName}": ${error}`); this.dependencies.logger.error(`[CLUSTER]: Failed to connect to "${this.contextName}": ${error}`);
if (isRequestError(error)) { if (isRequestError(error)) {
if (error.statusCode) { if (error.statusCode) {
@ -594,7 +591,7 @@ export class Cluster implements ClusterModel, ClusterState {
* @param state cluster state * @param state cluster state
*/ */
pushState(state = this.getState()) { pushState(state = this.getState()) {
logger.silly(`[CLUSTER]: push-state`, state); this.dependencies.logger.silly(`[CLUSTER]: push-state`, state);
broadcastMessage("cluster:state", this.id, state); broadcastMessage("cluster:state", this.id, state);
} }
@ -617,7 +614,7 @@ export class Cluster implements ClusterModel, ClusterState {
broadcastConnectUpdate(message: string, isError = false): void { broadcastConnectUpdate(message: string, isError = false): void {
const update: KubeAuthUpdate = { message, isError }; const update: KubeAuthUpdate = { message, isError };
logger.debug(`[CLUSTER]: broadcasting connection update`, { ...update, meta: this.getMeta() }); this.dependencies.logger.debug(`[CLUSTER]: broadcasting connection update`, { ...update, meta: this.getMeta() });
broadcastMessage(`cluster:${this.id}:connection-update`, update); broadcastMessage(`cluster:${this.id}:connection-update`, update);
} }
@ -637,7 +634,7 @@ export class Cluster implements ClusterModel, ClusterState {
if (namespaceList.length === 0 && error instanceof HttpError && error.statusCode === 403) { if (namespaceList.length === 0 && error instanceof HttpError && error.statusCode === 403) {
const { response } = error as HttpError & { response: Response }; const { response } = error as HttpError & { response: Response };
logger.info("[CLUSTER]: listing namespaces is forbidden, broadcasting", { clusterId: this.id, error: response.body }); this.dependencies.logger.info("[CLUSTER]: listing namespaces is forbidden, broadcasting", { clusterId: this.id, error: response.body });
broadcastMessage(clusterListNamespaceForbiddenChannel, this.id); broadcastMessage(clusterListNamespaceForbiddenChannel, this.id);
} }

View File

@ -15,6 +15,7 @@ export interface Logger {
error: (message: string, ...args: any) => void; error: (message: string, ...args: any) => void;
debug: (message: string, ...args: any) => void; debug: (message: string, ...args: any) => void;
warn: (message: string, ...args: any) => void; warn: (message: string, ...args: any) => void;
silly: (message: string, ...args: any) => void;
} }
const logLevel = process.env.LOG_LEVEL const logLevel = process.env.LOG_LEVEL

View File

@ -3,32 +3,6 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
const logger = {
silly: jest.fn(),
debug: jest.fn(),
log: jest.fn(),
info: jest.fn(),
error: jest.fn(),
crit: jest.fn(),
};
jest.mock("winston", () => ({
format: {
colorize: jest.fn(),
combine: jest.fn(),
simple: jest.fn(),
label: jest.fn(),
timestamp: jest.fn(),
printf: jest.fn(),
splat: jest.fn(),
},
createLogger: jest.fn().mockReturnValue(logger),
transports: {
Console: jest.fn(),
File: jest.fn(),
},
}));
jest.mock("../../common/ipc"); jest.mock("../../common/ipc");
jest.mock("request"); jest.mock("request");
jest.mock("request-promise-native"); jest.mock("request-promise-native");
@ -109,6 +83,7 @@ describe("create clusters", () => {
}); });
afterEach(() => { afterEach(() => {
cluster.disconnect();
mockFs.restore(); mockFs.restore();
}); });

View File

@ -12,6 +12,7 @@ import createContextHandlerInjectable from "../context-handler/create-context-ha
import { createClusterInjectionToken } from "../../common/cluster/create-cluster-injection-token"; import { createClusterInjectionToken } from "../../common/cluster/create-cluster-injection-token";
import authorizationReviewInjectable from "../../common/cluster/authorization-review.injectable"; import authorizationReviewInjectable from "../../common/cluster/authorization-review.injectable";
import listNamespacesInjectable from "../../common/cluster/list-namespaces.injectable"; import listNamespacesInjectable from "../../common/cluster/list-namespaces.injectable";
import loggerInjectable from "../../common/logger.injectable";
const createClusterInjectable = getInjectable({ const createClusterInjectable = getInjectable({
id: "create-cluster", id: "create-cluster",
@ -24,6 +25,7 @@ const createClusterInjectable = getInjectable({
createContextHandler: di.inject(createContextHandlerInjectable), createContextHandler: di.inject(createContextHandlerInjectable),
createAuthorizationReview: di.inject(authorizationReviewInjectable), createAuthorizationReview: di.inject(authorizationReviewInjectable),
createListNamespaces: di.inject(listNamespacesInjectable), createListNamespaces: di.inject(listNamespacesInjectable),
logger: di.inject(loggerInjectable),
}; };
return (model) => new Cluster(dependencies, model); return (model) => new Cluster(dependencies, model);

View File

@ -108,6 +108,7 @@ export const getDiForUnitTesting = (
debug: noop, debug: noop,
error: (message: string, ...args: any) => console.error(message, ...args), error: (message: string, ...args: any) => console.error(message, ...args),
info: noop, info: noop,
silly: noop,
})); }));
} }

View File

@ -7,6 +7,7 @@ import type { ClusterDependencies } from "../../common/cluster/cluster";
import { Cluster } from "../../common/cluster/cluster"; import { Cluster } from "../../common/cluster/cluster";
import directoryForKubeConfigsInjectable from "../../common/app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable"; import directoryForKubeConfigsInjectable from "../../common/app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable";
import { createClusterInjectionToken } from "../../common/cluster/create-cluster-injection-token"; import { createClusterInjectionToken } from "../../common/cluster/create-cluster-injection-token";
import loggerInjectable from "../../common/logger.injectable";
const createClusterInjectable = getInjectable({ const createClusterInjectable = getInjectable({
id: "create-cluster", id: "create-cluster",
@ -14,11 +15,12 @@ const createClusterInjectable = getInjectable({
instantiate: (di) => { instantiate: (di) => {
const dependencies: ClusterDependencies = { const dependencies: ClusterDependencies = {
directoryForKubeConfigs: di.inject(directoryForKubeConfigsInjectable), directoryForKubeConfigs: di.inject(directoryForKubeConfigsInjectable),
createKubeconfigManager: () => { throw new Error("Tried to access back-end feature in front-end."); }, createKubeconfigManager: () => undefined,
createKubectl: () => { throw new Error("Tried to access back-end feature in front-end.");}, createKubectl: () => { throw new Error("Tried to access back-end feature in front-end.");},
createContextHandler: () => { throw new Error("Tried to access back-end feature in front-end."); }, createContextHandler: () => undefined,
createAuthorizationReview: () => { throw new Error("Tried to access back-end feature in front-end."); }, createAuthorizationReview: () => { throw new Error("Tried to access back-end feature in front-end."); },
createListNamespaces: () => { throw new Error("Tried to access back-end feature in front-end."); }, createListNamespaces: () => { throw new Error("Tried to access back-end feature in front-end."); },
logger: di.inject(loggerInjectable),
}; };
return (model) => new Cluster(dependencies, model); return (model) => new Cluster(dependencies, model);