1 package services
2
3 import (
4 "context"
5 "database/sql"
6 "encoding/json"
7 "errors"
8 "fmt"
9 "testing"
10 "time"
11
12 "github.com/DATA-DOG/go-sqlmock"
13 kustomizeApi "github.com/fluxcd/kustomize-controller/api/v1"
14 sourceApi "github.com/fluxcd/source-controller/api/v1"
15 "github.com/lib/pq"
16 "github.com/stretchr/testify/assert"
17
18 "edge-infra.dev/pkg/edge/api/graph/model"
19 "edge-infra.dev/pkg/edge/api/services/artifacts"
20 sqlquery "edge-infra.dev/pkg/edge/api/sql"
21 "edge-infra.dev/pkg/edge/api/status"
22 "edge-infra.dev/pkg/edge/constants"
23 "edge-infra.dev/pkg/edge/constants/api/fleet"
24 "edge-infra.dev/pkg/edge/ctlfish/monitor"
25 whv1 "edge-infra.dev/pkg/f8n/warehouse/k8s/apis/v1alpha1"
26 "edge-infra.dev/pkg/lib/runtime/version"
27 )
28
29 var (
30 testStoreClusterEdgeID = "test-store-cluster-edge-id"
31 testNetworkID = "dfsdgjskgsad"
32 testNetworkID2 = "omeromgserga"
33 testIP = "8.8.8.8"
34 testIP2 = "0.0.0.0"
35 testFamily = "inet"
36 testDNSServiceType = "dns"
37 testNTPServiceType = "ntp"
38 testPriority = 100
39 testPriority2 = 99
40 testNetworkIDmap = map[string]string{testNetworkID: testDNSServiceType, testNetworkID2: testNTPServiceType}
41 )
42
43 const (
44 supportVersionResource = `["{\"metadata\":{\"name\":\"test\",\"labels\":{\"feature.node.kubernetes.io/ien-version\":\"v1.15.0\"}}}","test-support-status-cluster"]`
45 unsupportedVersionResource = `["{\"metadata\":{\"name\":\"test\",\"labels\":{\"feature.node.kubernetes.io/ien-version\":\"v1.2.0\"}}}","test-unsupported-status-cluster"]`
46 noVersionResource = `["{\"metadata\":{\"name\":\"test\",\"labels\":{\"feature.node.kubernetes.io/ien-version\":\"\"}}}","test-no-terminal-version-status-cluster"]`
47 )
48
49 func TestDeleteClusterSQLEntry(t *testing.T) {
50 db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
51 if err != nil {
52 t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
53 }
54 defer db.Close()
55 testStoreClusterEdgeID := "mv8wx3jwjgtg"
56 mock.ExpectExec(sqlquery.ClusterDeleteQuery).WithArgs(testStoreClusterEdgeID).
57 WillReturnResult(sqlmock.NewResult(1, 1))
58 service := NewStoreClusterService(nil, nil, db, nil, nil, nil)
59 if err := service.DeleteStoreEntry(context.Background(), testStoreClusterEdgeID); err != nil {
60 t.Errorf("error was not expected while deleting cluster: %s", err)
61 }
62
63 if err := mock.ExpectationsWereMet(); err != nil {
64 t.Errorf("there were unfulfilled expectations: %s", err)
65 }
66 }
67
68 func TestGetClusterFromSQL(t *testing.T) {
69 db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
70 if err != nil {
71 t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
72 }
73 defer db.Close()
74 mock.ExpectQuery(sqlquery.GetClusterByEdgeID).
75 WithArgs("uuid-1").
76 WillReturnRows(mock.NewRows([]string{"cluster_edge_id", "cluster_name", "project_id", "registered", "active", "banner_edge_id", "bsl_site_id", "fleet_version"}).
77 AddRow("uuid-1", "test-store", "test_project_id", true, true, "banner_edge_id", "bsl_site_id", "latest"))
78 mock.ExpectQuery(sqlquery.SelectEdgeLabelsForCluster).
79 WithArgs("uuid-1").
80 WillReturnRows(mock.NewRows([]string{"label_edge_id", "label_key", "color", "visible", "editable", "banner_edge_id", "label_unique", "description", "label_type"}).
81 AddRow("label_edge_id", "test-label-key", "color", true, true, nil, true, "description", "label_type"))
82 mock.ExpectQuery(sqlquery.GetArtifactVersionsAndCompatibility).WithArgs(fleet.Store, version.New().SemVer).
83 WillReturnRows(mock.NewRows([]string{"artifact_name", "artifact_version", "nth_index", "compatible_artifact_name", "compatible_artifact_version"}).
84 AddRow(fleet.Store, version.New().SemVer, 2, compatibleArtifactVersionA.Name, compatibleArtifactVersionA.Version).
85 AddRow(fleet.Store, version.New().SemVer, 2, compatibleArtifactVersionB.Name, compatibleArtifactVersionB.Version))
86 service := NewStoreClusterService(nil, nil, db, nil, nil, nil)
87 c, err := service.GetCluster(context.Background(), "uuid-1")
88 assert.Nil(t, err)
89 assert.Equal(t, "test-store", c.Name)
90 assert.Equal(t, "test-label-key", c.Labels[0].Key)
91 }
92
93 func TestGetClustersFromSQL(t *testing.T) {
94 db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
95 if err != nil {
96 t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
97 }
98 defer db.Close()
99 mock.ExpectQuery(sqlquery.GetClustersWithLabelQuery).
100 WithArgs(projectID, pq.Array([]string{"test-label-key"})).
101 WillReturnRows(mock.NewRows([]string{"uuid-1", "cluster_name", "project_id", "registered", "active", "banner_edge_id", "bsl_site_id", "fleet_version"}).
102 AddRow("uuid-2", "test-store", "test_project_id", true, true, "banner_edge_id", "bsl_site_id", "latest"))
103 mock.ExpectQuery(sqlquery.SelectEdgeLabelsForCluster).
104 WithArgs("uuid-2").
105 WillReturnRows(mock.NewRows([]string{"label_edge_id", "label_key", "color", "visible", "editable", "banner_edge_id", "label_unique", "description", "label_type"}).
106 AddRow("label_edge_id", "test-label-key", "color", true, true, nil, true, "description", "label_type"))
107 mock.ExpectQuery(sqlquery.GetClustersQuery).
108 WithArgs(projectID).
109 WillReturnRows(mock.NewRows([]string{"uuid", "cluster_name", "project_id", "registered", "active", "banner_edge_id", "bsl_site_id", "fleet_version"}).
110 AddRow("uuid-1", "test-store-1", "test_project_id", true, true, "banner_edge_id", "bsl_site_id", "latest").
111 AddRow("uuid-2", "test-store-2", "test_project_id", true, true, "banner_edge_id", "bsl_site_id", "latest"))
112 mock.ExpectQuery(sqlquery.SelectEdgeLabelsForCluster).
113 WithArgs("uuid-1").
114 WillReturnRows(mock.NewRows([]string{"label_edge_id", "label_key", "color", "visible", "editable", "banner_edge_id", "label_unique", "description", "label_type"}).
115 AddRow("label_edge_id", "test-label-key-1", "color", true, true, "banner_edge_id", true, "description", "label_type").
116 AddRow("label_edge_id", "test-label-key-2", "color", true, true, "banner_edge_id", true, "description", "label_type"))
117 mock.ExpectQuery(sqlquery.SelectEdgeLabelsForCluster).
118 WithArgs("uuid-2").
119 WillReturnRows(mock.NewRows([]string{"label_edge_id", "label_key", "color", "visible", "editable", "banner_edge_id", "label_unique", "description", "label_type"}).
120 AddRow("label_edge_id", "test-label-key-2", "color", true, true, "banner_edge_id", true, "description", "label_type"))
121
122 service := NewStoreClusterService(nil, nil, db, nil, nil, nil)
123 clusters, err := service.GetClusters(context.Background(), projectID, []string{"test-label-key"})
124 assert.Nil(t, err)
125 assert.Equal(t, 1, len(clusters))
126 assert.Equal(t, "test-store", clusters[0].Name)
127 assert.Equal(t, "test-label-key", clusters[0].Labels[0].Key)
128 clusters, err = service.GetClusters(context.Background(), projectID, nil)
129 assert.Nil(t, err)
130 assert.Equal(t, 2, len(clusters))
131 assert.Equal(t, "test-store-1", clusters[0].Name)
132 assert.Equal(t, 2, len(clusters[0].Labels))
133 assert.Equal(t, "test-label-key-1", clusters[0].Labels[0].Key)
134 assert.Equal(t, "test-label-key-2", clusters[0].Labels[1].Key)
135 assert.Equal(t, "test-store-2", clusters[1].Name)
136 assert.Equal(t, 1, len(clusters[1].Labels))
137 assert.Equal(t, "test-label-key-2", clusters[1].Labels[0].Key)
138 }
139
140 func TestGetClustersFromSQLEmptyResponse(t *testing.T) {
141 db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
142 if err != nil {
143 t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
144 }
145 defer db.Close()
146 mock.ExpectQuery(sqlquery.GetClustersWithLabelQuery).
147 WithArgs(projectID, pq.Array([]string{"test-label-key"})).
148 WillReturnRows(mock.NewRows([]string{"uuid", "cluster_name", "project_id", "registered", "active", "banner_edge_id", "bsl_site_id", "labels"}))
149 mock.ExpectQuery(sqlquery.GetClustersQuery).
150 WithArgs(projectID).
151 WillReturnRows(mock.NewRows([]string{"uuid", "cluster_name", "project_id", "registered", "active", "banner_edge_id", "bsl_site_id", "labels"}))
152 service := NewStoreClusterService(nil, nil, db, nil, nil, nil)
153 clusters, err := service.GetClusters(context.Background(), projectID, []string{"test-label-key"})
154 assert.Nil(t, err)
155 assert.Equal(t, []*model.Cluster{}, clusters)
156 clusters, err = service.GetClusters(context.Background(), projectID, nil)
157 assert.Nil(t, err)
158 assert.Equal(t, []*model.Cluster{}, clusters)
159 }
160
161 func TestToBucketStatusInformation(t *testing.T) {
162 testSyncInfo := monitor.SyncInfo{
163 LastUpdated: "test-last-updated",
164 Revision: "test-revision",
165 StatusMessage: "test-status-message",
166 Error: false,
167 Suspended: true,
168 }
169 bucketInfo := map[string]monitor.BucketInfo{
170 "test-bucket-1": {
171 Excludes: "test-excludes-1",
172 BucketName: "test-bucket-name-1",
173 FluxStatus: testSyncInfo,
174 },
175 }
176 buckets := toBucketStatusInformation(bucketInfo)
177 assert.Equal(t, 1, len(buckets))
178 assert.Equal(t, "test-excludes-1", buckets[0].Excludes)
179 assert.Equal(t, "test-bucket-name-1", buckets[0].BucketName)
180 assert.Equal(t, "test-bucket-1", buckets[0].FluxStatus.Name)
181 }
182
183 func TestToKustomizationStatusInformation(t *testing.T) {
184 testSyncInfo := monitor.SyncInfo{
185 LastUpdated: "test-last-updated",
186 Revision: "test-revision",
187 StatusMessage: "test-status-message",
188 Error: false,
189 Suspended: true,
190 }
191 kustomizationInfo := map[string]monitor.KustomizationInfo{
192 "test-kustomization-1": {Path: "test-path-1", Source: "test-source-1", FluxStatus: testSyncInfo},
193 "test-kustomization-2": {Path: "test-path-2", Source: "test-source-2", FluxStatus: testSyncInfo},
194 }
195 kustomizations := toKustomizationStatusInformation(kustomizationInfo)
196 assert.Equal(t, 2, len(kustomizations))
197 assert.Contains(t, "test-path-1, test-path-2", kustomizations[0].Path)
198 assert.Contains(t, "test-source-1, test-source-2", kustomizations[0].Source)
199 assert.Contains(t, "test-path-1, test-path-2", kustomizations[1].Path)
200 assert.Contains(t, "test-source-1, test-source-2", kustomizations[1].Source)
201 assert.Contains(t, "test-kustomization-1 test-kustomization-2", kustomizations[0].FluxStatus.Name)
202 assert.Contains(t, "test-kustomization-1 test-kustomization-2", kustomizations[1].FluxStatus.Name)
203 }
204
205 func TestGetFluxStatusInfo(t *testing.T) {
206 testSyncInfo := monitor.SyncInfo{
207 LastUpdated: "test-last-updated",
208 Revision: "test-revision",
209 StatusMessage: "test-status-message",
210 Error: false,
211 Suspended: true,
212 }
213 fluxStatus := getFluxStatusInfo("test-flux-name", &testSyncInfo)
214 assert.Equal(t, "test-flux-name", fluxStatus.Name)
215 assert.Equal(t, "test-last-updated", fluxStatus.LastUpdated)
216 assert.Equal(t, "test-revision", fluxStatus.Revision)
217 assert.Equal(t, "test-status-message", fluxStatus.StatusMessage)
218 assert.Equal(t, false, fluxStatus.Error)
219 assert.Equal(t, true, fluxStatus.Suspended)
220 }
221
222 func TestCreateClusterNetworkServiceSQLEntry(t *testing.T) {
223 db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
224 if err != nil {
225 t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
226 }
227 defer db.Close()
228
229 newClusterNetworkService := model.CreateNetworkServiceInfo{
230 ServiceType: testDNSServiceType,
231 IP: testIP2,
232 Family: testFamily,
233 Priority: &testPriority,
234 }
235
236 newClusterNetworkServices := []*model.CreateNetworkServiceInfo{&newClusterNetworkService}
237
238 mock.ExpectQuery(sqlquery.GetClusterNetworkServices).WithArgs(testStoreClusterEdgeID).WillReturnRows(mock.NewRows([]string{"network_service_id", "ip", "family", "service_type", "priority"}).
239 AddRow(testNetworkID, testIP, testFamily, testDNSServiceType, testPriority))
240 mock.ExpectQuery(sqlquery.CreateClusterNetworkServices).WithArgs(testStoreClusterEdgeID, testIP2, testFamily, testDNSServiceType, testPriority).WillReturnRows(mock.NewRows([]string{"network_service_id", "ip", "family", "service_type", "priority"}).
241 AddRow(testNetworkID2, testIP2, testFamily, testDNSServiceType, testPriority))
242
243 service := NewStoreClusterService(nil, nil, db, nil, nil, nil)
244
245 clusterNetworkServices, err := service.CreateClusterNetworkServices(context.Background(), testStoreClusterEdgeID, newClusterNetworkServices)
246 if err != nil {
247 t.Errorf("error was not expected while creating cluster network services: %s", err)
248 }
249
250 expected := model.ClusterNetworkServiceInfo{
251 NetworkServiceID: testNetworkID2,
252 ServiceType: testDNSServiceType,
253 IP: testIP2,
254 Family: testFamily,
255 Priority: &testPriority,
256 }
257
258 returnedEntry := *clusterNetworkServices[0]
259 assert.Equal(t, returnedEntry, expected)
260 }
261
262 func TestGetClusterNetworkServiceSQLEntry(t *testing.T) {
263 db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
264 if err != nil {
265 t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
266 }
267 defer db.Close()
268
269 cluster := model.Cluster{
270 ClusterEdgeID: testStoreClusterEdgeID,
271 }
272
273 mock.ExpectQuery(sqlquery.GetClusterNetworkServices).WithArgs(testStoreClusterEdgeID).WillReturnRows(mock.NewRows([]string{"network_service_id", "ip", "family", "service_type", "priority"}).
274 AddRow(testNetworkID, testIP, testFamily, testDNSServiceType, testPriority))
275
276 service := NewStoreClusterService(nil, nil, db, nil, nil, nil)
277
278 clusterNetworkServices, err := service.GetClusterNetworkServices(context.Background(), cluster.ClusterEdgeID)
279 if err != nil {
280 t.Errorf("error was not expected while getting cluster network services: %s", err)
281 }
282
283 expected := model.ClusterNetworkServiceInfo{
284 NetworkServiceID: testNetworkID,
285 ServiceType: testDNSServiceType,
286 IP: testIP,
287 Family: testFamily,
288 Priority: &testPriority,
289 }
290
291 returnedEntry := *clusterNetworkServices[0]
292 assert.Equal(t, returnedEntry, expected)
293 }
294
295 func TestDeleteClusterNetworkServiceSQLEntry(t *testing.T) {
296 db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
297 if err != nil {
298 t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
299 }
300 defer db.Close()
301
302 mock.ExpectQuery(sqlquery.GetClusterNetworkServiceByNetworkID).WithArgs(testStoreClusterEdgeID, testNetworkID).WillReturnRows(mock.NewRows([]string{"network_service_id", "ip", "family", "service_type", "priority"}).
303 AddRow(testNetworkID, testIP, testFamily, testDNSServiceType, testPriority))
304 mock.ExpectExec(sqlquery.DeleteClusterNetworkService).WithArgs(testStoreClusterEdgeID, testNetworkID).
305 WillReturnResult(sqlmock.NewResult(1, 1))
306
307 service := NewStoreClusterService(nil, nil, db, nil, nil, nil)
308
309 deleted, err := service.DeleteClusterNetworkService(context.Background(), testStoreClusterEdgeID, testNetworkID)
310 if err != nil {
311 t.Errorf("error was not expected while deleting cluster network services: %s", err)
312 }
313
314 assert.True(t, deleted)
315 }
316
317 func TestUpdateClusterNetworkServiceSQLEntry(t *testing.T) {
318 db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
319 if err != nil {
320 t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
321 }
322 defer db.Close()
323
324 newClusterNetworkService := model.UpdateNetworkServiceInfo{
325 NetworkServiceID: testNetworkID,
326 IP: testIP,
327 Family: testFamily,
328 Priority: &testPriority2,
329 }
330
331 newClusterNetworkServices := []*model.UpdateNetworkServiceInfo{&newClusterNetworkService}
332
333 mock.ExpectQuery(sqlquery.GetClusterNetworkServices).WithArgs(testStoreClusterEdgeID).WillReturnRows(mock.NewRows([]string{"network_service_id", "ip", "family", "service_type", "priority"}).
334 AddRow(testNetworkID, testIP, testFamily, testDNSServiceType, testPriority))
335 mock.ExpectQuery(sqlquery.UpdateClusterNetworkServices).WithArgs(testIP, testFamily, testPriority2, testNetworkID, testStoreClusterEdgeID).WillReturnRows(mock.NewRows([]string{"network_service_id", "ip", "family", "service_type", "priority"}).
336 AddRow(testNetworkID, testIP, testFamily, testDNSServiceType, testPriority2))
337
338 service := NewStoreClusterService(nil, nil, db, nil, nil, nil)
339
340 clusterNetworkServices, err := service.UpdateClusterNetworkServices(context.Background(), testStoreClusterEdgeID, newClusterNetworkServices, testNetworkIDmap)
341 if err != nil {
342 t.Errorf("error was not expected while updating cluster network services: %s", err)
343 }
344
345 expected := model.ClusterNetworkServiceInfo{
346 NetworkServiceID: testNetworkID,
347 ServiceType: testDNSServiceType,
348 IP: testIP,
349 Family: testFamily,
350 Priority: &testPriority2,
351 }
352
353 returnedEntry := *clusterNetworkServices[0]
354 assert.Equal(t, returnedEntry, expected)
355 }
356
357 func TestCreateClusterNetworkServiceSQLEntryInvalidNTP(t *testing.T) {
358 db, _, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
359 if err != nil {
360 t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
361 }
362 defer db.Close()
363
364 newClusterNetworkService := model.CreateNetworkServiceInfo{
365 ServiceType: "ntp",
366 IP: "domain!.test",
367 Family: testFamily,
368 Priority: &testPriority,
369 }
370
371 newClusterNetworkServices := []*model.CreateNetworkServiceInfo{&newClusterNetworkService}
372
373 service := NewStoreClusterService(nil, nil, db, nil, nil, nil)
374
375 _, err = service.CreateClusterNetworkServices(context.Background(), testStoreClusterEdgeID, newClusterNetworkServices)
376 assert.Error(t, err)
377 }
378
379 func TestUpdateClusterNetworkServiceSQLEntryInvalidNTP(t *testing.T) {
380 db, _, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
381 if err != nil {
382 t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
383 }
384 defer db.Close()
385
386 newClusterNetworkService := model.UpdateNetworkServiceInfo{
387 NetworkServiceID: testNetworkID,
388 IP: "8.8.8.",
389 Family: testFamily,
390 Priority: &testPriority,
391 }
392
393 newClusterNetworkServices := []*model.UpdateNetworkServiceInfo{&newClusterNetworkService}
394
395 service := NewStoreClusterService(nil, nil, db, nil, nil, nil)
396
397 _, err = service.UpdateClusterNetworkServices(context.Background(), testStoreClusterEdgeID, newClusterNetworkServices, testNetworkIDmap)
398 assert.Error(t, err)
399 }
400
401 func TestUpdateClusterNetworkServiceSQLEntryValidNTP(t *testing.T) {
402 db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
403 if err != nil {
404 t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
405 }
406 defer db.Close()
407
408 newClusterNetworkService := model.UpdateNetworkServiceInfo{
409 NetworkServiceID: testNetworkID2,
410 IP: "time.google.com",
411 Family: testFamily,
412 Priority: &testPriority,
413 }
414
415 newClusterNetworkServices := []*model.UpdateNetworkServiceInfo{&newClusterNetworkService}
416
417 mock.ExpectQuery(sqlquery.GetClusterNetworkServices).WithArgs(testStoreClusterEdgeID).WillReturnRows(mock.NewRows([]string{"network_service_id", "ip", "family", "service_type", "priority"}).
418 AddRow(testNetworkID2, testIP, testFamily, testNTPServiceType, testPriority))
419 mock.ExpectQuery(sqlquery.UpdateClusterNetworkServices).WithArgs("time.google.com", testFamily, testPriority, testNetworkID2, testStoreClusterEdgeID).WillReturnRows(mock.NewRows([]string{"network_service_id", "ip", "family", "service_type", "priority"}).
420 AddRow(testNetworkID2, "time.google.com", testFamily, testNTPServiceType, testPriority))
421
422 service := NewStoreClusterService(nil, nil, db, nil, nil, nil)
423
424 clusterNetworkServices, err := service.UpdateClusterNetworkServices(context.Background(), testStoreClusterEdgeID, newClusterNetworkServices, testNetworkIDmap)
425 if err != nil {
426 t.Errorf("error was not expected while updating cluster network services: %s", err)
427 }
428
429 expected := model.ClusterNetworkServiceInfo{
430 NetworkServiceID: testNetworkID2,
431 ServiceType: "ntp",
432 IP: "time.google.com",
433 Family: testFamily,
434 Priority: &testPriority,
435 }
436
437 returnedEntry := *clusterNetworkServices[0]
438 assert.Equal(t, returnedEntry, expected)
439 }
440
441 func TestCreateClusterNetworkServiceSQLEntryNoPrioritySet(t *testing.T) {
442 db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
443 if err != nil {
444 t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
445 }
446 defer db.Close()
447
448 newClusterNetworkService := model.CreateNetworkServiceInfo{
449 ServiceType: testDNSServiceType,
450 IP: testIP2,
451 Family: testFamily,
452 }
453
454 newClusterNetworkServices := []*model.CreateNetworkServiceInfo{&newClusterNetworkService}
455
456 mock.ExpectQuery(sqlquery.GetClusterNetworkServices).WithArgs(testStoreClusterEdgeID).WillReturnRows(mock.NewRows([]string{"network_service_id", "ip", "family", "service_type", "priority"}).
457 AddRow(testNetworkID, testIP, testFamily, testDNSServiceType, testPriority))
458 mock.ExpectQuery(sqlquery.CreateClusterNetworkServices).WithArgs(testStoreClusterEdgeID, testIP2, testFamily, testDNSServiceType, testPriority).WillReturnRows(mock.NewRows([]string{"network_service_id", "ip", "family", "service_type", "priority"}).
459 AddRow(testNetworkID2, testIP2, testFamily, testDNSServiceType, testPriority))
460
461 service := NewStoreClusterService(nil, nil, db, nil, nil, nil)
462
463 clusterNetworkServices, err := service.CreateClusterNetworkServices(context.Background(), testStoreClusterEdgeID, newClusterNetworkServices)
464 if err != nil {
465 t.Errorf("error was not expected while creating cluster network services: %s", err)
466 }
467
468 expected := model.ClusterNetworkServiceInfo{
469 NetworkServiceID: testNetworkID2,
470 ServiceType: testDNSServiceType,
471 IP: testIP2,
472 Family: testFamily,
473 Priority: &testPriority,
474 }
475
476 returnedEntry := *clusterNetworkServices[0]
477 assert.Equal(t, returnedEntry, expected)
478 }
479
480 func TestCreateClusterNetworkServiceSQLEntryPrioritySetToNegativeInt(t *testing.T) {
481 db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
482 if err != nil {
483 t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
484 }
485 defer db.Close()
486 negativePriority := -10
487 newClusterNetworkService := model.CreateNetworkServiceInfo{
488 ServiceType: testDNSServiceType,
489 IP: testIP2,
490 Family: testFamily,
491 Priority: &negativePriority,
492 }
493
494 newClusterNetworkServices := []*model.CreateNetworkServiceInfo{&newClusterNetworkService}
495
496 mock.ExpectQuery(sqlquery.GetClusterNetworkServices).WithArgs(testStoreClusterEdgeID).WillReturnRows(mock.NewRows([]string{"network_service_id", "ip", "family", "service_type", "priority"}).
497 AddRow(testNetworkID, testIP, testFamily, testDNSServiceType, testPriority))
498 mock.ExpectQuery(sqlquery.CreateClusterNetworkServices).WithArgs(testStoreClusterEdgeID, testIP2, testFamily, testDNSServiceType, testPriority).WillReturnRows(mock.NewRows([]string{"network_service_id", "ip", "family", "service_type", "priority"}).
499 AddRow(testNetworkID2, testIP2, testFamily, testDNSServiceType, testPriority))
500
501 service := NewStoreClusterService(nil, nil, db, nil, nil, nil)
502
503 clusterNetworkServices, err := service.CreateClusterNetworkServices(context.Background(), testStoreClusterEdgeID, newClusterNetworkServices)
504 if err != nil {
505 t.Errorf("error was not expected while creating cluster network services: %s", err)
506 }
507
508 expected := model.ClusterNetworkServiceInfo{
509 NetworkServiceID: testNetworkID2,
510 ServiceType: testDNSServiceType,
511 IP: testIP2,
512 Family: testFamily,
513 Priority: &testPriority,
514 }
515
516 returnedEntry := *clusterNetworkServices[0]
517 assert.Equal(t, returnedEntry, expected)
518 }
519
520 func TestCreateClusterNetworkServiceSQLEntryDuplicateIP(t *testing.T) {
521 db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
522 if err != nil {
523 t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
524 }
525 defer db.Close()
526
527 newClusterNetworkServiceWithDuplicateIP := &model.CreateNetworkServiceInfo{
528 ServiceType: testDNSServiceType,
529 IP: testIP,
530 Family: testFamily,
531 Priority: &testPriority,
532 }
533 newClusterNetworkServices := []*model.CreateNetworkServiceInfo{newClusterNetworkServiceWithDuplicateIP}
534
535 mock.ExpectQuery(sqlquery.GetClusterNetworkServices).WithArgs(testStoreClusterEdgeID).WillReturnRows(mock.NewRows([]string{"network_service_id", "ip", "family", "service_type", "priority"}).
536 AddRow(testNetworkID, testIP, testFamily, testDNSServiceType, testPriority))
537
538 service := NewStoreClusterService(nil, nil, db, nil, nil, nil)
539
540 _, err = service.CreateClusterNetworkServices(context.Background(), testStoreClusterEdgeID, newClusterNetworkServices)
541 assert.Error(t, err)
542 }
543
544 func TestUpdateClusterNetworkServiceSQLEntryDuplicateIP(t *testing.T) {
545 db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
546 if err != nil {
547 t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
548 }
549 defer db.Close()
550
551 clusterNetworkServiceWithDuplicateIP := &model.UpdateNetworkServiceInfo{
552 NetworkServiceID: testNetworkID,
553 IP: testIP2,
554 Family: testFamily,
555 Priority: &testPriority,
556 }
557 newClusterNetworkServices := []*model.UpdateNetworkServiceInfo{clusterNetworkServiceWithDuplicateIP}
558
559 mock.ExpectQuery(sqlquery.GetClusterNetworkServices).WithArgs(testStoreClusterEdgeID).WillReturnRows(mock.NewRows([]string{"network_service_id", "ip", "family", "service_type", "priority"}).
560 AddRow(testNetworkID, testIP, testFamily, testNTPServiceType, testPriority).
561 AddRow(testNetworkID2, testIP2, testFamily, testNTPServiceType, testPriority))
562
563 service := NewStoreClusterService(nil, nil, db, nil, nil, nil)
564
565 testNetworkIDmapNTP := map[string]string{testNetworkID: testNTPServiceType, testNetworkID2: testNTPServiceType}
566 _, err = service.UpdateClusterNetworkServices(context.Background(), testStoreClusterEdgeID, newClusterNetworkServices, testNetworkIDmapNTP)
567 assert.Error(t, err)
568 }
569
570 func TestUpdateStoreSiteID(t *testing.T) {
571 db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
572 if err != nil {
573 t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
574 }
575 defer db.Close()
576 mock.ExpectExec(sqlquery.UpdateStoreSiteIDQuery).WithArgs("testSiteID", testStoreClusterEdgeID).
577 WillReturnResult(sqlmock.NewResult(1, 1))
578
579 service := NewStoreClusterService(nil, nil, db, nil, nil, nil)
580
581 err = service.UpdateStoreSiteID(context.Background(), testStoreClusterEdgeID, "testSiteID")
582
583 if err != nil {
584 t.Errorf("error was not expected while updating siteID: %s", err)
585 }
586
587 assert.NoError(t, err)
588 }
589
590 func TestGetEventsForCluster(t *testing.T) {
591 db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
592 if err != nil {
593 t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
594 }
595 defer db.Close()
596 shipmentMessage := "Applied 11 pallets: [...]"
597 kustoMessage := "Reconciliation finished in 4s, next run in 1m0s"
598 createdAt := time.Now().Format(time.RFC3339)
599 annotations := map[string]string{
600 "pallet.edge.ncr.com/created": createdAt,
601 "pallet.edge.ncr.com/name": "fluxcd-syncing-config",
602 "pallet.edge.ncr.com/version": "0.18.0-rc.0123456789+commit.a01234b",
603 }
604 jsonData, err := json.Marshal(annotations)
605 assert.NoError(t, err)
606 mock.ExpectQuery(sqlquery.GetClusterEvents).
607 WithArgs("uuid-1").
608 WillReturnRows(mock.NewRows([]string{"event_edge_id", "event_name", "involved_kind", "involved_namespace", "involved_name", "reason", "message", "status", "source_component", "annotations", "terminal_id", "cluster_edge_id", "created_at"}).
609 AddRow("event_edge_id", "test-event-name", "Shipment", "", "test-shipment-name", "Succeeded", shipmentMessage, "Normal", "lumperctl", "", "terminal_id", "uuid-1", createdAt).
610 AddRow("event_edge_id2", "test-event-name2", "Kustomization", "flux-config", "test-kusto-name", "ReconciliationSucceeded", kustoMessage, "Normal", "kustomize-controller", string(jsonData), "terminal_id", "uuid-1", createdAt))
611
612 service := NewStoreClusterService(nil, nil, db, nil, nil, nil)
613 events, err := service.GetEventsForCluster(context.Background(), "uuid-1")
614 assert.NoError(t, err)
615 assert.NotNil(t, events)
616 assert.Equal(t, 2, len(events))
617
618 for _, event := range events {
619 if event.EventEdgeID == "event_edge_id2" {
620 assert.Equal(t, "test-event-name2", event.Name)
621 assert.Equal(t, "Kustomization", event.InvolvedObject.Kind)
622 assert.Equal(t, "flux-config", *event.InvolvedObject.Namespace)
623 assert.Equal(t, "test-kusto-name", event.InvolvedObject.Name)
624 assert.Equal(t, "ReconciliationSucceeded", event.Reason)
625 assert.Equal(t, kustoMessage, event.Message)
626 assert.Equal(t, "kustomize-controller", event.Source)
627 assert.Equal(t, string(jsonData), *event.Annotations)
628 assert.Equal(t, "Normal", event.Status)
629 assert.Equal(t, "terminal_id", *event.TerminalID)
630 assert.Equal(t, "uuid-1", event.ClusterEdgeID)
631 assert.Equal(t, createdAt, event.CreatedAt)
632 }
633 }
634 }
635
636 func TestGetInfraStatusForCluster(t *testing.T) {
637 clusterEdgeID := "test-infra-status"
638
639 db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
640 if err != nil {
641 t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
642 }
643 defer db.Close()
644
645 expectedCombinedStatus := &model.ClusterStatus{
646 Status: "HEALTHY",
647 Message: "SYNCED",
648 }
649
650 service := NewStoreClusterService(nil, nil, db, nil, nil, nil)
651
652 type test struct {
653 testName string
654 clusterEdgeID string
655 expected *model.ClusterStatus
656 mockSQLQuery func() *sqlmock.ExpectedQuery
657 }
658
659 tests := []test{{
660 testName: "ClusterInfraReadyStatus",
661 clusterEdgeID: clusterEdgeID,
662 expected: expectedCombinedStatus,
663 mockSQLQuery: func() *sqlmock.ExpectedQuery {
664 return mock.ExpectQuery(sqlquery.GetClusterInfraStatusByID).
665 WithArgs(clusterEdgeID).
666 WillReturnRows(sqlmock.NewRows([]string{"cluster_edge_id", "cluster_name", "infra_status", "infra_status_details"}).
667 AddRow(clusterEdgeID, "test-cluster", "READY", "SYNCED"))
668 },
669 },
670 {
671 testName: "ClusterInfraStatusNotReady",
672 clusterEdgeID: clusterEdgeID,
673 expected: &model.ClusterStatus{
674 Status: "UNHEALTHY",
675 Message: "ReconcileFailed",
676 },
677 mockSQLQuery: func() *sqlmock.ExpectedQuery {
678 return mock.ExpectQuery(sqlquery.GetClusterInfraStatusByID).
679 WithArgs(clusterEdgeID).
680 WillReturnRows(sqlmock.NewRows([]string{"cluster_edge_id", "cluster_name", "infra_status", "infra_status_details"}).
681 AddRow(clusterEdgeID, "test-cluster", "ERROR", "ReconcileFailed"))
682 },
683 },
684 {
685 testName: "ClusterInfraStatusProvisioning",
686 clusterEdgeID: clusterEdgeID,
687 expected: &model.ClusterStatus{
688 Status: "PROVISIONING",
689 Message: "",
690 },
691 mockSQLQuery: func() *sqlmock.ExpectedQuery {
692 return mock.ExpectQuery(sqlquery.GetClusterInfraStatusByID).
693 WithArgs(clusterEdgeID).
694 WillReturnRows(sqlmock.NewRows([]string{"cluster_edge_id", "cluster_name", "infra_status", "infra_status_details"}).
695 AddRow(clusterEdgeID, "test-cluster", "PROVISIONING", ""))
696 },
697 },
698 }
699
700 for _, tc := range tests {
701 tc.mockSQLQuery()
702
703 t.Run(tc.testName, func(t *testing.T) {
704 clusterInfraStatus, err := service.GetInfraStatus(context.Background(), clusterEdgeID)
705 assert.NoError(t, err)
706 assert.Equal(t, tc.expected.Status, clusterInfraStatus.Status)
707 })
708 }
709 }
710
711 func TestReplicationStatus(t *testing.T) {
712 clusterEdgeID := "test-replication-status"
713
714 db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
715 if err != nil {
716 t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
717 }
718 defer db.Close()
719
720 service := NewStoreClusterService(nil, nil, db, nil, nil, nil)
721
722 type test struct {
723 testName string
724 clusterEdgeID string
725 expected []*model.ReplicationStatus
726 mockSQLQuery func() *sqlmock.ExpectedQuery
727 }
728
729 tests := []test{{
730 testName: "ReplicationStatusFound",
731 clusterEdgeID: clusterEdgeID,
732 expected: []*model.ReplicationStatus{{Name: "test-db", Status: "True"}},
733 mockSQLQuery: func() *sqlmock.ExpectedQuery {
734 return mock.ExpectQuery(sqlquery.GetReplicationStatus).
735 WithArgs(clusterEdgeID).
736 WillReturnRows(sqlmock.NewRows([]string{"name", "value"}).
737 AddRow("test-db", "True"))
738 },
739 },
740 {
741 testName: "ReplicationStatusEmpty",
742 clusterEdgeID: clusterEdgeID,
743 expected: []*model.ReplicationStatus{},
744 mockSQLQuery: func() *sqlmock.ExpectedQuery {
745 return mock.ExpectQuery(sqlquery.GetReplicationStatus).
746 WithArgs(clusterEdgeID).
747 WillReturnRows(sqlmock.NewRows([]string{"name", "value"}))
748 },
749 },
750 {
751 testName: "ReplicationStatusNotFound",
752 clusterEdgeID: clusterEdgeID,
753 expected: []*model.ReplicationStatus{{Name: "test-db", Status: "False"}},
754 mockSQLQuery: func() *sqlmock.ExpectedQuery {
755 return mock.ExpectQuery(sqlquery.GetReplicationStatus).
756 WithArgs(clusterEdgeID).
757 WillReturnRows(sqlmock.NewRows([]string{"name", "value"}).
758 AddRow("test-db", "False"))
759 },
760 },
761 }
762
763 for _, tc := range tests {
764 tc.mockSQLQuery()
765
766 t.Run(tc.testName, func(t *testing.T) {
767 replicationStatus, err := service.GetReplicationStatus(context.Background(), clusterEdgeID)
768 assert.NoError(t, err)
769 assert.Equal(t, tc.expected, replicationStatus)
770 })
771 }
772 }
773
774 func TestGetCombinedClusterStatus(t *testing.T) {
775 clusterEdgeID := "11fd4df6-db4c-422b-ac9d-2b43dae86d7e"
776 db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
777 if err != nil {
778 t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
779 }
780 defer db.Close()
781
782 service := NewStoreClusterService(nil, nil, db, nil, nil, nil)
783
784 testCases := []struct {
785 testName string
786 cluster *model.CombinedStatus
787 expected *model.ClusterStatus
788 mockSQLQueries []func() *sqlmock.ExpectedQuery
789 err error
790 }{
791 {
792 testName: "missing-cluster",
793 cluster: nil,
794 err: ErrClusterMissing,
795 expected: nil,
796 mockSQLQueries: []func() *sqlmock.ExpectedQuery{},
797 },
798 {
799 testName: "cluster-not-active",
800 cluster: &model.CombinedStatus{
801 ClusterEdgeID: clusterEdgeID,
802 Active: false,
803 },
804 err: nil,
805 expected: &model.ClusterStatus{
806 Status: status.Registered,
807 Message: status.RegisteredMessage,
808 },
809 mockSQLQueries: []func() *sqlmock.ExpectedQuery{},
810 },
811 {
812 testName: "ready-status",
813 cluster: &model.CombinedStatus{
814 ClusterEdgeID: clusterEdgeID,
815 Active: true,
816 },
817 err: nil,
818 expected: &model.ClusterStatus{
819 Status: status.Ready,
820 Message: status.ReadyMessage,
821 },
822 mockSQLQueries: []func() *sqlmock.ExpectedQuery{
823 func() *sqlmock.ExpectedQuery {
824 return mock.ExpectQuery(sqlquery.GetClusterStatuses).
825 WithArgs(clusterEdgeID, false).
826 WillReturnRows(sqlmock.NewRows([]string{"kind", "jsonpath", "value"}).
827 AddRow("Shipment", `$.status.conditions[?(@.type == "Ready")].status`, "True").
828 AddRow("Kustomization", `$.status.conditions[?(@.type == "Ready")].status`, "True").
829 AddRow("Bucket", `$.status.conditions[?(@.type == "Ready")].status`, "True"),
830 )
831 },
832 },
833 },
834 {
835 testName: "error-status-one-error-resource",
836 cluster: &model.CombinedStatus{
837 ClusterEdgeID: clusterEdgeID,
838 Active: true,
839 },
840 err: nil,
841 expected: &model.ClusterStatus{
842 Status: status.Error,
843 Message: "timeout waiting for: [UnpackedPallet/vncserver-76d26410 status: 'InProgress', UnpackedPallet/display-76d26410 status: 'InProgress']",
844 },
845 mockSQLQueries: []func() *sqlmock.ExpectedQuery{
846 func() *sqlmock.ExpectedQuery {
847 return mock.ExpectQuery(sqlquery.GetClusterStatuses).
848 WithArgs(clusterEdgeID, false).
849 WillReturnRows(sqlmock.NewRows([]string{"kind", "jsonpath", "value"}).
850 AddRow("Shipment", `$.status.conditions[?(@.type == "Ready")].status`, "False").
851 AddRow("Kustomization", `$.status.conditions[?(@.type == "Ready")].status`, "True").
852 AddRow("Bucket", `$.status.conditions[?(@.type == "Ready")].status`, "True"),
853 )
854 },
855 func() *sqlmock.ExpectedQuery {
856 return mock.ExpectQuery(sqlquery.GetClusterErrorStatusMessage).
857 WithArgs("Shipment", clusterEdgeID, false).
858 WillReturnRows(sqlmock.NewRows([]string{"value"}).
859 AddRow("timeout waiting for: [UnpackedPallet/vncserver-76d26410 status: 'InProgress', UnpackedPallet/display-76d26410 status: 'InProgress']"),
860 )
861 },
862 },
863 },
864 {
865 testName: "error-status-two-not-ready-resources-one-not-reported",
866 cluster: &model.CombinedStatus{
867 ClusterEdgeID: clusterEdgeID,
868 Active: true,
869 },
870 err: nil,
871 expected: &model.ClusterStatus{
872 Status: status.Installing,
873 Message: "timeout waiting for: [UnpackedPallet/vncserver-76d26410 status: 'InProgress', UnpackedPallet/display-76d26410 status: 'InProgress'] and Waiting for Kustomization status",
874 },
875 mockSQLQueries: []func() *sqlmock.ExpectedQuery{
876 func() *sqlmock.ExpectedQuery {
877 return mock.ExpectQuery(sqlquery.GetClusterStatuses).
878 WithArgs(clusterEdgeID, false).
879 WillReturnRows(sqlmock.NewRows([]string{"kind", "jsonpath", "value"}).
880 AddRow("Shipment", `$.status.conditions[?(@.type == "Ready")].status`, "False").
881 AddRow("Kustomization", `$.status.conditions[?(@.type == "Ready")].status`, "False").
882 AddRow("Bucket", `$.status.conditions[?(@.type == "Ready")].status`, "True"),
883 )
884 },
885 func() *sqlmock.ExpectedQuery {
886 return mock.ExpectQuery(sqlquery.GetClusterErrorStatusMessage).
887 WithArgs("Shipment", clusterEdgeID, false).
888 WillReturnRows(sqlmock.NewRows([]string{"value"}).
889 AddRow("timeout waiting for: [UnpackedPallet/vncserver-76d26410 status: 'InProgress', UnpackedPallet/display-76d26410 status: 'InProgress']"),
890 )
891 },
892 func() *sqlmock.ExpectedQuery {
893 return mock.ExpectQuery(sqlquery.GetClusterErrorStatusMessage).
894 WithArgs("Kustomization", clusterEdgeID, false).
895 WillReturnError(sql.ErrNoRows)
896 },
897 },
898 },
899 {
900 testName: "error-status-three-not-ready-resources-three-errors",
901 cluster: &model.CombinedStatus{
902 ClusterEdgeID: clusterEdgeID,
903 Active: true,
904 },
905 err: nil,
906 expected: &model.ClusterStatus{
907 Status: status.Error,
908 Message: `timeout waiting for: [UnpackedPallet/vncserver-76d26410 status: 'InProgress', UnpackedPallet/display-76d26410 status: 'InProgress'], kustomization path not found: stat /tmp/kustomization-2906021254/e0da4d18-0786-440e-acc7-b37ea6198c09/shipments: no such file or directory, and failed to confirm existence of 'ret-edge-y95i8vtpeyfqmv99fx0i4' bucket: Get "https://storage.googleapis.com/storage/v1/b/ret-edge-y95i8vtpeyfqmv99fx0i4?alt=json&prettyPrint=false&projection=full": oauth2: cannot fetch token: Post "https://oauth2.googleapis.com/token": dial tcp: lookup oauth2.googleapis.com on 10.63.0.18:53: read udp 100.137.192.153:57882->10.66.0.10:53: i/o timeout`,
909 },
910 mockSQLQueries: []func() *sqlmock.ExpectedQuery{
911 func() *sqlmock.ExpectedQuery {
912 return mock.ExpectQuery(sqlquery.GetClusterStatuses).
913 WithArgs(clusterEdgeID, false).
914 WillReturnRows(sqlmock.NewRows([]string{"kind", "jsonpath", "value"}).
915 AddRow("Shipment", `$.status.conditions[?(@.type == "Ready")].status`, "False").
916 AddRow("Kustomization", `$.status.conditions[?(@.type == "Ready")].status`, "False").
917 AddRow("Bucket", `$.status.conditions[?(@.type == "Ready")].status`, "False"),
918 )
919 },
920 func() *sqlmock.ExpectedQuery {
921 return mock.ExpectQuery(sqlquery.GetClusterErrorStatusMessage).
922 WithArgs("Shipment", clusterEdgeID, false).
923 WillReturnRows(sqlmock.NewRows([]string{"value"}).
924 AddRow(`timeout waiting for: [UnpackedPallet/vncserver-76d26410 status: 'InProgress', UnpackedPallet/display-76d26410 status: 'InProgress']`),
925 )
926 },
927 func() *sqlmock.ExpectedQuery {
928 return mock.ExpectQuery(sqlquery.GetClusterErrorStatusMessage).
929 WithArgs("Kustomization", clusterEdgeID, false).
930 WillReturnRows(sqlmock.NewRows([]string{"value"}).
931 AddRow(`kustomization path not found: stat /tmp/kustomization-2906021254/e0da4d18-0786-440e-acc7-b37ea6198c09/shipments: no such file or directory`),
932 )
933 },
934 func() *sqlmock.ExpectedQuery {
935 return mock.ExpectQuery(sqlquery.GetClusterErrorStatusMessage).
936 WithArgs("Bucket", clusterEdgeID, false).
937 WillReturnRows(sqlmock.NewRows([]string{"value"}).
938 AddRow(`failed to confirm existence of 'ret-edge-y95i8vtpeyfqmv99fx0i4' bucket: Get "https://storage.googleapis.com/storage/v1/b/ret-edge-y95i8vtpeyfqmv99fx0i4?alt=json&prettyPrint=false&projection=full": oauth2: cannot fetch token: Post "https://oauth2.googleapis.com/token": dial tcp: lookup oauth2.googleapis.com on 10.63.0.18:53: read udp 100.137.192.153:57882->10.66.0.10:53: i/o timeout`),
939 )
940 },
941 },
942 },
943 }
944
945 for _, tc := range testCases {
946 for _, mockSQLFn := range tc.mockSQLQueries {
947 mockSQLFn()
948 }
949
950 t.Run(tc.testName, func(t *testing.T) {
951 clusterStatus, err := service.GetCombinedClusterStatus(context.Background(), tc.cluster)
952 if tc.err != nil {
953 assert.True(t, errors.Is(err, tc.err))
954 } else {
955 assert.NoError(t, err)
956 assert.Equal(t, tc.expected.Status, clusterStatus.Status)
957 assert.Equal(t, tc.expected.Message, clusterStatus.Message)
958 }
959 })
960 }
961 }
962
963 func TestGetComponentStatus(t *testing.T) {
964 clusterEdgeID := "11fd4df6-db4c-422b-ac9d-2b43dae86d7e"
965 db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
966 if err != nil {
967 t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
968 }
969 defer db.Close()
970
971 service := NewStoreClusterService(nil, nil, db, nil, nil, nil)
972
973 testCases := []struct {
974 title string
975 clusterEdgeID string
976 kind string
977 active bool
978 expected *model.ClusterStatus
979 mockSQLQueries []func() *sqlmock.ExpectedQuery
980 err error
981 }{
982 {
983 title: "Test Case 1 - InActive Cluster",
984 clusterEdgeID: clusterEdgeID,
985 kind: whv1.ShipmentGVK.Kind,
986 active: false,
987 expected: &model.ClusterStatus{
988 Status: status.NotAvailable,
989 Message: status.NotAvailableStatusMessage,
990 },
991 err: nil,
992 },
993 {
994 title: "Test Case 2 - Shipment Status, Active Cluster",
995 clusterEdgeID: clusterEdgeID,
996 kind: whv1.ShipmentGVK.Kind,
997 active: true,
998 expected: &model.ClusterStatus{
999 Status: status.Ready,
1000 Message: fmt.Sprintf(status.KindReadyMessage, whv1.ShipmentGVK.Kind),
1001 },
1002 err: nil,
1003 mockSQLQueries: []func() *sqlmock.ExpectedQuery{
1004 func() *sqlmock.ExpectedQuery {
1005 return mock.ExpectQuery(sqlquery.GetClusterStatus).
1006 WithArgs(whv1.ShipmentGVK.Kind, clusterEdgeID, false).
1007 WillReturnRows(sqlmock.NewRows([]string{"value"}).
1008 AddRow("True"),
1009 )
1010 },
1011 },
1012 },
1013 {
1014 title: "Test Case 3 - Shipment Status, Active Cluster, Missing Cluster Status",
1015 clusterEdgeID: clusterEdgeID,
1016 kind: whv1.ShipmentGVK.Kind,
1017 active: true,
1018 expected: &model.ClusterStatus{
1019 Status: status.NotAvailable,
1020 Message: status.NotAvailableStatusMessage,
1021 },
1022 err: nil,
1023 mockSQLQueries: []func() *sqlmock.ExpectedQuery{
1024 func() *sqlmock.ExpectedQuery {
1025 return mock.ExpectQuery(sqlquery.GetClusterStatus).
1026 WithArgs(whv1.ShipmentGVK.Kind, clusterEdgeID, false).
1027 WillReturnError(sql.ErrNoRows)
1028 },
1029 },
1030 },
1031 {
1032 title: "Test Case 4 - Shipment Status, Active Cluster, Not Reported",
1033 clusterEdgeID: clusterEdgeID,
1034 kind: whv1.ShipmentGVK.Kind,
1035 active: true,
1036 expected: &model.ClusterStatus{
1037 Status: status.Installing,
1038 Message: fmt.Sprintf("%s %s status", status.NotReportedFormat, whv1.ShipmentGVK.Kind),
1039 },
1040 err: nil,
1041 mockSQLQueries: []func() *sqlmock.ExpectedQuery{
1042 func() *sqlmock.ExpectedQuery {
1043 return mock.ExpectQuery(sqlquery.GetClusterStatus).
1044 WithArgs(whv1.ShipmentGVK.Kind, clusterEdgeID, false).
1045 WillReturnRows(sqlmock.NewRows([]string{"value"}).
1046 AddRow("False"),
1047 )
1048 },
1049 func() *sqlmock.ExpectedQuery {
1050 return mock.ExpectQuery(sqlquery.GetClusterErrorStatusMessage).
1051 WithArgs(whv1.ShipmentGVK.Kind, clusterEdgeID, false).
1052 WillReturnError(sql.ErrNoRows)
1053 },
1054 },
1055 },
1056 {
1057 title: "Test Case 5 - Shipment Status, Active Cluster, Error",
1058 clusterEdgeID: clusterEdgeID,
1059 kind: whv1.ShipmentGVK.Kind,
1060 active: true,
1061 expected: &model.ClusterStatus{
1062 Status: status.Error,
1063 Message: "timeout waiting for: [UnpackedPallet/display-823f6029 status: 'InProgress', UnpackedPallet/vncserver-823f6029 status: 'InProgress']",
1064 },
1065 err: nil,
1066 mockSQLQueries: []func() *sqlmock.ExpectedQuery{
1067 func() *sqlmock.ExpectedQuery {
1068 return mock.ExpectQuery(sqlquery.GetClusterStatus).
1069 WithArgs(whv1.ShipmentGVK.Kind, clusterEdgeID, false).
1070 WillReturnRows(sqlmock.NewRows([]string{"value"}).
1071 AddRow("False"),
1072 )
1073 },
1074 func() *sqlmock.ExpectedQuery {
1075 return mock.ExpectQuery(sqlquery.GetClusterErrorStatusMessage).
1076 WithArgs(whv1.ShipmentGVK.Kind, clusterEdgeID, false).
1077 WillReturnRows(sqlmock.NewRows([]string{"value"}).
1078 AddRow("timeout waiting for: [UnpackedPallet/display-823f6029 status: 'InProgress', UnpackedPallet/vncserver-823f6029 status: 'InProgress']"),
1079 )
1080 },
1081 },
1082 },
1083 {
1084 title: "Test Case 6 - Kustomization Status, Active Cluster, Ready",
1085 clusterEdgeID: clusterEdgeID,
1086 kind: kustomizeApi.KustomizationKind,
1087 active: true,
1088 expected: &model.ClusterStatus{
1089 Status: status.Ready,
1090 Message: fmt.Sprintf(status.KindReadyMessage, kustomizeApi.KustomizationKind),
1091 },
1092 err: nil,
1093 mockSQLQueries: []func() *sqlmock.ExpectedQuery{
1094 func() *sqlmock.ExpectedQuery {
1095 return mock.ExpectQuery(sqlquery.GetClusterStatus).
1096 WithArgs(kustomizeApi.KustomizationKind, clusterEdgeID, false).
1097 WillReturnRows(sqlmock.NewRows([]string{"value"}).
1098 AddRow("True"),
1099 )
1100 },
1101 },
1102 },
1103 {
1104 title: "Test Case 7 - Kustomization Status, Active Cluster, Missing Cluster Status",
1105 clusterEdgeID: clusterEdgeID,
1106 kind: kustomizeApi.KustomizationKind,
1107 active: true,
1108 expected: &model.ClusterStatus{
1109 Status: status.NotAvailable,
1110 Message: status.NotAvailableStatusMessage,
1111 },
1112 err: nil,
1113 mockSQLQueries: []func() *sqlmock.ExpectedQuery{
1114 func() *sqlmock.ExpectedQuery {
1115 return mock.ExpectQuery(sqlquery.GetClusterStatus).
1116 WithArgs(kustomizeApi.KustomizationKind, clusterEdgeID, false).
1117 WillReturnError(sql.ErrNoRows)
1118 },
1119 },
1120 },
1121 {
1122 title: "Test Case 8 - Kustomization Status, Active Cluster, Not Reported",
1123 clusterEdgeID: clusterEdgeID,
1124 kind: kustomizeApi.KustomizationKind,
1125 active: true,
1126 expected: &model.ClusterStatus{
1127 Status: status.Installing,
1128 Message: fmt.Sprintf("%s %s status", status.NotReportedFormat, kustomizeApi.KustomizationKind),
1129 },
1130 err: nil,
1131 mockSQLQueries: []func() *sqlmock.ExpectedQuery{
1132 func() *sqlmock.ExpectedQuery {
1133 return mock.ExpectQuery(sqlquery.GetClusterStatus).
1134 WithArgs(kustomizeApi.KustomizationKind, clusterEdgeID, false).
1135 WillReturnRows(sqlmock.NewRows([]string{"value"}).
1136 AddRow("False"),
1137 )
1138 },
1139 func() *sqlmock.ExpectedQuery {
1140 return mock.ExpectQuery(sqlquery.GetClusterErrorStatusMessage).
1141 WithArgs(kustomizeApi.KustomizationKind, clusterEdgeID, false).
1142 WillReturnError(sql.ErrNoRows)
1143 },
1144 },
1145 },
1146 {
1147 title: "Test Case 9 - Kustomization Status, Active Cluster, Error",
1148 clusterEdgeID: clusterEdgeID,
1149 kind: kustomizeApi.KustomizationKind,
1150 active: true,
1151 expected: &model.ClusterStatus{
1152 Status: status.Error,
1153 Message: "path /tmp/abc123 not found",
1154 },
1155 err: nil,
1156 mockSQLQueries: []func() *sqlmock.ExpectedQuery{
1157 func() *sqlmock.ExpectedQuery {
1158 return mock.ExpectQuery(sqlquery.GetClusterStatus).
1159 WithArgs(kustomizeApi.KustomizationKind, clusterEdgeID, false).
1160 WillReturnRows(sqlmock.NewRows([]string{"value"}).
1161 AddRow("False"),
1162 )
1163 },
1164 func() *sqlmock.ExpectedQuery {
1165 return mock.ExpectQuery(sqlquery.GetClusterErrorStatusMessage).
1166 WithArgs(kustomizeApi.KustomizationKind, clusterEdgeID, false).
1167 WillReturnRows(sqlmock.NewRows([]string{"value"}).
1168 AddRow("path /tmp/abc123 not found"),
1169 )
1170 },
1171 },
1172 },
1173 {
1174 title: "Test Case 10 - Bucket Status, Active Cluster, Ready",
1175 clusterEdgeID: clusterEdgeID,
1176 kind: sourceApi.BucketKind,
1177 active: true,
1178 expected: &model.ClusterStatus{
1179 Status: status.Ready,
1180 Message: fmt.Sprintf(status.KindReadyMessage, sourceApi.BucketKind),
1181 },
1182 err: nil,
1183 mockSQLQueries: []func() *sqlmock.ExpectedQuery{
1184 func() *sqlmock.ExpectedQuery {
1185 return mock.ExpectQuery(sqlquery.GetClusterStatus).
1186 WithArgs(sourceApi.BucketKind, clusterEdgeID, false).
1187 WillReturnRows(sqlmock.NewRows([]string{"value"}).
1188 AddRow("True"),
1189 )
1190 },
1191 },
1192 },
1193 {
1194 title: "Test Case 11 - Bucket Status, Active Cluster, Missing Cluster Status",
1195 clusterEdgeID: clusterEdgeID,
1196 kind: sourceApi.BucketKind,
1197 active: true,
1198 expected: &model.ClusterStatus{
1199 Status: status.NotAvailable,
1200 Message: status.NotAvailableStatusMessage,
1201 },
1202 err: nil,
1203 mockSQLQueries: []func() *sqlmock.ExpectedQuery{
1204 func() *sqlmock.ExpectedQuery {
1205 return mock.ExpectQuery(sqlquery.GetClusterStatus).
1206 WithArgs(sourceApi.BucketKind, clusterEdgeID, false).
1207 WillReturnError(sql.ErrNoRows)
1208 },
1209 },
1210 },
1211 {
1212 title: "Test Case 12 - Bucket Status, Active Cluster, Not Reported",
1213 clusterEdgeID: clusterEdgeID,
1214 kind: sourceApi.BucketKind,
1215 active: true,
1216 expected: &model.ClusterStatus{
1217 Status: status.Installing,
1218 Message: fmt.Sprintf("%s %s status", status.NotReportedFormat, sourceApi.BucketKind),
1219 },
1220 err: nil,
1221 mockSQLQueries: []func() *sqlmock.ExpectedQuery{
1222 func() *sqlmock.ExpectedQuery {
1223 return mock.ExpectQuery(sqlquery.GetClusterStatus).
1224 WithArgs(sourceApi.BucketKind, clusterEdgeID, false).
1225 WillReturnRows(sqlmock.NewRows([]string{"value"}).
1226 AddRow("False"),
1227 )
1228 },
1229 func() *sqlmock.ExpectedQuery {
1230 return mock.ExpectQuery(sqlquery.GetClusterErrorStatusMessage).
1231 WithArgs(sourceApi.BucketKind, clusterEdgeID, false).
1232 WillReturnError(sql.ErrNoRows)
1233 },
1234 },
1235 },
1236 {
1237 title: "Test Case 13 - Bucket Status, Active Cluster, Error",
1238 clusterEdgeID: clusterEdgeID,
1239 kind: sourceApi.BucketKind,
1240 active: true,
1241 expected: &model.ClusterStatus{
1242 Status: status.Error,
1243 Message: "some cool source bucket error here",
1244 },
1245 err: nil,
1246 mockSQLQueries: []func() *sqlmock.ExpectedQuery{
1247 func() *sqlmock.ExpectedQuery {
1248 return mock.ExpectQuery(sqlquery.GetClusterStatus).
1249 WithArgs(sourceApi.BucketKind, clusterEdgeID, false).
1250 WillReturnRows(sqlmock.NewRows([]string{"value"}).
1251 AddRow("False"),
1252 )
1253 },
1254 func() *sqlmock.ExpectedQuery {
1255 return mock.ExpectQuery(sqlquery.GetClusterErrorStatusMessage).
1256 WithArgs(sourceApi.BucketKind, clusterEdgeID, false).
1257 WillReturnRows(sqlmock.NewRows([]string{"value"}).
1258 AddRow("some cool source bucket error here"),
1259 )
1260 },
1261 },
1262 },
1263 {
1264 title: "Test Case 14 - No Cluster Edge ID Error",
1265 clusterEdgeID: "",
1266 kind: sourceApi.BucketKind,
1267 active: true,
1268 expected: nil,
1269 err: ErrClusterMissing,
1270 },
1271 {
1272 title: "Test Case 15 - No Kind Error",
1273 clusterEdgeID: clusterEdgeID,
1274 kind: "",
1275 active: true,
1276 expected: nil,
1277 err: ErrKindMissing,
1278 },
1279 }
1280
1281 for _, tc := range testCases {
1282 for _, mockSQLFn := range tc.mockSQLQueries {
1283 mockSQLFn()
1284 }
1285
1286 t.Run(tc.title, func(t *testing.T) {
1287 res, err := service.GetComponentStatus(context.Background(), tc.clusterEdgeID, tc.kind, tc.active)
1288 if tc.err != nil {
1289 assert.True(t, errors.Is(tc.err, err))
1290 }
1291 if tc.expected != nil {
1292 assert.Equal(t, tc.expected.Status, res.Status)
1293 assert.Equal(t, tc.expected.Message, res.Message)
1294 } else {
1295 assert.Equal(t, tc.expected, res)
1296 }
1297 })
1298 }
1299 }
1300
1301 func TestGetActiveVersion(t *testing.T) {
1302 clusterEdgeID := "test-active-version-cluster"
1303 db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
1304 if err != nil {
1305 t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
1306 }
1307 defer db.Close()
1308
1309 service := NewStoreClusterService(nil, nil, db, nil, nil, nil)
1310
1311 activeVersion := "0.18.0-rc.1715271464+commit.a8854d8"
1312
1313 type test struct {
1314 testName string
1315 clusterEdgeID string
1316 expected string
1317 mockSQLQuery func() *sqlmock.ExpectedQuery
1318 }
1319
1320 tests := []test{
1321 {
1322 testName: "GetActiveEdgeVersion",
1323 clusterEdgeID: clusterEdgeID,
1324 expected: activeVersion,
1325 mockSQLQuery: func() *sqlmock.ExpectedQuery {
1326 return mock.ExpectQuery(sqlquery.GetActiveEdgeVersionFromWatchedField).
1327 WithArgs(clusterEdgeID).
1328 WillReturnRows(sqlmock.NewRows([]string{"value"}).
1329 AddRow("\"0.18.0-rc.1715271464+commit.a8854d8\"").
1330 AddRow("\"0.18.0-rc.1715271464+commit.a8854d8\"").
1331 AddRow("True"))
1332 },
1333 },
1334 {
1335 testName: "GetActiveEdgeVersionEmpty",
1336 clusterEdgeID: clusterEdgeID,
1337 expected: "",
1338 mockSQLQuery: func() *sqlmock.ExpectedQuery {
1339 return mock.ExpectQuery(sqlquery.GetActiveEdgeVersionFromWatchedField).
1340 WithArgs(clusterEdgeID).
1341 WillReturnRows(sqlmock.NewRows([]string{"value"}).
1342 AddRow("\"\"").AddRow("\"\"").AddRow("True"))
1343 },
1344 },
1345 }
1346
1347 for _, tc := range tests {
1348 tc.mockSQLQuery()
1349
1350 t.Run(tc.testName, func(t *testing.T) {
1351 clusterInfraStatus, err := service.GetActiveEdgeVersion(context.Background(), clusterEdgeID)
1352 assert.NoError(t, err)
1353 assert.Equal(t, tc.expected, clusterInfraStatus)
1354 })
1355 }
1356 }
1357
1358
1359 func TestGetSupportStatus(t *testing.T) {
1360 supportedClusterEdgeID := "test-support-status-cluster"
1361 unsupportedClusterEdgeID := "test-unsupported-status-cluster"
1362 noTerminalVersionClusterEdgeID := "test-no-terminal-version-status-cluster"
1363 latestVersion := version.New().SemVer
1364 db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
1365 if err != nil {
1366 t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
1367 }
1368 defer db.Close()
1369
1370 getKubeResource := func() GetKubeResourceFunc {
1371 return func(_ context.Context, _projectID string, cluster *model.Cluster, _ model.LoqRequest) ([]string, error) {
1372 assert.Equal(t, projectID, _projectID)
1373 assert.Nil(t, cluster)
1374 return []string{supportVersionResource, unsupportedVersionResource, noVersionResource}, nil
1375 }
1376 }
1377 bqClientMock := createMockBQClient(t, getKubeResource())
1378 artifactService := artifacts.NewArtifactsService(db, nil)
1379 labelService := NewLabelService(artifactService, db)
1380 terminalService := NewTerminalServiceBQ(db, bqClientMock, labelService)
1381 compatibilityService := NewCompatibilityService(db)
1382 service := NewStoreClusterService(nil, bqClientMock, db, nil, terminalService, compatibilityService)
1383
1384 testCases := []struct {
1385 testName string
1386 cluster *model.CombinedStatus
1387 expected *model.SupportStatus
1388 mockSQLQueries []func() *sqlmock.ExpectedQuery
1389 err error
1390 }{
1391 {
1392 testName: "supported-gke-cluster",
1393 cluster: &model.CombinedStatus{
1394 ClusterEdgeID: supportedClusterEdgeID,
1395 },
1396 expected: &model.SupportStatus{
1397 InfraSupportStatus: &model.InfraSupportStatus{
1398 Status: status.Supported,
1399 Message: fmt.Sprintf("Edge Infra version %s supported", latestVersion),
1400 },
1401 EdgeOsSupportStatus: &model.EdgeOsSupportStatus{},
1402 },
1403 mockSQLQueries: []func() *sqlmock.ExpectedQuery{
1404 func() *sqlmock.ExpectedQuery {
1405 return mock.ExpectQuery(sqlquery.SelectEdgeLabelsForCluster).WithArgs(supportedClusterEdgeID).
1406 WillReturnRows(mock.NewRows([]string{"label_edge_id", "label_key", "color", "visible", "editable", "banner_edge_id", "label_unique", "description", "label_type"}).
1407 AddRow("label_edge_id", "test-label-key-1", "color", true, true, "banner_edge_id", true, "description", "label_type"))
1408 },
1409 func() *sqlmock.ExpectedQuery {
1410 return mock.ExpectQuery(sqlquery.GetArtifactVersionsAndCompatibilityForArtifactName).WithArgs(fleet.Store, latestVersion, constants.EdgeOSArtifact).
1411 WillReturnRows(mock.NewRows([]string{"artifact_name", "artifact_version", "nth_index", "compatible_artifact_name", "compatible_artifact_version"}).
1412 AddRow(fleet.Store, latestVersion, 2, constants.EdgeOSArtifact, "1.15").
1413 AddRow(fleet.Store, latestVersion, 2, constants.EdgeOSArtifact, "1.14").
1414 AddRow(fleet.Store, latestVersion, 2, constants.EdgeOSArtifact, "1.13"))
1415 },
1416 func() *sqlmock.ExpectedQuery {
1417 return mock.ExpectQuery(sqlquery.GetActiveEdgeVersionFromWatchedField).
1418 WithArgs(supportedClusterEdgeID).
1419 WillReturnRows(sqlmock.NewRows([]string{"value"}).
1420 AddRow(fmt.Sprintf("\"%s-rc.1715271464+commit.a8854d8\"", latestVersion)).
1421 AddRow(fmt.Sprintf("\"%s-rc.1715271464+commit.a8854d8\"", latestVersion)).
1422 AddRow("True"))
1423 },
1424 },
1425 err: nil,
1426 },
1427 {
1428 testName: "unsupported-gke-cluster",
1429 cluster: &model.CombinedStatus{
1430 ClusterEdgeID: unsupportedClusterEdgeID,
1431 },
1432 expected: &model.SupportStatus{
1433 InfraSupportStatus: &model.InfraSupportStatus{
1434 Status: status.ClusterOutOfSupport,
1435 Message: fmt.Sprintf("Edge Infra version %s is out of support with current version %s", "0.17.0", latestVersion),
1436 },
1437 EdgeOsSupportStatus: &model.EdgeOsSupportStatus{},
1438 },
1439 mockSQLQueries: []func() *sqlmock.ExpectedQuery{
1440 func() *sqlmock.ExpectedQuery {
1441 return mock.ExpectQuery(sqlquery.SelectEdgeLabelsForCluster).WithArgs(unsupportedClusterEdgeID).
1442 WillReturnRows(mock.NewRows([]string{"label_edge_id", "label_key", "color", "visible", "editable", "banner_edge_id", "label_unique", "description", "label_type"}).
1443 AddRow("label_edge_id", "test-label-key-1", "color", true, true, "banner_edge_id", true, "description", "label_type"))
1444 },
1445 func() *sqlmock.ExpectedQuery {
1446 return mock.ExpectQuery(sqlquery.GetArtifactVersionsAndCompatibilityForArtifactName).WithArgs(fleet.Store, latestVersion, constants.EdgeOSArtifact).
1447 WillReturnRows(mock.NewRows([]string{"artifact_name", "artifact_version", "nth_index", "compatible_artifact_name", "compatible_artifact_version"}).
1448 AddRow(fleet.Store, latestVersion, 2, constants.EdgeOSArtifact, "1.15").
1449 AddRow(fleet.Store, latestVersion, 2, constants.EdgeOSArtifact, "1.14").
1450 AddRow(fleet.Store, latestVersion, 2, constants.EdgeOSArtifact, "1.13"))
1451 },
1452 func() *sqlmock.ExpectedQuery {
1453 return mock.ExpectQuery(sqlquery.GetActiveEdgeVersionFromWatchedField).
1454 WithArgs(unsupportedClusterEdgeID).
1455 WillReturnRows(sqlmock.NewRows([]string{"value"}).
1456 AddRow("\"0.17.0-rc.1715271464+commit.a8854d8\"").
1457 AddRow("\"0.17.0-rc.1715271464+commit.a8854d8\"").
1458 AddRow("True"))
1459 },
1460 },
1461 err: nil,
1462 },
1463 {
1464 testName: "supported-dsds-cluster",
1465 cluster: &model.CombinedStatus{
1466 ClusterEdgeID: supportedClusterEdgeID,
1467 },
1468 expected: &model.SupportStatus{
1469 InfraSupportStatus: &model.InfraSupportStatus{
1470 Status: status.Supported,
1471 Message: fmt.Sprintf("Edge Infra version %s supported", latestVersion),
1472 },
1473 EdgeOsSupportStatus: &model.EdgeOsSupportStatus{
1474 Status: status.Supported,
1475 Message: fmt.Sprintf("EdgeOS version %s supported", "1.15.0"),
1476 },
1477 },
1478 mockSQLQueries: []func() *sqlmock.ExpectedQuery{
1479 func() *sqlmock.ExpectedQuery {
1480 return mock.ExpectQuery(sqlquery.SelectEdgeLabelsForCluster).WithArgs(supportedClusterEdgeID).
1481 WillReturnRows(mock.NewRows([]string{"label_edge_id", "label_key", "color", "visible", "editable", "banner_edge_id", "label_unique", "description", "label_type"}).
1482 AddRow("label_edge_id", "dsds", "color", true, true, "banner_edge_id", true, "description", "label_type"))
1483 },
1484 func() *sqlmock.ExpectedQuery {
1485 return mock.ExpectQuery(sqlquery.GetArtifactVersionsAndCompatibilityForArtifactName).WithArgs(fleet.Store, latestVersion, constants.EdgeOSArtifact).
1486 WillReturnRows(mock.NewRows([]string{"artifact_name", "artifact_version", "nth_index", "compatible_artifact_name", "compatible_artifact_version"}).
1487 AddRow(fleet.Store, latestVersion, 2, constants.EdgeOSArtifact, "1.15").
1488 AddRow(fleet.Store, latestVersion, 2, constants.EdgeOSArtifact, "1.14").
1489 AddRow(fleet.Store, latestVersion, 2, constants.EdgeOSArtifact, "1.13"))
1490 },
1491 func() *sqlmock.ExpectedQuery {
1492 return mock.ExpectQuery(sqlquery.GetActiveEdgeVersionFromWatchedField).
1493 WithArgs(supportedClusterEdgeID).
1494 WillReturnRows(sqlmock.NewRows([]string{"value"}).
1495 AddRow(fmt.Sprintf("\"%s-rc.1715271464+commit.a8854d8\"", latestVersion)).
1496 AddRow(fmt.Sprintf("\"%s-rc.1715271464+commit.a8854d8\"", latestVersion)).
1497 AddRow("True"))
1498 },
1499 func() *sqlmock.ExpectedQuery {
1500 return mock.ExpectQuery(sqlquery.GetTerminalByClusterEdgeIDQuery).WithArgs(supportedClusterEdgeID).
1501 WillReturnRows(mock.NewRows(terminalColumns).
1502 AddRow("t001", "lane1", "controlplane", supportedClusterEdgeID, "test-cluster", "server", "none", "", "", "", false, "test"))
1503 },
1504 func() *sqlmock.ExpectedQuery {
1505 return mock.ExpectQuery(sqlquery.GetTerminalDiskByTerminalIDQuery).WithArgs(sqlmock.AnyArg()).
1506 WillReturnRows(mock.NewRows(terminalDiskColumns).
1507 AddRow("", "", false, false, "", false))
1508 },
1509 func() *sqlmock.ExpectedQuery {
1510 return mock.ExpectQuery(sqlquery.GetTerminalInterfaceByTerminalIDQuery).WithArgs(sqlmock.AnyArg()).
1511 WillReturnRows(mock.NewRows(terminalIfaceColumns).
1512 AddRow("", "", false, false, "", "", ""))
1513 },
1514 func() *sqlmock.ExpectedQuery {
1515 return mock.ExpectQuery(sqlquery.GetTerminalAddressByInterfaceIDQuery).WithArgs(sqlmock.AnyArg()).
1516 WillReturnRows(mock.NewRows(terminalAddrColumns).
1517 AddRow("", "", 1, "", ""))
1518 },
1519 func() *sqlmock.ExpectedQuery {
1520 return mock.ExpectQuery(sqlquery.GetTerminalLabels).
1521 WithArgs(sqlmock.AnyArg(), sql.NullString{}).
1522 WillReturnRows(mock.NewRows([]string{"terminal_id", "terminal_label_edge_id", "label_edge_id", "labelkey", "color", "visible", "editable", "banner", "unique", "description", "label_type"}).
1523 AddRow("t001", "388d1144-27c5-44e2-856a-e69a3d4f859f", testLabelEdgeID, label.Key, label.Color, label.Visible, label.Editable, label.BannerEdgeID, label.Unique, label.Description, label.Type))
1524 },
1525 func() *sqlmock.ExpectedQuery {
1526 return mock.ExpectQuery(sqlquery.GetProjectIDByClusterEdgeID).
1527 WithArgs(supportedClusterEdgeID).
1528 WillReturnRows(mock.NewRows([]string{"project_id"}).
1529 AddRow("test-org"))
1530 },
1531 },
1532 err: nil,
1533 },
1534 {
1535 testName: "unsupported-dsds-cluster",
1536 cluster: &model.CombinedStatus{
1537 ClusterEdgeID: unsupportedClusterEdgeID,
1538 },
1539 expected: &model.SupportStatus{
1540 InfraSupportStatus: &model.InfraSupportStatus{
1541 Status: status.Supported,
1542 Message: fmt.Sprintf("Edge Infra version %s supported", latestVersion),
1543 },
1544 EdgeOsSupportStatus: &model.EdgeOsSupportStatus{
1545 Status: status.ClusterOutOfSupport,
1546 Message: fmt.Sprintf("One or more terminals on EdgeOS version %s is out of support", "1.2.0"),
1547 },
1548 },
1549 mockSQLQueries: []func() *sqlmock.ExpectedQuery{
1550 func() *sqlmock.ExpectedQuery {
1551 return mock.ExpectQuery(sqlquery.SelectEdgeLabelsForCluster).WithArgs(unsupportedClusterEdgeID).
1552 WillReturnRows(mock.NewRows([]string{"label_edge_id", "label_key", "color", "visible", "editable", "banner_edge_id", "label_unique", "description", "label_type"}).
1553 AddRow("label_edge_id", "dsds", "color", true, true, "banner_edge_id", true, "description", "label_type"))
1554 },
1555 func() *sqlmock.ExpectedQuery {
1556 return mock.ExpectQuery(sqlquery.GetArtifactVersionsAndCompatibilityForArtifactName).WithArgs(fleet.Store, latestVersion, constants.EdgeOSArtifact).
1557 WillReturnRows(mock.NewRows([]string{"artifact_name", "artifact_version", "nth_index", "compatible_artifact_name", "compatible_artifact_version"}).
1558 AddRow(fleet.Store, latestVersion, 2, constants.EdgeOSArtifact, "1.15").
1559 AddRow(fleet.Store, latestVersion, 2, constants.EdgeOSArtifact, "1.14").
1560 AddRow(fleet.Store, latestVersion, 2, constants.EdgeOSArtifact, "1.13"))
1561 },
1562 func() *sqlmock.ExpectedQuery {
1563 return mock.ExpectQuery(sqlquery.GetActiveEdgeVersionFromWatchedField).
1564 WithArgs(unsupportedClusterEdgeID).
1565 WillReturnRows(sqlmock.NewRows([]string{"value"}).
1566 AddRow(fmt.Sprintf("\"%s-rc.1715271464+commit.a8854d8\"", latestVersion)).
1567 AddRow(fmt.Sprintf("\"%s-rc.1715271464+commit.a8854d8\"", latestVersion)).
1568 AddRow("True"))
1569 },
1570 func() *sqlmock.ExpectedQuery {
1571 return mock.ExpectQuery(sqlquery.GetTerminalByClusterEdgeIDQuery).WithArgs(unsupportedClusterEdgeID).
1572 WillReturnRows(mock.NewRows(terminalColumns).
1573 AddRow("t001", "lane1", "controlplane", unsupportedClusterEdgeID, "test-cluster", "server", "none", "", "", "", false, "test"))
1574 },
1575 func() *sqlmock.ExpectedQuery {
1576 return mock.ExpectQuery(sqlquery.GetTerminalDiskByTerminalIDQuery).WithArgs(sqlmock.AnyArg()).
1577 WillReturnRows(mock.NewRows(terminalDiskColumns).
1578 AddRow("", "", false, false, "", false))
1579 },
1580 func() *sqlmock.ExpectedQuery {
1581 return mock.ExpectQuery(sqlquery.GetTerminalInterfaceByTerminalIDQuery).WithArgs(sqlmock.AnyArg()).
1582 WillReturnRows(mock.NewRows(terminalIfaceColumns).
1583 AddRow("", "", false, false, "", "", ""))
1584 },
1585 func() *sqlmock.ExpectedQuery {
1586 return mock.ExpectQuery(sqlquery.GetTerminalAddressByInterfaceIDQuery).WithArgs(sqlmock.AnyArg()).
1587 WillReturnRows(mock.NewRows(terminalAddrColumns).
1588 AddRow("", "", 1, "", ""))
1589 },
1590 func() *sqlmock.ExpectedQuery {
1591 return mock.ExpectQuery(sqlquery.GetTerminalLabels).
1592 WithArgs(sqlmock.AnyArg(), sql.NullString{}).
1593 WillReturnRows(mock.NewRows([]string{"terminal_id", "terminal_label_edge_id", "label_edge_id", "labelkey", "color", "visible", "editable", "banner", "unique", "description", "label_type"}).
1594 AddRow("t001", "388d1144-27c5-44e2-856a-e69a3d4f859f", testLabelEdgeID, label.Key, label.Color, label.Visible, label.Editable, label.BannerEdgeID, label.Unique, label.Description, label.Type))
1595 },
1596 func() *sqlmock.ExpectedQuery {
1597 return mock.ExpectQuery(sqlquery.GetProjectIDByClusterEdgeID).
1598 WithArgs(unsupportedClusterEdgeID).
1599 WillReturnRows(mock.NewRows([]string{"project_id"}).
1600 AddRow("test-org"))
1601 },
1602 },
1603 err: nil,
1604 },
1605 {
1606 testName: "no-active-version-cluster",
1607 cluster: &model.CombinedStatus{
1608 ClusterEdgeID: unsupportedClusterEdgeID,
1609 },
1610 expected: &model.SupportStatus{
1611 InfraSupportStatus: &model.InfraSupportStatus{
1612 Status: status.ErrGettingVersion,
1613 Message: status.NoActiveVersion,
1614 },
1615 EdgeOsSupportStatus: &model.EdgeOsSupportStatus{},
1616 },
1617 mockSQLQueries: []func() *sqlmock.ExpectedQuery{
1618 func() *sqlmock.ExpectedQuery {
1619 return mock.ExpectQuery(sqlquery.SelectEdgeLabelsForCluster).WithArgs(unsupportedClusterEdgeID).
1620 WillReturnRows(mock.NewRows([]string{"label_edge_id", "label_key", "color", "visible", "editable", "banner_edge_id", "label_unique", "description", "label_type"}).
1621 AddRow("label_edge_id", "dsds", "color", true, true, "banner_edge_id", true, "description", "label_type"))
1622 },
1623 func() *sqlmock.ExpectedQuery {
1624 return mock.ExpectQuery(sqlquery.GetArtifactVersionsAndCompatibilityForArtifactName).WithArgs(fleet.Store, latestVersion, constants.EdgeOSArtifact).
1625 WillReturnRows(mock.NewRows([]string{"artifact_name", "artifact_version", "nth_index", "compatible_artifact_name", "compatible_artifact_version"}).
1626 AddRow(fleet.Store, latestVersion, 2, constants.EdgeOSArtifact, "1.15").
1627 AddRow(fleet.Store, latestVersion, 2, constants.EdgeOSArtifact, "1.14").
1628 AddRow(fleet.Store, latestVersion, 2, constants.EdgeOSArtifact, "1.13"))
1629 },
1630 func() *sqlmock.ExpectedQuery {
1631 return mock.ExpectQuery(sqlquery.GetActiveEdgeVersionFromWatchedField).
1632 WithArgs(unsupportedClusterEdgeID).
1633 WillReturnRows(sqlmock.NewRows([]string{"value"}).
1634 AddRow("").
1635 AddRow("").
1636 AddRow("True"))
1637 },
1638 },
1639 err: nil,
1640 },
1641 {
1642 testName: "no-terminal-version-cluster",
1643 cluster: &model.CombinedStatus{
1644 ClusterEdgeID: noTerminalVersionClusterEdgeID,
1645 },
1646 expected: &model.SupportStatus{
1647 InfraSupportStatus: &model.InfraSupportStatus{
1648 Status: status.Supported,
1649 Message: fmt.Sprintf("Edge Infra version %s supported", latestVersion),
1650 },
1651 EdgeOsSupportStatus: &model.EdgeOsSupportStatus{
1652 Status: status.ErrGettingVersion,
1653 Message: status.NoTerminalVersion,
1654 },
1655 },
1656 mockSQLQueries: []func() *sqlmock.ExpectedQuery{
1657 func() *sqlmock.ExpectedQuery {
1658 return mock.ExpectQuery(sqlquery.SelectEdgeLabelsForCluster).WithArgs(noTerminalVersionClusterEdgeID).
1659 WillReturnRows(mock.NewRows([]string{"label_edge_id", "label_key", "color", "visible", "editable", "banner_edge_id", "label_unique", "description", "label_type"}).
1660 AddRow("label_edge_id", "dsds", "color", true, true, "banner_edge_id", true, "description", "label_type"))
1661 },
1662 func() *sqlmock.ExpectedQuery {
1663 return mock.ExpectQuery(sqlquery.GetArtifactVersionsAndCompatibilityForArtifactName).WithArgs(fleet.Store, latestVersion, constants.EdgeOSArtifact).
1664 WillReturnRows(mock.NewRows([]string{"artifact_name", "artifact_version", "nth_index", "compatible_artifact_name", "compatible_artifact_version"}).
1665 AddRow(fleet.Store, latestVersion, 2, constants.EdgeOSArtifact, "1.15").
1666 AddRow(fleet.Store, latestVersion, 2, constants.EdgeOSArtifact, "1.14").
1667 AddRow(fleet.Store, latestVersion, 2, constants.EdgeOSArtifact, "1.13"))
1668 },
1669 func() *sqlmock.ExpectedQuery {
1670 return mock.ExpectQuery(sqlquery.GetActiveEdgeVersionFromWatchedField).
1671 WithArgs(noTerminalVersionClusterEdgeID).
1672 WillReturnRows(sqlmock.NewRows([]string{"value"}).
1673 AddRow(fmt.Sprintf("\"%s-rc.1715271464+commit.a8854d8\"", latestVersion)).
1674 AddRow(fmt.Sprintf("\"%s-rc.1715271464+commit.a8854d8\"", latestVersion)).
1675 AddRow("True"))
1676 },
1677 func() *sqlmock.ExpectedQuery {
1678 return mock.ExpectQuery(sqlquery.GetTerminalByClusterEdgeIDQuery).WithArgs(noTerminalVersionClusterEdgeID).
1679 WillReturnRows(mock.NewRows(terminalColumns).
1680 AddRow("t001", "lane1", "controlplane", noTerminalVersionClusterEdgeID, "test-cluster", "server", "none", "", "", "", false, "test"))
1681 },
1682 func() *sqlmock.ExpectedQuery {
1683 return mock.ExpectQuery(sqlquery.GetTerminalDiskByTerminalIDQuery).WithArgs(sqlmock.AnyArg()).
1684 WillReturnRows(mock.NewRows(terminalDiskColumns).
1685 AddRow("", "", false, false, "", false))
1686 },
1687 func() *sqlmock.ExpectedQuery {
1688 return mock.ExpectQuery(sqlquery.GetTerminalInterfaceByTerminalIDQuery).WithArgs(sqlmock.AnyArg()).
1689 WillReturnRows(mock.NewRows(terminalIfaceColumns).
1690 AddRow("", "", false, false, "", "", ""))
1691 },
1692 func() *sqlmock.ExpectedQuery {
1693 return mock.ExpectQuery(sqlquery.GetTerminalAddressByInterfaceIDQuery).WithArgs(sqlmock.AnyArg()).
1694 WillReturnRows(mock.NewRows(terminalAddrColumns).
1695 AddRow("", "", 1, "", ""))
1696 },
1697 func() *sqlmock.ExpectedQuery {
1698 return mock.ExpectQuery(sqlquery.GetTerminalLabels).
1699 WithArgs(sqlmock.AnyArg(), sql.NullString{}).
1700 WillReturnRows(mock.NewRows([]string{"terminal_id", "terminal_label_edge_id", "label_edge_id", "labelkey", "color", "visible", "editable", "banner", "unique", "description", "label_type"}).
1701 AddRow("t001", "388d1144-27c5-44e2-856a-e69a3d4f859f", testLabelEdgeID, label.Key, label.Color, label.Visible, label.Editable, label.BannerEdgeID, label.Unique, label.Description, label.Type))
1702 },
1703 func() *sqlmock.ExpectedQuery {
1704 return mock.ExpectQuery(sqlquery.GetProjectIDByClusterEdgeID).
1705 WithArgs(noTerminalVersionClusterEdgeID).
1706 WillReturnRows(mock.NewRows([]string{"project_id"}).
1707 AddRow("test-org"))
1708 },
1709 },
1710 err: nil,
1711 },
1712 }
1713
1714 for _, tc := range testCases {
1715 for _, mockSQLFn := range tc.mockSQLQueries {
1716 mockSQLFn()
1717 }
1718 t.Run(tc.testName, func(t *testing.T) {
1719 supportStatus, err := service.GetSupportStatus(context.Background(), tc.cluster)
1720 if tc.err != nil {
1721 assert.True(t, errors.Is(err, tc.err))
1722 } else {
1723 assert.NoError(t, err)
1724 assert.Equal(t, tc.expected.InfraSupportStatus, supportStatus.InfraSupportStatus)
1725 assert.Equal(t, tc.expected.EdgeOsSupportStatus, supportStatus.EdgeOsSupportStatus)
1726 }
1727 })
1728 }
1729 }
1730
View as plain text