package iplookup import ( "context" "math" "net" "testing" "github.com/stretchr/testify/assert" "edge-infra.dev/pkg/lib/fog" "edge-infra.dev/pkg/lib/logging" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/rest" ) var ( NODES = []string{"ien-1", "ien-2", "ien-3"} PODS = []string{"pod-1", "pod-2", "pod-3"} DS = "daemonset" NS = "default" QUERY = Query{ Namespace: NS, Daemonset: DS, } IPS = []string{"109.137.186.131", "240.182.74.195", "161.18.36.28"} FakeClusterConfig = func() (*rest.Config, error) { return &rest.Config{}, nil } TestLogger = logging.NewLogger().WithName("iplookup_test") ) func TestGetDaemonsetPodIP(t *testing.T) { tests := map[string]func(t *testing.T){ "Ideal State": testSuccessIdealState, "No Config": testFailNoConfig, "Empty Daemonset": testFailEmptyDaemonset, "Empty Namespace": testFailEmptyNamespace, } for desc, test := range tests { t.Run(desc, func(t *testing.T) { test(t) }) } } func TestDaemonsetPodIPLookup(t *testing.T) { tests := map[string]func(t *testing.T){ "One-Node Network": testSuccessOneNode, "Multi-Node Network": testSuccessMultipleNodes, "Empty Node Name": testFailEmptyNodeID, "Node Name Not In Cluster": testFailInvalidNodeID, "Namespace Not In Cluster": testFailInvalidNamespace, "Daemonset Not In Cluster": testFailInvalidDaemonset, "Empty Client": testFailEmptyClient, "Empty Clientset": testFailEmptyClientset, "Invalid IP Address": testFailInvalidIP, } for desc, test := range tests { t.Run(desc, func(t *testing.T) { test(t) }) } } func defaultFakeClientset() kubernetes.Interface { return fake.NewSimpleClientset(createPod(PODS[0], NS, DS, NODES[0], IPS[0])) } func createPod(name string, namespace string, dsName string, node string, ip string) *v1.Pod { return &v1.Pod{ ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: namespace, OwnerReferences: []metav1.OwnerReference{ { Name: dsName, Kind: "DaemonSet", }, }, }, Spec: v1.PodSpec{ NodeName: node, }, Status: v1.PodStatus{ PodIP: ip, }, } } func createPods(n int) []*v1.Pod { n = int(math.Max(float64(n), float64(len(NODES)))) objects := make([]*v1.Pod, 0) for i := 0; i < n; i++ { objects = append(objects, createPod(PODS[i], NS, DS, NODES[i], IPS[i])) } return objects } // GetDaemonsetPodIP tests func testSuccessIdealState(t *testing.T) { ctx := fog.IntoContext(context.Background(), TestLogger) c, _ := FakeClusterConfig() cs, err := kubernetes.NewForConfig(c) assert.NoError(t, err) ip := IPLookup{cs} _, err = ip.GetDaemonsetPodIP(ctx, NODES[0], QUERY) assert.ErrorContains(t, err, "failed to query kubernetes client") } func testFailNoConfig(t *testing.T) { _, err := New() assert.Error(t, err, ErrNotInCluster) } func testFailEmptyDaemonset(t *testing.T) { ip := IPLookup{} ctx := fog.IntoContext(context.Background(), TestLogger) queryWithEmptyDaemonset := Query{Namespace: NS, Daemonset: ""} _, err := ip.GetDaemonsetPodIP(ctx, NODES[0], queryWithEmptyDaemonset) assert.ErrorIs(t, ErrInvalidQuery, err) } func testFailEmptyNamespace(t *testing.T) { ip := IPLookup{} ctx := fog.IntoContext(context.Background(), TestLogger) queryWithEmptyNamespace := Query{Namespace: "", Daemonset: DS} _, err := ip.GetDaemonsetPodIP(ctx, NODES[0], queryWithEmptyNamespace) assert.ErrorIs(t, ErrInvalidQuery, err) } // daemonsetPodIPLookup tests func testSuccessOneNode(t *testing.T) { ctx := fog.IntoContext(context.Background(), TestLogger) clientset := defaultFakeClientset() iplookup := IPLookup{clientset: clientset} ip, err := iplookup.daemonsetPodIPLookup(ctx, NODES[0], QUERY) assert.NoError(t, err) assert.Equal(t, ip, net.ParseIP(IPS[0])) } func testSuccessMultipleNodes(t *testing.T) { ctx := fog.IntoContext(context.Background(), TestLogger) objects := createPods(3) clientset := fake.NewSimpleClientset(objects[0], objects[1], objects[2]) iplookup := IPLookup{clientset} for i := 0; i < 3; i++ { ip, err := iplookup.GetDaemonsetPodIP(ctx, NODES[i], QUERY) assert.NoError(t, err) assert.Equal(t, ip, net.ParseIP(IPS[i])) } } func testFailEmptyNodeID(t *testing.T) { ctx := fog.IntoContext(context.Background(), TestLogger) iplookup := IPLookup{defaultFakeClientset()} _, err := iplookup.GetDaemonsetPodIP(ctx, "", QUERY) assert.ErrorIs(t, err, ErrNoReturn) } func testFailInvalidNodeID(t *testing.T) { ctx := fog.IntoContext(context.Background(), TestLogger) iplookup := IPLookup{defaultFakeClientset()} _, err := iplookup.GetDaemonsetPodIP(ctx, "ien-that-does-not-exist", QUERY) assert.ErrorIs(t, err, ErrNoReturn) } func testFailInvalidNamespace(t *testing.T) { ctx := fog.IntoContext(context.Background(), TestLogger) iplookup := IPLookup{defaultFakeClientset()} queryWithInvalidNamespace := Query{Namespace: "namespace-not-in-network", Daemonset: DS} _, err := iplookup.GetDaemonsetPodIP(ctx, NODES[0], queryWithInvalidNamespace) assert.ErrorIs(t, err, ErrNoReturn) } func testFailInvalidDaemonset(t *testing.T) { ctx := fog.IntoContext(context.Background(), TestLogger) iplookup := IPLookup{defaultFakeClientset()} queryWithInvalidDaemonset := Query{Namespace: NS, Daemonset: "daemonset-not-in-network"} _, err := iplookup.GetDaemonsetPodIP(ctx, NODES[0], queryWithInvalidDaemonset) assert.ErrorIs(t, err, ErrNoReturn) } func testFailEmptyClient(t *testing.T) { ctx := fog.IntoContext(context.Background(), TestLogger) iplookup := IPLookup{defaultFakeClientset()} _, err := iplookup.GetDaemonsetPodIP(ctx, NODES[0], Query{}) assert.ErrorIs(t, err, ErrInvalidQuery) } func testFailEmptyClientset(t *testing.T) { ctx := fog.IntoContext(context.Background(), TestLogger) clientset := fake.NewSimpleClientset() iplookup := IPLookup{clientset} _, err := iplookup.GetDaemonsetPodIP(ctx, NODES[0], QUERY) assert.ErrorIs(t, err, ErrNoReturn) } func testFailInvalidIP(t *testing.T) { ctx := fog.IntoContext(context.Background(), TestLogger) clientset := fake.NewSimpleClientset(createPod(PODS[0], NS, DS, NODES[0], "")) iplookup := IPLookup{clientset} _, err := iplookup.GetDaemonsetPodIP(ctx, NODES[0], QUERY) assert.ErrorIs(t, err, ErrInvalidIP) }