github.com/verrazzano/verrazzano@v1.7.0/application-operator/mcagent/mcagent_appconfig_test.go (about) 1 // Copyright (c) 2021, 2022, Oracle and/or its affiliates. 2 // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 4 package mcagent 5 6 import ( 7 "context" 8 "encoding/json" 9 "path/filepath" 10 "testing" 11 12 oamv1alpha2 "github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2" 13 asserts "github.com/stretchr/testify/assert" 14 clustersv1alpha1 "github.com/verrazzano/verrazzano/application-operator/apis/clusters/v1alpha1" 15 "github.com/verrazzano/verrazzano/application-operator/constants" 16 clusterstest "github.com/verrazzano/verrazzano/application-operator/controllers/clusters/test" 17 vzconst "github.com/verrazzano/verrazzano/pkg/constants" 18 "go.uber.org/zap" 19 "k8s.io/apimachinery/pkg/api/errors" 20 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 "k8s.io/apimachinery/pkg/runtime" 22 "k8s.io/apimachinery/pkg/types" 23 "sigs.k8s.io/controller-runtime/pkg/client/fake" 24 ) 25 26 var mcAppConfigExpectedLabels = map[string]string{"label1": "test1", vzconst.VerrazzanoManagedLabelKey: constants.LabelVerrazzanoManagedDefault} 27 var mcAppConfigExpectedLabelsAfterUpdate = map[string]string{"label1": "test1updated", vzconst.VerrazzanoManagedLabelKey: constants.LabelVerrazzanoManagedDefault} 28 29 // TestCreateMCAppConfig tests the synchronization method for the following use case. 30 // GIVEN a request to sync MultiClusterApplicationConfiguration objects 31 // WHEN the new object exists 32 // THEN ensure that the MultiClusterApplicationConfiguration and its associated OAM Component are created. 33 func TestCreateMCAppConfig(t *testing.T) { 34 assert := asserts.New(t) 35 log := zap.S().With("test") 36 37 // Test data 38 testMCAppConfig, err := getSampleMCAppConfig("testdata/multicluster-appconfig.yaml") 39 assert.NoError(err, "failed to read sample data for MultiClusterApplicationConfiguration") 40 41 testComponent, err := getSampleOamComponent("testdata/hello-component.yaml") 42 assert.NoError(err, "failed to read sample data for OAM Component") 43 44 adminClient := fake.NewClientBuilder().WithScheme(newScheme()).WithObjects(&testMCAppConfig, &testComponent).Build() 45 46 localClient := fake.NewClientBuilder().WithScheme(newScheme()).Build() 47 48 // Make the request 49 s := &Syncer{ 50 AdminClient: adminClient, 51 LocalClient: localClient, 52 Log: log, 53 ManagedClusterName: testClusterName, 54 Context: context.TODO(), 55 } 56 err = s.syncMCApplicationConfigurationObjects(testMCAppConfigNamespace) 57 58 // Validate the results 59 assert.NoError(err) 60 61 // Verify the associated OAM component got created on local cluster 62 component := &oamv1alpha2.Component{} 63 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testComponent.Name, Namespace: testComponent.Namespace}, component) 64 assert.NoError(err) 65 assert.Equal(s.ManagedClusterName, component.Labels[managedClusterLabel]) 66 assert.Equal(testMCAppConfig.Name, component.Labels[mcAppConfigsLabel]) 67 assert.Equal(constants.LabelVerrazzanoManagedDefault, component.Labels[vzconst.VerrazzanoManagedLabelKey]) 68 69 // Verify MultiClusterApplicationConfiguration got created on local cluster 70 mcAppConfig := &clustersv1alpha1.MultiClusterApplicationConfiguration{} 71 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testMCAppConfig.Name, Namespace: testMCAppConfig.Namespace}, mcAppConfig) 72 assert.NoError(err) 73 assert.Equal(mcAppConfig.Labels, mcAppConfigExpectedLabels, "mcappconfig labels did not match") 74 assert.Equal(testClusterName, mcAppConfig.Spec.Placement.Clusters[0].Name, "mcappconfig does not contain expected placement") 75 } 76 77 // TestCreateMCAppConfigNoOAMComponent tests the synchronization method for the following use case. 78 // GIVEN a request to sync MultiClusterApplicationConfiguration objects 79 // WHEN the component referenced is a MultiClusterComponent 80 // THEN ensure that the MultiClusterApplicationConfiguration is created but not the OAM component 81 func TestCreateMCAppConfigNoOAMComponent(t *testing.T) { 82 assert := asserts.New(t) 83 log := zap.S().With("test") 84 85 // Test data 86 testMCAppConfig, err := getSampleMCAppConfig("testdata/multicluster-appconfig.yaml") 87 assert.NoError(err, "failed to read sample data for MultiClusterApplicationConfiguration") 88 89 testMCComponent, err := getSampleMCComponent("testdata/mc-hello-component.yaml") 90 assert.NoError(err, "failed to read sample data for MultiCusterComponent") 91 92 adminClient := fake.NewClientBuilder().WithScheme(newScheme()).WithObjects(&testMCAppConfig).Build() 93 94 localClient := fake.NewClientBuilder().WithScheme(newScheme()).WithObjects(&testMCComponent).Build() 95 96 // Make the request 97 s := &Syncer{ 98 AdminClient: adminClient, 99 LocalClient: localClient, 100 Log: log, 101 ManagedClusterName: testClusterName, 102 Context: context.TODO(), 103 } 104 err = s.syncMCApplicationConfigurationObjects(testMCAppConfigNamespace) 105 106 // Validate the results 107 assert.NoError(err) 108 109 // Verify the associated OAM component did not get created on local cluster since we are 110 // using a MultiClusterComponent instead of an OAM Component in the MultuClusterApplicationConfiguration 111 component := &oamv1alpha2.Component{} 112 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testMCComponent.Name, Namespace: testMCComponent.Namespace}, component) 113 assert.True(errors.IsNotFound(err)) 114 115 // Verify MultiClusterApplicationConfiguration got created on local cluster 116 mcAppConfig := &clustersv1alpha1.MultiClusterApplicationConfiguration{} 117 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testMCAppConfig.Name, Namespace: testMCAppConfig.Namespace}, mcAppConfig) 118 assert.NoError(err) 119 assert.Equal(mcAppConfig.Labels, mcAppConfigExpectedLabels, "mcappconfig labels did not match") 120 assert.Equal(testClusterName, mcAppConfig.Spec.Placement.Clusters[0].Name, "mcappconfig does not contain expected placement") 121 } 122 123 // TestUpdateMCAppConfig tests the synchronization method for the following use case. 124 // GIVEN a request to sync MultiClusterApplicationConfiguration objects 125 // WHEN the object exists 126 // THEN ensure that the MultiClusterApplicationConfiguration is updated. 127 func TestUpdateMCAppConfig(t *testing.T) { 128 assert := asserts.New(t) 129 log := zap.S().With("test") 130 131 // Test data 132 testMCAppConfig, err := getSampleMCAppConfig("testdata/multicluster-appconfig.yaml") 133 assert.NoError(err, "failed to read sample data for MultiClusterApplicationConfiguration") 134 135 testMCAppConfigUpdate, err := getSampleMCAppConfig("testdata/multicluster-appconfig-update.yaml") 136 assert.NoError(err, "failed to read sample data for MultiClusterApplicationConfiguration") 137 138 testComponent1, err := getSampleOamComponent("testdata/hello-component.yaml") 139 assert.NoError(err, "failed to read sample data for OAM Component") 140 141 testComponent2, err := getSampleOamComponent("testdata/goodbye-component.yaml") 142 assert.NoError(err, "failed to read sample data for OAM Component") 143 144 adminClient := fake.NewClientBuilder().WithScheme(newScheme()).WithObjects(&testMCAppConfigUpdate, &testComponent1, &testComponent2).Build() 145 146 localClient := fake.NewClientBuilder().WithScheme(newScheme()).WithObjects(&testMCAppConfig, &testComponent1, &testComponent2).Build() 147 148 // Make the request 149 s := &Syncer{ 150 AdminClient: adminClient, 151 LocalClient: localClient, 152 Log: log, 153 ManagedClusterName: testClusterName, 154 Context: context.TODO(), 155 } 156 err = s.syncMCApplicationConfigurationObjects(testMCAppConfigNamespace) 157 158 // Validate the results 159 assert.NoError(err) 160 161 // Verify the MultiClusterApplicationConfiguration on the managed cluster is equal to the one on the admin cluster 162 mcAppConfig := &clustersv1alpha1.MultiClusterApplicationConfiguration{} 163 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testMCAppConfig.Name, Namespace: testMCAppConfig.Namespace}, mcAppConfig) 164 assert.NoError(err) 165 assert.Equal(mcAppConfigExpectedLabelsAfterUpdate, mcAppConfig.Labels, "mcappconfig labels did not match") 166 assert.Equal("Hello application updated", mcAppConfig.Spec.Template.Metadata.Annotations["description"]) 167 assert.Equal(2, len(mcAppConfig.Spec.Template.Spec.Components)) 168 comp0 := mcAppConfig.Spec.Template.Spec.Components[0] 169 comp1 := mcAppConfig.Spec.Template.Spec.Components[1] 170 assert.Equal("hello-component", comp0.ComponentName) 171 assert.Equal("goodbye-component", comp1.ComponentName) 172 173 // Verify the associated OAM component got created on local cluster 174 component1 := &oamv1alpha2.Component{} 175 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testComponent1.Name, Namespace: testComponent1.Namespace}, component1) 176 assert.NoError(err) 177 assert.Equal(s.ManagedClusterName, component1.Labels[managedClusterLabel]) 178 assert.Equal(testMCAppConfig.Name, component1.Labels[mcAppConfigsLabel]) 179 180 component2 := &oamv1alpha2.Component{} 181 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testComponent2.Name, Namespace: testComponent2.Namespace}, component2) 182 assert.NoError(err) 183 assert.Equal(s.ManagedClusterName, component2.Labels[managedClusterLabel]) 184 assert.Equal(testMCAppConfig.Name, component2.Labels[mcAppConfigsLabel]) 185 } 186 187 // TestDeleteMCAppConfig tests the synchronization method for the following use case. 188 // GIVEN a request to sync MultiClusterApplicationConfiguration objects 189 // WHEN the object exists on the local cluster but not on the admin cluster 190 // THEN ensure that the MultiClusterApplicationConfiguration is deleted. 191 func TestDeleteMCAppConfig(t *testing.T) { 192 assert := asserts.New(t) 193 log := zap.S().With("test") 194 195 // Test data 196 testMCAppConfig, err := getSampleMCAppConfig("testdata/multicluster-appconfig.yaml") 197 assert.NoError(err, "failed to read sample data for MultiClusterApplicationConfiguration") 198 199 testMCAppConfigOrphan, err := getSampleMCAppConfig("testdata/multicluster-appconfig.yaml") 200 assert.NoError(err, "failed to read sample data for MultiClusterApplicationConfiguration") 201 testMCAppConfigOrphan.Name = "orphaned-resource" 202 203 testComponent, err := getSampleOamComponent("testdata/hello-component.yaml") 204 assert.NoError(err, "failed to read sample data for OAM Component") 205 206 adminClient := fake.NewClientBuilder().WithScheme(newScheme()).WithObjects(&testMCAppConfig, &testComponent).Build() 207 localClient := fake.NewClientBuilder().WithScheme(newScheme()).WithObjects(&testComponent, &testMCAppConfig, &testMCAppConfigOrphan).Build() 208 209 // Make the request 210 s := &Syncer{ 211 AdminClient: adminClient, 212 LocalClient: localClient, 213 Log: log, 214 ManagedClusterName: testClusterName, 215 Context: context.TODO(), 216 } 217 err = s.syncMCApplicationConfigurationObjects(testMCAppConfigNamespace) 218 219 // Validate the results 220 assert.NoError(err) 221 222 // Expect the orphaned MultiClusterApplicationConfiguration object to be deleted from the local cluster 223 appConfig := &clustersv1alpha1.MultiClusterApplicationConfiguration{} 224 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testMCAppConfigOrphan.Name, Namespace: testMCAppConfigOrphan.Namespace}, appConfig) 225 assert.True(errors.IsNotFound(err)) 226 227 // Delete the MultiClusterApplicationConfiguration from the admin cluster 228 err = s.AdminClient.Delete(s.Context, &testMCAppConfig) 229 assert.NoError(err) 230 231 // Synchronize again and check for cleanup on the local cluster 232 err = s.syncMCApplicationConfigurationObjects(testMCAppConfigNamespace) 233 assert.NoError(err) 234 235 // Expect the MultiClusterApplicationConfiguration object to be deleted from the local cluster 236 appConfig2 := &clustersv1alpha1.MultiClusterApplicationConfiguration{} 237 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testMCAppConfig.Name, Namespace: testMCAppConfig.Namespace}, appConfig2) 238 assert.True(errors.IsNotFound(err)) 239 240 // Expect the OAM Component used by the application to be deleted from the local cluster 241 component := &oamv1alpha2.Component{} 242 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testComponent.Name, Namespace: testComponent.Namespace}, component) 243 assert.True(errors.IsNotFound(err)) 244 } 245 246 // TestDeleteMCAppConfigNoOAMComponent tests the synchronization method for the following use case. 247 // GIVEN a request to sync MultiClusterApplicationConfiguration objects 248 // WHEN a MultiClusterApplicationConfiguration object is deleted from the admin cluster that references a 249 // MultiClusterComponent object. 250 // THEN ensure that the MultiClusterApplicationConfiguration is deleted and OAM component object is not deleted 251 func TestDeleteMCAppConfigNoOAMComponent(t *testing.T) { 252 assert := asserts.New(t) 253 log := zap.S().With("test") 254 255 // Test data 256 testMCAppConfig, err := getSampleMCAppConfig("testdata/multicluster-appconfig.yaml") 257 assert.NoError(err, "failed to read sample data for MultiClusterApplicationConfiguration") 258 259 testOAMComponent, err := getSampleOamComponent("testdata/hello-component.yaml") 260 assert.NoError(err, "failed to read sample data for Component") 261 262 testMCComponent, err := getSampleMCComponent("testdata/mc-hello-component.yaml") 263 assert.NoError(err, "failed to read sample data for MultiClusterComponent") 264 265 adminClient := fake.NewClientBuilder().WithScheme(newScheme()).WithObjects(&testMCAppConfig).Build() 266 localClient := fake.NewClientBuilder().WithScheme(newScheme()).WithObjects(&testOAMComponent, &testMCComponent).Build() 267 268 // Make the request 269 s := &Syncer{ 270 AdminClient: adminClient, 271 LocalClient: localClient, 272 Log: log, 273 ManagedClusterName: testClusterName, 274 Context: context.TODO(), 275 } 276 277 // Set cluster label on OAM Component 278 testOAMComponent.Labels[managedClusterLabel] = "managed1" 279 err = s.LocalClient.Update(s.Context, &testOAMComponent) 280 assert.NoError(err) 281 282 err = s.syncMCApplicationConfigurationObjects(testMCAppConfigNamespace) 283 assert.NoError(err) 284 285 // Verify OAM Component exists on local cluster 286 component := &oamv1alpha2.Component{} 287 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testOAMComponent.Name, Namespace: testOAMComponent.Namespace}, component) 288 assert.NoError(err) 289 290 // Verify MultiClusterApplicationConfiguration got created on local cluster 291 mcAppConfig := &clustersv1alpha1.MultiClusterApplicationConfiguration{} 292 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testMCAppConfig.Name, Namespace: testMCAppConfig.Namespace}, mcAppConfig) 293 assert.NoError(err) 294 295 // Delete the MultiClusterApplicationConfiguration from the admin cluster 296 err = s.AdminClient.Delete(s.Context, &testMCAppConfig) 297 assert.NoError(err) 298 299 // Synchronize again and check for cleanup on the local cluster 300 err = s.syncMCApplicationConfigurationObjects(testMCAppConfigNamespace) 301 assert.NoError(err) 302 303 // Expect the MultiClusterApplicationConfiguration object to be deleted from the local cluster 304 mcAppConfig = &clustersv1alpha1.MultiClusterApplicationConfiguration{} 305 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testMCAppConfig.Name, Namespace: testMCAppConfig.Namespace}, mcAppConfig) 306 assert.True(errors.IsNotFound(err)) 307 308 // Expect the OAM Component used by the application to NOT be deleted from the local cluster 309 component = &oamv1alpha2.Component{} 310 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testOAMComponent.Name, Namespace: testOAMComponent.Namespace}, component) 311 assert.NoError(err) 312 } 313 314 // TestDeleteMCAppConfigShared tests the synchronization method for the following use case. 315 // GIVEN a request to sync two MultiClusterApplicationConfiguration objects that shared an OAM Component 316 // WHEN the object exists on the local cluster but not on the admin cluster 317 // THEN ensure that when MultiClusterApplicationConfiguration is deleted, the shared OAM component is not 318 // GIVEN a request to sync MultiClusterApplicationConfiguration objects 319 // WHEN no remaining MultiClusterApplicationConfiguration exist on the admin cluster 320 // THEN ensure that when MultiClusterApplicationConfiguration is deleted, the OAM component that is no longer shared is deleted 321 func TestDeleteMCAppConfigShared(t *testing.T) { 322 assert := asserts.New(t) 323 log := zap.S().With("test") 324 325 // Test data 326 testMCAppConfig, err := getSampleMCAppConfig("testdata/multicluster-appconfig.yaml") 327 assert.NoError(err, "failed to read sample data for MultiClusterApplicationConfiguration") 328 329 testMCAppConfig2, err := getSampleMCAppConfig("testdata/multicluster-appconfig.yaml") 330 assert.NoError(err, "failed to read sample data for MultiClusterApplicationConfiguration") 331 testMCAppConfig2.Name = testMCAppConfig.Name + "2" 332 333 testComponent, err := getSampleOamComponent("testdata/hello-component.yaml") 334 assert.NoError(err, "failed to read sample data for OAM Component") 335 336 adminClient := fake.NewClientBuilder().WithScheme(newScheme()).WithObjects(&testMCAppConfig, &testComponent).Build() 337 localClient := fake.NewClientBuilder().WithScheme(newScheme()).WithObjects(&testComponent, &testMCAppConfig, &testMCAppConfig2).Build() 338 339 // Make the request 340 s := &Syncer{ 341 AdminClient: adminClient, 342 LocalClient: localClient, 343 Log: log, 344 ManagedClusterName: testClusterName, 345 Context: context.TODO(), 346 } 347 err = s.syncMCApplicationConfigurationObjects(testMCAppConfigNamespace) 348 349 // Validate the results 350 assert.NoError(err) 351 352 // Expect the MultiClusterApplicationConfiguration object to be deleted from the local cluster 353 appConfig := &clustersv1alpha1.MultiClusterApplicationConfiguration{} 354 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testMCAppConfig2.Name, Namespace: testMCAppConfig2.Namespace}, appConfig) 355 assert.True(errors.IsNotFound(err)) 356 357 // Expect the OAM Component shared by the applications to still exist on the local cluster 358 component := &oamv1alpha2.Component{} 359 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testComponent.Name, Namespace: testComponent.Namespace}, component) 360 assert.NoError(err) 361 assert.Equal(testMCAppConfig.Name, component.Labels[mcAppConfigsLabel]) 362 363 // Delete the remaining MultiClusterApplicationConfiguration in the Admin cluster and verify cleanup on the local cluster 364 err = s.AdminClient.Delete(s.Context, &testMCAppConfig) 365 assert.NoError(err) 366 err = s.syncMCApplicationConfigurationObjects(testMCAppConfigNamespace) 367 assert.NoError(err) 368 369 // Expect the MultiClusterApplicationConfiguration object to be deleted from the local cluster 370 appConfig2 := &clustersv1alpha1.MultiClusterApplicationConfiguration{} 371 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testMCAppConfig.Name, Namespace: testMCAppConfig.Namespace}, appConfig2) 372 assert.True(errors.IsNotFound(err)) 373 374 // Expect the OAM Component that used to be shared by the applications to be deleted from the local cluster 375 component2 := &oamv1alpha2.Component{} 376 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testComponent.Name, Namespace: testComponent.Namespace}, component2) 377 assert.True(errors.IsNotFound(err)) 378 } 379 380 // TestDeleteOrphanedComponents tests the synchronization method for the following use case. 381 // GIVEN a request to sync MultiClusterApplicationConfiguration objects 382 // WHEN an OAM component exists on a cluster that is no longer associated with any MultiClusterApplicationConfiguration 383 // THEN ensure that the orphaned OAM component gets deleted 384 func TestDeleteOrphanedComponents(t *testing.T) { 385 assert := asserts.New(t) 386 log := zap.S().With("test") 387 388 // Test data 389 390 // Add labels that would have been applied when the OAM component was synced to the local system 391 testComponent1, err := getSampleOamComponent("testdata/hello-component.yaml") 392 assert.NoError(err, "failed to read sample data for OAM Component") 393 testComponent1.Labels[managedClusterLabel] = testClusterName 394 testComponent1.Labels[mcAppConfigsLabel] = "" 395 396 // Do not add any Verrazzano labels to this component 397 testComponent2, err := getSampleOamComponent("testdata/goodbye-component.yaml") 398 assert.NoError(err, "failed to read sample data for OAM Component") 399 400 adminClient := fake.NewClientBuilder().WithScheme(newScheme()).Build() 401 localClient := fake.NewClientBuilder().WithScheme(newScheme()).WithObjects(&testComponent1, &testComponent2).Build() 402 403 // Make the request 404 s := &Syncer{ 405 AdminClient: adminClient, 406 LocalClient: localClient, 407 Log: log, 408 ManagedClusterName: testClusterName, 409 Context: context.TODO(), 410 } 411 err = s.syncMCApplicationConfigurationObjects(testMCAppConfigNamespace) 412 413 // Validate the results 414 assert.NoError(err) 415 416 // Expect the orphaned OAM Component to be deleted from the local cluster 417 component1 := &oamv1alpha2.Component{} 418 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testComponent1.Name, Namespace: testComponent1.Namespace}, component1) 419 assert.True(errors.IsNotFound(err)) 420 421 // Expect the OAM component that was not synced to still exist 422 component2 := &oamv1alpha2.Component{} 423 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testComponent2.Name, Namespace: testComponent2.Namespace}, component2) 424 assert.NoError(err) 425 } 426 427 // TestMCAppConfigPlacement tests the synchronization method for the following use case. 428 // GIVEN a request to sync MultiClusterApplicationConfiguration objects 429 // WHEN an object exists that is not targeted for the cluster 430 // THEN ensure that the MultiClusterApplicationConfiguration is not created or updated 431 func TestMCAppConfigPlacement(t *testing.T) { 432 assert := asserts.New(t) 433 log := zap.S().With("test") 434 435 // Test data 436 adminMCAppConfig, err := getSampleMCAppConfig("testdata/multicluster-appconfig.yaml") 437 assert.NoError(err, "failed to read sample data for MultiClusterApplicationConfiguration") 438 adminMCAppConfig.Spec.Placement.Clusters[0].Name = "not-my-cluster" 439 440 localMCAppConfig, err := getSampleMCAppConfig("testdata/multicluster-appconfig.yaml") 441 assert.NoError(err, "failed to read sample data for MultiClusterApplicationConfiguration") 442 443 adminClient := fake.NewClientBuilder().WithScheme(newScheme()).WithObjects(&adminMCAppConfig).Build() 444 445 localClient := fake.NewClientBuilder().WithScheme(newScheme()).WithObjects(&localMCAppConfig).Build() 446 447 // Make the request 448 s := &Syncer{ 449 AdminClient: adminClient, 450 LocalClient: localClient, 451 Log: log, 452 ManagedClusterName: testClusterName, 453 Context: context.TODO(), 454 } 455 err = s.syncMCApplicationConfigurationObjects(testMCAppConfigNamespace) 456 457 // Verify the local MultiClusterApplicationConiguration was deleted 458 assert.NoError(err) 459 delAppConfig := &clustersv1alpha1.MultiClusterApplicationConfiguration{} 460 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: localMCAppConfig.Name, Namespace: localMCAppConfig.Namespace}, delAppConfig) 461 assert.True(errors.IsNotFound(err)) 462 } 463 464 // TestSyncComponentList tests the synchronization method for the following use case. 465 // GIVEN a request to sync MultiClusterApplicationConfiguration objects 466 // WHEN it contains a list of OAM Components 467 // THEN ensure that the embedded OAM Components are created or updated 468 func TestSyncComponentList(t *testing.T) { 469 appName := "test" 470 appNamespace := "test-ns" 471 compName1 := "test-comp-1" 472 compName2 := "test-comp-2" 473 param1 := "parameter-1" 474 param2 := "parameter-2" 475 testLabel := "test-label" 476 testAnnot := "test-annotation" 477 478 assert := asserts.New(t) 479 log := zap.S().With("test") 480 481 // Create a fake client for the admin cluster 482 adminClient := fake.NewClientBuilder().WithScheme(newScheme()).WithObjects( 483 &oamv1alpha2.Component{ 484 ObjectMeta: metav1.ObjectMeta{ 485 Name: compName1, 486 Namespace: appNamespace, 487 Labels: map[string]string{"test": testLabel}, 488 Annotations: map[string]string{"test": testAnnot}}, 489 Spec: oamv1alpha2.ComponentSpec{ 490 Parameters: []oamv1alpha2.ComponentParameter{ 491 { 492 Name: param1, 493 }, 494 }, 495 }, 496 }, 497 &oamv1alpha2.Component{ 498 ObjectMeta: metav1.ObjectMeta{ 499 Name: compName2, 500 Namespace: appNamespace, 501 Labels: map[string]string{"test": testLabel}, 502 Annotations: map[string]string{"test": testAnnot}}, 503 Spec: oamv1alpha2.ComponentSpec{ 504 Parameters: []oamv1alpha2.ComponentParameter{ 505 { 506 Name: param2, 507 }, 508 }, 509 }, 510 }, 511 ).Build() 512 513 // Create a fake client for the local cluster 514 localClient := fake.NewClientBuilder().WithScheme(newScheme()).Build() 515 516 // MultiClusterApplicationConfiguration test data 517 mcAppConfig := clustersv1alpha1.MultiClusterApplicationConfiguration{ 518 ObjectMeta: metav1.ObjectMeta{Name: appName, Namespace: appNamespace}, 519 Spec: clustersv1alpha1.MultiClusterApplicationConfigurationSpec{ 520 Template: clustersv1alpha1.ApplicationConfigurationTemplate{ 521 Spec: oamv1alpha2.ApplicationConfigurationSpec{ 522 Components: []oamv1alpha2.ApplicationConfigurationComponent{ 523 { 524 ComponentName: compName1, 525 }, 526 { 527 ComponentName: compName2, 528 }, 529 }, 530 }, 531 }, 532 }, 533 } 534 535 // Make the request 536 s := &Syncer{ 537 AdminClient: adminClient, 538 LocalClient: localClient, 539 Log: log, 540 ManagedClusterName: testClusterName, 541 Context: context.TODO(), 542 } 543 err := s.syncComponentList(mcAppConfig) 544 assert.NoError(err) 545 546 // Verify the components were created locally 547 component1 := &oamv1alpha2.Component{} 548 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: compName1, Namespace: appNamespace}, component1) 549 assert.NoError(err) 550 assert.Equal(param1, component1.Spec.Parameters[0].Name) 551 assert.Equal(testLabel, component1.ObjectMeta.Labels["test"]) 552 assert.Equal(testAnnot, component1.ObjectMeta.Annotations["test"]) 553 554 component2 := &oamv1alpha2.Component{} 555 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: compName2, Namespace: appNamespace}, component2) 556 assert.NoError(err) 557 assert.Equal(param2, component2.Spec.Parameters[0].Name) 558 assert.Equal(testLabel, component2.ObjectMeta.Labels["test"]) 559 assert.Equal(testAnnot, component2.ObjectMeta.Annotations["test"]) 560 } 561 562 // getSampleMCAppConfig creates and returns a sample MultiClusterApplicationConfiguration used in tests 563 func getSampleMCAppConfig(filePath string) (clustersv1alpha1.MultiClusterApplicationConfiguration, error) { 564 mcAppConfig := clustersv1alpha1.MultiClusterApplicationConfiguration{} 565 sampleAppConfigFile, err := filepath.Abs(filePath) 566 if err != nil { 567 return mcAppConfig, err 568 } 569 570 rawResource, err := clusterstest.ReadYaml2Json(sampleAppConfigFile) 571 if err != nil { 572 return mcAppConfig, err 573 } 574 575 err = json.Unmarshal(rawResource, &mcAppConfig) 576 return mcAppConfig, err 577 } 578 579 // getSampleOamComponent creates and returns a sample OAM Component 580 func getSampleOamComponent(filePath string) (oamv1alpha2.Component, error) { 581 component := oamv1alpha2.Component{} 582 sampleComponentFile, err := filepath.Abs(filePath) 583 if err != nil { 584 return component, err 585 } 586 587 rawResource, err := clusterstest.ReadYaml2Json(sampleComponentFile) 588 if err != nil { 589 return component, err 590 } 591 592 err = json.Unmarshal(rawResource, &component) 593 return component, err 594 } 595 596 func newScheme() *runtime.Scheme { 597 scheme := runtime.NewScheme() 598 oamv1alpha2.SchemeBuilder.AddToScheme(scheme) 599 clustersv1alpha1.AddToScheme(scheme) 600 return scheme 601 }