From 17833498725d35ec118af13ada07fec9a8fa2cd2 Mon Sep 17 00:00:00 2001 From: catsby Date: Fri, 13 Dec 2024 17:11:33 -0600 Subject: [PATCH] add tests and pepr format Signed-off-by: catsby --- .../network/generators/kubeNodes.spec.ts | 181 ++++++++++-------- 1 file changed, 103 insertions(+), 78 deletions(-) diff --git a/src/pepr/operator/controllers/network/generators/kubeNodes.spec.ts b/src/pepr/operator/controllers/network/generators/kubeNodes.spec.ts index 62fb68ca6..3b69d7bf5 100644 --- a/src/pepr/operator/controllers/network/generators/kubeNodes.spec.ts +++ b/src/pepr/operator/controllers/network/generators/kubeNodes.spec.ts @@ -8,27 +8,17 @@ import { beforeEach, beforeAll, describe, expect, it, jest } from "@jest/globals import { initAllNodesTarget, nodeCIDRs, - // updateKubeNodesFromCreateUpdate, - // updateKubeNodesFromDelete, + updateKubeNodesFromCreateUpdate, + updateKubeNodesFromDelete, } from "./kubeNodes"; import { K8s, kind } from "pepr"; -// import { Component, setupLogger } from "../../../../logger"; +import { V1NetworkPolicyList } from "@kubernetes/client-node"; +import { anywhere } from "./anywhere"; type KubernetesList = { items: T[]; }; -// // Mock logger if needed -// jest.mock("../../../../logger", () => ({ -// Component: { OPERATOR_GENERATORS: "OPERATOR_GENERATORS" }, -// setupLogger: () => ({ -// info: jest.fn(), -// warn: jest.fn(), -// error: jest.fn(), -// debug: jest.fn(), -// }), -// })); - jest.mock("pepr", () => { const originalModule = jest.requireActual("pepr") as object; return { @@ -61,6 +51,30 @@ describe("kubeNodes module", () => { ], }; + const mockNetworkPolicyList: V1NetworkPolicyList = { + apiVersion: "networking.k8s.io/v1", + kind: "NetworkPolicyList", + items: [ + { + apiVersion: "networking.k8s.io/v1", + kind: "NetworkPolicy", + metadata: { + name: "example-policy", + namespace: "default", + }, + spec: { + podSelector: {}, // required field + policyTypes: ["Egress"], // or ["Ingress"], or both + egress: [ + { + to: [{ ipBlock: { cidr: "0.0.0.0/0" } }], // an IP we don't want + }, + ], + }, + }, + ], + }; + const mockK8sGetNodes = jest.fn<() => Promise>>(); const mockGetNetworkPolicies = jest.fn<() => Promise>>(); const mockApply = jest.fn(); @@ -77,13 +91,6 @@ describe("kubeNodes module", () => { beforeEach(() => { jest.clearAllMocks(); - (K8s as jest.Mock).mockImplementation(() => ({ - Get: mockK8sGetNodes, - WithLabel: jest.fn(() => ({ - Get: mockGetNetworkPolicies, - })), - Apply: mockApply, - })); }); describe("initAllNodesTarget", () => { @@ -100,74 +107,92 @@ describe("kubeNodes module", () => { ]), ); }); - - // it("should handle errors and default to anywhere if no nodes", async () => { - // mockK8sGetNodes.mockRejectedValueOnce(new Error("Network Error")); - // await initAllNodesTarget(); - // const cidrs = nodeCIDRs(); - // // Expect fallback to anywhere - // expect(cidrs).toEqual([{ ipBlock: { cidr: "0.0.0.0/0" } }]); - // }); }); describe("nodeCIDRs", () => { - it("should return CIDRs for currently known nodes", async () => { - mockK8sGetNodes.mockResolvedValue(mockNodeList); + it("should return anywhere if no nodes known", async () => { + mockK8sGetNodes.mockResolvedValue({ items: [] }); await initAllNodesTarget(); const cidrs = nodeCIDRs(); - expect(cidrs).toHaveLength(2); + // expect it to match "anywhere" + expect(cidrs).toEqual([anywhere]); + }); + }); + + describe("updateKubeNodesFromCreateUpdate", () => { + it("should add a node IP if node is ready", async () => { + mockK8sGetNodes.mockResolvedValueOnce({ items: [] }); + mockGetNetworkPolicies.mockResolvedValue(mockNetworkPolicyList); + await initAllNodesTarget(); // start empty + await updateKubeNodesFromCreateUpdate(mockNodeList.items[0]); + let cidrs = nodeCIDRs(); + expect(cidrs).toHaveLength(1); expect(cidrs[0].ipBlock?.cidr).toBe("10.0.0.1/32"); + expect(mockApply).toHaveBeenCalled(); + + await updateKubeNodesFromCreateUpdate(mockNodeList.items[1]); + cidrs = nodeCIDRs(); + expect(cidrs).toHaveLength(2); expect(cidrs[1].ipBlock?.cidr).toBe("10.0.0.2/32"); + expect(mockApply).toHaveBeenCalled(); }); - it("should return anywhere if no nodes known", async () => { - mockK8sGetNodes.mockResolvedValue({ items: [] }); - await initAllNodesTarget(); + it("should not add a node IP if node not ready", async () => { + const notReadyNode = { + metadata: { name: "node3" }, + status: { + addresses: [{ type: "InternalIP", address: "10.0.0.3" }], + conditions: [{ type: "Ready", status: "False" }], + }, + }; + mockK8sGetNodes.mockResolvedValueOnce({ items: [] }); + await initAllNodesTarget(); // start empty + await updateKubeNodesFromCreateUpdate(notReadyNode); const cidrs = nodeCIDRs(); - expect(cidrs).toEqual([{ ipBlock: { cidr: "0.0.0.0/0" } }]); + expect(cidrs).toEqual([anywhere]); + expect(mockApply).toHaveBeenCalled(); // Still called to update polices even if empty + }); + + it("should remove a node that's no longer ready", async () => { + mockK8sGetNodes.mockResolvedValue(mockNodeList); + await initAllNodesTarget(); + let cidrs = nodeCIDRs(); + // Should have two IPs from mockNodeList + expect(cidrs).toHaveLength(2); + expect(cidrs).toEqual( + expect.arrayContaining([ + { ipBlock: { cidr: "10.0.0.1/32" } }, + { ipBlock: { cidr: "10.0.0.2/32" } }, + ]), + ); + + const notReadyNode = { + metadata: { name: "node2" }, + status: { + addresses: [{ type: "InternalIP", address: "10.0.0.1" }], + conditions: [{ type: "Ready", status: "False" }], + }, + }; + await updateKubeNodesFromCreateUpdate(notReadyNode); + cidrs = nodeCIDRs(); + expect(cidrs).toHaveLength(1); + expect(cidrs).toEqual(expect.arrayContaining([{ ipBlock: { cidr: "10.0.0.2/32" } }])); + expect(mockApply).toHaveBeenCalled(); // Still called to update polices even if empty }); }); - // describe("updateKubeNodesFromCreateUpdate", () => { - // it("should add a node IP if node is ready", async () => { - // mockK8sGet.mockResolvedValueOnce({ items: [] }); - // await initAllNodesTarget(); // start empty - // await updateKubeNodesFromCreateUpdate(mockNodeList.items[0]); - // const cidrs = nodeCIDRs(); - // expect(cidrs).toHaveLength(1); - // expect(cidrs[0].ipBlock?.cidr).toBe("10.0.0.1/32"); - // expect(mockK8sApply).toHaveBeenCalled(); - // }); - - // it("should not add a node IP if node not ready", async () => { - // const notReadyNode = { - // metadata: { name: "node3" }, - // status: { - // addresses: [{ type: "InternalIP", address: "10.0.0.3" }], - // conditions: [{ type: "Ready", status: "False" }], - // }, - // }; - // mockK8sGet.mockResolvedValueOnce({ items: [] }); - // await initAllNodesTarget(); // start empty - // await updateKubeNodesFromCreateUpdate(notReadyNode); - // const cidrs = nodeCIDRs(); - // expect(cidrs).toEqual([{ ipBlock: { cidr: "0.0.0.0/0" } }]); // no change - // expect(mockK8sApply).toHaveBeenCalled(); // Still called to update polices even if empty - // }); - // }); - - // describe("updateKubeNodesFromDelete", () => { - // it("should remove the node IP from nodeSet", async () => { - // mockK8sGet.mockResolvedValueOnce(mockNodeList); - // await initAllNodesTarget(); - // const cidrsBeforeDelete = nodeCIDRs(); - // expect(cidrsBeforeDelete).toHaveLength(2); - - // await updateKubeNodesFromDelete(mockNodeList.items[0]); - // const cidrsAfterDelete = nodeCIDRs(); - // expect(cidrsAfterDelete).toHaveLength(1); - // expect(cidrsAfterDelete[0].ipBlock?.cidr).toBe("10.0.0.2/32"); - // expect(mockK8sApply).toHaveBeenCalled(); - // }); - // }); + describe("updateKubeNodesFromDelete", () => { + it("should remove the node IP from nodeSet", async () => { + mockK8sGetNodes.mockResolvedValueOnce(mockNodeList); + await initAllNodesTarget(); + const cidrsBeforeDelete = nodeCIDRs(); + expect(cidrsBeforeDelete).toHaveLength(2); + + await updateKubeNodesFromDelete(mockNodeList.items[0]); + const cidrsAfterDelete = nodeCIDRs(); + expect(cidrsAfterDelete).toHaveLength(1); + expect(cidrsAfterDelete[0].ipBlock?.cidr).toBe("10.0.0.2/32"); + expect(mockApply).toHaveBeenCalled(); + }); + }); });