mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Refactor k8s api to common (#3553)
* refactor kube api to common Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * refactor more utils to common Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * refactor more utils to common Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix tests Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * switch to use node-fetch on both sides Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * cleanup Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * improve logger Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix lint errors Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix/improve tests Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix tests Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix node-fetch require error on prod build Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * preload fix Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fixes Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * read serverAddress from apiBase Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * cleanup Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
1 parent
476aa74101
commit
58a446bd45
250 files changed
+1244
-644
No files matched your search
@@ -1,63 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { ingressStore } from "../../components/+network-ingresses/ingress.store";
|
||||
import { apiManager } from "../api-manager";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { KubeObject } from "../kube-object";
|
||||
|
||||
class TestApi extends KubeApi<KubeObject> {
|
||||
|
||||
protected async checkPreferredVersion() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
describe("ApiManager", () => {
|
||||
describe("registerApi", () => {
|
||||
it("re-register store if apiBase changed", async () => {
|
||||
const apiBase = "apis/v1/foo";
|
||||
const fallbackApiBase = "/apis/extensions/v1beta1/foo";
|
||||
const kubeApi = new TestApi({
|
||||
objectConstructor: KubeObject,
|
||||
apiBase,
|
||||
fallbackApiBases: [fallbackApiBase],
|
||||
checkPreferredVersion: true,
|
||||
});
|
||||
|
||||
apiManager.registerApi(apiBase, kubeApi);
|
||||
|
||||
// Define to use test api for ingress store
|
||||
Object.defineProperty(ingressStore, "api", { value: kubeApi });
|
||||
apiManager.registerStore(ingressStore, [kubeApi]);
|
||||
|
||||
// Test that store is returned with original apiBase
|
||||
expect(apiManager.getStore(kubeApi)).toBe(ingressStore);
|
||||
|
||||
// Change apiBase similar as checkPreferredVersion does
|
||||
Object.defineProperty(kubeApi, "apiBase", { value: fallbackApiBase });
|
||||
apiManager.registerApi(fallbackApiBase, kubeApi);
|
||||
|
||||
// Test that store is returned with new apiBase
|
||||
expect(apiManager.getStore(kubeApi)).toBe(ingressStore);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,112 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { CustomResourceDefinition } from "../endpoints";
|
||||
import type { KubeObjectMetadata } from "../kube-object";
|
||||
|
||||
describe("Crds", () => {
|
||||
describe("getVersion", () => {
|
||||
it("should get the first version name from the list of versions", () => {
|
||||
const crd = new CustomResourceDefinition({
|
||||
apiVersion: "foo",
|
||||
kind: "CustomResourceDefinition",
|
||||
metadata: {} as KubeObjectMetadata,
|
||||
});
|
||||
|
||||
crd.spec = {
|
||||
versions: [
|
||||
{
|
||||
name: "123",
|
||||
served: false,
|
||||
storage: false,
|
||||
}
|
||||
]
|
||||
} as any;
|
||||
|
||||
expect(crd.getVersion()).toBe("123");
|
||||
});
|
||||
|
||||
it("should get the first version name from the list of versions (length 2)", () => {
|
||||
const crd = new CustomResourceDefinition({
|
||||
apiVersion: "foo",
|
||||
kind: "CustomResourceDefinition",
|
||||
metadata: {} as KubeObjectMetadata,
|
||||
});
|
||||
|
||||
crd.spec = {
|
||||
versions: [
|
||||
{
|
||||
name: "123",
|
||||
served: false,
|
||||
storage: false,
|
||||
},
|
||||
{
|
||||
name: "1234",
|
||||
served: false,
|
||||
storage: false,
|
||||
}
|
||||
]
|
||||
} as any;
|
||||
|
||||
expect(crd.getVersion()).toBe("123");
|
||||
});
|
||||
|
||||
it("should get the first version name from the list of versions (length 2) even with version field", () => {
|
||||
const crd = new CustomResourceDefinition({
|
||||
apiVersion: "foo",
|
||||
kind: "CustomResourceDefinition",
|
||||
metadata: {} as KubeObjectMetadata,
|
||||
});
|
||||
|
||||
crd.spec = {
|
||||
version: "abc",
|
||||
versions: [
|
||||
{
|
||||
name: "123",
|
||||
served: false,
|
||||
storage: false,
|
||||
},
|
||||
{
|
||||
name: "1234",
|
||||
served: false,
|
||||
storage: false,
|
||||
}
|
||||
]
|
||||
} as any;
|
||||
|
||||
expect(crd.getVersion()).toBe("123");
|
||||
});
|
||||
|
||||
it("should get the first version name from the version field", () => {
|
||||
const crd = new CustomResourceDefinition({
|
||||
apiVersion: "foo",
|
||||
kind: "CustomResourceDefinition",
|
||||
metadata: {} as KubeObjectMetadata,
|
||||
});
|
||||
|
||||
crd.spec = {
|
||||
version: "abc"
|
||||
} as any;
|
||||
|
||||
expect(crd.getVersion()).toBe("abc");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,60 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { EndpointSubset } from "../endpoints";
|
||||
|
||||
describe("endpoint tests", () => {
|
||||
describe("EndpointSubset", () => {
|
||||
it.each([
|
||||
4,
|
||||
false,
|
||||
null,
|
||||
{},
|
||||
[],
|
||||
"ahe",
|
||||
/a/,
|
||||
])("should always initialize fields when given %j", (data: any) => {
|
||||
const sub = new EndpointSubset(data);
|
||||
|
||||
expect(sub.addresses).toStrictEqual([]);
|
||||
expect(sub.notReadyAddresses).toStrictEqual([]);
|
||||
expect(sub.ports).toStrictEqual([]);
|
||||
});
|
||||
|
||||
it("toString should be addresses X ports", () => {
|
||||
const sub = new EndpointSubset({
|
||||
addresses: [{
|
||||
ip: "1.1.1.1",
|
||||
}, {
|
||||
ip: "1.1.1.2",
|
||||
}] as any,
|
||||
notReadyAddresses: [],
|
||||
ports: [{
|
||||
port: "81",
|
||||
}, {
|
||||
port: "82",
|
||||
}] as any,
|
||||
});
|
||||
|
||||
expect(sub.toString()).toBe("1.1.1.1:81, 1.1.1.1:82, 1.1.1.2:81, 1.1.1.2:82");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,146 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
jest.mock("../kube-object");
|
||||
jest.mock("../kube-api");
|
||||
jest.mock("../api-manager", () => ({
|
||||
apiManager() {
|
||||
return {
|
||||
registerStore: jest.fn(),
|
||||
};
|
||||
}
|
||||
}));
|
||||
|
||||
import { IKubeApiParsed, parseKubeApi } from "../kube-api-parse";
|
||||
|
||||
/**
|
||||
* [<input-url>, <expected-result>]
|
||||
*/
|
||||
type KubeApiParseTestData = [string, Required<IKubeApiParsed>];
|
||||
|
||||
const tests: KubeApiParseTestData[] = [
|
||||
["/apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions/prometheuses.monitoring.coreos.com", {
|
||||
apiBase: "/apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions",
|
||||
apiPrefix: "/apis",
|
||||
apiGroup: "apiextensions.k8s.io",
|
||||
apiVersion: "v1beta1",
|
||||
apiVersionWithGroup: "apiextensions.k8s.io/v1beta1",
|
||||
namespace: undefined,
|
||||
resource: "customresourcedefinitions",
|
||||
name: "prometheuses.monitoring.coreos.com"
|
||||
}],
|
||||
["/api/v1/namespaces/kube-system/pods/coredns-6955765f44-v8p27", {
|
||||
apiBase: "/api/v1/pods",
|
||||
apiPrefix: "/api",
|
||||
apiGroup: "",
|
||||
apiVersion: "v1",
|
||||
apiVersionWithGroup: "v1",
|
||||
namespace: "kube-system",
|
||||
resource: "pods",
|
||||
name: "coredns-6955765f44-v8p27"
|
||||
}],
|
||||
["/apis/stable.example.com/foo1/crontabs", {
|
||||
apiBase: "/apis/stable.example.com/foo1/crontabs",
|
||||
apiPrefix: "/apis",
|
||||
apiGroup: "stable.example.com",
|
||||
apiVersion: "foo1",
|
||||
apiVersionWithGroup: "stable.example.com/foo1",
|
||||
resource: "crontabs",
|
||||
name: undefined,
|
||||
namespace: undefined,
|
||||
}],
|
||||
["/apis/cluster.k8s.io/v1alpha1/clusters", {
|
||||
apiBase: "/apis/cluster.k8s.io/v1alpha1/clusters",
|
||||
apiPrefix: "/apis",
|
||||
apiGroup: "cluster.k8s.io",
|
||||
apiVersion: "v1alpha1",
|
||||
apiVersionWithGroup: "cluster.k8s.io/v1alpha1",
|
||||
resource: "clusters",
|
||||
name: undefined,
|
||||
namespace: undefined,
|
||||
}],
|
||||
["/api/v1/namespaces", {
|
||||
apiBase: "/api/v1/namespaces",
|
||||
apiPrefix: "/api",
|
||||
apiGroup: "",
|
||||
apiVersion: "v1",
|
||||
apiVersionWithGroup: "v1",
|
||||
resource: "namespaces",
|
||||
name: undefined,
|
||||
namespace: undefined,
|
||||
}],
|
||||
["/api/v1/secrets", {
|
||||
apiBase: "/api/v1/secrets",
|
||||
apiPrefix: "/api",
|
||||
apiGroup: "",
|
||||
apiVersion: "v1",
|
||||
apiVersionWithGroup: "v1",
|
||||
resource: "secrets",
|
||||
name: undefined,
|
||||
namespace: undefined,
|
||||
}],
|
||||
["/api/v1/nodes/minikube", {
|
||||
apiBase: "/api/v1/nodes",
|
||||
apiPrefix: "/api",
|
||||
apiGroup: "",
|
||||
apiVersion: "v1",
|
||||
apiVersionWithGroup: "v1",
|
||||
resource: "nodes",
|
||||
name: "minikube",
|
||||
namespace: undefined,
|
||||
}],
|
||||
["/api/foo-bar/nodes/minikube", {
|
||||
apiBase: "/api/foo-bar/nodes",
|
||||
apiPrefix: "/api",
|
||||
apiGroup: "",
|
||||
apiVersion: "foo-bar",
|
||||
apiVersionWithGroup: "foo-bar",
|
||||
resource: "nodes",
|
||||
name: "minikube",
|
||||
namespace: undefined,
|
||||
}],
|
||||
["/api/v1/namespaces/kube-public", {
|
||||
apiBase: "/api/v1/namespaces",
|
||||
apiPrefix: "/api",
|
||||
apiGroup: "",
|
||||
apiVersion: "v1",
|
||||
apiVersionWithGroup: "v1",
|
||||
resource: "namespaces",
|
||||
name: "kube-public",
|
||||
namespace: undefined,
|
||||
}],
|
||||
];
|
||||
|
||||
const throwtests = [
|
||||
undefined,
|
||||
"",
|
||||
"ajklsmh"
|
||||
];
|
||||
|
||||
describe("parseApi unit tests", () => {
|
||||
it.each(tests)("testing %j", (url, expected) => {
|
||||
expect(parseKubeApi(url)).toStrictEqual(expected);
|
||||
});
|
||||
|
||||
it.each(throwtests)("testing %j should throw", (url) => {
|
||||
expect(() => parseKubeApi(url)).toThrowError("invalid apiPath");
|
||||
});
|
||||
});
|
||||
@@ -1,106 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { KubeObject } from "../kube-object";
|
||||
|
||||
describe("KubeApi", () => {
|
||||
it("uses url from apiBase if apiBase contains the resource", async () => {
|
||||
(fetch as any).mockResponse(async (request: any) => {
|
||||
if (request.url === "/api-kube/apis/networking.k8s.io/v1") {
|
||||
return {
|
||||
body: JSON.stringify({
|
||||
resources: [{
|
||||
name: "ingresses"
|
||||
}] as any[]
|
||||
})
|
||||
};
|
||||
} else if (request.url === "/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"
|
||||
}] as any[]
|
||||
})
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
body: JSON.stringify({
|
||||
resources: [] as any[]
|
||||
})
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
const apiBase = "/apis/networking.k8s.io/v1/ingresses";
|
||||
const fallbackApiBase = "/apis/extensions/v1beta1/ingresses";
|
||||
const kubeApi = new KubeApi({
|
||||
objectConstructor: KubeObject,
|
||||
apiBase,
|
||||
fallbackApiBases: [fallbackApiBase],
|
||||
checkPreferredVersion: true,
|
||||
});
|
||||
|
||||
await kubeApi.get();
|
||||
expect(kubeApi.apiPrefix).toEqual("/apis");
|
||||
expect(kubeApi.apiGroup).toEqual("networking.k8s.io");
|
||||
});
|
||||
|
||||
it("uses url from fallbackApiBases if apiBase lacks the resource", async () => {
|
||||
(fetch as any).mockResponse(async (request: any) => {
|
||||
if (request.url === "/api-kube/apis/networking.k8s.io/v1") {
|
||||
return {
|
||||
body: JSON.stringify({
|
||||
resources: [] as any[]
|
||||
})
|
||||
};
|
||||
} else if (request.url === "/api-kube/apis/extensions/v1beta1") {
|
||||
return {
|
||||
body: JSON.stringify({
|
||||
resources: [{
|
||||
name: "ingresses"
|
||||
}] as any[]
|
||||
})
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
body: JSON.stringify({
|
||||
resources: [] as any[]
|
||||
})
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
const apiBase = "apis/networking.k8s.io/v1/ingresses";
|
||||
const fallbackApiBase = "/apis/extensions/v1beta1/ingresses";
|
||||
const kubeApi = new KubeApi({
|
||||
objectConstructor: KubeObject,
|
||||
apiBase,
|
||||
fallbackApiBases: [fallbackApiBase],
|
||||
checkPreferredVersion: true,
|
||||
});
|
||||
|
||||
await kubeApi.get();
|
||||
expect(kubeApi.apiPrefix).toEqual("/apis");
|
||||
expect(kubeApi.apiGroup).toEqual("extensions");
|
||||
});
|
||||
});
|
||||
@@ -1,235 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { KubeObject } from "../kube-object";
|
||||
|
||||
describe("KubeObject", () => {
|
||||
describe("isJsonApiData", () => {
|
||||
{
|
||||
type TestCase = [any];
|
||||
const tests: TestCase[] = [
|
||||
[false],
|
||||
[true],
|
||||
[null],
|
||||
[undefined],
|
||||
[""],
|
||||
[1],
|
||||
[(): unknown => void 0],
|
||||
[Symbol("hello")],
|
||||
[{}],
|
||||
];
|
||||
|
||||
it.each(tests)("should reject invalid value: %p", (input) => {
|
||||
expect(KubeObject.isJsonApiData(input)).toBe(false);
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
type TestCase = [string, any];
|
||||
const tests: TestCase[] = [
|
||||
["kind", { apiVersion: "", metadata: {uid: "", name: "", resourceVersion: "", selfLink: ""} }],
|
||||
["apiVersion", { kind: "", metadata: {uid: "", name: "", resourceVersion: "", selfLink: ""} }],
|
||||
["metadata", { kind: "", apiVersion: "" }],
|
||||
["metadata.uid", { kind: "", apiVersion: "", metadata: { name: "", resourceVersion: "", selfLink: ""} }],
|
||||
["metadata.name", { kind: "", apiVersion: "", metadata: { uid: "", resourceVersion: "", selfLink: "" } }],
|
||||
["metadata.resourceVersion", { kind: "", apiVersion: "", metadata: { uid: "", name: "", selfLink: "" } }],
|
||||
];
|
||||
|
||||
it.each(tests)("should reject with missing: %s", (missingField, input) => {
|
||||
expect(KubeObject.isJsonApiData(input)).toBe(false);
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
type TestCase = [string, any];
|
||||
const tests: TestCase[] = [
|
||||
["kind", { kind: 1, apiVersion: "", metadata: {} }],
|
||||
["apiVersion", { apiVersion: 1, kind: "", metadata: {} }],
|
||||
["metadata", { kind: "", apiVersion: "", metadata: "" }],
|
||||
["metadata.uid", { kind: "", apiVersion: "", metadata: { uid: 1 } }],
|
||||
["metadata.name", { kind: "", apiVersion: "", metadata: { uid: "", name: 1 } }],
|
||||
["metadata.resourceVersion", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: 1 } }],
|
||||
["metadata.selfLink", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: 1 } }],
|
||||
["metadata.namespace", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", namespace: 1 } }],
|
||||
["metadata.creationTimestamp", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", creationTimestamp: 1 } }],
|
||||
["metadata.continue", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", continue: 1 } }],
|
||||
["metadata.finalizers", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", finalizers: 1 } }],
|
||||
["metadata.finalizers", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", finalizers: [1] } }],
|
||||
["metadata.finalizers", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", finalizers: {} } }],
|
||||
["metadata.labels", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", labels: 1 } }],
|
||||
["metadata.labels", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", labels: { food: 1 } } }],
|
||||
["metadata.annotations", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", annotations: 1 } }],
|
||||
["metadata.annotations", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", annotations: { food: 1 } } }],
|
||||
];
|
||||
|
||||
it.each(tests)("should reject with wrong type for field: %s", (missingField, input) => {
|
||||
expect(KubeObject.isJsonApiData(input)).toBe(false);
|
||||
});
|
||||
}
|
||||
|
||||
it("should accept valid KubeJsonApiData (ignoring other fields)", () => {
|
||||
const valid = { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", annotations: { food: "" } } };
|
||||
|
||||
expect(KubeObject.isJsonApiData(valid)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isPartialJsonApiData", () => {
|
||||
{
|
||||
type TestCase = [any];
|
||||
const tests: TestCase[] = [
|
||||
[false],
|
||||
[true],
|
||||
[null],
|
||||
[undefined],
|
||||
[""],
|
||||
[1],
|
||||
[(): unknown => void 0],
|
||||
[Symbol("hello")],
|
||||
];
|
||||
|
||||
it.each(tests)("should reject invalid value: %p", (input) => {
|
||||
expect(KubeObject.isPartialJsonApiData(input)).toBe(false);
|
||||
});
|
||||
}
|
||||
|
||||
it("should accept {}", () => {
|
||||
expect(KubeObject.isPartialJsonApiData({})).toBe(true);
|
||||
});
|
||||
|
||||
{
|
||||
type TestCase = [string, any];
|
||||
const tests: TestCase[] = [
|
||||
["kind", { apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "" } }],
|
||||
["apiVersion", { kind: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "" } }],
|
||||
["metadata", { kind: "", apiVersion: "" }],
|
||||
];
|
||||
|
||||
it.each(tests)("should not reject with missing top level field: %s", (missingField, input) => {
|
||||
expect(KubeObject.isPartialJsonApiData(input)).toBe(true);
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
type TestCase = [string, any];
|
||||
const tests: TestCase[] = [
|
||||
["kind", { kind: 1, apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "" } }],
|
||||
["apiVersion", { apiVersion: 1, kind: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "" } }],
|
||||
["metadata", { kind: "", apiVersion: "", metadata: "" }],
|
||||
["metadata.uid", { kind: "", apiVersion: "", metadata: { uid: 1, name: "", resourceVersion: "", selfLink: "" } }],
|
||||
["metadata.name", { kind: "", apiVersion: "", metadata: { uid: "", name: 1, resourceVersion: "", selfLink: "" } }],
|
||||
["metadata.resourceVersion", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: 1, selfLink: "" } }],
|
||||
["metadata.selfLink", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: 1 } }],
|
||||
["metadata.namespace", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", namespace: 1 } }],
|
||||
["metadata.creationTimestamp", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", creationTimestamp: 1 } }],
|
||||
["metadata.continue", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", continue: 1 } }],
|
||||
["metadata.finalizers", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", finalizers: 1 } }],
|
||||
["metadata.finalizers", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", finalizers: [1] } }],
|
||||
["metadata.finalizers", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", finalizers: {} } }],
|
||||
["metadata.labels", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", labels: 1 } }],
|
||||
["metadata.labels", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", labels: { food: 1 } } }],
|
||||
["metadata.annotations", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", annotations: 1 } }],
|
||||
["metadata.annotations", { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", annotations: { food: 1 } } }],
|
||||
];
|
||||
|
||||
it.each(tests)("should reject with wrong type for field: %s", (missingField, input) => {
|
||||
expect(KubeObject.isPartialJsonApiData(input)).toBe(false);
|
||||
});
|
||||
}
|
||||
|
||||
it("should accept valid Partial<KubeJsonApiData> (ignoring other fields)", () => {
|
||||
const valid = { kind: "", apiVersion: "", metadata: { uid: "", name: "", resourceVersion: "", selfLink: "", annotations: { food: "" } } };
|
||||
|
||||
expect(KubeObject.isPartialJsonApiData(valid)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isJsonApiDataList", () => {
|
||||
function isAny(val: unknown): val is any {
|
||||
return !Boolean(void val);
|
||||
}
|
||||
|
||||
function isNotAny(val: unknown): val is any {
|
||||
return Boolean(void val);
|
||||
}
|
||||
|
||||
function isBoolean(val: unknown): val is Boolean {
|
||||
return typeof val === "boolean";
|
||||
}
|
||||
|
||||
{
|
||||
type TestCase = [any];
|
||||
const tests: TestCase[] = [
|
||||
[false],
|
||||
[true],
|
||||
[null],
|
||||
[undefined],
|
||||
[""],
|
||||
[1],
|
||||
[(): unknown => void 0],
|
||||
[Symbol("hello")],
|
||||
[{}],
|
||||
];
|
||||
|
||||
it.each(tests)("should reject invalid value: %p", (input) => {
|
||||
expect(KubeObject.isJsonApiDataList(input, isAny)).toBe(false);
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
type TestCase = [string, any];
|
||||
const tests: TestCase[] = [
|
||||
["kind", { apiVersion: "", items: [], metadata: { resourceVersion: "", selfLink: "" } }],
|
||||
["apiVersion", { kind: "", items: [], metadata: { resourceVersion: "", selfLink: "" } }],
|
||||
["metadata", { kind: "", items: [], apiVersion: "" }],
|
||||
];
|
||||
|
||||
it.each(tests)("should reject with missing: %s", (missingField, input) => {
|
||||
expect(KubeObject.isJsonApiDataList(input, isAny)).toBe(false);
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
type TestCase = [string, any];
|
||||
const tests: TestCase[] = [
|
||||
["kind", { kind: 1, items: [], apiVersion: "", metadata: { resourceVersion: "", selfLink: "" } }],
|
||||
["apiVersion", { kind: "", items: [], apiVersion: 1, metadata: { resourceVersion: "", selfLink: "" } }],
|
||||
["metadata", { kind: "", items: [], apiVersion: "", metadata: 1 }],
|
||||
["metadata.resourceVersion", { kind: "", items: [], apiVersion: "", metadata: { resourceVersion: 1, selfLink: "" } }],
|
||||
["metadata.selfLink", { kind: "", items: [], apiVersion: "", metadata: { resourceVersion: "", selfLink: 1 } }],
|
||||
["items", { kind: "", items: 1, apiVersion: "", metadata: { resourceVersion: "", selfLink: "" } }],
|
||||
["items", { kind: "", items: "", apiVersion: "", metadata: { resourceVersion: "", selfLink: "" } }],
|
||||
["items", { kind: "", items: {}, apiVersion: "", metadata: { resourceVersion: "", selfLink: "" } }],
|
||||
["items[0]", { kind: "", items: [""], apiVersion: "", metadata: { resourceVersion: "", selfLink: "" } }],
|
||||
];
|
||||
|
||||
it.each(tests)("should reject with wrong type for field: %s", (missingField, input) => {
|
||||
expect(KubeObject.isJsonApiDataList(input, isNotAny)).toBe(false);
|
||||
});
|
||||
}
|
||||
|
||||
it("should accept valid KubeJsonApiDataList (ignoring other fields)", () => {
|
||||
const valid = { kind: "", items: [false], apiVersion: "", metadata: { resourceVersion: "", selfLink: "" } };
|
||||
|
||||
expect(KubeObject.isJsonApiDataList(valid, isBoolean)).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,38 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { Pod } from "../endpoints";
|
||||
|
||||
describe("Pod tests", () => {
|
||||
it("getAllContainers() should never throw", () => {
|
||||
const pod = new Pod({
|
||||
apiVersion: "foo",
|
||||
kind: "Pod",
|
||||
metadata: {
|
||||
name: "foobar",
|
||||
resourceVersion: "foobar",
|
||||
uid: "foobar",
|
||||
},
|
||||
});
|
||||
|
||||
expect(pod.getAllContainers()).toStrictEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -1,324 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { Pod } from "../endpoints";
|
||||
|
||||
interface GetDummyPodOptions {
|
||||
running?: number;
|
||||
dead?: number;
|
||||
initRunning?: number;
|
||||
initDead?: number;
|
||||
}
|
||||
|
||||
function getDummyPodDefaultOptions(): Required<GetDummyPodOptions> {
|
||||
return {
|
||||
running: 0,
|
||||
dead: 0,
|
||||
initDead: 0,
|
||||
initRunning: 0,
|
||||
};
|
||||
}
|
||||
|
||||
function getDummyPod(opts: GetDummyPodOptions = getDummyPodDefaultOptions()): Pod {
|
||||
const pod = new Pod({
|
||||
apiVersion: "v1",
|
||||
kind: "Pod",
|
||||
metadata: {
|
||||
uid: "1",
|
||||
name: "test",
|
||||
resourceVersion: "v1",
|
||||
selfLink: "http"
|
||||
}
|
||||
});
|
||||
|
||||
pod.spec = {
|
||||
containers: [],
|
||||
initContainers: [],
|
||||
serviceAccount: "dummy",
|
||||
serviceAccountName: "dummy",
|
||||
};
|
||||
|
||||
pod.status = {
|
||||
phase: "Running",
|
||||
conditions: [],
|
||||
hostIP: "10.0.0.1",
|
||||
podIP: "10.0.0.1",
|
||||
startTime: "now",
|
||||
containerStatuses: [],
|
||||
initContainerStatuses: [],
|
||||
};
|
||||
|
||||
for (let i = 0; i < opts.running; i += 1) {
|
||||
const name = `container_r_${i}`;
|
||||
|
||||
pod.spec.containers.push({
|
||||
image: "dummy",
|
||||
imagePullPolicy: "dummy",
|
||||
name,
|
||||
});
|
||||
pod.status.containerStatuses.push({
|
||||
image: "dummy",
|
||||
imageID: "dummy",
|
||||
name,
|
||||
ready: true,
|
||||
restartCount: i,
|
||||
state: {
|
||||
running: {
|
||||
startedAt: "before"
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (let i = 0; i < opts.dead; i += 1) {
|
||||
const name = `container_d_${i}`;
|
||||
|
||||
pod.spec.containers.push({
|
||||
image: "dummy",
|
||||
imagePullPolicy: "dummy",
|
||||
name,
|
||||
});
|
||||
pod.status.containerStatuses.push({
|
||||
image: "dummy",
|
||||
imageID: "dummy",
|
||||
name,
|
||||
ready: false,
|
||||
restartCount: i,
|
||||
state: {
|
||||
terminated: {
|
||||
startedAt: "before",
|
||||
exitCode: i+1,
|
||||
finishedAt: "later",
|
||||
reason: `reason_${i}`
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (let i = 0; i < opts.initRunning; i += 1) {
|
||||
const name = `container_ir_${i}`;
|
||||
|
||||
pod.spec.initContainers.push({
|
||||
image: "dummy",
|
||||
imagePullPolicy: "dummy",
|
||||
name,
|
||||
});
|
||||
pod.status.initContainerStatuses.push({
|
||||
image: "dummy",
|
||||
imageID: "dummy",
|
||||
name,
|
||||
ready: true,
|
||||
restartCount: i,
|
||||
state: {
|
||||
running: {
|
||||
startedAt: "before"
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (let i = 0; i < opts.initDead; i += 1) {
|
||||
const name = `container_id_${i}`;
|
||||
|
||||
pod.spec.initContainers.push({
|
||||
image: "dummy",
|
||||
imagePullPolicy: "dummy",
|
||||
name,
|
||||
});
|
||||
pod.status.initContainerStatuses.push({
|
||||
image: "dummy",
|
||||
imageID: "dummy",
|
||||
name,
|
||||
ready: false,
|
||||
restartCount: i,
|
||||
state: {
|
||||
terminated: {
|
||||
startedAt: "before",
|
||||
exitCode: i+1,
|
||||
finishedAt: "later",
|
||||
reason: `reason_${i}`
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return pod;
|
||||
}
|
||||
|
||||
describe("Pods", () => {
|
||||
const podTests = [];
|
||||
|
||||
for (let r = 0; r < 3; r += 1) {
|
||||
for (let d = 0; d < 3; d += 1) {
|
||||
for (let ir = 0; ir < 3; ir += 1) {
|
||||
for (let id = 0; id < 3; id += 1) {
|
||||
podTests.push([r, d, ir, id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
describe.each(podTests)("for [%d running, %d dead] & initial [%d running, %d dead]", (running, dead, initRunning, initDead) => {
|
||||
const pod = getDummyPod({ running, dead, initRunning, initDead });
|
||||
|
||||
function getNamedContainer(name: string) {
|
||||
return {
|
||||
image: "dummy",
|
||||
imagePullPolicy: "dummy",
|
||||
name
|
||||
};
|
||||
}
|
||||
|
||||
it("getRunningContainers should return only running and init running", () => {
|
||||
const res = [
|
||||
...Array.from(new Array(running), (val, index) => getNamedContainer(`container_r_${index}`)),
|
||||
...Array.from(new Array(initRunning), (val, index) => getNamedContainer(`container_ir_${index}`)),
|
||||
];
|
||||
|
||||
expect(pod.getRunningContainers()).toStrictEqual(res);
|
||||
});
|
||||
|
||||
it("getAllContainers should return all containers", () => {
|
||||
const res = [
|
||||
...Array.from(new Array(running), (val, index) => getNamedContainer(`container_r_${index}`)),
|
||||
...Array.from(new Array(dead), (val, index) => getNamedContainer(`container_d_${index}`)),
|
||||
...Array.from(new Array(initRunning), (val, index) => getNamedContainer(`container_ir_${index}`)),
|
||||
...Array.from(new Array(initDead), (val, index) => getNamedContainer(`container_id_${index}`)),
|
||||
];
|
||||
|
||||
expect(pod.getAllContainers()).toStrictEqual(res);
|
||||
});
|
||||
|
||||
it("getRestartsCount should return total restart counts", () => {
|
||||
function sum(len: number): number {
|
||||
let res = 0;
|
||||
|
||||
for (let i = 0; i < len; i += 1) {
|
||||
res += i;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
expect(pod.getRestartsCount()).toStrictEqual(sum(running) + sum(dead));
|
||||
});
|
||||
|
||||
it("hasIssues should return false", () => {
|
||||
expect(pod.hasIssues()).toStrictEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getSelectedNodeOs", () => {
|
||||
it("should return stable", () => {
|
||||
const pod = getDummyPod();
|
||||
|
||||
pod.spec.nodeSelector = {
|
||||
"kubernetes.io/os": "foobar"
|
||||
};
|
||||
|
||||
expect(pod.getSelectedNodeOs()).toStrictEqual("foobar");
|
||||
});
|
||||
|
||||
it("should return beta", () => {
|
||||
const pod = getDummyPod();
|
||||
|
||||
pod.spec.nodeSelector = {
|
||||
"beta.kubernetes.io/os": "foobar1"
|
||||
};
|
||||
|
||||
expect(pod.getSelectedNodeOs()).toStrictEqual("foobar1");
|
||||
});
|
||||
|
||||
it("should return stable over beta", () => {
|
||||
const pod = getDummyPod();
|
||||
|
||||
pod.spec.nodeSelector = {
|
||||
"kubernetes.io/os": "foobar2",
|
||||
"beta.kubernetes.io/os": "foobar3"
|
||||
};
|
||||
|
||||
expect(pod.getSelectedNodeOs()).toStrictEqual("foobar2");
|
||||
});
|
||||
|
||||
it("should return undefined if none set", () => {
|
||||
const pod = getDummyPod();
|
||||
|
||||
expect(pod.getSelectedNodeOs()).toStrictEqual(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe("hasIssues", () => {
|
||||
it("should return true if a condition isn't ready", () => {
|
||||
const pod = getDummyPod({ running: 1 });
|
||||
|
||||
pod.status.conditions.push({
|
||||
type: "Ready",
|
||||
status: "foobar",
|
||||
lastProbeTime: 1,
|
||||
lastTransitionTime: "longer ago"
|
||||
});
|
||||
|
||||
expect(pod.hasIssues()).toStrictEqual(true);
|
||||
});
|
||||
|
||||
it("should return false if a condition is non-ready", () => {
|
||||
const pod = getDummyPod({ running: 1 });
|
||||
|
||||
pod.status.conditions.push({
|
||||
type: "dummy",
|
||||
status: "foobar",
|
||||
lastProbeTime: 1,
|
||||
lastTransitionTime: "longer ago"
|
||||
});
|
||||
|
||||
expect(pod.hasIssues()).toStrictEqual(false);
|
||||
});
|
||||
|
||||
it("should return true if a current container is in a crash loop back off", () => {
|
||||
const pod = getDummyPod({ running: 1 });
|
||||
|
||||
pod.status.containerStatuses[0].state = {
|
||||
waiting: {
|
||||
reason: "CrashLookBackOff",
|
||||
message: "too much foobar"
|
||||
}
|
||||
};
|
||||
|
||||
expect(pod.hasIssues()).toStrictEqual(true);
|
||||
});
|
||||
|
||||
it("should return true if a current phase isn't running", () => {
|
||||
const pod = getDummyPod({ running: 1 });
|
||||
|
||||
pod.status.phase = "not running";
|
||||
|
||||
expect(pod.hasIssues()).toStrictEqual(true);
|
||||
});
|
||||
|
||||
it("should return false if a current phase is running", () => {
|
||||
const pod = getDummyPod({ running: 1 });
|
||||
|
||||
pod.status.phase = "Running";
|
||||
|
||||
expect(pod.hasIssues()).toStrictEqual(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user