1 package iplookup
2
3 import (
4 "context"
5 "math"
6 "net"
7 "testing"
8
9 "github.com/stretchr/testify/assert"
10
11 "edge-infra.dev/pkg/lib/fog"
12 "edge-infra.dev/pkg/lib/logging"
13
14 v1 "k8s.io/api/core/v1"
15 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
16 "k8s.io/client-go/kubernetes"
17 "k8s.io/client-go/kubernetes/fake"
18 "k8s.io/client-go/rest"
19 )
20
21 var (
22 NODES = []string{"ien-1", "ien-2", "ien-3"}
23 PODS = []string{"pod-1", "pod-2", "pod-3"}
24 DS = "daemonset"
25 NS = "default"
26 QUERY = Query{
27 Namespace: NS,
28 Daemonset: DS,
29 }
30 IPS = []string{"109.137.186.131", "240.182.74.195", "161.18.36.28"}
31
32 FakeClusterConfig = func() (*rest.Config, error) { return &rest.Config{}, nil }
33 TestLogger = logging.NewLogger().WithName("iplookup_test")
34 )
35
36 func TestGetDaemonsetPodIP(t *testing.T) {
37 tests := map[string]func(t *testing.T){
38 "Ideal State": testSuccessIdealState,
39 "No Config": testFailNoConfig,
40 "Empty Daemonset": testFailEmptyDaemonset,
41 "Empty Namespace": testFailEmptyNamespace,
42 }
43 for desc, test := range tests {
44 t.Run(desc, func(t *testing.T) { test(t) })
45 }
46 }
47
48 func TestDaemonsetPodIPLookup(t *testing.T) {
49 tests := map[string]func(t *testing.T){
50 "One-Node Network": testSuccessOneNode,
51 "Multi-Node Network": testSuccessMultipleNodes,
52 "Empty Node Name": testFailEmptyNodeID,
53 "Node Name Not In Cluster": testFailInvalidNodeID,
54 "Namespace Not In Cluster": testFailInvalidNamespace,
55 "Daemonset Not In Cluster": testFailInvalidDaemonset,
56 "Empty Client": testFailEmptyClient,
57 "Empty Clientset": testFailEmptyClientset,
58 "Invalid IP Address": testFailInvalidIP,
59 }
60 for desc, test := range tests {
61 t.Run(desc, func(t *testing.T) { test(t) })
62 }
63 }
64
65 func defaultFakeClientset() kubernetes.Interface {
66 return fake.NewSimpleClientset(createPod(PODS[0], NS, DS, NODES[0], IPS[0]))
67 }
68
69 func createPod(name string, namespace string, dsName string, node string, ip string) *v1.Pod {
70 return &v1.Pod{
71 ObjectMeta: metav1.ObjectMeta{
72 Name: name,
73 Namespace: namespace,
74 OwnerReferences: []metav1.OwnerReference{
75 {
76 Name: dsName,
77 Kind: "DaemonSet",
78 },
79 },
80 },
81 Spec: v1.PodSpec{
82 NodeName: node,
83 },
84 Status: v1.PodStatus{
85 PodIP: ip,
86 },
87 }
88 }
89 func createPods(n int) []*v1.Pod {
90 n = int(math.Max(float64(n), float64(len(NODES))))
91 objects := make([]*v1.Pod, 0)
92 for i := 0; i < n; i++ {
93 objects = append(objects, createPod(PODS[i], NS, DS, NODES[i], IPS[i]))
94 }
95 return objects
96 }
97
98
99 func testSuccessIdealState(t *testing.T) {
100 ctx := fog.IntoContext(context.Background(), TestLogger)
101
102 c, _ := FakeClusterConfig()
103 cs, err := kubernetes.NewForConfig(c)
104 assert.NoError(t, err)
105
106 ip := IPLookup{cs}
107
108 _, err = ip.GetDaemonsetPodIP(ctx, NODES[0], QUERY)
109 assert.ErrorContains(t, err, "failed to query kubernetes client")
110 }
111
112 func testFailNoConfig(t *testing.T) {
113 _, err := New()
114 assert.Error(t, err, ErrNotInCluster)
115 }
116
117 func testFailEmptyDaemonset(t *testing.T) {
118 ip := IPLookup{}
119 ctx := fog.IntoContext(context.Background(), TestLogger)
120 queryWithEmptyDaemonset := Query{Namespace: NS, Daemonset: ""}
121 _, err := ip.GetDaemonsetPodIP(ctx, NODES[0], queryWithEmptyDaemonset)
122 assert.ErrorIs(t, ErrInvalidQuery, err)
123 }
124
125 func testFailEmptyNamespace(t *testing.T) {
126 ip := IPLookup{}
127 ctx := fog.IntoContext(context.Background(), TestLogger)
128 queryWithEmptyNamespace := Query{Namespace: "", Daemonset: DS}
129 _, err := ip.GetDaemonsetPodIP(ctx, NODES[0], queryWithEmptyNamespace)
130 assert.ErrorIs(t, ErrInvalidQuery, err)
131 }
132
133
134 func testSuccessOneNode(t *testing.T) {
135 ctx := fog.IntoContext(context.Background(), TestLogger)
136 clientset := defaultFakeClientset()
137
138 iplookup := IPLookup{clientset: clientset}
139
140 ip, err := iplookup.daemonsetPodIPLookup(ctx, NODES[0], QUERY)
141 assert.NoError(t, err)
142 assert.Equal(t, ip, net.ParseIP(IPS[0]))
143 }
144
145 func testSuccessMultipleNodes(t *testing.T) {
146 ctx := fog.IntoContext(context.Background(), TestLogger)
147 objects := createPods(3)
148 clientset := fake.NewSimpleClientset(objects[0], objects[1], objects[2])
149
150 iplookup := IPLookup{clientset}
151
152 for i := 0; i < 3; i++ {
153 ip, err := iplookup.GetDaemonsetPodIP(ctx, NODES[i], QUERY)
154 assert.NoError(t, err)
155 assert.Equal(t, ip, net.ParseIP(IPS[i]))
156 }
157 }
158
159 func testFailEmptyNodeID(t *testing.T) {
160 ctx := fog.IntoContext(context.Background(), TestLogger)
161 iplookup := IPLookup{defaultFakeClientset()}
162 _, err := iplookup.GetDaemonsetPodIP(ctx, "", QUERY)
163 assert.ErrorIs(t, err, ErrNoReturn)
164 }
165
166 func testFailInvalidNodeID(t *testing.T) {
167 ctx := fog.IntoContext(context.Background(), TestLogger)
168 iplookup := IPLookup{defaultFakeClientset()}
169 _, err := iplookup.GetDaemonsetPodIP(ctx, "ien-that-does-not-exist", QUERY)
170 assert.ErrorIs(t, err, ErrNoReturn)
171 }
172
173 func testFailInvalidNamespace(t *testing.T) {
174 ctx := fog.IntoContext(context.Background(), TestLogger)
175 iplookup := IPLookup{defaultFakeClientset()}
176 queryWithInvalidNamespace := Query{Namespace: "namespace-not-in-network", Daemonset: DS}
177 _, err := iplookup.GetDaemonsetPodIP(ctx, NODES[0], queryWithInvalidNamespace)
178 assert.ErrorIs(t, err, ErrNoReturn)
179 }
180
181 func testFailInvalidDaemonset(t *testing.T) {
182 ctx := fog.IntoContext(context.Background(), TestLogger)
183 iplookup := IPLookup{defaultFakeClientset()}
184 queryWithInvalidDaemonset := Query{Namespace: NS, Daemonset: "daemonset-not-in-network"}
185 _, err := iplookup.GetDaemonsetPodIP(ctx, NODES[0], queryWithInvalidDaemonset)
186 assert.ErrorIs(t, err, ErrNoReturn)
187 }
188
189 func testFailEmptyClient(t *testing.T) {
190 ctx := fog.IntoContext(context.Background(), TestLogger)
191 iplookup := IPLookup{defaultFakeClientset()}
192 _, err := iplookup.GetDaemonsetPodIP(ctx, NODES[0], Query{})
193 assert.ErrorIs(t, err, ErrInvalidQuery)
194 }
195
196 func testFailEmptyClientset(t *testing.T) {
197 ctx := fog.IntoContext(context.Background(), TestLogger)
198 clientset := fake.NewSimpleClientset()
199 iplookup := IPLookup{clientset}
200
201 _, err := iplookup.GetDaemonsetPodIP(ctx, NODES[0], QUERY)
202 assert.ErrorIs(t, err, ErrNoReturn)
203 }
204
205 func testFailInvalidIP(t *testing.T) {
206 ctx := fog.IntoContext(context.Background(), TestLogger)
207
208 clientset := fake.NewSimpleClientset(createPod(PODS[0], NS, DS, NODES[0], ""))
209 iplookup := IPLookup{clientset}
210
211 _, err := iplookup.GetDaemonsetPodIP(ctx, NODES[0], QUERY)
212 assert.ErrorIs(t, err, ErrInvalidIP)
213 }
214
View as plain text