@@ -19,20 +19,22 @@ package disruption
19
19
import (
20
20
"context"
21
21
"fmt"
22
+ "reflect"
22
23
"testing"
23
24
"time"
24
25
25
- "k8s.io/apiextensions-apiserver/test/integration/fixtures"
26
-
27
- apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
26
+ "github.com/google/go-cmp/cmp"
28
27
29
28
v1 "k8s.io/api/core/v1"
30
29
policyv1 "k8s.io/api/policy/v1"
31
30
"k8s.io/api/policy/v1beta1"
31
+ apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
32
32
apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
33
+ "k8s.io/apiextensions-apiserver/test/integration/fixtures"
33
34
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
34
35
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
35
36
"k8s.io/apimachinery/pkg/runtime/schema"
37
+ "k8s.io/apimachinery/pkg/types"
36
38
"k8s.io/apimachinery/pkg/util/intstr"
37
39
"k8s.io/apimachinery/pkg/util/wait"
38
40
cacheddiscovery "k8s.io/client-go/discovery/cached/memory"
@@ -47,6 +49,7 @@ import (
47
49
"k8s.io/kubernetes/pkg/controller/disruption"
48
50
"k8s.io/kubernetes/test/integration/etcd"
49
51
"k8s.io/kubernetes/test/integration/framework"
52
+ "k8s.io/utils/pointer"
50
53
)
51
54
52
55
func setup (t * testing.T ) (* kubeapiservertesting.TestServer , * disruption.DisruptionController , informers.SharedInformerFactory , clientset.Interface , * apiextensionsclientset.Clientset , dynamic.Interface ) {
@@ -493,3 +496,143 @@ func waitToObservePods(t *testing.T, podInformer cache.SharedIndexInformer, podN
493
496
t .Fatal (err )
494
497
}
495
498
}
499
+
500
+ func TestPatchCompatibility (t * testing.T ) {
501
+ s , _ , _ , clientSet , _ , _ := setup (t )
502
+ defer s .TearDownFn ()
503
+
504
+ testcases := []struct {
505
+ name string
506
+ version string
507
+ startingSelector * metav1.LabelSelector
508
+ patchType types.PatchType
509
+ patch string
510
+ force * bool
511
+ fieldManager string
512
+ expectSelector * metav1.LabelSelector
513
+ }{
514
+ {
515
+ name : "v1beta1-smp" ,
516
+ version : "v1beta1" ,
517
+ patchType : types .StrategicMergePatchType ,
518
+ patch : `{"spec":{"selector":{"matchLabels":{"patchmatch":"true"},"matchExpressions":[{"key":"patchexpression","operator":"In","values":["true"]}]}}}` ,
519
+ // matchLabels portion is merged, matchExpressions portion is replaced (because it's a list with no patchStrategy defined)
520
+ expectSelector : & metav1.LabelSelector {
521
+ MatchLabels : map [string ]string {"basematch" : "true" , "patchmatch" : "true" },
522
+ MatchExpressions : []metav1.LabelSelectorRequirement {{Key : "patchexpression" , Operator : "In" , Values : []string {"true" }}},
523
+ },
524
+ },
525
+ {
526
+ name : "v1-smp" ,
527
+ version : "v1" ,
528
+ patchType : types .StrategicMergePatchType ,
529
+ patch : `{"spec":{"selector":{"matchLabels":{"patchmatch":"true"},"matchExpressions":[{"key":"patchexpression","operator":"In","values":["true"]}]}}}` ,
530
+ // matchLabels and matchExpressions are both replaced (because selector patchStrategy=replace in v1)
531
+ expectSelector : & metav1.LabelSelector {
532
+ MatchLabels : map [string ]string {"patchmatch" : "true" },
533
+ MatchExpressions : []metav1.LabelSelectorRequirement {{Key : "patchexpression" , Operator : "In" , Values : []string {"true" }}},
534
+ },
535
+ },
536
+
537
+ {
538
+ name : "v1beta1-mergepatch" ,
539
+ version : "v1beta1" ,
540
+ patchType : types .MergePatchType ,
541
+ patch : `{"spec":{"selector":{"matchLabels":{"patchmatch":"true"},"matchExpressions":[{"key":"patchexpression","operator":"In","values":["true"]}]}}}` ,
542
+ // matchLabels portion is merged, matchExpressions portion is replaced (because it's a list)
543
+ expectSelector : & metav1.LabelSelector {
544
+ MatchLabels : map [string ]string {"basematch" : "true" , "patchmatch" : "true" },
545
+ MatchExpressions : []metav1.LabelSelectorRequirement {{Key : "patchexpression" , Operator : "In" , Values : []string {"true" }}},
546
+ },
547
+ },
548
+ {
549
+ name : "v1-mergepatch" ,
550
+ version : "v1" ,
551
+ patchType : types .MergePatchType ,
552
+ patch : `{"spec":{"selector":{"matchLabels":{"patchmatch":"true"},"matchExpressions":[{"key":"patchexpression","operator":"In","values":["true"]}]}}}` ,
553
+ // matchLabels portion is merged, matchExpressions portion is replaced (because it's a list)
554
+ expectSelector : & metav1.LabelSelector {
555
+ MatchLabels : map [string ]string {"basematch" : "true" , "patchmatch" : "true" },
556
+ MatchExpressions : []metav1.LabelSelectorRequirement {{Key : "patchexpression" , Operator : "In" , Values : []string {"true" }}},
557
+ },
558
+ },
559
+
560
+ {
561
+ name : "v1beta1-apply" ,
562
+ version : "v1beta1" ,
563
+ patchType : types .ApplyPatchType ,
564
+ patch : `{"apiVersion":"policy/v1beta1","kind":"PodDisruptionBudget","spec":{"selector":{"matchLabels":{"patchmatch":"true"},"matchExpressions":[{"key":"patchexpression","operator":"In","values":["true"]}]}}}` ,
565
+ force : pointer .Bool (true ),
566
+ fieldManager : "test" ,
567
+ // entire selector is replaced (because structType=atomic)
568
+ expectSelector : & metav1.LabelSelector {
569
+ MatchLabels : map [string ]string {"patchmatch" : "true" },
570
+ MatchExpressions : []metav1.LabelSelectorRequirement {{Key : "patchexpression" , Operator : "In" , Values : []string {"true" }}},
571
+ },
572
+ },
573
+ {
574
+ name : "v1-apply" ,
575
+ version : "v1" ,
576
+ patchType : types .ApplyPatchType ,
577
+ patch : `{"apiVersion":"policy/v1","kind":"PodDisruptionBudget","spec":{"selector":{"matchLabels":{"patchmatch":"true"},"matchExpressions":[{"key":"patchexpression","operator":"In","values":["true"]}]}}}` ,
578
+ force : pointer .Bool (true ),
579
+ fieldManager : "test" ,
580
+ // entire selector is replaced (because structType=atomic)
581
+ expectSelector : & metav1.LabelSelector {
582
+ MatchLabels : map [string ]string {"patchmatch" : "true" },
583
+ MatchExpressions : []metav1.LabelSelectorRequirement {{Key : "patchexpression" , Operator : "In" , Values : []string {"true" }}},
584
+ },
585
+ },
586
+ }
587
+
588
+ for _ , tc := range testcases {
589
+ t .Run (tc .name , func (t * testing.T ) {
590
+ ns := "default"
591
+ maxUnavailable := int32 (2 )
592
+ pdb := & policyv1.PodDisruptionBudget {
593
+ ObjectMeta : metav1.ObjectMeta {
594
+ Name : "test-pdb" ,
595
+ },
596
+ Spec : policyv1.PodDisruptionBudgetSpec {
597
+ MaxUnavailable : & intstr.IntOrString {Type : intstr .Int , IntVal : maxUnavailable },
598
+ Selector : & metav1.LabelSelector {
599
+ MatchLabels : map [string ]string {"basematch" : "true" },
600
+ MatchExpressions : []metav1.LabelSelectorRequirement {{Key : "baseexpression" , Operator : "In" , Values : []string {"true" }}},
601
+ },
602
+ },
603
+ }
604
+ if _ , err := clientSet .PolicyV1 ().PodDisruptionBudgets (ns ).Create (context .TODO (), pdb , metav1.CreateOptions {}); err != nil {
605
+ t .Fatalf ("Error creating PodDisruptionBudget: %v" , err )
606
+ }
607
+ defer func () {
608
+ err := clientSet .PolicyV1 ().PodDisruptionBudgets (ns ).Delete (context .TODO (), pdb .Name , metav1.DeleteOptions {})
609
+ if err != nil {
610
+ t .Fatal (err )
611
+ }
612
+ }()
613
+
614
+ var resultSelector * metav1.LabelSelector
615
+ switch tc .version {
616
+ case "v1" :
617
+ result , err := clientSet .PolicyV1 ().PodDisruptionBudgets (ns ).Patch (context .TODO (), pdb .Name , tc .patchType , []byte (tc .patch ), metav1.PatchOptions {Force : tc .force , FieldManager : tc .fieldManager })
618
+ if err != nil {
619
+ t .Fatal (err )
620
+ }
621
+ resultSelector = result .Spec .Selector
622
+ case "v1beta1" :
623
+ result , err := clientSet .PolicyV1beta1 ().PodDisruptionBudgets (ns ).Patch (context .TODO (), pdb .Name , tc .patchType , []byte (tc .patch ), metav1.PatchOptions {Force : tc .force , FieldManager : tc .fieldManager })
624
+ if err != nil {
625
+ t .Fatal (err )
626
+ }
627
+ resultSelector = result .Spec .Selector
628
+ default :
629
+ t .Error ("unknown version" )
630
+ }
631
+
632
+ if ! reflect .DeepEqual (resultSelector , tc .expectSelector ) {
633
+ t .Fatalf ("unexpected selector:\n %s" , cmp .Diff (tc .expectSelector , resultSelector ))
634
+ }
635
+ })
636
+ }
637
+
638
+ }
0 commit comments