@@ -34,7 +34,6 @@ import (
34
34
"k8s.io/apimachinery/pkg/runtime"
35
35
"k8s.io/apimachinery/pkg/types"
36
36
utilclock "k8s.io/apimachinery/pkg/util/clock"
37
- "k8s.io/apimachinery/pkg/util/diff"
38
37
utilerrors "k8s.io/apimachinery/pkg/util/errors"
39
38
"k8s.io/apimachinery/pkg/util/intstr"
40
39
"k8s.io/apimachinery/pkg/util/wait"
@@ -3667,9 +3666,13 @@ func TestUpdates(t *testing.T) {
3667
3666
}
3668
3667
3669
3668
func TestSyncOperatorGroups (t * testing.T ) {
3670
- logrus .SetLevel (logrus .DebugLevel )
3669
+ logrus .SetLevel (logrus .WarnLevel )
3671
3670
clockFake := utilclock .NewFakeClock (time .Date (2006 , time .January , 2 , 15 , 4 , 5 , 0 , time .FixedZone ("MST" , - 7 * 3600 )))
3672
3671
now := metav1 .NewTime (clockFake .Now ().UTC ())
3672
+ const (
3673
+ timeout = 5 * time .Second
3674
+ tick = 50 * time .Millisecond
3675
+ )
3673
3676
3674
3677
operatorNamespace := "operator-ns"
3675
3678
targetNamespace := "target-ns"
@@ -4305,6 +4308,10 @@ func TestSyncOperatorGroups(t *testing.T) {
4305
4308
expectedEqual : true ,
4306
4309
initial : initial {
4307
4310
operatorGroup : & v1.OperatorGroup {
4311
+ TypeMeta : metav1.TypeMeta {
4312
+ Kind : v1 .OperatorGroupKind ,
4313
+ APIVersion : v1 .GroupVersion .String (),
4314
+ },
4308
4315
ObjectMeta : metav1.ObjectMeta {
4309
4316
Name : "operator-group-1" ,
4310
4317
Namespace : operatorNamespace ,
@@ -4334,6 +4341,10 @@ func TestSyncOperatorGroups(t *testing.T) {
4334
4341
final : final {objects : map [string ][]runtime.Object {
4335
4342
operatorNamespace : {
4336
4343
& v1.OperatorGroup {
4344
+ TypeMeta : metav1.TypeMeta {
4345
+ Kind : v1 .OperatorGroupKind ,
4346
+ APIVersion : v1 .GroupVersion .String (),
4347
+ },
4337
4348
ObjectMeta : metav1.ObjectMeta {
4338
4349
Name : "operator-group-1" ,
4339
4350
Namespace : operatorNamespace ,
@@ -4415,124 +4426,154 @@ func TestSyncOperatorGroups(t *testing.T) {
4415
4426
"AllNamespaces InstallModeType not supported, cannot configure to watch all namespaces" ,
4416
4427
now ),
4417
4428
},
4418
- "" : {},
4419
- targetNamespace : {},
4420
4429
}},
4421
4430
},
4422
4431
}
4423
4432
4433
+ copyObjs := func (objs []runtime.Object ) []runtime.Object {
4434
+ if len (objs ) < 1 {
4435
+ return nil
4436
+ }
4437
+
4438
+ copied := make ([]runtime.Object , len (objs ))
4439
+ for i , obj := range objs {
4440
+ copied [i ] = obj .DeepCopyObject ()
4441
+ }
4442
+
4443
+ return copied
4444
+ }
4445
+
4424
4446
for _ , tt := range tests {
4425
4447
t .Run (tt .name , func (t * testing.T ) {
4426
- namespaces := []string {}
4427
4448
// Pick out Namespaces
4449
+ var namespaces []string
4428
4450
for _ , obj := range tt .initial .k8sObjs {
4429
4451
if ns , ok := obj .(* corev1.Namespace ); ok {
4430
4452
namespaces = append (namespaces , ns .GetName ())
4431
4453
}
4432
4454
}
4433
4455
4434
- // Append operatorGroup to initialObjs
4435
- tt .initial .clientObjs = append (tt .initial .clientObjs , tt .initial .operatorGroup )
4456
+ // DeepCopy test fixtures to prevent test case pollution
4457
+ var (
4458
+ operatorGroup = tt .initial .operatorGroup .DeepCopy ()
4459
+ clientObjs = copyObjs (append (tt .initial .clientObjs , operatorGroup ))
4460
+ k8sObjs = copyObjs (tt .initial .k8sObjs )
4461
+ extObjs = copyObjs (tt .initial .crds )
4462
+ regObjs = copyObjs (tt .initial .apis )
4463
+ )
4436
4464
4437
4465
// Create test operator
4438
- ctx , cancel := context .WithCancel (context .TODO ())
4466
+ ctx , cancel := context .WithCancel (context .Background ())
4439
4467
defer cancel ()
4468
+
4440
4469
op , err := NewFakeOperator (
4441
4470
ctx ,
4442
4471
withClock (clockFake ),
4443
4472
withNamespaces (namespaces ... ),
4444
4473
withOperatorNamespace (operatorNamespace ),
4445
- withClientObjs (tt . initial . clientObjs ... ),
4446
- withK8sObjs (tt . initial . k8sObjs ... ),
4447
- withExtObjs (tt . initial . crds ... ),
4448
- withRegObjs (tt . initial . apis ... ),
4474
+ withClientObjs (clientObjs ... ),
4475
+ withK8sObjs (k8sObjs ... ),
4476
+ withExtObjs (extObjs ... ),
4477
+ withRegObjs (regObjs ... ),
4449
4478
)
4450
4479
require .NoError (t , err )
4451
4480
4452
- simulateSuccessfulRollout := func (csv * v1alpha1.ClusterServiceVersion , client operatorclient.ClientInterface ) {
4453
- // get the deployment, which should exist
4454
- dep , err := client .GetDeployment (tt .initial .operatorGroup .GetNamespace (), deploymentName )
4481
+ simulateSuccessfulRollout := func (csv * v1alpha1.ClusterServiceVersion ) {
4482
+ // Get the deployment, which should exist
4483
+ namespace := operatorGroup .GetNamespace ()
4484
+ dep , err := op .opClient .GetDeployment (namespace , deploymentName )
4455
4485
require .NoError (t , err )
4456
4486
4457
- // force it healthy
4487
+ // Force it healthy
4458
4488
dep .Status .Replicas = 1
4459
4489
dep .Status .UpdatedReplicas = 1
4460
4490
dep .Status .AvailableReplicas = 1
4461
4491
dep .Status .Conditions = []appsv1.DeploymentCondition {{
4462
4492
Type : appsv1 .DeploymentAvailable ,
4463
4493
Status : corev1 .ConditionTrue ,
4464
4494
}}
4465
- _ , err = client .KubernetesInterface ().AppsV1 ().Deployments (tt .initial .operatorGroup .GetNamespace ()).UpdateStatus (context .TODO (), dep , metav1.UpdateOptions {})
4495
+ _ , err = op .opClient .KubernetesInterface ().AppsV1 ().Deployments (namespace ).UpdateStatus (ctx , dep , metav1.UpdateOptions {})
4496
+ require .NoError (t , err )
4497
+
4498
+ // Wait for the lister cache to catch up
4499
+ err = wait .PollImmediateWithContext (ctx , tick , timeout , func (ctx context.Context ) (bool , error ) {
4500
+ deployment , err := op .lister .AppsV1 ().DeploymentLister ().Deployments (namespace ).Get (dep .GetName ())
4501
+ if err != nil || deployment == nil {
4502
+ return false , err
4503
+ }
4504
+
4505
+ for _ , condition := range deployment .Status .Conditions {
4506
+ if condition .Type == appsv1 .DeploymentAvailable {
4507
+ return condition .Status == corev1 .ConditionTrue , nil
4508
+ }
4509
+ }
4510
+
4511
+ return false , nil
4512
+ })
4466
4513
require .NoError (t , err )
4467
4514
}
4468
4515
4469
- err = op .syncOperatorGroups (tt . initial . operatorGroup )
4516
+ err = op .syncOperatorGroups (operatorGroup )
4470
4517
require .NoError (t , err )
4471
4518
4472
- // wait on operator group updated status to be in the cache as it is required for later CSV operations
4473
- err = wait .PollImmediate ( 1 * time . Millisecond , 5 * time . Second , func () (bool , error ) {
4474
- operatorGroup , err := op .lister .OperatorsV1 ().OperatorGroupLister ().OperatorGroups (tt . initial . operatorGroup .GetNamespace ()).Get (tt . initial . operatorGroup .GetName ())
4519
+ // Wait on operator group updated status to be in the cache as it is required for later CSV operations
4520
+ err = wait .PollImmediateWithContext ( ctx , tick , timeout , func (ctx context. Context ) (bool , error ) {
4521
+ og , err := op .lister .OperatorsV1 ().OperatorGroupLister ().OperatorGroups (operatorGroup .GetNamespace ()).Get (operatorGroup .GetName ())
4475
4522
if err != nil {
4476
4523
return false , err
4477
4524
}
4478
4525
sort .Strings (tt .expectedStatus .Namespaces )
4479
- sort .Strings (operatorGroup .Status .Namespaces )
4480
- if ! reflect .DeepEqual (tt .expectedStatus , operatorGroup .Status ) {
4526
+ sort .Strings (og .Status .Namespaces )
4527
+ if ! reflect .DeepEqual (tt .expectedStatus , og .Status ) {
4481
4528
return false , err
4482
4529
}
4530
+
4531
+ operatorGroup = og
4532
+
4483
4533
return true , nil
4484
4534
})
4485
4535
require .NoError (t , err )
4486
4536
4487
- // this must be done twice to have annotateCSVs run in syncOperatorGroups
4488
- // and to catch provided API changes
4489
- err = op .syncOperatorGroups (tt .initial .operatorGroup )
4537
+ // This must be done (at least) twice to have annotateCSVs run in syncOperatorGroups and to catch provided API changes
4538
+ // syncOperatorGroups is eventually consistent and may return errors until the cache has caught up with the cluster (fake client here)
4539
+ wait .PollImmediateWithContext (ctx , tick , timeout , func (ctx context.Context ) (bool , error ) { // Throw away timeout errors since any timeout will coincide with err != nil anyway
4540
+ err = op .syncOperatorGroups (operatorGroup )
4541
+ return err == nil , nil
4542
+ })
4490
4543
require .NoError (t , err )
4491
4544
4492
- // Sync csvs enough to get them back to succeeded state
4493
- for i := 0 ; i < 16 ; i ++ {
4494
- opGroupCSVs , err := op .client .OperatorsV1alpha1 ().ClusterServiceVersions (operatorNamespace ).List (context .TODO (), metav1.ListOptions {})
4495
- require .NoError (t , err )
4545
+ // Sync csvs enough to get them back to a succeeded state
4546
+ err = wait .PollImmediateWithContext (ctx , tick , timeout , func (ctx context.Context ) (bool , error ) {
4547
+ csvs , err := op .client .OperatorsV1alpha1 ().ClusterServiceVersions (operatorNamespace ).List (ctx , metav1.ListOptions {})
4548
+ if err != nil {
4549
+ return false , err
4550
+ }
4496
4551
4497
- for i , obj := range opGroupCSVs .Items {
4498
- if obj .Status .Phase == v1alpha1 .CSVPhaseInstalling {
4499
- simulateSuccessfulRollout (& obj , op . opClient )
4552
+ for _ , csv := range csvs .Items {
4553
+ if csv .Status .Phase == v1alpha1 .CSVPhaseInstalling {
4554
+ simulateSuccessfulRollout (& csv )
4500
4555
}
4501
- err = op .syncClusterServiceVersion (& obj )
4502
- require .NoError (t , err , "%#v" , obj )
4503
4556
4504
- err = op .syncCopyCSV (& obj )
4505
- if ! tt .ignoreCopyError {
4506
- require .NoError (t , err , "%#v" , obj )
4557
+ if err := op .syncClusterServiceVersion (& csv ); err != nil {
4558
+ return false , err
4507
4559
}
4508
4560
4509
- if i == 0 {
4510
- err = wait .PollImmediate (1 * time .Millisecond , 10 * time .Second , func () (bool , error ) {
4511
- for namespace , objects := range tt .final .objects {
4512
- if err := RequireObjectsInCache (t , op .lister , namespace , objects , false ); err != nil {
4513
- return false , nil
4514
- }
4515
- }
4516
- return true , nil
4517
- })
4518
- require .NoError (t , err )
4561
+ if err := op .syncCopyCSV (& csv ); err != nil && ! tt .ignoreCopyError {
4562
+ return false , err
4519
4563
}
4564
+ }
4520
4565
4521
- if i == 16 {
4522
- err = wait .PollImmediate (1 * time .Millisecond , 10 * time .Second , func () (bool , error ) {
4523
- for namespace , objects := range tt .final .objects {
4524
- if err := RequireObjectsInCache (t , op .lister , namespace , objects , true ); err != nil {
4525
- return false , nil
4526
- }
4527
- }
4528
- return true , nil
4529
- })
4530
- require .NoError (t , err )
4566
+ for namespace , objects := range tt .final .objects {
4567
+ if err := RequireObjectsInCache (t , op .lister , namespace , objects , true ); err != nil {
4568
+ return false , nil
4531
4569
}
4532
4570
}
4533
- }
4534
4571
4535
- operatorGroup , err := op .client .OperatorsV1 ().OperatorGroups (tt .initial .operatorGroup .GetNamespace ()).Get (context .TODO (), tt .initial .operatorGroup .GetName (), metav1.GetOptions {})
4572
+ return true , nil
4573
+ })
4574
+ require .NoError (t , err )
4575
+
4576
+ operatorGroup , err = op .client .OperatorsV1 ().OperatorGroups (operatorGroup .GetNamespace ()).Get (ctx , operatorGroup .GetName (), metav1.GetOptions {})
4536
4577
require .NoError (t , err )
4537
4578
sort .Strings (tt .expectedStatus .Namespaces )
4538
4579
sort .Strings (operatorGroup .Status .Namespaces )
@@ -4799,7 +4840,7 @@ func RequireObjectsInNamespace(t *testing.T, opClient operatorclient.ClientInter
4799
4840
require .Failf (t , "couldn't find expected object" , "%#v" , object )
4800
4841
}
4801
4842
require .NoError (t , err , "couldn't fetch %s %v" , namespace , object )
4802
- require .True (t , reflect .DeepEqual (object , fetched ), diff . ObjectDiff (object , fetched ))
4843
+ require .True (t , reflect .DeepEqual (object , fetched ), cmp . Diff (object , fetched ))
4803
4844
}
4804
4845
}
4805
4846
0 commit comments