k8s.io/perf-tests/clusterloader2@v0.0.0-20240304094227-64bdb12da87e/pkg/measurement/util/wait_for_conditions_test.go (about) 1 /* 2 Copyright 2023 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 util 18 19 import ( 20 "context" 21 "testing" 22 "time" 23 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 26 "k8s.io/apimachinery/pkg/runtime" 27 "k8s.io/apimachinery/pkg/runtime/schema" 28 "k8s.io/client-go/dynamic/fake" 29 ) 30 31 func TestWaitForGenericK8sObjects(t *testing.T) { 32 33 tests := []struct { 34 name string 35 timeout time.Duration 36 options *WaitForGenericK8sObjectsOptions 37 existingObjects []exampleObject 38 wantErr bool 39 }{ 40 { 41 name: "one successful object", 42 timeout: 1 * time.Second, 43 options: &WaitForGenericK8sObjectsOptions{ 44 GroupVersionResource: schema.GroupVersionResource{ 45 Group: "kuberentes.io", 46 Version: "v1alpha1", 47 Resource: "Conditions", 48 }, 49 Namespaces: NamespacesRange{ 50 Prefix: "namespace", 51 Min: 1, 52 Max: 1, 53 }, 54 SuccessfulConditions: []string{"Successful=True"}, 55 FailedConditions: []string{}, 56 MinDesiredObjectCount: 1, 57 MaxFailedObjectCount: 0, 58 CallerName: "test", 59 WaitInterval: 100 * time.Millisecond, 60 }, 61 existingObjects: []exampleObject{ 62 newExampleObject("test-1", "namespace-1", []interface{}{ 63 map[string]interface{}{ 64 "type": "Successful", 65 "status": "True", 66 }, 67 }), 68 }, 69 }, 70 { 71 name: "one failed object", 72 timeout: 1 * time.Second, 73 options: &WaitForGenericK8sObjectsOptions{ 74 GroupVersionResource: schema.GroupVersionResource{ 75 Group: "kuberentes.io", 76 Version: "v1alpha1", 77 Resource: "Conditions", 78 }, 79 Namespaces: NamespacesRange{ 80 Prefix: "namespace", 81 Min: 1, 82 Max: 1, 83 }, 84 SuccessfulConditions: []string{"Successful=True"}, 85 FailedConditions: []string{"Failed=True"}, 86 MinDesiredObjectCount: 1, 87 MaxFailedObjectCount: 0, 88 CallerName: "test", 89 WaitInterval: 100 * time.Millisecond, 90 }, 91 existingObjects: []exampleObject{ 92 newExampleObject("test-1", "namespace-1", []interface{}{ 93 map[string]interface{}{ 94 "type": "Successful", 95 "status": "False", 96 }, 97 map[string]interface{}{ 98 "type": "Failed", 99 "status": "True", 100 }, 101 }), 102 }, 103 wantErr: true, 104 }, 105 { 106 name: "one failed object, but one is acceptable", 107 timeout: 1 * time.Second, 108 options: &WaitForGenericK8sObjectsOptions{ 109 GroupVersionResource: schema.GroupVersionResource{ 110 Group: "kuberentes.io", 111 Version: "v1alpha1", 112 Resource: "Conditions", 113 }, 114 Namespaces: NamespacesRange{ 115 Prefix: "namespace", 116 Min: 1, 117 Max: 1, 118 }, 119 SuccessfulConditions: []string{"Successful=True"}, 120 FailedConditions: []string{"Failed=True"}, 121 MinDesiredObjectCount: 3, 122 MaxFailedObjectCount: 1, 123 CallerName: "test", 124 WaitInterval: 100 * time.Millisecond, 125 }, 126 existingObjects: []exampleObject{ 127 newExampleObject("test-1", "namespace-1", []interface{}{ 128 map[string]interface{}{ 129 "type": "Successful", 130 "status": "False", 131 }, 132 map[string]interface{}{ 133 "type": "Failed", 134 "status": "True", 135 }, 136 }), 137 newExampleObject("test-2", "namespace-1", []interface{}{ 138 map[string]interface{}{ 139 "type": "Successful", 140 "status": "True", 141 }, 142 }), 143 newExampleObject("test-3", "namespace-1", []interface{}{ 144 map[string]interface{}{ 145 "type": "Successful", 146 "status": "True", 147 }, 148 }), 149 }, 150 }, 151 { 152 name: "timeout due not enough objects", 153 timeout: 1 * time.Second, 154 options: &WaitForGenericK8sObjectsOptions{ 155 GroupVersionResource: schema.GroupVersionResource{ 156 Group: "kuberentes.io", 157 Version: "v1alpha1", 158 Resource: "Conditions", 159 }, 160 Namespaces: NamespacesRange{ 161 Prefix: "namespace", 162 Min: 1, 163 Max: 1, 164 }, 165 SuccessfulConditions: []string{"Successful=True"}, 166 FailedConditions: []string{"Failed=True"}, 167 MinDesiredObjectCount: 3, 168 MaxFailedObjectCount: 1, 169 CallerName: "test", 170 WaitInterval: 100 * time.Millisecond, 171 }, 172 existingObjects: []exampleObject{ 173 newExampleObject("test-1", "namespace-1", []interface{}{ 174 map[string]interface{}{ 175 "type": "Successful", 176 "status": "False", 177 }, 178 map[string]interface{}{ 179 "type": "Failed", 180 "status": "True", 181 }, 182 }), 183 newExampleObject("test-2", "namespace-1", []interface{}{ 184 map[string]interface{}{ 185 "type": "Successful", 186 "status": "True", 187 }, 188 }), 189 }, 190 wantErr: true, 191 }, 192 } 193 for _, tt := range tests { 194 tt := tt 195 t.Run(tt.name, func(t *testing.T) { 196 t.Parallel() 197 ctx, cancel := context.WithTimeout(context.Background(), tt.timeout) 198 defer cancel() 199 dynamicClient := fake.NewSimpleDynamicClientWithCustomListKinds(runtime.NewScheme(), map[schema.GroupVersionResource]string{ 200 tt.options.GroupVersionResource: "ConditionsList", 201 }) 202 for _, o := range tt.existingObjects { 203 c := dynamicClient.Resource(tt.options.GroupVersionResource).Namespace(o.Namespace) 204 if _, err := c.Create(ctx, o.Unstructured, metav1.CreateOptions{}); err != nil { 205 t.Fatalf("Failed to create an existing object %v, got error: %v", o, err) 206 } 207 } 208 209 if err := WaitForGenericK8sObjects(ctx, dynamicClient, tt.options); (err != nil) != tt.wantErr { 210 t.Errorf("WaitForGenericK8sObjects() error = %v, wantErr %v", err, tt.wantErr) 211 } 212 }) 213 } 214 } 215 216 type exampleObject struct { 217 Namespace string 218 Unstructured *unstructured.Unstructured 219 } 220 221 func newExampleObject(name, namespace string, conditions []interface{}) exampleObject { 222 return exampleObject{ 223 Namespace: namespace, 224 Unstructured: &unstructured.Unstructured{ 225 Object: map[string]interface{}{ 226 "metadata": map[string]interface{}{ 227 "name": name, 228 "namespace": namespace, 229 }, 230 "status": map[string]interface{}{ 231 "conditions": conditions, 232 }, 233 }, 234 }, 235 } 236 }