mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Remove jest-fetch-mock and make fetch injectable
Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
5a2a9248e8
commit
b1d1b69b3d
@ -396,7 +396,6 @@
|
||||
"jest": "^28.1.3",
|
||||
"jest-canvas-mock": "^2.3.1",
|
||||
"jest-environment-jsdom": "^28.1.3",
|
||||
"jest-fetch-mock": "^3.0.3",
|
||||
"jest-mock-extended": "^2.0.9",
|
||||
"make-plural": "^6.2.2",
|
||||
"mini-css-extract-plugin": "^2.6.1",
|
||||
|
||||
11
src/common/fetch/fetch.global-override-for-injectable.ts
Normal file
11
src/common/fetch/fetch.global-override-for-injectable.ts
Normal file
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getGlobalOverride } from "../test-utils/get-global-override";
|
||||
import fetchInjectable from "./fetch.injectable";
|
||||
|
||||
export default getGlobalOverride(fetchInjectable, () => () => {
|
||||
throw new Error("tried to fetch a resource without override in test");
|
||||
});
|
||||
17
src/common/fetch/fetch.injectable.ts
Normal file
17
src/common/fetch/fetch.injectable.ts
Normal file
@ -0,0 +1,17 @@
|
||||
/**
|
||||
* 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 type { RequestInfo, RequestInit, Response } from "node-fetch";
|
||||
import fetch from "node-fetch";
|
||||
|
||||
export type Fetch = (url: RequestInfo, init?: RequestInit) => Promise<Response>;
|
||||
|
||||
const fetchInjectable = getInjectable({
|
||||
id: "fetch",
|
||||
instantiate: (): Fetch => fetch,
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default fetchInjectable;
|
||||
@ -2,37 +2,40 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { forRemoteCluster, KubeApi } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { KubeJsonApi } from "../kube-json-api";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { delay } from "../../utils/delay";
|
||||
import { PassThrough } from "stream";
|
||||
import { ApiManager } from "../api-manager";
|
||||
import type { FetchMock } from "jest-fetch-mock/types";
|
||||
import type { ApiManager } from "../api-manager";
|
||||
import { DeploymentApi, Ingress, IngressApi, Pod, PodApi } from "../endpoints";
|
||||
import { getDiForUnitTesting } from "../../../renderer/getDiForUnitTesting";
|
||||
import apiManagerInjectable from "../api-manager/manager.injectable";
|
||||
import autoRegistrationInjectable from "../api-manager/auto-registration.injectable";
|
||||
import type { JsonApiDependencies } from "../json-api";
|
||||
import loggerInjectable from "../../logger.injectable";
|
||||
import type { Fetch } from "../../fetch/fetch.injectable";
|
||||
import fetchInjectable from "../../fetch/fetch.injectable";
|
||||
import type { CreateKubeApiForRemoteCluster } from "../create-kube-api-for-remote-cluster.injectable";
|
||||
import createKubeApiForRemoteClusterInjectable from "../create-kube-api-for-remote-cluster.injectable";
|
||||
import { Headers, Response } from "node-fetch";
|
||||
import AbortController from "abort-controller";
|
||||
|
||||
jest.mock("../api-manager");
|
||||
|
||||
const mockFetch = fetch as FetchMock;
|
||||
|
||||
describe("forRemoteCluster", () => {
|
||||
let apiManager: jest.Mocked<ApiManager>;
|
||||
describe("createKubeApiForRemoteCluster", () => {
|
||||
let createKubeApiForRemoteCluster: CreateKubeApiForRemoteCluster;
|
||||
let fetchMock: jest.MockedFunction<Fetch>;
|
||||
|
||||
beforeEach(() => {
|
||||
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
apiManager = new ApiManager() as jest.Mocked<ApiManager>;
|
||||
fetchMock = jest.fn();
|
||||
di.override(fetchInjectable, () => fetchMock);
|
||||
|
||||
di.override(apiManagerInjectable, () => apiManager);
|
||||
createKubeApiForRemoteCluster = di.inject(createKubeApiForRemoteClusterInjectable);
|
||||
});
|
||||
|
||||
it("builds api client for KubeObject", async () => {
|
||||
const api = forRemoteCluster({
|
||||
const api = createKubeApiForRemoteCluster({
|
||||
cluster: {
|
||||
server: "https://127.0.0.1:6443",
|
||||
},
|
||||
@ -45,7 +48,7 @@ describe("forRemoteCluster", () => {
|
||||
});
|
||||
|
||||
it("builds api client for given KubeApi", async () => {
|
||||
const api = forRemoteCluster({
|
||||
const api = createKubeApiForRemoteCluster({
|
||||
cluster: {
|
||||
server: "https://127.0.0.1:6443",
|
||||
},
|
||||
@ -58,7 +61,7 @@ describe("forRemoteCluster", () => {
|
||||
});
|
||||
|
||||
it("calls right api endpoint", async () => {
|
||||
const api = forRemoteCluster({
|
||||
const api = createKubeApiForRemoteCluster({
|
||||
cluster: {
|
||||
server: "https://127.0.0.1:6443",
|
||||
},
|
||||
@ -67,65 +70,42 @@ describe("forRemoteCluster", () => {
|
||||
},
|
||||
}, Pod);
|
||||
|
||||
mockFetch.mockResponse(async (request: any) => {
|
||||
expect(request.url).toEqual("https://127.0.0.1:6443/api/v1/pods");
|
||||
fetchMock.mockImplementation(async (url) => {
|
||||
expect(url).toBe("https://127.0.0.1:6443/api/v1/pods");
|
||||
|
||||
return {
|
||||
body: "hello",
|
||||
};
|
||||
return new Response("hello");
|
||||
});
|
||||
|
||||
expect.hasAssertions();
|
||||
|
||||
await api.list();
|
||||
expect(await api.list()).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("KubeApi", () => {
|
||||
let request: KubeJsonApi;
|
||||
let apiManager: jest.Mocked<ApiManager>;
|
||||
let registerApiSpy: jest.SpiedFunction<ApiManager["registerApi"]>;
|
||||
let fetchMock: jest.MockedFunction<Fetch>;
|
||||
|
||||
beforeEach(() => {
|
||||
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
request = new KubeJsonApi({
|
||||
fetchMock = jest.fn();
|
||||
di.override(fetchInjectable, () => fetchMock);
|
||||
|
||||
const dependencies: JsonApiDependencies = {
|
||||
logger: di.inject(loggerInjectable),
|
||||
fetch: di.inject(fetchInjectable),
|
||||
};
|
||||
|
||||
request = new KubeJsonApi(dependencies, {
|
||||
serverAddress: `http://127.0.0.1:9999`,
|
||||
apiBase: "/api-kube",
|
||||
});
|
||||
apiManager = new ApiManager() as jest.Mocked<ApiManager>;
|
||||
registerApiSpy = jest.spyOn(di.inject(apiManagerInjectable), "registerApi");
|
||||
|
||||
di.override(apiManagerInjectable, () => apiManager);
|
||||
di.inject(autoRegistrationInjectable);
|
||||
});
|
||||
|
||||
it("uses url from apiBase if apiBase contains the resource", async () => {
|
||||
mockFetch.mockResponse(async (request: any) => {
|
||||
if (request.url === "http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1") {
|
||||
return {
|
||||
body: JSON.stringify({
|
||||
resources: [{
|
||||
name: "ingresses",
|
||||
}],
|
||||
}),
|
||||
};
|
||||
} else if (request.url === "http://127.0.0.1:9999/api-kube/apis/extensions/v1beta1") {
|
||||
// Even if the old API contains ingresses, KubeApi should prefer the apiBase url
|
||||
return {
|
||||
body: JSON.stringify({
|
||||
resources: [{
|
||||
name: "ingresses",
|
||||
}],
|
||||
}),
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
body: JSON.stringify({
|
||||
resources: [],
|
||||
}),
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
const apiBase = "/apis/networking.k8s.io/v1/ingresses";
|
||||
const fallbackApiBase = "/apis/extensions/v1beta1/ingresses";
|
||||
const kubeApi = new IngressApi({
|
||||
@ -136,6 +116,46 @@ describe("KubeApi", () => {
|
||||
checkPreferredVersion: true,
|
||||
});
|
||||
|
||||
fetchMock.mockImplementation(async (url) => {
|
||||
if (url === "http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1") {
|
||||
return new Response(JSON.stringify({
|
||||
resources: [{
|
||||
name: "ingresses",
|
||||
}],
|
||||
}));
|
||||
}
|
||||
|
||||
if (url === "http://127.0.0.1:9999/api-kube/apis/extensions/v1beta1") {
|
||||
return new Response(JSON.stringify({
|
||||
resources: [{
|
||||
name: "ingresses",
|
||||
}],
|
||||
}));
|
||||
}
|
||||
|
||||
return new Response(JSON.stringify({ resources: [] }));
|
||||
});
|
||||
|
||||
fetchMock.mockImplementation(async (url) => {
|
||||
if (url === "http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1") {
|
||||
return new Response(JSON.stringify({
|
||||
resources: [{
|
||||
name: "ingresses",
|
||||
}],
|
||||
}));
|
||||
}
|
||||
|
||||
if (url === "http://127.0.0.1:9999/api-kube/apis/extensions/v1beta1") {
|
||||
return new Response(JSON.stringify({
|
||||
resources: [{
|
||||
name: "ingresses",
|
||||
}],
|
||||
}));
|
||||
}
|
||||
|
||||
return new Response(JSON.stringify({ resources: [] }));
|
||||
});
|
||||
|
||||
await kubeApi.get({
|
||||
name: "foo",
|
||||
namespace: "default",
|
||||
@ -145,30 +165,6 @@ describe("KubeApi", () => {
|
||||
});
|
||||
|
||||
it("uses url from fallbackApiBases if apiBase lacks the resource", async () => {
|
||||
mockFetch.mockResponse(async (request: any) => {
|
||||
if (request.url === "http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1") {
|
||||
return {
|
||||
body: JSON.stringify({
|
||||
resources: [],
|
||||
}),
|
||||
};
|
||||
} else if (request.url === "http://127.0.0.1:9999/api-kube/apis/extensions/v1beta1") {
|
||||
return {
|
||||
body: JSON.stringify({
|
||||
resources: [{
|
||||
name: "ingresses",
|
||||
}],
|
||||
}),
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
body: JSON.stringify({
|
||||
resources: [],
|
||||
}),
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
const apiBase = "apis/networking.k8s.io/v1/ingresses";
|
||||
const fallbackApiBase = "/apis/extensions/v1beta1/ingresses";
|
||||
const kubeApi = new IngressApi({
|
||||
@ -179,10 +175,30 @@ describe("KubeApi", () => {
|
||||
checkPreferredVersion: true,
|
||||
});
|
||||
|
||||
|
||||
fetchMock.mockImplementation(async (url) => {
|
||||
if (url === "http://127.0.0.1:9999/api-kube/apis/networking.k8s.io/v1") {
|
||||
return new Response(JSON.stringify({
|
||||
resources: [],
|
||||
}));
|
||||
}
|
||||
|
||||
if (url === "http://127.0.0.1:9999/api-kube/apis/extensions/v1beta1") {
|
||||
return new Response(JSON.stringify({
|
||||
resources: [{
|
||||
name: "ingresses",
|
||||
}],
|
||||
}));
|
||||
}
|
||||
|
||||
return new Response(JSON.stringify({ resources: [] }));
|
||||
});
|
||||
|
||||
await kubeApi.get({
|
||||
name: "foo",
|
||||
namespace: "default",
|
||||
});
|
||||
|
||||
expect(kubeApi.apiPrefix).toEqual("/apis");
|
||||
expect(kubeApi.apiGroup).toEqual("extensions");
|
||||
});
|
||||
@ -225,7 +241,7 @@ describe("KubeApi", () => {
|
||||
await (api as any).checkPreferredVersion();
|
||||
|
||||
expect(api.apiVersionPreferred).toBe("v1beta1");
|
||||
expect(apiManager.registerApi).toBeCalledWith(api);
|
||||
expect(registerApiSpy).toBeCalledWith(api);
|
||||
});
|
||||
|
||||
it("registers with apiManager if checkPreferredVersion changes apiVersionPreferred with non-grouped apis", async () => {
|
||||
@ -265,7 +281,7 @@ describe("KubeApi", () => {
|
||||
await (api as any).checkPreferredVersion();
|
||||
|
||||
expect(api.apiVersionPreferred).toBe("v1beta1");
|
||||
expect(apiManager.registerApi).toBeCalledWith(api);
|
||||
expect(registerApiSpy).toBeCalledWith(api);
|
||||
});
|
||||
});
|
||||
|
||||
@ -281,12 +297,12 @@ describe("KubeApi", () => {
|
||||
it("sends strategic patch by default", async () => {
|
||||
expect.hasAssertions();
|
||||
|
||||
mockFetch.mockResponse(async request => {
|
||||
expect(request.method).toEqual("PATCH");
|
||||
expect(request.headers.get("content-type")).toMatch("strategic-merge-patch");
|
||||
expect(request.body?.toString()).toEqual(JSON.stringify({ spec: { replicas: 2 }}));
|
||||
fetchMock.mockImplementation(async (url, init) => {
|
||||
expect(init?.method).toEqual("patch");
|
||||
expect(new Headers(init?.headers).get("content-type")).toMatch("strategic-merge-patch");
|
||||
expect(init?.body?.toString()).toEqual(JSON.stringify({ spec: { replicas: 2 }}));
|
||||
|
||||
return {};
|
||||
return new Response();
|
||||
});
|
||||
|
||||
await api.patch({ name: "test", namespace: "default" }, {
|
||||
@ -297,12 +313,12 @@ describe("KubeApi", () => {
|
||||
it("allows to use merge patch", async () => {
|
||||
expect.hasAssertions();
|
||||
|
||||
mockFetch.mockResponse(async request => {
|
||||
expect(request.method).toEqual("PATCH");
|
||||
expect(request.headers.get("content-type")).toMatch("merge-patch");
|
||||
expect(request.body?.toString()).toEqual(JSON.stringify({ spec: { replicas: 2 }}));
|
||||
fetchMock.mockImplementation(async (url, init) => {
|
||||
expect(init?.method).toEqual("patch");
|
||||
expect(new Headers(init?.headers).get("content-type")).toMatch("merge-patch");
|
||||
expect(init?.body?.toString()).toEqual(JSON.stringify({ spec: { replicas: 2 }}));
|
||||
|
||||
return {};
|
||||
return new Response();
|
||||
});
|
||||
|
||||
await api.patch({ name: "test", namespace: "default" }, {
|
||||
@ -313,12 +329,12 @@ describe("KubeApi", () => {
|
||||
it("allows to use json patch", async () => {
|
||||
expect.hasAssertions();
|
||||
|
||||
mockFetch.mockResponse(async request => {
|
||||
expect(request.method).toEqual("PATCH");
|
||||
expect(request.headers.get("content-type")).toMatch("json-patch");
|
||||
expect(request.body?.toString()).toEqual(JSON.stringify([{ op: "replace", path: "/spec/replicas", value: 2 }]));
|
||||
fetchMock.mockImplementation(async (url, init) => {
|
||||
expect(init?.method).toEqual("patch");
|
||||
expect(new Headers(init?.headers).get("content-type")).toMatch("json-patch");
|
||||
expect(init?.body?.toString()).toEqual(JSON.stringify([{ op: "replace", path: "/spec/replicas", value: 2 }]));
|
||||
|
||||
return {};
|
||||
return new Response();
|
||||
});
|
||||
|
||||
await api.patch({ name: "test", namespace: "default" }, [
|
||||
@ -329,12 +345,12 @@ describe("KubeApi", () => {
|
||||
it("allows deep partial patch", async () => {
|
||||
expect.hasAssertions();
|
||||
|
||||
mockFetch.mockResponse(async request => {
|
||||
expect(request.method).toEqual("PATCH");
|
||||
expect(request.headers.get("content-type")).toMatch("merge-patch");
|
||||
expect(request.body?.toString()).toEqual(JSON.stringify({ metadata: { annotations: { provisioned: "true" }}}));
|
||||
fetchMock.mockImplementation(async (url, init) => {
|
||||
expect(init?.method).toEqual("patch");
|
||||
expect(new Headers(init?.headers).get("content-type")).toMatch("merge-patch");
|
||||
expect(init?.body?.toString()).toEqual(JSON.stringify({ metadata: { annotations: { provisioned: "true" }}}));
|
||||
|
||||
return {};
|
||||
return new Response();
|
||||
});
|
||||
|
||||
await api.patch(
|
||||
@ -357,11 +373,11 @@ describe("KubeApi", () => {
|
||||
|
||||
it("sends correct request with empty namespace", async () => {
|
||||
expect.hasAssertions();
|
||||
mockFetch.mockResponse(async request => {
|
||||
expect(request.method).toEqual("DELETE");
|
||||
expect(request.url).toEqual("http://127.0.0.1:9999/api-kube/api/v1/pods/foo?propagationPolicy=Background");
|
||||
fetchMock.mockImplementation(async (url, init) => {
|
||||
expect(init?.method).toEqual("delete");
|
||||
expect(url).toEqual("http://127.0.0.1:9999/api-kube/api/v1/pods/foo?propagationPolicy=Background");
|
||||
|
||||
return {};
|
||||
return new Response();
|
||||
});
|
||||
|
||||
await api.delete({ name: "foo", namespace: "" });
|
||||
@ -369,11 +385,11 @@ describe("KubeApi", () => {
|
||||
|
||||
it("sends correct request without namespace", async () => {
|
||||
expect.hasAssertions();
|
||||
mockFetch.mockResponse(async request => {
|
||||
expect(request.method).toEqual("DELETE");
|
||||
expect(request.url).toEqual("http://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods/foo?propagationPolicy=Background");
|
||||
fetchMock.mockImplementation(async (url, init) => {
|
||||
expect(init?.method).toEqual("delete");
|
||||
expect(url).toEqual("http://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods/foo?propagationPolicy=Background");
|
||||
|
||||
return {};
|
||||
return new Response();
|
||||
});
|
||||
|
||||
await api.delete({ name: "foo" });
|
||||
@ -381,11 +397,11 @@ describe("KubeApi", () => {
|
||||
|
||||
it("sends correct request with namespace", async () => {
|
||||
expect.hasAssertions();
|
||||
mockFetch.mockResponse(async request => {
|
||||
expect(request.method).toEqual("DELETE");
|
||||
expect(request.url).toEqual("http://127.0.0.1:9999/api-kube/api/v1/namespaces/kube-system/pods/foo?propagationPolicy=Background");
|
||||
fetchMock.mockImplementation(async (url, init) => {
|
||||
expect(init?.method).toEqual("delete");
|
||||
expect(url).toEqual("http://127.0.0.1:9999/api-kube/api/v1/namespaces/kube-system/pods/foo?propagationPolicy=Background");
|
||||
|
||||
return {};
|
||||
return new Response();
|
||||
});
|
||||
|
||||
await api.delete({ name: "foo", namespace: "kube-system" });
|
||||
@ -393,11 +409,11 @@ describe("KubeApi", () => {
|
||||
|
||||
it("allows to change propagationPolicy", async () => {
|
||||
expect.hasAssertions();
|
||||
mockFetch.mockResponse(async request => {
|
||||
expect(request.method).toEqual("DELETE");
|
||||
expect(request.url).toMatch("propagationPolicy=Orphan");
|
||||
fetchMock.mockImplementation(async (url, init) => {
|
||||
expect(init?.method).toEqual("delete");
|
||||
expect(url).toMatch("propagationPolicy=Orphan");
|
||||
|
||||
return {};
|
||||
return new Response();
|
||||
});
|
||||
|
||||
await api.delete({ name: "foo", namespace: "default", propagationPolicy: "Orphan" });
|
||||
@ -424,11 +440,8 @@ describe("KubeApi", () => {
|
||||
it("sends a valid watch request", () => {
|
||||
const spy = jest.spyOn(request, "getResponse");
|
||||
|
||||
mockFetch.mockResponse(async () => {
|
||||
return {
|
||||
// needed for https://github.com/jefflau/jest-fetch-mock/issues/218
|
||||
body: stream as unknown as string,
|
||||
};
|
||||
fetchMock.mockImplementation(async () => {
|
||||
return new Response(stream);
|
||||
});
|
||||
|
||||
api.watch({ namespace: "kube-system" });
|
||||
@ -438,11 +451,8 @@ describe("KubeApi", () => {
|
||||
it("sends timeout as a query parameter", async () => {
|
||||
const spy = jest.spyOn(request, "getResponse");
|
||||
|
||||
mockFetch.mockResponse(async () => {
|
||||
return {
|
||||
// needed for https://github.com/jefflau/jest-fetch-mock/issues/218
|
||||
body: stream as unknown as string,
|
||||
};
|
||||
fetchMock.mockImplementation(async () => {
|
||||
return new Response(stream);
|
||||
});
|
||||
|
||||
api.watch({ namespace: "kube-system", timeout: 60 });
|
||||
@ -452,15 +462,12 @@ describe("KubeApi", () => {
|
||||
it("aborts watch using abortController", (done) => {
|
||||
const spy = jest.spyOn(request, "getResponse");
|
||||
|
||||
mockFetch.mockResponse(async request => {
|
||||
request.signal.addEventListener("abort", () => {
|
||||
fetchMock.mockImplementation(async (url, init) => {
|
||||
init?.signal?.addEventListener("abort", () => {
|
||||
done();
|
||||
});
|
||||
|
||||
return {
|
||||
// needed for https://github.com/jefflau/jest-fetch-mock/issues/218
|
||||
body: stream as unknown as string,
|
||||
};
|
||||
return new Response(stream);
|
||||
});
|
||||
|
||||
const abortController = new AbortController();
|
||||
@ -490,12 +497,10 @@ describe("KubeApi", () => {
|
||||
return stream;
|
||||
});
|
||||
|
||||
// we need to mock using jest as jest-fetch-mock doesn't support mocking the body completely
|
||||
jest.spyOn(global, "fetch").mockImplementation(async () => {
|
||||
return {
|
||||
ok: true,
|
||||
body: stream as never,
|
||||
} as Partial<Response> as Response;
|
||||
fetchMock.mockImplementation(async () => {
|
||||
return new Response(stream, {
|
||||
status: 200,
|
||||
});
|
||||
});
|
||||
|
||||
api.watch({
|
||||
@ -513,11 +518,8 @@ describe("KubeApi", () => {
|
||||
it("if request not closed after timeout", (done) => {
|
||||
const spy = jest.spyOn(request, "getResponse");
|
||||
|
||||
mockFetch.mockResponse(async () => {
|
||||
return {
|
||||
// needed for https://github.com/jefflau/jest-fetch-mock/issues/218
|
||||
body: stream as unknown as string,
|
||||
};
|
||||
fetchMock.mockImplementation(async () => {
|
||||
return new Response(stream);
|
||||
});
|
||||
|
||||
const timeoutSeconds = 1;
|
||||
@ -550,11 +552,10 @@ describe("KubeApi", () => {
|
||||
});
|
||||
|
||||
// we need to mock using jest as jest-fetch-mock doesn't support mocking the body completely
|
||||
jest.spyOn(global, "fetch").mockImplementation(async () => {
|
||||
return {
|
||||
ok: true,
|
||||
body: stream as never,
|
||||
} as Partial<Response> as Response;
|
||||
fetchMock.mockImplementation(async () => {
|
||||
return new Response(stream, {
|
||||
status: 200,
|
||||
});
|
||||
});
|
||||
|
||||
const timeoutSeconds = 0.5;
|
||||
@ -591,9 +592,9 @@ describe("KubeApi", () => {
|
||||
it("should add kind and apiVersion", async () => {
|
||||
expect.hasAssertions();
|
||||
|
||||
mockFetch.mockResponse(async request => {
|
||||
expect(request.method).toEqual("POST");
|
||||
expect(JSON.parse(String(request.body))).toEqual({
|
||||
fetchMock.mockImplementation(async (url, init) => {
|
||||
expect(init?.method).toEqual("post");
|
||||
expect(JSON.parse(String(init?.body))).toEqual({
|
||||
kind: "Pod",
|
||||
apiVersion: "v1",
|
||||
metadata: {
|
||||
@ -617,7 +618,7 @@ describe("KubeApi", () => {
|
||||
},
|
||||
});
|
||||
|
||||
return {};
|
||||
return new Response();
|
||||
});
|
||||
|
||||
await api.create({
|
||||
@ -645,9 +646,9 @@ describe("KubeApi", () => {
|
||||
it("doesn't override metadata.labels", async () => {
|
||||
expect.hasAssertions();
|
||||
|
||||
mockFetch.mockResponse(async request => {
|
||||
expect(request.method).toEqual("POST");
|
||||
expect(JSON.parse(String(request.body))).toEqual({
|
||||
fetchMock.mockImplementation(async (url, init) => {
|
||||
expect(init?.method).toEqual("post");
|
||||
expect(JSON.parse(String(init?.body))).toEqual({
|
||||
kind: "Pod",
|
||||
apiVersion: "v1",
|
||||
metadata: {
|
||||
@ -659,7 +660,7 @@ describe("KubeApi", () => {
|
||||
},
|
||||
});
|
||||
|
||||
return {};
|
||||
return new Response();
|
||||
});
|
||||
|
||||
await api.create({
|
||||
@ -688,9 +689,9 @@ describe("KubeApi", () => {
|
||||
it("doesn't override metadata.labels", async () => {
|
||||
expect.hasAssertions();
|
||||
|
||||
mockFetch.mockResponse(async request => {
|
||||
expect(request.method).toEqual("PUT");
|
||||
expect(JSON.parse(String(request.body))).toEqual({
|
||||
fetchMock.mockImplementation(async (url, init) => {
|
||||
expect(init?.method).toEqual("put");
|
||||
expect(JSON.parse(String(init?.body))).toEqual({
|
||||
metadata: {
|
||||
name: "foobar",
|
||||
namespace: "default",
|
||||
@ -700,7 +701,7 @@ describe("KubeApi", () => {
|
||||
},
|
||||
});
|
||||
|
||||
return {};
|
||||
return new Response();
|
||||
});
|
||||
|
||||
await api.update({
|
||||
|
||||
66
src/common/k8s-api/create-kube-api-for-cluster.injectable.ts
Normal file
66
src/common/k8s-api/create-kube-api-for-cluster.injectable.ts
Normal file
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* 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 fetchInjectable from "../fetch/fetch.injectable";
|
||||
import loggerInjectable from "../logger.injectable";
|
||||
import { apiKubePrefix } from "../vars";
|
||||
import isDevelopmentInjectable from "../vars/is-development.injectable";
|
||||
import { apiBaseInjectionToken } from "./api-base";
|
||||
import type { JsonApiDependencies } from "./json-api";
|
||||
import type { KubeApiOptions } from "./kube-api";
|
||||
import { KubeApi } from "./kube-api";
|
||||
import { KubeJsonApi } from "./kube-json-api";
|
||||
import type { KubeJsonApiDataFor, KubeObject, KubeObjectConstructor } from "./kube-object";
|
||||
|
||||
export interface CreateKubeApiForLocalClusterConfig {
|
||||
metadata: {
|
||||
uid: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface CreateKubeApiForCluster {
|
||||
<Object extends KubeObject, Api extends KubeApi<Object>, Data extends KubeJsonApiDataFor<Object>>(
|
||||
cluster: CreateKubeApiForLocalClusterConfig,
|
||||
kubeClass: KubeObjectConstructor<Object, Data>,
|
||||
apiClass: new (apiOpts: KubeApiOptions<Object>) => Api
|
||||
): Api;
|
||||
<Object extends KubeObject, Data extends KubeJsonApiDataFor<Object>>(
|
||||
cluster: CreateKubeApiForLocalClusterConfig,
|
||||
kubeClass: KubeObjectConstructor<Object, Data>,
|
||||
apiClass?: new (apiOpts: KubeApiOptions<Object>) => KubeApi<Object>
|
||||
): KubeApi<Object>;
|
||||
}
|
||||
|
||||
const createKubeApiForClusterInjectable = getInjectable({
|
||||
id: "create-kube-api-for-cluster",
|
||||
instantiate: (di): CreateKubeApiForCluster => {
|
||||
const apiBase = di.inject(apiBaseInjectionToken);
|
||||
const isDevelopment = di.inject(isDevelopmentInjectable);
|
||||
const dependencies: JsonApiDependencies = {
|
||||
fetch: di.inject(fetchInjectable),
|
||||
logger: di.inject(loggerInjectable),
|
||||
};
|
||||
|
||||
return (cluster: CreateKubeApiForLocalClusterConfig, kubeClass: KubeObjectConstructor<KubeObject, KubeJsonApiDataFor<KubeObject>>, apiClass = KubeApi) => {
|
||||
const url = new URL(apiBase.config.serverAddress);
|
||||
const request = new KubeJsonApi(dependencies, {
|
||||
serverAddress: apiBase.config.serverAddress,
|
||||
apiBase: apiKubePrefix,
|
||||
debug: isDevelopment,
|
||||
}, {
|
||||
headers: {
|
||||
"Host": `${cluster.metadata.uid}.localhost:${url.port}`,
|
||||
},
|
||||
});
|
||||
|
||||
return new apiClass({
|
||||
objectConstructor: kubeClass,
|
||||
request,
|
||||
});
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default createKubeApiForClusterInjectable;
|
||||
@ -0,0 +1,110 @@
|
||||
/**
|
||||
* 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 type { AgentOptions } from "https";
|
||||
import { Agent } from "https";
|
||||
import type { RequestInit } from "node-fetch";
|
||||
import fetchInjectable from "../fetch/fetch.injectable";
|
||||
import loggerInjectable from "../logger.injectable";
|
||||
import isDevelopmentInjectable from "../vars/is-development.injectable";
|
||||
import type { JsonApiDependencies } from "./json-api";
|
||||
import type { KubeApiOptions } from "./kube-api";
|
||||
import { KubeApi } from "./kube-api";
|
||||
import { KubeJsonApi } from "./kube-json-api";
|
||||
import type { KubeJsonApiDataFor, KubeObject, KubeObjectConstructor } from "./kube-object";
|
||||
|
||||
export interface CreateKubeApiForRemoteClusterConfig {
|
||||
cluster: {
|
||||
server: string;
|
||||
caData?: string;
|
||||
skipTLSVerify?: boolean;
|
||||
};
|
||||
user: {
|
||||
token?: string | (() => Promise<string>);
|
||||
clientCertificateData?: string;
|
||||
clientKeyData?: string;
|
||||
};
|
||||
/**
|
||||
* Custom instance of https.agent to use for the requests
|
||||
*
|
||||
* @remarks the custom agent replaced default agent, options skipTLSVerify,
|
||||
* clientCertificateData, clientKeyData and caData are ignored.
|
||||
*/
|
||||
agent?: Agent;
|
||||
}
|
||||
|
||||
export interface CreateKubeApiForRemoteCluster {
|
||||
<Object extends KubeObject, Api extends KubeApi<Object>, Data extends KubeJsonApiDataFor<Object>>(
|
||||
config: CreateKubeApiForRemoteClusterConfig,
|
||||
kubeClass: KubeObjectConstructor<Object, Data>,
|
||||
apiClass: new (apiOpts: KubeApiOptions<Object>) => Api,
|
||||
): Api;
|
||||
<Object extends KubeObject, Data extends KubeJsonApiDataFor<Object>>(
|
||||
config: CreateKubeApiForRemoteClusterConfig,
|
||||
kubeClass: KubeObjectConstructor<Object, Data>,
|
||||
apiClass?: new (apiOpts: KubeApiOptions<Object>) => KubeApi<Object>,
|
||||
): KubeApi<Object>;
|
||||
}
|
||||
|
||||
const createKubeApiForRemoteClusterInjectable = getInjectable({
|
||||
id: "create-kube-api-for-remote-cluster",
|
||||
instantiate: (di): CreateKubeApiForRemoteCluster => {
|
||||
const isDevelopment = di.inject(isDevelopmentInjectable);
|
||||
const dependencies: JsonApiDependencies = {
|
||||
fetch: di.inject(fetchInjectable),
|
||||
logger: di.inject(loggerInjectable),
|
||||
};
|
||||
|
||||
return (config: CreateKubeApiForRemoteClusterConfig, kubeClass: KubeObjectConstructor<KubeObject, KubeJsonApiDataFor<KubeObject>>, apiClass = KubeApi) => {
|
||||
const reqInit: RequestInit = {};
|
||||
const agentOptions: AgentOptions = {};
|
||||
|
||||
if (config.cluster.skipTLSVerify === true) {
|
||||
agentOptions.rejectUnauthorized = false;
|
||||
}
|
||||
|
||||
if (config.user.clientCertificateData) {
|
||||
agentOptions.cert = config.user.clientCertificateData;
|
||||
}
|
||||
|
||||
if (config.user.clientKeyData) {
|
||||
agentOptions.key = config.user.clientKeyData;
|
||||
}
|
||||
|
||||
if (config.cluster.caData) {
|
||||
agentOptions.ca = config.cluster.caData;
|
||||
}
|
||||
|
||||
if (Object.keys(agentOptions).length > 0) {
|
||||
reqInit.agent = new Agent(agentOptions);
|
||||
}
|
||||
|
||||
if (config.agent) {
|
||||
reqInit.agent = config.agent;
|
||||
}
|
||||
|
||||
const token = config.user.token;
|
||||
const request = new KubeJsonApi(dependencies, {
|
||||
serverAddress: config.cluster.server,
|
||||
apiBase: "",
|
||||
debug: isDevelopment,
|
||||
...(token ? {
|
||||
getRequestOptions: async () => ({
|
||||
headers: {
|
||||
"Authorization": `Bearer ${typeof token === "function" ? await token() : token}`,
|
||||
},
|
||||
}),
|
||||
} : {}),
|
||||
}, reqInit);
|
||||
|
||||
return new apiClass({
|
||||
objectConstructor: kubeClass,
|
||||
request,
|
||||
});
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default createKubeApiForRemoteClusterInjectable;
|
||||
@ -3,8 +3,11 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import fetchInjectable from "../fetch/fetch.injectable";
|
||||
import loggerInjectable from "../logger.injectable";
|
||||
import { apiKubePrefix, isDebugging } from "../vars";
|
||||
import { apiBaseInjectionToken } from "./api-base";
|
||||
import type { JsonApiDependencies } from "./json-api";
|
||||
import { KubeJsonApi } from "./kube-json-api";
|
||||
|
||||
export type CreateKubeJsonApiForCluster = (clusterId: string) => KubeJsonApi;
|
||||
@ -13,11 +16,15 @@ const createKubeJsonApiForClusterInjectable = getInjectable({
|
||||
id: "create-kube-json-api-for-cluster",
|
||||
instantiate: (di): CreateKubeJsonApiForCluster => {
|
||||
const apiBase = di.inject(apiBaseInjectionToken);
|
||||
const dependencies: JsonApiDependencies = {
|
||||
fetch: di.inject(fetchInjectable),
|
||||
logger: di.inject(loggerInjectable),
|
||||
};
|
||||
|
||||
return (clusterId) => {
|
||||
const url = new URL(apiBase.config.serverAddress);
|
||||
|
||||
return new KubeJsonApi({
|
||||
return new KubeJsonApi(dependencies, {
|
||||
serverAddress: apiBase.config.serverAddress,
|
||||
apiBase: apiKubePrefix,
|
||||
debug: isDebugging,
|
||||
|
||||
@ -9,12 +9,12 @@ import { Agent as HttpAgent } from "http";
|
||||
import { Agent as HttpsAgent } from "https";
|
||||
import { merge } from "lodash";
|
||||
import type { Response, RequestInit } from "node-fetch";
|
||||
import fetch from "node-fetch";
|
||||
import { stringify } from "querystring";
|
||||
import type { Patch } from "rfc6902";
|
||||
import type { PartialDeep, ValueOf } from "type-fest";
|
||||
import { EventEmitter } from "../../common/event-emitter";
|
||||
import logger from "../../common/logger";
|
||||
import type { Logger } from "../../common/logger";
|
||||
import type { Fetch } from "../fetch/fetch.injectable";
|
||||
import type { Defaulted } from "../utils";
|
||||
import { json } from "../utils";
|
||||
|
||||
@ -59,6 +59,11 @@ export type ParamsAndQuery<Params, Query> = (
|
||||
: Params & { query?: undefined }
|
||||
);
|
||||
|
||||
export interface JsonApiDependencies {
|
||||
fetch: Fetch;
|
||||
readonly logger: Logger;
|
||||
}
|
||||
|
||||
export class JsonApi<Data = JsonApiData, Params extends JsonApiParams<Data> = JsonApiParams<Data>> {
|
||||
static readonly reqInitDefault = {
|
||||
headers: {
|
||||
@ -71,7 +76,7 @@ export class JsonApi<Data = JsonApiData, Params extends JsonApiParams<Data> = Js
|
||||
debug: false,
|
||||
};
|
||||
|
||||
constructor(public readonly config: JsonApiConfig, reqInit?: RequestInit) {
|
||||
constructor(protected readonly dependencies: JsonApiDependencies, public readonly config: JsonApiConfig, reqInit?: RequestInit) {
|
||||
this.config = Object.assign({}, JsonApi.configDefault, config);
|
||||
this.reqInit = merge({}, JsonApi.reqInitDefault, reqInit);
|
||||
this.parseResponse = this.parseResponse.bind(this);
|
||||
@ -105,7 +110,7 @@ export class JsonApi<Data = JsonApiData, Params extends JsonApiParams<Data> = Js
|
||||
reqUrl += (reqUrl.includes("?") ? "&" : "?") + queryString;
|
||||
}
|
||||
|
||||
return fetch(reqUrl, reqInit);
|
||||
return this.dependencies.fetch(reqUrl, reqInit);
|
||||
}
|
||||
|
||||
get<OutData = Data, Query = QueryParams>(
|
||||
@ -177,7 +182,7 @@ export class JsonApi<Data = JsonApiData, Params extends JsonApiParams<Data> = Js
|
||||
reqInit,
|
||||
};
|
||||
|
||||
const res = await fetch(reqUrl, reqInit);
|
||||
const res = await this.dependencies.fetch(reqUrl, reqInit);
|
||||
|
||||
return this.parseResponse<OutData>(res, infoLog);
|
||||
}
|
||||
@ -233,7 +238,7 @@ export class JsonApi<Data = JsonApiData, Params extends JsonApiParams<Data> = Js
|
||||
protected writeLog(log: JsonApiLog) {
|
||||
const { method, reqUrl, ...params } = log;
|
||||
|
||||
logger.debug(`[JSON-API] request ${method} ${reqUrl}`, params);
|
||||
this.dependencies.logger.debug(`[JSON-API] request ${method} ${reqUrl}`, params);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -5,22 +5,18 @@
|
||||
|
||||
// Base class for building all kubernetes apis
|
||||
|
||||
import { isFunction, merge } from "lodash";
|
||||
import { merge } from "lodash";
|
||||
import { stringify } from "querystring";
|
||||
import { apiKubePrefix, isDevelopment } from "../../common/vars";
|
||||
import { apiBase, apiKube } from "./index";
|
||||
import { apiKube } from "./index";
|
||||
import { createKubeApiURL, parseKubeApi } from "./kube-api-parse";
|
||||
import type { KubeObjectConstructor, KubeJsonApiDataFor, KubeObjectMetadata } from "./kube-object";
|
||||
import { KubeObject, KubeStatus, isKubeStatusData } from "./kube-object";
|
||||
import byline from "byline";
|
||||
import type { IKubeWatchEvent } from "./kube-watch-event";
|
||||
import type { KubeJsonApiData } from "./kube-json-api";
|
||||
import { KubeJsonApi } from "./kube-json-api";
|
||||
import type { KubeJsonApiData, KubeJsonApi } from "./kube-json-api";
|
||||
import type { Disposer } from "../utils";
|
||||
import { isDefined, noop, WrappedAbortController } from "../utils";
|
||||
import type { RequestInit } from "node-fetch";
|
||||
import type { AgentOptions } from "https";
|
||||
import { Agent } from "https";
|
||||
import type { Patch } from "rfc6902";
|
||||
import assert from "assert";
|
||||
import type { PartialDeep } from "type-fest";
|
||||
@ -145,136 +141,8 @@ export interface KubeApiResourceList {
|
||||
resources: KubeApiResource[];
|
||||
}
|
||||
|
||||
export interface ILocalKubeApiConfig {
|
||||
metadata: {
|
||||
uid: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type PropagationPolicy = undefined | "Orphan" | "Foreground" | "Background";
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
export interface IKubeApiCluster extends ILocalKubeApiConfig { }
|
||||
|
||||
export interface IRemoteKubeApiConfig {
|
||||
cluster: {
|
||||
server: string;
|
||||
caData?: string;
|
||||
skipTLSVerify?: boolean;
|
||||
};
|
||||
user: {
|
||||
token?: string | (() => Promise<string>);
|
||||
clientCertificateData?: string;
|
||||
clientKeyData?: string;
|
||||
};
|
||||
/**
|
||||
* Custom instance of https.agent to use for the requests
|
||||
*
|
||||
* @remarks the custom agent replaced default agent, options skipTLSVerify,
|
||||
* clientCertificateData, clientKeyData and caData are ignored.
|
||||
*/
|
||||
agent?: Agent;
|
||||
}
|
||||
|
||||
export function forCluster<
|
||||
Object extends KubeObject,
|
||||
Api extends KubeApi<Object>,
|
||||
Data extends KubeJsonApiDataFor<Object>,
|
||||
>(cluster: ILocalKubeApiConfig, kubeClass: KubeObjectConstructor<Object, Data>, apiClass: new (apiOpts: KubeApiOptions<Object>) => Api): Api;
|
||||
export function forCluster<
|
||||
Object extends KubeObject,
|
||||
Data extends KubeJsonApiDataFor<Object>,
|
||||
>(cluster: ILocalKubeApiConfig, kubeClass: KubeObjectConstructor<Object, Data>, apiClass?: new (apiOpts: KubeApiOptions<Object>) => KubeApi<Object>): KubeApi<Object>;
|
||||
|
||||
export function forCluster<
|
||||
Object extends KubeObject,
|
||||
Data extends KubeJsonApiDataFor<Object>,
|
||||
>(cluster: ILocalKubeApiConfig, kubeClass: KubeObjectConstructor<Object, Data>, apiClass: (new (apiOpts: KubeApiOptions<Object>) => KubeApi<Object>) = KubeApi): KubeApi<Object> {
|
||||
const url = new URL(apiBase.config.serverAddress);
|
||||
const request = new KubeJsonApi({
|
||||
serverAddress: apiBase.config.serverAddress,
|
||||
apiBase: apiKubePrefix,
|
||||
debug: isDevelopment,
|
||||
}, {
|
||||
headers: {
|
||||
"Host": `${cluster.metadata.uid}.localhost:${url.port}`,
|
||||
},
|
||||
});
|
||||
|
||||
return new apiClass({
|
||||
objectConstructor: kubeClass as KubeObjectConstructor<Object, KubeJsonApiDataFor<Object>>,
|
||||
request,
|
||||
});
|
||||
}
|
||||
|
||||
export function forRemoteCluster<
|
||||
Object extends KubeObject,
|
||||
Api extends KubeApi<Object>,
|
||||
Data extends KubeJsonApiDataFor<Object>,
|
||||
>(config: IRemoteKubeApiConfig, kubeClass: KubeObjectConstructor<Object, Data>, apiClass: new (apiOpts: KubeApiOptions<Object>) => Api): Api;
|
||||
export function forRemoteCluster<
|
||||
Object extends KubeObject,
|
||||
Data extends KubeJsonApiDataFor<Object>,
|
||||
>(config: IRemoteKubeApiConfig, kubeClass: KubeObjectConstructor<Object, Data>, apiClass?: new (apiOpts: KubeApiOptions<Object>) => KubeApi<Object>): KubeApi<Object>;
|
||||
|
||||
export function forRemoteCluster<
|
||||
Object extends KubeObject,
|
||||
Api extends KubeApi<Object>,
|
||||
Data extends KubeJsonApiDataFor<Object>,
|
||||
>(config: IRemoteKubeApiConfig, kubeClass: KubeObjectConstructor<Object, Data>, apiClass: new (apiOpts: KubeApiOptions<Object>) => KubeApi<Object> = KubeApi): KubeApi<Object> {
|
||||
const reqInit: RequestInit = {};
|
||||
const agentOptions: AgentOptions = {};
|
||||
|
||||
if (config.cluster.skipTLSVerify === true) {
|
||||
agentOptions.rejectUnauthorized = false;
|
||||
}
|
||||
|
||||
if (config.user.clientCertificateData) {
|
||||
agentOptions.cert = config.user.clientCertificateData;
|
||||
}
|
||||
|
||||
if (config.user.clientKeyData) {
|
||||
agentOptions.key = config.user.clientKeyData;
|
||||
}
|
||||
|
||||
if (config.cluster.caData) {
|
||||
agentOptions.ca = config.cluster.caData;
|
||||
}
|
||||
|
||||
if (Object.keys(agentOptions).length > 0) {
|
||||
reqInit.agent = new Agent(agentOptions);
|
||||
}
|
||||
|
||||
if (config.agent) {
|
||||
reqInit.agent = config.agent;
|
||||
}
|
||||
|
||||
const token = config.user.token;
|
||||
const request = new KubeJsonApi({
|
||||
serverAddress: config.cluster.server,
|
||||
apiBase: "",
|
||||
debug: isDevelopment,
|
||||
...(token ? {
|
||||
getRequestOptions: async () => ({
|
||||
headers: {
|
||||
"Authorization": `Bearer ${isFunction(token) ? await token() : token}`,
|
||||
},
|
||||
}),
|
||||
} : {}),
|
||||
}, reqInit);
|
||||
|
||||
if (!apiClass) {
|
||||
apiClass = KubeApi as new (apiOpts: KubeApiOptions<Object>) => Api;
|
||||
}
|
||||
|
||||
return new apiClass({
|
||||
objectConstructor: kubeClass as KubeObjectConstructor<Object, KubeJsonApiDataFor<Object>>,
|
||||
request,
|
||||
});
|
||||
}
|
||||
|
||||
export type KubeApiWatchCallback<T extends KubeJsonApiData = KubeJsonApiData> = (data: IKubeWatchEvent<T>, error: any) => void;
|
||||
|
||||
export interface KubeApiWatchOptions<Object extends KubeObject, Data extends KubeJsonApiDataFor<Object>> {
|
||||
|
||||
@ -9,18 +9,28 @@
|
||||
|
||||
export { ResourceStack } from "../../common/k8s/resource-stack";
|
||||
import apiManagerInjectable from "../../common/k8s-api/api-manager/manager.injectable";
|
||||
import createKubeApiForClusterInjectable from "../../common/k8s-api/create-kube-api-for-cluster.injectable";
|
||||
import createKubeApiForRemoteClusterInjectable from "../../common/k8s-api/create-kube-api-for-remote-cluster.injectable";
|
||||
import { asLegacyGlobalFunctionForExtensionApi } from "../as-legacy-globals-for-extension-api/as-legacy-global-function-for-extension-api";
|
||||
import { asLegacyGlobalForExtensionApi } from "../as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api";
|
||||
|
||||
export const apiManager = asLegacyGlobalForExtensionApi(apiManagerInjectable);
|
||||
export const forCluster = asLegacyGlobalFunctionForExtensionApi(createKubeApiForClusterInjectable);
|
||||
export const forRemoteCluster = asLegacyGlobalFunctionForExtensionApi(createKubeApiForRemoteClusterInjectable);
|
||||
|
||||
export {
|
||||
KubeApi,
|
||||
forCluster,
|
||||
forRemoteCluster,
|
||||
type ILocalKubeApiConfig,
|
||||
type IRemoteKubeApiConfig,
|
||||
type IKubeApiCluster,
|
||||
} from "../../common/k8s-api/kube-api";
|
||||
export { KubeApi } from "../../common/k8s-api/kube-api";
|
||||
|
||||
/**
|
||||
* @deprecated This type is unused
|
||||
*/
|
||||
export interface IKubeApiCluster {
|
||||
metadata: {
|
||||
uid: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type { CreateKubeApiForRemoteClusterConfig as IRemoteKubeApiConfig } from "../../common/k8s-api/create-kube-api-for-remote-cluster.injectable";
|
||||
export type { CreateKubeApiForLocalClusterConfig as ILocalKubeApiConfig } from "../../common/k8s-api/create-kube-api-for-cluster.injectable";
|
||||
|
||||
export {
|
||||
KubeObject,
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import fetchMock from "jest-fetch-mock";
|
||||
import configurePackages from "./common/configure-packages";
|
||||
import { configure } from "mobx";
|
||||
import { setImmediate } from "timers";
|
||||
@ -20,9 +19,6 @@ configure({
|
||||
safeDescriptors: false,
|
||||
});
|
||||
|
||||
// rewire global.fetch to call 'fetchMock'
|
||||
fetchMock.enableMocks();
|
||||
|
||||
// Mock __non_webpack_require__ for tests
|
||||
globalThis.__non_webpack_require__ = jest.fn();
|
||||
|
||||
|
||||
@ -65,6 +65,7 @@ import forceUpdateModalRootFrameComponentInjectable from "./application-update/f
|
||||
import legacyOnChannelListenInjectable from "./ipc/legacy-channel-listen.injectable";
|
||||
import getEntitySettingCommandsInjectable from "./components/command-palette/registered-commands/get-entity-setting-commands.injectable";
|
||||
import storageSaveDelayInjectable from "./utils/create-storage/storage-save-delay.injectable";
|
||||
import environmentVariablesInjectable from "../common/utils/environment-variables.injectable";
|
||||
import type { GlobalOverride } from "../common/test-utils/get-global-override";
|
||||
import type { PartialDeep } from "type-fest";
|
||||
|
||||
@ -164,6 +165,7 @@ export const getDiForUnitTesting = (
|
||||
}));
|
||||
});
|
||||
|
||||
di.override(environmentVariablesInjectable, () => ({}));
|
||||
di.override(watchHistoryStateInjectable, () => () => () => {});
|
||||
di.override(openAppContextMenuInjectable, () => () => {});
|
||||
di.override(goBackInjectable, () => () => {});
|
||||
|
||||
22
yarn.lock
22
yarn.lock
@ -4516,13 +4516,6 @@ create-require@^1.1.0:
|
||||
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
|
||||
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
|
||||
|
||||
cross-fetch@^3.0.4:
|
||||
version "3.1.5"
|
||||
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f"
|
||||
integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==
|
||||
dependencies:
|
||||
node-fetch "2.6.7"
|
||||
|
||||
cross-spawn@^6.0.0:
|
||||
version "6.0.5"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
|
||||
@ -7748,14 +7741,6 @@ jest-environment-node@^28.1.3:
|
||||
jest-mock "^28.1.3"
|
||||
jest-util "^28.1.3"
|
||||
|
||||
jest-fetch-mock@^3.0.3:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/jest-fetch-mock/-/jest-fetch-mock-3.0.3.tgz#31749c456ae27b8919d69824f1c2bd85fe0a1f3b"
|
||||
integrity sha512-Ux1nWprtLrdrH4XwE7O7InRY6psIi3GOsqNESJgMJ+M5cv4A8Lh7SN9d2V2kKRZ8ebAfcd1LNyZguAOb6JiDqw==
|
||||
dependencies:
|
||||
cross-fetch "^3.0.4"
|
||||
promise-polyfill "^8.1.3"
|
||||
|
||||
jest-get-type@^28.0.2:
|
||||
version "28.0.2"
|
||||
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-28.0.2.tgz#34622e628e4fdcd793d46db8a242227901fcf203"
|
||||
@ -9341,7 +9326,7 @@ node-addon-api@^5.0.0:
|
||||
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.0.0.tgz#7d7e6f9ef89043befdb20c1989c905ebde18c501"
|
||||
integrity sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==
|
||||
|
||||
node-fetch@2.6.7, node-fetch@^2.6.7:
|
||||
node-fetch@^2.6.7:
|
||||
version "2.6.7"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
|
||||
integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
|
||||
@ -10453,11 +10438,6 @@ promise-inflight@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
|
||||
integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM=
|
||||
|
||||
promise-polyfill@^8.1.3:
|
||||
version "8.2.3"
|
||||
resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-8.2.3.tgz#2edc7e4b81aff781c88a0d577e5fe9da822107c6"
|
||||
integrity sha512-Og0+jCRQetV84U8wVjMNccfGCnMQ9mGs9Hv78QFe+pSDD3gWTpz0y+1QCuxy5d/vBFuZ3iwP2eycAkvqIMPmWg==
|
||||
|
||||
promise-retry@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user