import { getKubectlPath, Kubectl } from "./kubectl"; import * as exec from "@actions/exec"; import * as io from "@actions/io"; import * as core from "@actions/core"; import * as toolCache from "@actions/tool-cache"; import { config } from "process"; describe("Kubectl path", () => { const version = "1.1"; const path = "path"; it("gets the kubectl path", async () => { jest.spyOn(core, "getInput").mockImplementationOnce(() => undefined); jest.spyOn(io, "which").mockImplementationOnce(async () => path); expect(await getKubectlPath()).toBe(path); }); it("gets the kubectl path with version", async () => { jest.spyOn(core, "getInput").mockImplementationOnce(() => version); jest.spyOn(toolCache, "find").mockImplementationOnce(() => path); expect(await getKubectlPath()).toBe(path); }); it("throws if kubectl not found", async () => { // without version jest.spyOn(io, "which").mockImplementationOnce(async () => undefined); await expect(() => getKubectlPath()).rejects.toThrow(); // with verision jest.spyOn(core, "getInput").mockImplementationOnce(() => undefined); jest.spyOn(io, "which").mockImplementationOnce(async () => undefined); await expect(() => getKubectlPath()).rejects.toThrow(); }); }); const kubectlPath = "kubectlPath"; const testNamespace = "testNamespace"; const defaultNamespace = "default"; describe("Kubectl class", () => { describe("default namespace behavior", () => { const kubectl = new Kubectl(kubectlPath, defaultNamespace); const execReturn = { exitCode: 0, stdout: "Output", stderr: "" }; beforeEach(() => { jest.spyOn(exec, "getExecOutput").mockImplementation(async () => { return execReturn; }); }); describe("omits default namespace from commands", () => { it("executes a command without appending --namespace arg", async () => { // no args const command = "command"; expect(await kubectl.executeCommand(command)).toBe(execReturn); expect(exec.getExecOutput).toBeCalledWith( kubectlPath, [command], { silent: false } ); }); }); }); describe("with a success exec return in testNamespace", () => { const kubectl = new Kubectl(kubectlPath, testNamespace); const execReturn = { exitCode: 0, stdout: "Output", stderr: "" }; beforeEach(() => { jest.spyOn(exec, "getExecOutput").mockImplementation(async () => { return execReturn; }); }); it("applies a configuration with a single config path", async () => { const configPaths = "configPaths"; const result = await kubectl.apply(configPaths); expect(result).toBe(execReturn); expect(exec.getExecOutput).toBeCalledWith( kubectlPath, ["apply", "-f", configPaths, "--namespace", testNamespace], { silent: false } ); }); it("applies a configuration with multiple config paths", async () => { const configPaths = ["configPath1", "configPath2", "configPath3"]; const result = await kubectl.apply(configPaths); expect(result).toBe(execReturn); expect(exec.getExecOutput).toBeCalledWith( kubectlPath, [ "apply", "-f", configPaths[0] + "," + configPaths[1] + "," + configPaths[2], "--namespace", testNamespace, ], { silent: false } ); }); it("applies a configuration with force when specified", async () => { const configPaths = ["configPath1", "configPath2", "configPath3"]; const result = await kubectl.apply(configPaths, true); expect(result).toBe(execReturn); expect(exec.getExecOutput).toBeCalledWith( kubectlPath, [ "apply", "-f", configPaths[0] + "," + configPaths[1] + "," + configPaths[2], "--force", "--namespace", testNamespace, ], { silent: false } ); }); it("describes a resource", async () => { const resourceType = "type"; const resourceName = "name"; const result = await kubectl.describe(resourceType, resourceName); expect(result).toBe(execReturn); expect(exec.getExecOutput).toBeCalledWith( kubectlPath, ["describe", resourceType, resourceName, "--namespace", testNamespace], { silent: false } ); }); it("describes a resource silently", async () => { const resourceType = "type"; const resourceName = "name"; const result = await kubectl.describe(resourceType, resourceName, true); expect(result).toBe(execReturn); expect(exec.getExecOutput).toBeCalledWith( kubectlPath, ["describe", resourceType, resourceName, "--namespace", testNamespace], { silent: true } ); }); it("annotates resource", async () => { const resourceType = "type"; const resourceName = "name"; const annotation = "annotation"; const result = await kubectl.annotate( resourceType, resourceName, annotation ); expect(result).toBe(execReturn); expect(exec.getExecOutput).toBeCalledWith( kubectlPath, [ "annotate", resourceType, resourceName, annotation, "--overwrite", "--namespace", testNamespace, ], { silent: false } ); }); it("annotates files with single file", async () => { const file = "file"; const annotation = "annotation"; const result = await kubectl.annotateFiles(file, annotation); expect(result).toBe(execReturn); expect(exec.getExecOutput).toBeCalledWith( kubectlPath, [ "annotate", "-f", file, annotation, "--overwrite", "--namespace", testNamespace, ], { silent: false } ); }); it("annotates files with mulitple files", async () => { const files = ["file1", "file2", "file3"]; const annotation = "annotation"; const result = await kubectl.annotateFiles(files, annotation); expect(result).toBe(execReturn); expect(exec.getExecOutput).toBeCalledWith( kubectlPath, [ "annotate", "-f", files.join(","), annotation, "--overwrite", "--namespace", testNamespace, ], { silent: false } ); }); it("labels files with single file", async () => { const file = "file"; const labels = ["label1", "label2"]; const result = await kubectl.labelFiles(file, labels); expect(result).toBe(execReturn); expect(exec.getExecOutput).toBeCalledWith( kubectlPath, [ "label", "-f", file, ...labels, "--overwrite", "--namespace", testNamespace, ], { silent: false } ); }); it("labels files with multiple files", async () => { const files = ["file1", "file2", "file3"]; const labels = ["label1", "label2"]; const result = await kubectl.labelFiles(files, labels); expect(result).toBe(execReturn); expect(exec.getExecOutput).toBeCalledWith( kubectlPath, [ "label", "-f", files.join(","), ...labels, "--overwrite", "--namespace", testNamespace, ], { silent: false } ); }); it("gets all pods", async () => { expect(await kubectl.getAllPods()).toBe(execReturn); expect(exec.getExecOutput).toBeCalledWith( kubectlPath, ["get", "pods", "-o", "json", "--namespace", testNamespace], { silent: true } ); }); it("checks rollout status", async () => { const resourceType = "type"; const name = "name"; expect(await kubectl.checkRolloutStatus(resourceType, name)).toBe( execReturn ); expect(exec.getExecOutput).toBeCalledWith( kubectlPath, [ "rollout", "status", `${resourceType}/${name}`, "--namespace", testNamespace, ], { silent: false } ); }); it("gets resource", async () => { const resourceType = "type"; const name = "name"; expect(await kubectl.getResource(resourceType, name)).toBe(execReturn); expect(exec.getExecOutput).toBeCalledWith( kubectlPath, [ "get", `${resourceType}/${name}`, "-o", "json", "--namespace", testNamespace, ], { silent: false } ); }); it("executes a command", async () => { // no args const command = "command"; expect(await kubectl.executeCommand(command)).toBe(execReturn); expect(exec.getExecOutput).toBeCalledWith( kubectlPath, [command, "--namespace", testNamespace], { silent: false } ); // with args const args = "args"; expect(await kubectl.executeCommand(command, args)).toBe(execReturn); expect(exec.getExecOutput).toBeCalledWith( kubectlPath, [command, args, "--namespace", testNamespace], { silent: false } ); }); it("deletes with single argument", async () => { const arg = "argument"; expect(await kubectl.delete(arg)).toBe(execReturn); expect(exec.getExecOutput).toBeCalledWith( kubectlPath, ["delete", arg, "--namespace", testNamespace], { silent: false } ); }); it("deletes with multiple arguments", async () => { const args = ["argument1", "argument2", "argument3"]; expect(await kubectl.delete(args)).toBe(execReturn); expect(exec.getExecOutput).toBeCalledWith( kubectlPath, ["delete", ...args, "--namespace", testNamespace], { silent: false } ); }); }); it("gets new replica sets", async () => { const kubectl = new Kubectl(kubectlPath, testNamespace); const newReplicaSetName = "newreplicaset"; const name = "name"; const describeReturn = { exitCode: 0, stdout: newReplicaSetName + name + " " + "extra", stderr: "", }; jest.spyOn(exec, "getExecOutput").mockImplementationOnce(async () => { return describeReturn; }); const deployment = "deployment"; const result = await kubectl.getNewReplicaSet(deployment); expect(result).toBe(name); }); });