1 package services
2
3 import (
4 "context"
5 "net/http"
6 "net/http/httptest"
7 "testing"
8
9 "github.com/gin-gonic/gin"
10 "github.com/stretchr/testify/assert"
11 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12 "sigs.k8s.io/controller-runtime/pkg/client"
13 "sigs.k8s.io/controller-runtime/pkg/client/fake"
14
15 api "edge-infra.dev/pkg/edge/device-registrar/api/v1alpha1"
16 )
17
18 func injectmockClientDiscover(router *gin.Engine, mockClient client.Client, t *testing.T) {
19 router.Use(
20
21 func(c *gin.Context) {
22 c.Set("k8sClient", mockClient)
23 c.Next()
24
25 k8sClient, exists := c.Get("k8sClient")
26
27
28 assert.True(t, exists, "k8sClient should exist in the context")
29 assert.NotNil(t, k8sClient, "k8sClient should not be nil")
30 },
31 )
32 }
33
34 func TestDiscovery(t *testing.T) {
35 router, scheme := setupTest()
36
37 discovery := api.Discovery{
38 ObjectMeta: metav1.ObjectMeta{
39 Name: "example",
40 Namespace: "device-registrar-clients",
41 },
42 Spec: api.DiscoverySpec{
43 Name: "example-discovery",
44 URL: "example-url.com/config",
45 },
46 }
47
48 device := api.ExternalDevice{
49 ObjectMeta: metav1.ObjectMeta{
50 Name: "example",
51 Namespace: "device-registrar-clients",
52 },
53 Spec: api.ExternalDeviceSpec{
54 SN: "my-serial-number",
55 Name: "test-device-name",
56 },
57 }
58
59 mockClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&discovery, &device).Build()
60
61 injectmockClientDiscover(router, mockClient, t)
62
63
64 router.GET("/discover/:serviceName", DiscoverService)
65
66
67 req, _ := http.NewRequest(http.MethodGet, "/discover/example-discovery", nil)
68 req.Header.Set("X-Client-DN", "OU=urn:storeID:my-store-id=urn:deviceName:test-device-name+OU=urn:SN:my-serial-number")
69
70 w := httptest.NewRecorder()
71 router.ServeHTTP(w, req)
72
73
74 assert.Equal(t, http.StatusOK, w.Code, "Expected status code 200")
75
76 assert.Contains(t, w.Body.String(), "name")
77 assert.Contains(t, w.Body.String(), "url")
78
79 assert.Equal(t, w.Body.String(), `{"name":"example-discovery","url":"example-url.com/config"}`)
80 }
81
82 func TestNoDiscovery(t *testing.T) {
83 router, scheme := setupTest()
84
85 device := api.ExternalDevice{
86 ObjectMeta: metav1.ObjectMeta{
87 Name: "example",
88 Namespace: "device-registrar-clients",
89 },
90 Spec: api.ExternalDeviceSpec{
91 SN: "my-serial-number",
92 Name: "test-device-name",
93 },
94 }
95
96 mockClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&device).Build()
97
98 injectmockClientDiscover(router, mockClient, t)
99
100
101 router.GET("/discover/:serviceName", DiscoverService)
102
103
104 req, _ := http.NewRequest(http.MethodGet, "/discover/example-discovery", nil)
105 req.Header.Set("X-Client-DN", "OU=urn:storeID:my-store-id=urn:deviceName:test-device-name+OU=urn:SN:my-serial-number")
106
107 w := httptest.NewRecorder()
108 router.ServeHTTP(w, req)
109
110
111 assert.Equal(t, http.StatusOK, w.Code, "Expected status code 200")
112
113 assert.Contains(t, w.Body.String(), "name")
114 assert.Contains(t, w.Body.String(), "url")
115
116 assert.Equal(t, w.Body.String(), `{"name":"example-discovery","url":null}`)
117 }
118
119 func TestMissingServiceName(t *testing.T) {
120 router, scheme := setupTest()
121
122 device := api.ExternalDevice{
123 ObjectMeta: metav1.ObjectMeta{
124 Name: "example",
125 Namespace: "device-registrar-clients",
126 },
127 Spec: api.ExternalDeviceSpec{
128 SN: "my-serial-number",
129 Name: "test-device-name",
130 },
131 }
132
133 mockClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&device).Build()
134
135 injectmockClientDiscover(router, mockClient, t)
136
137
138 router.GET("/discover/:serviceName", DiscoverService)
139
140
141 req, _ := http.NewRequest(http.MethodGet, "/discover/", nil)
142 req.Header.Set("X-Client-DN", "OU=urn:storeID:my-store-id=urn:deviceName:test-device-name+OU=urn:SN:my-serial-number")
143
144 w := httptest.NewRecorder()
145 router.ServeHTTP(w, req)
146
147 assert.Equal(t, w.Body.String(), "404 page not found")
148 }
149
150 func TestEmptyDiscoveryList(t *testing.T) {
151 router, scheme := setupTest()
152 device := api.ExternalDevice{
153 ObjectMeta: metav1.ObjectMeta{
154 Name: "example",
155 Namespace: "device-registrar-clients",
156 },
157 Spec: api.ExternalDeviceSpec{
158 SN: "my-serial-number",
159 Name: "test-device-name",
160 },
161 }
162
163 mockClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&device).Build()
164
165 injectmockClientDiscover(router, mockClient, t)
166
167
168 router.GET("/discover/:serviceName", DiscoverService)
169
170 req, _ := http.NewRequest(http.MethodGet, "/discover/example-discovery", nil)
171 req.Header.Set("X-Client-DN", "OU=urn:storeID:my-store-id=urn:deviceName:test-device-name+OU=urn:SN:my-serial-number")
172
173 w := httptest.NewRecorder()
174 router.ServeHTTP(w, req)
175
176
177 assert.Equal(t, http.StatusOK, w.Code, "Expected status code 200")
178
179 assert.Equal(t, w.Body.String(), `{"name":"example-discovery","url":null}`)
180 }
181 func TestDiscoveryNoHeader(t *testing.T) {
182 router, scheme := setupTest()
183 mockClient := fake.NewClientBuilder().WithScheme(scheme).Build()
184
185 injectmockClientDiscover(router, mockClient, t)
186
187
188 router.GET("/discover/:serviceName", DiscoverService)
189
190
191 req, _ := http.NewRequest(http.MethodGet, "/discover/example-discovery", nil)
192
193 w := httptest.NewRecorder()
194 router.ServeHTTP(w, req)
195
196
197 assert.Equal(t, http.StatusUnauthorized, w.Code, "Expected status code 401")
198
199 assert.Equal(t, w.Body.String(), `{"error":"X-Client-DN is required"}`)
200 }
201
202 func TestDiscoveryIncorrectSN(t *testing.T) {
203 router, scheme := setupTest()
204
205 device := api.ExternalDevice{
206 ObjectMeta: metav1.ObjectMeta{
207 Name: "example",
208 Namespace: "device-registrar-clients",
209 },
210 Spec: api.ExternalDeviceSpec{
211 SN: "my-serial-number-different",
212 Name: "test-device-name",
213 },
214 }
215
216 mockClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&device).Build()
217
218 injectmockClientDiscover(router, mockClient, t)
219
220
221 router.GET("/discover/:serviceName", DiscoverService)
222
223
224 req, _ := http.NewRequest(http.MethodGet, "/discover/example-discovery", nil)
225 req.Header.Set("X-Client-DN", "OU=urn:storeID:my-store-id=urn:deviceName:test-device-name+OU=urn:SN:my-serial-number")
226
227 w := httptest.NewRecorder()
228 router.ServeHTTP(w, req)
229
230
231 assert.Equal(t, http.StatusUnauthorized, w.Code, "Expected status code 401")
232
233 assert.Equal(t, w.Body.String(), `{"error":"Unauthorized Serial Number"}`)
234 }
235
236 func TestDiscoveryNoSN(t *testing.T) {
237 router, scheme := setupTest()
238
239 mockClient := fake.NewClientBuilder().WithScheme(scheme).Build()
240
241 injectmockClientDiscover(router, mockClient, t)
242
243
244 router.GET("/discover/:serviceName", DiscoverService)
245
246
247 req, _ := http.NewRequest(http.MethodGet, "/discover/example-discovery", nil)
248 req.Header.Set("X-Client-DN", "OU=urn:storeID:my-store-id=urn:deviceName:test-device-name")
249
250 w := httptest.NewRecorder()
251 router.ServeHTTP(w, req)
252
253
254 assert.Equal(t, http.StatusUnauthorized, w.Code, "Expected status code 401")
255
256 assert.Equal(t, w.Body.String(), `{"error":"Serial Number is required in X-Client-DN"}`)
257 }
258
259 func TestParseSN(t *testing.T) {
260 sn := parseSerialNumber("OU=urn:storeID:my-store-id+OU=urn:deviceName:test-device-name+OU=urn:SN:a1b2c3d4")
261 assert.Equal(t, sn, "a1b2c3d4")
262 }
263
264 func TestIsSNAuthorized(t *testing.T) {
265 _, scheme := setupTest()
266
267 device := api.ExternalDevice{
268 ObjectMeta: metav1.ObjectMeta{
269 Name: "example",
270 Namespace: "device-registrar-clients",
271 },
272 Spec: api.ExternalDeviceSpec{
273 SN: "my-serial-number",
274 Name: "test-device-name",
275 },
276 }
277
278 ctx := context.Background()
279 mockClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&device).Build()
280
281 assert.True(t, isSNAuthorized(ctx, mockClient, "my-serial-number"))
282 assert.False(t, isSNAuthorized(ctx, mockClient, "different-serial-number"))
283 }
284
View as plain text