k8s.io/kubernetes@v1.29.3/test/integration/apiserver/flowcontrol/fs_condition_test.go (about) 1 /* 2 Copyright 2022 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package flowcontrol 18 19 import ( 20 "encoding/json" 21 "testing" 22 "time" 23 24 flowcontrol "k8s.io/api/flowcontrol/v1" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 machinerytypes "k8s.io/apimachinery/pkg/types" 27 "k8s.io/apimachinery/pkg/util/wait" 28 fcboot "k8s.io/apiserver/pkg/apis/flowcontrol/bootstrap" 29 flowcontrolapply "k8s.io/client-go/applyconfigurations/flowcontrol/v1" 30 clientset "k8s.io/client-go/kubernetes" 31 "k8s.io/klog/v2" 32 ) 33 34 func TestConditionIsolation(t *testing.T) { 35 ctx, kubeConfig, closeFn := setup(t, 10, 10) 36 defer closeFn() 37 38 loopbackClient := clientset.NewForConfigOrDie(kubeConfig) 39 40 fsOrig := fcboot.SuggestedFlowSchemas[0] 41 t.Logf("Testing Status Condition isolation in FlowSchema %q", fsOrig.Name) 42 fsClient := loopbackClient.FlowcontrolV1().FlowSchemas() 43 var dangleOrig *flowcontrol.FlowSchemaCondition 44 45 wait.PollUntil(time.Second, func() (bool, error) { 46 fsGot, err := fsClient.Get(ctx, fsOrig.Name, metav1.GetOptions{}) 47 if err != nil { 48 klog.Errorf("Failed to fetch FlowSchema %q: %v", fsOrig.Name, err) 49 return false, nil 50 } 51 dangleOrig = getCondition(fsGot.Status.Conditions, flowcontrol.FlowSchemaConditionDangling) 52 return dangleOrig != nil, nil 53 }, ctx.Done()) 54 55 ssaType := flowcontrol.FlowSchemaConditionType("test-ssa") 56 patchSSA := flowcontrolapply.FlowSchema(fsOrig.Name). 57 WithStatus(flowcontrolapply.FlowSchemaStatus(). 58 WithConditions(flowcontrolapply.FlowSchemaCondition(). 59 WithType(ssaType). 60 WithStatus(flowcontrol.ConditionTrue). 61 WithReason("SSA test"). 62 WithMessage("for testing"). 63 WithLastTransitionTime(metav1.Now()), 64 )) 65 66 postSSA, err := fsClient.ApplyStatus(ctx, patchSSA, metav1.ApplyOptions{FieldManager: "ssa-test"}) 67 if err != nil { 68 t.Error(err) 69 } 70 danglePostSSA := getCondition(postSSA.Status.Conditions, flowcontrol.FlowSchemaConditionDangling) 71 if danglePostSSA == nil || danglePostSSA.Status != dangleOrig.Status { 72 t.Errorf("Bad dangle condition after SSA, the FS is now %s", fmtFS(t, postSSA)) 73 } 74 ssaPostSSA := getCondition(postSSA.Status.Conditions, ssaType) 75 if ssaPostSSA == nil || ssaPostSSA.Status != flowcontrol.ConditionTrue { 76 t.Errorf("Bad SSA condition after SSA, the FS is now %s", fmtFS(t, postSSA)) 77 } 78 79 smpType := flowcontrol.FlowSchemaConditionType("test-smp") 80 smpBytes, err := makeFlowSchemaConditionPatch(flowcontrol.FlowSchemaCondition{ 81 Type: smpType, 82 Status: flowcontrol.ConditionFalse, 83 Reason: "SMP test", 84 Message: "for testing too", 85 LastTransitionTime: metav1.Now(), 86 }) 87 if err != nil { 88 t.Error(err) 89 } 90 postSMP, err := fsClient.Patch(ctx, fsOrig.Name, machinerytypes.StrategicMergePatchType, smpBytes, 91 metav1.PatchOptions{FieldManager: "smp-test"}, "status") 92 if err != nil { 93 t.Error(err) 94 } 95 if false /* disabled until patch annotations go into the API (see https://github.com/kubernetes/kubernetes/issues/107574) */ { 96 danglePostSMP := getCondition(postSMP.Status.Conditions, flowcontrol.FlowSchemaConditionDangling) 97 if danglePostSMP == nil || danglePostSMP.Status != dangleOrig.Status { 98 t.Errorf("Bad dangle condition after SMP, the FS is now %s", fmtFS(t, postSMP)) 99 } 100 ssaPostSMP := getCondition(postSMP.Status.Conditions, ssaType) 101 if ssaPostSMP == nil || ssaPostSMP.Status != flowcontrol.ConditionTrue { 102 t.Errorf("Bad SSA condition after SMP, the FS is now %s", fmtFS(t, postSMP)) 103 } 104 } 105 smpPostSMP := getCondition(postSMP.Status.Conditions, smpType) 106 if smpPostSMP == nil || smpPostSMP.Status != flowcontrol.ConditionFalse { 107 t.Errorf("Bad SMP condition after SMP, the FS is now %s", fmtFS(t, postSMP)) 108 } 109 110 } 111 112 func getCondition(conds []flowcontrol.FlowSchemaCondition, condType flowcontrol.FlowSchemaConditionType) *flowcontrol.FlowSchemaCondition { 113 for _, cond := range conds { 114 if cond.Type == condType { 115 return &cond 116 } 117 } 118 return nil 119 } 120 121 // makeFlowSchemaConditionPatch takes in a condition and returns the patch status as a json. 122 func makeFlowSchemaConditionPatch(condition flowcontrol.FlowSchemaCondition) ([]byte, error) { 123 o := struct { 124 Status flowcontrol.FlowSchemaStatus `json:"status"` 125 }{ 126 Status: flowcontrol.FlowSchemaStatus{ 127 Conditions: []flowcontrol.FlowSchemaCondition{ 128 condition, 129 }, 130 }, 131 } 132 return json.Marshal(o) 133 } 134 135 func fmtFS(t *testing.T, fs *flowcontrol.FlowSchema) string { 136 asBytes, err := json.Marshal(fs) 137 if err != nil { 138 t.Error(err) 139 } 140 return string(asBytes) 141 }