github.com/argoproj/argo-cd/v3@v3.2.1/server/badge/badge_test.go (about) 1 package badge 2 3 import ( 4 "fmt" 5 "image/color" 6 "net/http" 7 "net/http/httptest" 8 "strings" 9 "testing" 10 11 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1" 12 appclientset "github.com/argoproj/argo-cd/v3/pkg/client/clientset/versioned/fake" 13 "github.com/argoproj/argo-cd/v3/util/settings" 14 15 "github.com/argoproj/gitops-engine/pkg/health" 16 "github.com/stretchr/testify/assert" 17 "github.com/stretchr/testify/require" 18 corev1 "k8s.io/api/core/v1" 19 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 20 "k8s.io/apimachinery/pkg/runtime" 21 "k8s.io/client-go/kubernetes/fake" 22 ) 23 24 func argoCDSecret() *corev1.Secret { 25 return &corev1.Secret{ 26 ObjectMeta: metav1.ObjectMeta{Name: "argocd-secret", Namespace: "default"}, 27 Data: map[string][]byte{ 28 "admin.password": []byte("test"), 29 "server.secretkey": []byte("test"), 30 }, 31 } 32 } 33 34 func argoCDCm() *corev1.ConfigMap { 35 return &corev1.ConfigMap{ 36 ObjectMeta: metav1.ObjectMeta{ 37 Name: "argocd-cm", 38 Namespace: "default", 39 Labels: map[string]string{ 40 "app.kubernetes.io/part-of": "argocd", 41 }, 42 }, 43 Data: map[string]string{ 44 "statusbadge.enabled": "true", 45 }, 46 } 47 } 48 49 func testApp() *v1alpha1.Application { 50 return &v1alpha1.Application{ 51 ObjectMeta: metav1.ObjectMeta{Name: "test-app", Namespace: "default"}, 52 Status: v1alpha1.ApplicationStatus{ 53 Sync: v1alpha1.SyncStatus{Status: v1alpha1.SyncStatusCodeSynced}, 54 Health: v1alpha1.AppHealthStatus{Status: health.HealthStatusHealthy}, 55 OperationState: &v1alpha1.OperationState{ 56 SyncResult: &v1alpha1.SyncOperationResult{ 57 Revision: "aa29b85", 58 }, 59 }, 60 }, 61 } 62 } 63 64 func testApp2() *v1alpha1.Application { 65 return &v1alpha1.Application{ 66 ObjectMeta: metav1.ObjectMeta{Name: "test-app", Namespace: "argocd-test"}, 67 Status: v1alpha1.ApplicationStatus{ 68 Sync: v1alpha1.SyncStatus{Status: v1alpha1.SyncStatusCodeSynced}, 69 Health: v1alpha1.AppHealthStatus{Status: health.HealthStatusHealthy}, 70 OperationState: &v1alpha1.OperationState{ 71 SyncResult: &v1alpha1.SyncOperationResult{ 72 Revision: "aa29b85", 73 }, 74 }, 75 }, 76 } 77 } 78 79 func testApp3() *v1alpha1.Application { 80 return &v1alpha1.Application{ 81 ObjectMeta: metav1.ObjectMeta{Name: "test-app", Namespace: "argocd-test"}, 82 Status: v1alpha1.ApplicationStatus{ 83 Sync: v1alpha1.SyncStatus{Status: v1alpha1.SyncStatusCodeSynced}, 84 Health: v1alpha1.AppHealthStatus{Status: health.HealthStatusHealthy}, 85 OperationState: &v1alpha1.OperationState{ 86 SyncResult: &v1alpha1.SyncOperationResult{ 87 Revision: "aa29b85ababababababab", 88 }, 89 }, 90 }, 91 } 92 } 93 94 func testProject() *v1alpha1.AppProject { 95 return &v1alpha1.AppProject{ 96 ObjectMeta: metav1.ObjectMeta{Name: "test-project", Namespace: "default"}, 97 Spec: v1alpha1.AppProjectSpec{}, 98 } 99 } 100 101 func TestHandlerFeatureIsEnabled(t *testing.T) { 102 settingsMgr := settings.NewSettingsManager(t.Context(), fake.NewClientset(argoCDCm(), argoCDSecret()), "default") 103 handler := NewHandler(appclientset.NewSimpleClientset(testApp()), settingsMgr, "default", []string{}) 104 req, err := http.NewRequest(http.MethodGet, "/api/badge?name=test-app", http.NoBody) 105 require.NoError(t, err) 106 107 rr := httptest.NewRecorder() 108 handler.ServeHTTP(rr, req) 109 110 assert.Equal(t, "private, no-store", rr.Header().Get("Cache-Control")) 111 assert.Equal(t, "*", rr.Header().Get("Access-Control-Allow-Origin")) 112 113 response := rr.Body.String() 114 assert.Equal(t, toRGBString(Green), leftRectColorPattern.FindStringSubmatch(response)[1]) 115 assert.Equal(t, toRGBString(Green), rightRectColorPattern.FindStringSubmatch(response)[1]) 116 assert.Equal(t, "Healthy", leftTextPattern.FindStringSubmatch(response)[1]) 117 assert.Equal(t, "Synced", rightTextPattern.FindStringSubmatch(response)[1]) 118 assert.NotContains(t, response, "test-app") 119 assert.NotContains(t, response, "(aa29b85)") 120 } 121 122 func TestHandlerFeatureProjectIsEnabled(t *testing.T) { 123 projectTests := []struct { 124 testApp []*v1alpha1.Application 125 response int 126 apiEndPoint string 127 namespace string 128 health string 129 status string 130 healthColor color.RGBA 131 statusColor color.RGBA 132 }{ 133 { 134 createApplications([]string{"Healthy:Synced", "Healthy:Synced"}, []string{"default", "default"}, "test"), 135 http.StatusOK, "/api/badge?project=default", "test", "Healthy", "Synced", Green, Green, 136 }, 137 { 138 createApplications([]string{"Healthy:Synced", "Healthy:OutOfSync"}, []string{"test-project", "test-project"}, "default"), 139 http.StatusOK, "/api/badge?project=test-project", "default", "Healthy", "OutOfSync", Green, Orange, 140 }, 141 { 142 createApplications([]string{"Healthy:Synced", "Degraded:Synced"}, []string{"default", "default"}, "test"), 143 http.StatusOK, "/api/badge?project=default", "test", "Degraded", "Synced", Red, Green, 144 }, 145 { 146 createApplications([]string{"Healthy:Synced", "Degraded:OutOfSync"}, []string{"test-project", "test-project"}, "default"), 147 http.StatusOK, "/api/badge?project=test-project", "default", "Degraded", "OutOfSync", Red, Orange, 148 }, 149 { 150 createApplications([]string{"Healthy:Synced", "Healthy:Synced"}, []string{"test-project", "default"}, "test"), 151 http.StatusOK, "/api/badge?project=default&project=test-project", "test", "Healthy", "Synced", Green, Green, 152 }, 153 { 154 createApplications([]string{"Healthy:OutOfSync", "Healthy:Synced"}, []string{"test-project", "default"}, "default"), 155 http.StatusOK, "/api/badge?project=default&project=test-project", "default", "Healthy", "OutOfSync", Green, Orange, 156 }, 157 { 158 createApplications([]string{"Degraded:Synced", "Healthy:Synced"}, []string{"test-project", "default"}, "test"), 159 http.StatusOK, "/api/badge?project=default&project=test-project", "test", "Degraded", "Synced", Red, Green, 160 }, 161 { 162 createApplications([]string{"Degraded:OutOfSync", "Healthy:OutOfSync"}, []string{"test-project", "default"}, "default"), 163 http.StatusOK, "/api/badge?project=default&project=test-project", "default", "Degraded", "OutOfSync", Red, Orange, 164 }, 165 { 166 createApplications([]string{"Unknown:Unknown", "Unknown:Unknown"}, []string{"test-project", "default"}, "default"), 167 http.StatusOK, "/api/badge?project=", "default", "Unknown", "Unknown", Purple, Purple, 168 }, 169 { 170 createApplications([]string{"Unknown:Unknown", "Unknown:Unknown"}, []string{"test-project", "default"}, "default"), 171 http.StatusBadRequest, "/api/badge?project=test$project", "default", "Unknown", "Unknown", Purple, Purple, 172 }, 173 { 174 createApplications([]string{"Unknown:Unknown", "Unknown:Unknown"}, []string{"test-project", "default"}, "default"), 175 http.StatusOK, "/api/badge?project=unknown", "default", "Unknown", "Unknown", Purple, Purple, 176 }, 177 { 178 createApplications([]string{"Unknown:Unknown", "Unknown:Unknown"}, []string{"test-project", "default"}, "default"), 179 http.StatusBadRequest, "/api/badge?name=foo_bar", "default", "Unknown", "Unknown", Purple, Purple, 180 }, 181 { 182 createApplications([]string{"Unknown:Unknown", "Unknown:Unknown"}, []string{"test-project", "default"}, "default"), 183 http.StatusOK, "/api/badge?name=foobar", "default", "Not Found", "", Purple, Purple, 184 }, 185 { 186 createApplicationsWithName([]string{"Healthy:Synced"}, []string{"default"}, "test", "test.application"), 187 http.StatusOK, "/api/badge?name=test.application-0", "test", "Healthy", "Synced", Green, Green, 188 }, 189 { 190 createApplicationsWithName([]string{"Healthy:Synced"}, []string{"default"}, "test", "test.invalid_name"), 191 http.StatusBadRequest, "/api/badge?name=test.invalid_name-0", "test", "Healthy", "Synced", Green, Green, 192 }, 193 } 194 for _, tt := range projectTests { 195 argoCDCm := argoCDCm() 196 argoCDSecret := argoCDSecret() 197 argoCDCm.Namespace = tt.namespace 198 argoCDSecret.Namespace = tt.namespace 199 200 settingsMgr := settings.NewSettingsManager(t.Context(), fake.NewClientset(argoCDCm, argoCDSecret), tt.namespace) 201 objects := []runtime.Object{testProject()} 202 for _, v := range tt.testApp { 203 objects = append(objects, v) 204 } 205 handler := NewHandler(appclientset.NewSimpleClientset(objects...), settingsMgr, tt.namespace, []string{}) 206 rr := httptest.NewRecorder() 207 req, err := http.NewRequest(http.MethodGet, tt.apiEndPoint, http.NoBody) 208 require.NoError(t, err) 209 handler.ServeHTTP(rr, req) 210 require.Equal(t, tt.response, rr.Result().StatusCode) 211 if rr.Result().StatusCode != http.StatusBadRequest { 212 assert.Equal(t, "private, no-store", rr.Header().Get("Cache-Control")) 213 assert.Equal(t, "*", rr.Header().Get("Access-Control-Allow-Origin")) 214 response := rr.Body.String() 215 require.Greater(t, len(response), 2) 216 assert.Equal(t, toRGBString(tt.healthColor), leftRectColorPattern.FindStringSubmatch(response)[1]) 217 assert.Equal(t, toRGBString(tt.statusColor), rightRectColorPattern.FindStringSubmatch(response)[1]) 218 assert.Equal(t, tt.health, leftTextPattern.FindStringSubmatch(response)[1]) 219 assert.Equal(t, tt.status, rightTextPattern.FindStringSubmatch(response)[1]) 220 assert.Equal(t, "\"20\"", svgHeightPattern.FindStringSubmatch(response)[2]) 221 } 222 } 223 } 224 225 func TestHandlerNamespacesIsEnabled(t *testing.T) { 226 t.Run("Application in allowed namespace", func(t *testing.T) { 227 settingsMgr := settings.NewSettingsManager(t.Context(), fake.NewClientset(argoCDCm(), argoCDSecret()), "default") 228 handler := NewHandler(appclientset.NewSimpleClientset(testApp2()), settingsMgr, "default", []string{"argocd-test"}) 229 req, err := http.NewRequest(http.MethodGet, "/api/badge?name=test-app&namespace=argocd-test", http.NoBody) 230 require.NoError(t, err) 231 232 rr := httptest.NewRecorder() 233 handler.ServeHTTP(rr, req) 234 235 assert.Equal(t, "private, no-store", rr.Header().Get("Cache-Control")) 236 assert.Equal(t, "*", rr.Header().Get("Access-Control-Allow-Origin")) 237 238 response := rr.Body.String() 239 assert.Equal(t, toRGBString(Green), leftRectColorPattern.FindStringSubmatch(response)[1]) 240 assert.Equal(t, toRGBString(Green), rightRectColorPattern.FindStringSubmatch(response)[1]) 241 assert.Equal(t, "Healthy", leftTextPattern.FindStringSubmatch(response)[1]) 242 assert.Equal(t, "Synced", rightTextPattern.FindStringSubmatch(response)[1]) 243 assert.NotContains(t, response, "test-app") 244 assert.NotContains(t, response, "(aa29b85)") 245 }) 246 247 t.Run("Application in disallowed namespace", func(t *testing.T) { 248 settingsMgr := settings.NewSettingsManager(t.Context(), fake.NewClientset(argoCDCm(), argoCDSecret()), "default") 249 handler := NewHandler(appclientset.NewSimpleClientset(testApp2()), settingsMgr, "default", []string{"argocd-test"}) 250 req, err := http.NewRequest(http.MethodGet, "/api/badge?name=test-app&namespace=kube-system", http.NoBody) 251 require.NoError(t, err) 252 253 rr := httptest.NewRecorder() 254 handler.ServeHTTP(rr, req) 255 256 require.Equal(t, http.StatusOK, rr.Result().StatusCode) 257 response := rr.Body.String() 258 assert.Equal(t, toRGBString(Purple), leftRectColorPattern.FindStringSubmatch(response)[1]) 259 assert.Equal(t, toRGBString(Purple), rightRectColorPattern.FindStringSubmatch(response)[1]) 260 assert.Equal(t, "Not Found", leftTextPattern.FindStringSubmatch(response)[1]) 261 assert.Empty(t, rightTextPattern.FindStringSubmatch(response)[1]) 262 }) 263 264 t.Run("Request with illegal namespace", func(t *testing.T) { 265 settingsMgr := settings.NewSettingsManager(t.Context(), fake.NewClientset(argoCDCm(), argoCDSecret()), "default") 266 handler := NewHandler(appclientset.NewSimpleClientset(testApp2()), settingsMgr, "default", []string{"argocd-test"}) 267 req, err := http.NewRequest(http.MethodGet, "/api/badge?name=test-app&namespace=kube()system", http.NoBody) 268 require.NoError(t, err) 269 270 rr := httptest.NewRecorder() 271 handler.ServeHTTP(rr, req) 272 273 require.Equal(t, http.StatusBadRequest, rr.Result().StatusCode) 274 }) 275 } 276 277 func TestHandlerFeatureIsEnabledKeepFullRevisionIsEnabled(t *testing.T) { 278 settingsMgr := settings.NewSettingsManager(t.Context(), fake.NewClientset(argoCDCm(), argoCDSecret()), "default") 279 handler := NewHandler(appclientset.NewSimpleClientset(testApp3()), settingsMgr, "argocd-test", []string{""}) 280 req, err := http.NewRequest(http.MethodGet, "/api/badge?name=test-app&revision=true&keepFullRevision=true", http.NoBody) 281 require.NoError(t, err) 282 283 rr := httptest.NewRecorder() 284 handler.ServeHTTP(rr, req) 285 286 assert.Equal(t, "private, no-store", rr.Header().Get("Cache-Control")) 287 assert.Equal(t, "*", rr.Header().Get("Access-Control-Allow-Origin")) 288 289 response := rr.Body.String() 290 assert.Equal(t, toRGBString(Green), leftRectColorPattern.FindStringSubmatch(response)[1]) 291 assert.Equal(t, toRGBString(Green), rightRectColorPattern.FindStringSubmatch(response)[1]) 292 assert.Equal(t, "Healthy", leftTextPattern.FindStringSubmatch(response)[1]) 293 assert.Equal(t, "Synced", rightTextPattern.FindStringSubmatch(response)[1]) 294 assert.NotContains(t, response, "test-app") 295 assert.Contains(t, response, "(aa29b85ababababababab)") 296 } 297 298 func TestHandlerFeatureIsEnabledKeepFullRevisionIsDisabled(t *testing.T) { 299 settingsMgr := settings.NewSettingsManager(t.Context(), fake.NewClientset(argoCDCm(), argoCDSecret()), "default") 300 handler := NewHandler(appclientset.NewSimpleClientset(testApp3()), settingsMgr, "argocd-test", []string{}) 301 req, err := http.NewRequest(http.MethodGet, "/api/badge?name=test-app&revision=true&keepFullRevision=false", http.NoBody) 302 require.NoError(t, err) 303 304 rr := httptest.NewRecorder() 305 handler.ServeHTTP(rr, req) 306 307 assert.Equal(t, "private, no-store", rr.Header().Get("Cache-Control")) 308 assert.Equal(t, "*", rr.Header().Get("Access-Control-Allow-Origin")) 309 310 response := rr.Body.String() 311 assert.Equal(t, toRGBString(Green), leftRectColorPattern.FindStringSubmatch(response)[1]) 312 assert.Equal(t, toRGBString(Green), rightRectColorPattern.FindStringSubmatch(response)[1]) 313 assert.Equal(t, "Healthy", leftTextPattern.FindStringSubmatch(response)[1]) 314 assert.Equal(t, "Synced", rightTextPattern.FindStringSubmatch(response)[1]) 315 assert.NotContains(t, response, "test-app") 316 assert.Contains(t, response, "(aa29b85)") 317 } 318 319 func TestHandlerFeatureIsEnabledKeepFullRevisionAndWidthIsEnabled(t *testing.T) { 320 settingsMgr := settings.NewSettingsManager(t.Context(), fake.NewClientset(argoCDCm(), argoCDSecret()), "default") 321 handler := NewHandler(appclientset.NewSimpleClientset(testApp3()), settingsMgr, "argocd-test", []string{""}) 322 req, err := http.NewRequest(http.MethodGet, "/api/badge?name=test-app&revision=true&keepFullRevision=true&width=500", http.NoBody) 323 require.NoError(t, err) 324 325 rr := httptest.NewRecorder() 326 handler.ServeHTTP(rr, req) 327 328 assert.Equal(t, "private, no-store", rr.Header().Get("Cache-Control")) 329 assert.Equal(t, "*", rr.Header().Get("Access-Control-Allow-Origin")) 330 331 response := rr.Body.String() 332 assert.Equal(t, toRGBString(Green), leftRectColorPattern.FindStringSubmatch(response)[1]) 333 assert.Equal(t, toRGBString(Green), rightRectColorPattern.FindStringSubmatch(response)[1]) 334 assert.Equal(t, "Healthy", leftTextPattern.FindStringSubmatch(response)[1]) 335 assert.Equal(t, "Synced", rightTextPattern.FindStringSubmatch(response)[1]) 336 assert.Equal(t, "500", svgWidthPattern.FindStringSubmatch(response)[1]) 337 assert.NotContains(t, response, "test-app") 338 assert.Contains(t, response, "(aa29b85ababababababab)") 339 } 340 341 func createApplicationFeatureProjectIsEnabled(healthStatus health.HealthStatusCode, syncStatus v1alpha1.SyncStatusCode, appName, projectName, namespace string) *v1alpha1.Application { 342 return &v1alpha1.Application{ 343 ObjectMeta: metav1.ObjectMeta{Name: appName, Namespace: namespace}, 344 Status: v1alpha1.ApplicationStatus{ 345 Sync: v1alpha1.SyncStatus{Status: syncStatus}, 346 Health: v1alpha1.AppHealthStatus{Status: healthStatus}, 347 OperationState: &v1alpha1.OperationState{ 348 SyncResult: &v1alpha1.SyncOperationResult{}, 349 }, 350 }, 351 Spec: v1alpha1.ApplicationSpec{ 352 Project: projectName, 353 }, 354 } 355 } 356 357 func createApplications(appCombo, projectName []string, namespace string) []*v1alpha1.Application { 358 return createApplicationsWithName(appCombo, projectName, namespace, "app") 359 } 360 361 func createApplicationsWithName(appCombo, projectName []string, namespace string, namePrefix string) []*v1alpha1.Application { 362 apps := make([]*v1alpha1.Application, len(appCombo)) 363 healthStatus := func(healthType string) health.HealthStatusCode { 364 switch healthType { 365 case "Healthy": 366 return health.HealthStatusHealthy 367 case "Degraded": 368 return health.HealthStatusDegraded 369 default: 370 return health.HealthStatusUnknown 371 } 372 } 373 syncStatus := func(syncType string) v1alpha1.SyncStatusCode { 374 switch syncType { 375 case "Synced": 376 return v1alpha1.SyncStatusCodeSynced 377 case "OutOfSync": 378 return v1alpha1.SyncStatusCodeOutOfSync 379 default: 380 return v1alpha1.SyncStatusCodeUnknown 381 } 382 } 383 for k, v := range appCombo { 384 a := strings.Split(v, ":") 385 healthApp := healthStatus(a[0]) 386 syncApp := syncStatus(a[1]) 387 appName := fmt.Sprintf("%s-%v", namePrefix, k) 388 apps[k] = createApplicationFeatureProjectIsEnabled(healthApp, syncApp, appName, projectName[k], namespace) 389 } 390 return apps 391 } 392 393 func TestHandlerFeatureIsEnabledRevisionIsEnabled(t *testing.T) { 394 settingsMgr := settings.NewSettingsManager(t.Context(), fake.NewClientset(argoCDCm(), argoCDSecret()), "default") 395 handler := NewHandler(appclientset.NewSimpleClientset(testApp()), settingsMgr, "default", []string{}) 396 req, err := http.NewRequest(http.MethodGet, "/api/badge?name=test-app&revision=true", http.NoBody) 397 require.NoError(t, err) 398 399 rr := httptest.NewRecorder() 400 handler.ServeHTTP(rr, req) 401 402 assert.Equal(t, "private, no-store", rr.Header().Get("Cache-Control")) 403 assert.Equal(t, "*", rr.Header().Get("Access-Control-Allow-Origin")) 404 405 response := rr.Body.String() 406 assert.Equal(t, toRGBString(Green), leftRectColorPattern.FindStringSubmatch(response)[1]) 407 assert.Equal(t, toRGBString(Green), rightRectColorPattern.FindStringSubmatch(response)[1]) 408 assert.Equal(t, "Healthy", leftTextPattern.FindStringSubmatch(response)[1]) 409 assert.Equal(t, "Synced", rightTextPattern.FindStringSubmatch(response)[1]) 410 assert.NotContains(t, response, "test-app") 411 assert.Contains(t, response, "(aa29b85)") 412 } 413 414 func TestHandlerRevisionIsEnabledNoOperationState(t *testing.T) { 415 app := testApp() 416 app.Status.OperationState = nil 417 418 settingsMgr := settings.NewSettingsManager(t.Context(), fake.NewClientset(argoCDCm(), argoCDSecret()), "default") 419 handler := NewHandler(appclientset.NewSimpleClientset(app), settingsMgr, "default", []string{}) 420 req, err := http.NewRequest(http.MethodGet, "/api/badge?name=test-app&revision=true", http.NoBody) 421 require.NoError(t, err) 422 423 rr := httptest.NewRecorder() 424 handler.ServeHTTP(rr, req) 425 426 assert.Equal(t, "private, no-store", rr.Header().Get("Cache-Control")) 427 assert.Equal(t, "*", rr.Header().Get("Access-Control-Allow-Origin")) 428 429 response := rr.Body.String() 430 assert.Equal(t, toRGBString(Green), leftRectColorPattern.FindStringSubmatch(response)[1]) 431 assert.Equal(t, toRGBString(Green), rightRectColorPattern.FindStringSubmatch(response)[1]) 432 assert.Equal(t, "Healthy", leftTextPattern.FindStringSubmatch(response)[1]) 433 assert.Equal(t, "Synced", rightTextPattern.FindStringSubmatch(response)[1]) 434 assert.NotContains(t, response, "test-app") 435 assert.NotContains(t, response, "(aa29b85)") 436 } 437 438 func TestHandlerRevisionIsEnabledShortCommitSHA(t *testing.T) { 439 app := testApp() 440 app.Status.OperationState.SyncResult.Revision = "abc" 441 442 settingsMgr := settings.NewSettingsManager(t.Context(), fake.NewClientset(argoCDCm(), argoCDSecret()), "default") 443 handler := NewHandler(appclientset.NewSimpleClientset(app), settingsMgr, "default", []string{}) 444 req, err := http.NewRequest(http.MethodGet, "/api/badge?name=test-app&revision=true", http.NoBody) 445 require.NoError(t, err) 446 447 rr := httptest.NewRecorder() 448 handler.ServeHTTP(rr, req) 449 450 response := rr.Body.String() 451 assert.Contains(t, response, "(abc)") 452 } 453 454 func TestHandlerRevisionIsEnabledMultipleSources(t *testing.T) { 455 app := testApp() 456 app.Status.OperationState.SyncResult.Revision = "" 457 app.Status.OperationState.SyncResult.Revisions = []string{"aa29b85", "cf41g63"} 458 459 settingsMgr := settings.NewSettingsManager(t.Context(), fake.NewClientset(argoCDCm(), argoCDSecret()), "default") 460 handler := NewHandler(appclientset.NewSimpleClientset(app), settingsMgr, "default", []string{}) 461 req, err := http.NewRequest(http.MethodGet, "/api/badge?name=test-app&revision=true", http.NoBody) 462 require.NoError(t, err) 463 464 rr := httptest.NewRecorder() 465 handler.ServeHTTP(rr, req) 466 467 response := rr.Body.String() 468 assert.Contains(t, response, "(aa29b85)") 469 assert.NotContains(t, response, "(cf41g63)") 470 } 471 472 func TestHandlerFeatureIsDisabled(t *testing.T) { 473 argoCDCmDisabled := argoCDCm() 474 delete(argoCDCmDisabled.Data, "statusbadge.enabled") 475 476 settingsMgr := settings.NewSettingsManager(t.Context(), fake.NewSimpleClientset(argoCDCmDisabled, argoCDSecret()), "default") 477 handler := NewHandler(appclientset.NewSimpleClientset(testApp()), settingsMgr, "default", []string{}) 478 req, err := http.NewRequest(http.MethodGet, "/api/badge?name=test-app", http.NoBody) 479 require.NoError(t, err) 480 481 rr := httptest.NewRecorder() 482 handler.ServeHTTP(rr, req) 483 484 assert.Equal(t, "private, no-store", rr.Header().Get("Cache-Control")) 485 assert.Equal(t, "*", rr.Header().Get("Access-Control-Allow-Origin")) 486 487 response := rr.Body.String() 488 assert.Equal(t, toRGBString(Purple), leftRectColorPattern.FindStringSubmatch(response)[1]) 489 assert.Equal(t, toRGBString(Purple), rightRectColorPattern.FindStringSubmatch(response)[1]) 490 assert.Equal(t, "Unknown", leftTextPattern.FindStringSubmatch(response)[1]) 491 assert.Equal(t, "Unknown", rightTextPattern.FindStringSubmatch(response)[1]) 492 assert.NotContains(t, response, "test-app") 493 assert.Equal(t, "\"20\"", svgHeightPattern.FindStringSubmatch(response)[2]) 494 } 495 496 func TestHandlerApplicationNameInBadgeIsEnabled(t *testing.T) { 497 settingsMgr := settings.NewSettingsManager(t.Context(), fake.NewSimpleClientset(argoCDCm(), argoCDSecret()), "default") 498 handler := NewHandler(appclientset.NewSimpleClientset(testApp()), settingsMgr, "default", []string{}) 499 req, err := http.NewRequest(http.MethodGet, "/api/badge?name=test-app&showAppName=true", http.NoBody) 500 require.NoError(t, err) 501 502 rr := httptest.NewRecorder() 503 handler.ServeHTTP(rr, req) 504 505 assert.Equal(t, "private, no-store", rr.Header().Get("Cache-Control")) 506 assert.Equal(t, "*", rr.Header().Get("Access-Control-Allow-Origin")) 507 508 response := rr.Body.String() 509 assert.Equal(t, toRGBString(Green), leftRectColorPattern.FindStringSubmatch(response)[1]) 510 assert.Equal(t, toRGBString(Green), rightRectColorPattern.FindStringSubmatch(response)[1]) 511 assert.Equal(t, "Healthy", leftTextPattern.FindStringSubmatch(response)[1]) 512 assert.Equal(t, "Synced", rightTextPattern.FindStringSubmatch(response)[1]) 513 assert.NotContains(t, response, "(aa29b85)") 514 515 assert.Equal(t, "test-app", titleTextPattern.FindStringSubmatch(response)[1]) 516 assert.Equal(t, fmt.Sprintf("\"%d\"", svgHeightWithAppName), svgHeightPattern.FindStringSubmatch(response)[2]) 517 assert.Equal(t, fmt.Sprintf("\"%d\"", badgeRowHeight), leftRectYCoodPattern.FindStringSubmatch(response)[2]) 518 assert.Equal(t, fmt.Sprintf("\"%d\"", badgeRowHeight), rightRectYCoodPattern.FindStringSubmatch(response)[2]) 519 assert.Equal(t, fmt.Sprintf("\"%d\"", badgeRowHeight), revisionRectYCoodPattern.FindStringSubmatch(response)[2]) 520 assert.Equal(t, fmt.Sprintf("\"%d\"", logoYCoodWithAppName), logoYCoodPattern.FindStringSubmatch(response)[2]) 521 } 522 523 func TestHandlerApplicationNameInBadgeIsDisabled(t *testing.T) { 524 settingsMgr := settings.NewSettingsManager(t.Context(), fake.NewSimpleClientset(argoCDCm(), argoCDSecret()), "default") 525 handler := NewHandler(appclientset.NewSimpleClientset(testApp()), settingsMgr, "default", []string{}) 526 req, err := http.NewRequest(http.MethodGet, "/api/badge?name=test-app", http.NoBody) 527 require.NoError(t, err) 528 529 rr := httptest.NewRecorder() 530 handler.ServeHTTP(rr, req) 531 532 assert.Equal(t, "private, no-store", rr.Header().Get("Cache-Control")) 533 assert.Equal(t, "*", rr.Header().Get("Access-Control-Allow-Origin")) 534 535 response := rr.Body.String() 536 assert.Equal(t, toRGBString(Green), leftRectColorPattern.FindStringSubmatch(response)[1]) 537 assert.Equal(t, toRGBString(Green), rightRectColorPattern.FindStringSubmatch(response)[1]) 538 assert.Equal(t, "Healthy", leftTextPattern.FindStringSubmatch(response)[1]) 539 assert.Equal(t, "Synced", rightTextPattern.FindStringSubmatch(response)[1]) 540 assert.Equal(t, "\"20\"", svgHeightPattern.FindStringSubmatch(response)[2]) 541 assert.Equal(t, "\"0\"", leftRectYCoodPattern.FindStringSubmatch(response)[2]) 542 assert.Equal(t, "\"0\"", rightRectYCoodPattern.FindStringSubmatch(response)[2]) 543 assert.Equal(t, "\"0\"", revisionRectYCoodPattern.FindStringSubmatch(response)[2]) 544 assert.Equal(t, "\"2\"", logoYCoodPattern.FindStringSubmatch(response)[2]) 545 assert.NotContains(t, response, "test-app") 546 }