@@ -21,10 +21,12 @@ import (
21
21
"fmt"
22
22
"net/http"
23
23
"reflect"
24
+ "sync"
24
25
"testing"
25
26
26
27
apiequality "k8s.io/apimachinery/pkg/api/equality"
27
28
"k8s.io/apimachinery/pkg/api/errors"
29
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
28
30
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29
31
"k8s.io/apimachinery/pkg/fields"
30
32
"k8s.io/apimachinery/pkg/labels"
@@ -451,3 +453,123 @@ func TestCategories(t *testing.T) {
451
453
expected := []string {"all" }
452
454
registrytest .AssertCategories (t , storage .Deployment , expected )
453
455
}
456
+
457
+ func TestScalePatchErrors (t * testing.T ) {
458
+ storage , server := newStorage (t )
459
+ defer server .Terminate (t )
460
+ validObj := validNewDeployment ()
461
+ resourceStore := storage .Deployment .Store
462
+ scaleStore := storage .Scale
463
+
464
+ defer resourceStore .DestroyFunc ()
465
+ ctx := genericapirequest .WithNamespace (genericapirequest .NewContext (), namespace )
466
+
467
+ {
468
+ applyNotFoundPatch := func () rest.TransformFunc {
469
+ return func (_ context.Context , _ , currentObject runtime.Object ) (objToUpdate runtime.Object , patchErr error ) {
470
+ t .Errorf ("notfound patch called" )
471
+ return currentObject , nil
472
+ }
473
+ }
474
+ _ , _ , err := scaleStore .Update (ctx , "bad-name" , rest .DefaultUpdatedObjectInfo (nil , applyNotFoundPatch ()), rest .ValidateAllObjectFunc , rest .ValidateAllObjectUpdateFunc , false , & metav1.UpdateOptions {})
475
+ if ! apierrors .IsNotFound (err ) {
476
+ t .Errorf ("expected notfound, got %v" , err )
477
+ }
478
+ }
479
+
480
+ if _ , err := resourceStore .Create (ctx , validObj , rest .ValidateAllObjectFunc , & metav1.CreateOptions {}); err != nil {
481
+ t .Errorf ("Unexpected error: %v" , err )
482
+ }
483
+
484
+ {
485
+ applyBadUIDPatch := func () rest.TransformFunc {
486
+ return func (_ context.Context , _ , currentObject runtime.Object ) (objToUpdate runtime.Object , patchErr error ) {
487
+ currentObject .(* autoscaling.Scale ).UID = "123"
488
+ return currentObject , nil
489
+ }
490
+ }
491
+ _ , _ , err := scaleStore .Update (ctx , name , rest .DefaultUpdatedObjectInfo (nil , applyBadUIDPatch ()), rest .ValidateAllObjectFunc , rest .ValidateAllObjectUpdateFunc , false , & metav1.UpdateOptions {})
492
+ if ! apierrors .IsConflict (err ) {
493
+ t .Errorf ("expected conflict, got %v" , err )
494
+ }
495
+ }
496
+
497
+ {
498
+ applyBadResourceVersionPatch := func () rest.TransformFunc {
499
+ return func (_ context.Context , _ , currentObject runtime.Object ) (objToUpdate runtime.Object , patchErr error ) {
500
+ currentObject .(* autoscaling.Scale ).ResourceVersion = "123"
501
+ return currentObject , nil
502
+ }
503
+ }
504
+ _ , _ , err := scaleStore .Update (ctx , name , rest .DefaultUpdatedObjectInfo (nil , applyBadResourceVersionPatch ()), rest .ValidateAllObjectFunc , rest .ValidateAllObjectUpdateFunc , false , & metav1.UpdateOptions {})
505
+ if ! apierrors .IsConflict (err ) {
506
+ t .Errorf ("expected conflict, got %v" , err )
507
+ }
508
+ }
509
+ }
510
+
511
+ func TestScalePatchConflicts (t * testing.T ) {
512
+ storage , server := newStorage (t )
513
+ defer server .Terminate (t )
514
+ validObj := validNewDeployment ()
515
+ resourceStore := storage .Deployment .Store
516
+ scaleStore := storage .Scale
517
+
518
+ defer resourceStore .DestroyFunc ()
519
+ ctx := genericapirequest .WithNamespace (genericapirequest .NewContext (), namespace )
520
+ if _ , err := resourceStore .Create (ctx , validObj , rest .ValidateAllObjectFunc , & metav1.CreateOptions {}); err != nil {
521
+ t .Fatalf ("Unexpected error: %v" , err )
522
+ }
523
+ applyLabelPatch := func (labelName , labelValue string ) rest.TransformFunc {
524
+ return func (_ context.Context , _ , currentObject runtime.Object ) (objToUpdate runtime.Object , patchErr error ) {
525
+ currentObject .(metav1.Object ).SetLabels (map [string ]string {labelName : labelValue })
526
+ return currentObject , nil
527
+ }
528
+ }
529
+ stopCh := make (chan struct {})
530
+ wg := & sync.WaitGroup {}
531
+ wg .Add (1 )
532
+ go func () {
533
+ defer wg .Done ()
534
+ // continuously submits a patch that updates a label and verifies the label update was effective
535
+ labelName := "timestamp"
536
+ for i := 0 ; ; i ++ {
537
+ select {
538
+ case <- stopCh :
539
+ return
540
+ default :
541
+ expectedLabelValue := fmt .Sprint (i )
542
+ updated , _ , err := resourceStore .Update (ctx , name , rest .DefaultUpdatedObjectInfo (nil , applyLabelPatch (labelName , fmt .Sprint (i ))), rest .ValidateAllObjectFunc , rest .ValidateAllObjectUpdateFunc , false , & metav1.UpdateOptions {})
543
+ if err != nil {
544
+ t .Errorf ("error patching main resource: %v" , err )
545
+ return
546
+ }
547
+ gotLabelValue := updated .(metav1.Object ).GetLabels ()[labelName ]
548
+ if gotLabelValue != expectedLabelValue {
549
+ t .Errorf ("wrong label value: expected: %s, got: %s" , expectedLabelValue , gotLabelValue )
550
+ return
551
+ }
552
+ }
553
+ }
554
+ }()
555
+
556
+ // continuously submits a scale patch of replicas for a monotonically increasing replica value
557
+ applyReplicaPatch := func (replicas int ) rest.TransformFunc {
558
+ return func (_ context.Context , _ , currentObject runtime.Object ) (objToUpdate runtime.Object , patchErr error ) {
559
+ currentObject .(* autoscaling.Scale ).Spec .Replicas = int32 (replicas )
560
+ return currentObject , nil
561
+ }
562
+ }
563
+ for i := 0 ; i < 100 ; i ++ {
564
+ result , _ , err := scaleStore .Update (ctx , name , rest .DefaultUpdatedObjectInfo (nil , applyReplicaPatch (i )), rest .ValidateAllObjectFunc , rest .ValidateAllObjectUpdateFunc , false , & metav1.UpdateOptions {})
565
+ if err != nil {
566
+ t .Fatalf ("error patching scale: %v" , err )
567
+ }
568
+ scale := result .(* autoscaling.Scale )
569
+ if scale .Spec .Replicas != int32 (i ) {
570
+ t .Errorf ("wrong replicas count: expected: %d got: %d" , i , scale .Spec .Replicas )
571
+ }
572
+ }
573
+ close (stopCh )
574
+ wg .Wait ()
575
+ }
0 commit comments