From d216b8915b781f420cbf765fa14b0d632855a497 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 12 Apr 2022 11:09:14 -0400 Subject: [PATCH] fix api-manager.test.ts Signed-off-by: Sebastian Malton --- .../k8s-api/__tests__/api-manager.test.ts | 13 ++- src/common/k8s-api/kube-api.ts | 86 +++++++++---------- 2 files changed, 55 insertions(+), 44 deletions(-) diff --git a/src/common/k8s-api/__tests__/api-manager.test.ts b/src/common/k8s-api/__tests__/api-manager.test.ts index c78e7779b7..3e411b6584 100644 --- a/src/common/k8s-api/__tests__/api-manager.test.ts +++ b/src/common/k8s-api/__tests__/api-manager.test.ts @@ -3,7 +3,9 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { apiManager } from "../api-manager"; +import { getDiForUnitTesting } from "../../../renderer/getDiForUnitTesting"; +import type { ApiManager } from "../api-manager"; +import apiManagerInjectable from "../api-manager/manager.injectable"; import { KubeApi } from "../kube-api"; import { KubeObject } from "../kube-object"; import { KubeObjectStore } from "../kube-object.store"; @@ -19,6 +21,14 @@ class TestStore extends KubeObjectStore { } describe("ApiManager", () => { + let apiManager: ApiManager; + + beforeEach(() => { + const di = getDiForUnitTesting({ doGeneralOverrides: true }); + + apiManager = di.inject(apiManagerInjectable); + }); + describe("registerApi", () => { it("re-register store if apiBase changed", async () => { const apiBase = "apis/v1/foo"; @@ -26,6 +36,7 @@ describe("ApiManager", () => { const kubeApi = new TestApi({ objectConstructor: KubeObject, apiBase, + kind: "foo", fallbackApiBases: [fallbackApiBase], checkPreferredVersion: true, }); diff --git a/src/common/k8s-api/kube-api.ts b/src/common/k8s-api/kube-api.ts index 47295633c8..31ff29149d 100644 --- a/src/common/k8s-api/kube-api.ts +++ b/src/common/k8s-api/kube-api.ts @@ -33,7 +33,7 @@ import type { Logger } from "../logger"; /** * The options used for creating a `KubeApi` */ -export interface IKubeApiOptions, Data extends KubeJsonApiDataFor = KubeJsonApiDataFor> extends DerivedKubeApiOptions { +export interface KubeApiOptions, Data extends KubeJsonApiDataFor = KubeJsonApiDataFor> extends DerivedKubeApiOptions { /** * base api-path for listing all resources, e.g. "/api/v1/pods" * @@ -173,19 +173,19 @@ export interface IRemoteKubeApiConfig { } export function forCluster< - T extends KubeObject, - Y extends KubeApi, - Data extends KubeJsonApiDataFor, ->(cluster: ILocalKubeApiConfig, kubeClass: KubeObjectConstructor, apiClass: new (apiOpts: IKubeApiOptions) => Y): Y; + Object extends KubeObject, + Api extends KubeApi, + Data extends KubeJsonApiDataFor, +>(cluster: ILocalKubeApiConfig, kubeClass: KubeObjectConstructor, apiClass: new (apiOpts: KubeApiOptions) => Api): Api; export function forCluster< - T extends KubeObject, - Data extends KubeJsonApiDataFor, ->(cluster: ILocalKubeApiConfig, kubeClass: KubeObjectConstructor, apiClass?: new (apiOpts: IKubeApiOptions) => KubeApi): KubeApi; + Object extends KubeObject, + Data extends KubeJsonApiDataFor, +>(cluster: ILocalKubeApiConfig, kubeClass: KubeObjectConstructor, apiClass?: new (apiOpts: KubeApiOptions) => KubeApi): KubeApi; export function forCluster< - T extends KubeObject, - Data extends KubeJsonApiDataFor, ->(cluster: ILocalKubeApiConfig, kubeClass: KubeObjectConstructor, apiClass: (new (apiOpts: IKubeApiOptions) => KubeApi) = KubeApi): KubeApi { + Object extends KubeObject, + Data extends KubeJsonApiDataFor, +>(cluster: ILocalKubeApiConfig, kubeClass: KubeObjectConstructor, apiClass: (new (apiOpts: KubeApiOptions) => KubeApi) = KubeApi): KubeApi { const url = new URL(apiBase.config.serverAddress); const request = new KubeJsonApi({ serverAddress: apiBase.config.serverAddress, @@ -198,26 +198,26 @@ export function forCluster< }); return new apiClass({ - objectConstructor: kubeClass as KubeObjectConstructor>, + objectConstructor: kubeClass as KubeObjectConstructor>, request, }); } export function forRemoteCluster< - T extends KubeObject, - Y extends KubeApi, - Data extends KubeJsonApiDataFor, ->(config: IRemoteKubeApiConfig, kubeClass: KubeObjectConstructor, apiClass: new (apiOpts: IKubeApiOptions) => Y): Y; + Object extends KubeObject, + Api extends KubeApi, + Data extends KubeJsonApiDataFor, +>(config: IRemoteKubeApiConfig, kubeClass: KubeObjectConstructor, apiClass: new (apiOpts: KubeApiOptions) => Api): Api; export function forRemoteCluster< - T extends KubeObject, - Data extends KubeJsonApiDataFor, ->(config: IRemoteKubeApiConfig, kubeClass: KubeObjectConstructor, apiClass?: new (apiOpts: IKubeApiOptions) => KubeApi): KubeApi; + Object extends KubeObject, + Data extends KubeJsonApiDataFor, +>(config: IRemoteKubeApiConfig, kubeClass: KubeObjectConstructor, apiClass?: new (apiOpts: KubeApiOptions) => KubeApi): KubeApi; export function forRemoteCluster< - K extends KubeObject, - Y extends KubeApi, - Data extends KubeJsonApiDataFor, ->(config: IRemoteKubeApiConfig, kubeClass: KubeObjectConstructor, apiClass: new (apiOpts: IKubeApiOptions) => KubeApi = KubeApi): KubeApi { + Object extends KubeObject, + Api extends KubeApi, + Data extends KubeJsonApiDataFor, +>(config: IRemoteKubeApiConfig, kubeClass: KubeObjectConstructor, apiClass: new (apiOpts: KubeApiOptions) => KubeApi = KubeApi): KubeApi { const reqInit: RequestInit = {}; const agentOptions: AgentOptions = {}; @@ -256,18 +256,18 @@ export function forRemoteCluster< }, reqInit); if (!apiClass) { - apiClass = KubeApi as new (apiOpts: IKubeApiOptions) => Y; + apiClass = KubeApi as new (apiOpts: KubeApiOptions) => Api; } return new apiClass({ - objectConstructor: kubeClass as KubeObjectConstructor>, + objectConstructor: kubeClass as KubeObjectConstructor>, request, }); } export type KubeApiWatchCallback = (data: IKubeWatchEvent, error: any) => void; -export interface KubeApiWatchOptions, Data extends KubeJsonApiDataFor> { +export interface KubeApiWatchOptions, Data extends KubeJsonApiDataFor> { namespace: string; callback?: KubeApiWatchCallback | undefined; abortController?: AbortController | undefined; @@ -310,8 +310,8 @@ export interface DeleteResourceDescriptor extends ResourceDescriptor { } export class KubeApi< - K extends KubeObject = KubeObject, - D extends KubeJsonApiDataFor = KubeJsonApiDataFor, + Object extends KubeObject = KubeObject, + Data extends KubeJsonApiDataFor = KubeJsonApiDataFor, > { readonly kind: string; readonly apiVersion: string; @@ -322,7 +322,7 @@ export class KubeApi< readonly apiResource: string; readonly isNamespaced: boolean; - public readonly objectConstructor: KubeObjectConstructor; + public readonly objectConstructor: KubeObjectConstructor; protected readonly request: KubeJsonApi; protected readonly resourceVersions = new Map(); protected readonly watchDisposer: Disposer | undefined; @@ -340,15 +340,15 @@ export class KubeApi< apiBase: fullApiPathname = objectConstructor.apiBase, checkPreferredVersion: doCheckPreferredVersion = false, fallbackApiBases, - }: IKubeApiOptions) { - assert(fullApiPathname); + }: KubeApiOptions) { + assert(fullApiPathname, "apiBase MUST be provied either via KubeApiOptions.apiBase or KubeApiOptions.objectConstructor.apiBase"); assert(request, "request MUST be provided if not in a cluster page frame context"); const { apiBase, apiPrefix, apiGroup, apiVersion, resource } = parseKubeApi(fullApiPathname); const di = getLegacyGlobalDiForExtensionApi(); - assert(kind); - assert(apiPrefix); + assert(kind, "kind MUST be provied either via KubeApiOptions.kind or KubeApiOptions.objectConstructor.kind"); + assert(apiPrefix, "apiBase MUST be parsable as a kubeApi selfLink style string"); this.logger = di.inject(loggerInjectable); this.doCheckPreferredVersion = doCheckPreferredVersion; @@ -364,7 +364,7 @@ export class KubeApi< this.request = request; this.objectConstructor = objectConstructor; this.parseResponse = this.parseResponse.bind(this); - apiManager.registerApi>(apiBase, this); + apiManager.registerApi>(apiBase, this); } get apiVersionWithGroup() { @@ -445,7 +445,7 @@ export class KubeApi< if (this.apiVersionPreferred) { this.apiBase = this.computeApiBase(); - apiManager.registerApi>(this.apiBase, this); + apiManager.registerApi>(this.apiBase, this); } } } @@ -494,7 +494,7 @@ export class KubeApi< return query; } - protected parseResponse(data: unknown, namespace?: string): K | K[] | null { + protected parseResponse(data: unknown, namespace?: string): Object | Object[] | null { if (!data) { return null; } @@ -517,7 +517,7 @@ export class KubeApi< } const object = new KubeObjectConstructor({ - ...(item as D), + ...(item as Data), kind: this.kind, apiVersion, }); @@ -556,7 +556,7 @@ export class KubeApi< }); } - async list({ namespace = "", reqInit }: KubeApiListOptions = {}, query?: KubeApiQueryParams): Promise { + async list({ namespace = "", reqInit }: KubeApiListOptions = {}, query?: KubeApiQueryParams): Promise { await this.checkPreferredVersion(); const url = this.getUrl({ namespace }); @@ -574,7 +574,7 @@ export class KubeApi< throw new Error(`GET multiple request to ${url} returned not an array: ${JSON.stringify(parsed)}`); } - async get(desc: ResourceDescriptor, query?: KubeApiQueryParams): Promise { + async get(desc: ResourceDescriptor, query?: KubeApiQueryParams): Promise { await this.checkPreferredVersion(); const url = this.getUrl(desc); @@ -588,7 +588,7 @@ export class KubeApi< return parsed; } - async create({ name, namespace }: Partial, data?: PartialDeep): Promise { + async create({ name, namespace }: Partial, data?: PartialDeep): Promise { await this.checkPreferredVersion(); const apiUrl = this.getUrl({ namespace }); @@ -611,7 +611,7 @@ export class KubeApi< return parsed; } - async update({ name, namespace }: ResourceDescriptor, data: PartialDeep): Promise { + async update({ name, namespace }: ResourceDescriptor, data: PartialDeep): Promise { await this.checkPreferredVersion(); const apiUrl = this.getUrl({ namespace, name }); @@ -632,7 +632,7 @@ export class KubeApi< return parsed; } - async patch(desc: ResourceDescriptor, data: PartialDeep | Patch, strategy: KubeApiPatchType = "strategic"): Promise { + async patch(desc: ResourceDescriptor, data: PartialDeep | Patch, strategy: KubeApiPatchType = "strategic"): Promise { await this.checkPreferredVersion(); const apiUrl = this.getUrl(desc); @@ -669,7 +669,7 @@ export class KubeApi< }); } - watch(opts: KubeApiWatchOptions = { namespace: "", retry: false }): () => void { + watch(opts: KubeApiWatchOptions = { namespace: "", retry: false }): () => void { let errorReceived = false; let timedRetry: NodeJS.Timeout; const { namespace, callback = noop, retry, timeout } = opts;