1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00
lens/src/common/k8s-api/__tests__/pods.test.ts
Jari Kolehmainen 58a446bd45
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>
2021-08-10 13:26:14 +03:00

325 lines
8.2 KiB
TypeScript

/**
* 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);
});
});
});