1/* 2Copyright 2017 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package apiextensions 18 19import ( 20 "reflect" 21 "testing" 22 "time" 23 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25) 26 27func TestCRDHasFinalizer(t *testing.T) { 28 tests := []struct { 29 name string 30 crd *CustomResourceDefinition 31 finalizerToCheck string 32 33 expected bool 34 }{ 35 { 36 name: "missing", 37 crd: &CustomResourceDefinition{ 38 ObjectMeta: metav1.ObjectMeta{Finalizers: []string{"not-it"}}, 39 }, 40 finalizerToCheck: "it", 41 expected: false, 42 }, 43 { 44 name: "present", 45 crd: &CustomResourceDefinition{ 46 ObjectMeta: metav1.ObjectMeta{Finalizers: []string{"not-it", "it"}}, 47 }, 48 finalizerToCheck: "it", 49 expected: true, 50 }, 51 } 52 for _, tc := range tests { 53 actual := CRDHasFinalizer(tc.crd, tc.finalizerToCheck) 54 if tc.expected != actual { 55 t.Errorf("%v expected %v, got %v", tc.name, tc.expected, actual) 56 } 57 } 58} 59 60func TestCRDRemoveFinalizer(t *testing.T) { 61 tests := []struct { 62 name string 63 crd *CustomResourceDefinition 64 finalizerToCheck string 65 66 expected []string 67 }{ 68 { 69 name: "missing", 70 crd: &CustomResourceDefinition{ 71 ObjectMeta: metav1.ObjectMeta{Finalizers: []string{"not-it"}}, 72 }, 73 finalizerToCheck: "it", 74 expected: []string{"not-it"}, 75 }, 76 { 77 name: "present", 78 crd: &CustomResourceDefinition{ 79 ObjectMeta: metav1.ObjectMeta{Finalizers: []string{"not-it", "it"}}, 80 }, 81 finalizerToCheck: "it", 82 expected: []string{"not-it"}, 83 }, 84 } 85 for _, tc := range tests { 86 CRDRemoveFinalizer(tc.crd, tc.finalizerToCheck) 87 if !reflect.DeepEqual(tc.expected, tc.crd.Finalizers) { 88 t.Errorf("%v expected %v, got %v", tc.name, tc.expected, tc.crd.Finalizers) 89 } 90 } 91} 92 93func TestSetCRDCondition(t *testing.T) { 94 tests := []struct { 95 name string 96 crdCondition []CustomResourceDefinitionCondition 97 newCondition CustomResourceDefinitionCondition 98 expectedcrdCondition []CustomResourceDefinitionCondition 99 }{ 100 { 101 name: "test setCRDcondition when one condition", 102 crdCondition: []CustomResourceDefinitionCondition{ 103 { 104 Type: Established, 105 Status: ConditionTrue, 106 Reason: "Accepted", 107 Message: "the initial names have been accepted", 108 LastTransitionTime: metav1.Date(2018, 1, 1, 0, 0, 0, 0, time.UTC), 109 }, 110 }, 111 newCondition: CustomResourceDefinitionCondition{ 112 Type: Established, 113 Status: ConditionFalse, 114 Reason: "NotAccepted", 115 Message: "Not accepted", 116 LastTransitionTime: metav1.Date(2018, 1, 2, 0, 0, 0, 0, time.UTC), 117 }, 118 expectedcrdCondition: []CustomResourceDefinitionCondition{ 119 { 120 Type: Established, 121 Status: ConditionFalse, 122 Reason: "NotAccepted", 123 Message: "Not accepted", 124 LastTransitionTime: metav1.Date(2018, 1, 2, 0, 0, 0, 0, time.UTC), 125 }, 126 }, 127 }, 128 { 129 name: "test setCRDcondition when two condition", 130 crdCondition: []CustomResourceDefinitionCondition{ 131 { 132 Type: Established, 133 Status: ConditionTrue, 134 Reason: "Accepted", 135 Message: "the initial names have been accepted", 136 LastTransitionTime: metav1.Date(2018, 1, 1, 0, 0, 0, 0, time.UTC), 137 }, 138 { 139 Type: NamesAccepted, 140 Status: ConditionTrue, 141 Reason: "NoConflicts", 142 Message: "no conflicts found", 143 LastTransitionTime: metav1.Date(2018, 1, 1, 0, 0, 0, 0, time.UTC), 144 }, 145 }, 146 newCondition: CustomResourceDefinitionCondition{ 147 Type: NamesAccepted, 148 Status: ConditionFalse, 149 Reason: "Conflicts", 150 Message: "conflicts found", 151 LastTransitionTime: metav1.Date(2018, 1, 2, 0, 0, 0, 0, time.UTC), 152 }, 153 expectedcrdCondition: []CustomResourceDefinitionCondition{ 154 { 155 Type: Established, 156 Status: ConditionTrue, 157 Reason: "Accepted", 158 Message: "the initial names have been accepted", 159 LastTransitionTime: metav1.Date(2018, 1, 1, 0, 0, 0, 0, time.UTC), 160 }, 161 { 162 Type: NamesAccepted, 163 Status: ConditionFalse, 164 Reason: "Conflicts", 165 Message: "conflicts found", 166 LastTransitionTime: metav1.Date(2018, 1, 2, 0, 0, 0, 0, time.UTC), 167 }, 168 }, 169 }, 170 { 171 name: "test setCRDcondition when condition needs to be appended", 172 crdCondition: []CustomResourceDefinitionCondition{ 173 { 174 Type: Established, 175 Status: ConditionTrue, 176 Reason: "Accepted", 177 Message: "the initial names have been accepted", 178 LastTransitionTime: metav1.Date(2018, 1, 1, 0, 0, 0, 0, time.UTC), 179 }, 180 }, 181 newCondition: CustomResourceDefinitionCondition{ 182 Type: Terminating, 183 Status: ConditionFalse, 184 Reason: "NeverEstablished", 185 Message: "resource was never established", 186 LastTransitionTime: metav1.Date(2018, 2, 1, 0, 0, 0, 0, time.UTC), 187 }, 188 expectedcrdCondition: []CustomResourceDefinitionCondition{ 189 { 190 Type: Established, 191 Status: ConditionTrue, 192 Reason: "Accepted", 193 Message: "the initial names have been accepted", 194 LastTransitionTime: metav1.Date(2018, 1, 1, 0, 0, 0, 0, time.UTC), 195 }, 196 { 197 Type: Terminating, 198 Status: ConditionFalse, 199 Reason: "NeverEstablished", 200 Message: "resource was never established", 201 LastTransitionTime: metav1.Date(2018, 2, 1, 0, 0, 0, 0, time.UTC), 202 }, 203 }, 204 }, 205 { 206 name: "set new condition which doesn't have lastTransitionTime set", 207 crdCondition: []CustomResourceDefinitionCondition{ 208 { 209 Type: Established, 210 Status: ConditionTrue, 211 Reason: "Accepted", 212 Message: "the initial names have been accepted", 213 LastTransitionTime: metav1.Date(2018, 1, 1, 0, 0, 0, 0, time.UTC), 214 }, 215 }, 216 newCondition: CustomResourceDefinitionCondition{ 217 Type: Established, 218 Status: ConditionFalse, 219 Reason: "NotAccepted", 220 Message: "Not accepted", 221 }, 222 expectedcrdCondition: []CustomResourceDefinitionCondition{ 223 { 224 Type: Established, 225 Status: ConditionFalse, 226 Reason: "NotAccepted", 227 Message: "Not accepted", 228 LastTransitionTime: metav1.Date(2018, 1, 2, 0, 0, 0, 0, time.UTC), 229 }, 230 }, 231 }, 232 { 233 name: "append new condition which doesn't have lastTransitionTime set", 234 crdCondition: []CustomResourceDefinitionCondition{ 235 { 236 Type: Established, 237 Status: ConditionTrue, 238 Reason: "Accepted", 239 Message: "the initial names have been accepted", 240 LastTransitionTime: metav1.Date(2018, 1, 1, 0, 0, 0, 0, time.UTC), 241 }, 242 }, 243 newCondition: CustomResourceDefinitionCondition{ 244 Type: Terminating, 245 Status: ConditionFalse, 246 Reason: "NeverEstablished", 247 Message: "resource was never established", 248 }, 249 expectedcrdCondition: []CustomResourceDefinitionCondition{ 250 { 251 Type: Established, 252 Status: ConditionTrue, 253 Reason: "Accepted", 254 Message: "the initial names have been accepted", 255 LastTransitionTime: metav1.Date(2018, 1, 1, 0, 0, 0, 0, time.UTC), 256 }, 257 { 258 Type: Terminating, 259 Status: ConditionFalse, 260 Reason: "NeverEstablished", 261 Message: "resource was never established", 262 LastTransitionTime: metav1.Date(2018, 2, 1, 0, 0, 0, 0, time.UTC), 263 }, 264 }, 265 }, 266 } 267 for _, tc := range tests { 268 crd := generateCRDwithCondition(tc.crdCondition) 269 SetCRDCondition(crd, tc.newCondition) 270 if len(tc.expectedcrdCondition) != len(crd.Status.Conditions) { 271 t.Errorf("%v expected %v, got %v", tc.name, tc.expectedcrdCondition, crd.Status.Conditions) 272 } 273 for i := range tc.expectedcrdCondition { 274 if !IsCRDConditionEquivalent(&tc.expectedcrdCondition[i], &crd.Status.Conditions[i]) { 275 t.Errorf("%v expected %v, got %v", tc.name, tc.expectedcrdCondition[i], crd.Status.Conditions[i]) 276 } 277 if crd.Status.Conditions[i].LastTransitionTime.IsZero() { 278 t.Errorf("%q/%d lastTransitionTime should not be null: %v", tc.name, i, crd.Status.Conditions[i]) 279 } 280 } 281 } 282} 283 284func TestRemoveCRDCondition(t *testing.T) { 285 tests := []struct { 286 name string 287 crdCondition []CustomResourceDefinitionCondition 288 conditionType CustomResourceDefinitionConditionType 289 expectedcrdCondition []CustomResourceDefinitionCondition 290 }{ 291 { 292 name: "test remove CRDCondition when the conditionType meets", 293 crdCondition: []CustomResourceDefinitionCondition{ 294 { 295 Type: Established, 296 Status: ConditionTrue, 297 Reason: "Accepted", 298 Message: "the initial names have been accepted", 299 LastTransitionTime: metav1.Date(2018, 1, 1, 0, 0, 0, 0, time.UTC), 300 }, 301 { 302 Type: NamesAccepted, 303 Status: ConditionTrue, 304 Reason: "NoConflicts", 305 Message: "no conflicts found", 306 LastTransitionTime: metav1.Date(2018, 1, 1, 0, 0, 0, 0, time.UTC), 307 }, 308 }, 309 conditionType: NamesAccepted, 310 expectedcrdCondition: []CustomResourceDefinitionCondition{ 311 { 312 Type: Established, 313 Status: ConditionTrue, 314 Reason: "Accepted", 315 Message: "the initial names have been accepted", 316 LastTransitionTime: metav1.Date(2011, 1, 2, 0, 0, 0, 0, time.UTC), 317 }, 318 }, 319 }, 320 { 321 name: "test remove CRDCondition when the conditionType not meets", 322 crdCondition: []CustomResourceDefinitionCondition{ 323 { 324 Type: Established, 325 Status: ConditionTrue, 326 Reason: "Accepted", 327 Message: "the initial names have been accepted", 328 LastTransitionTime: metav1.Date(2018, 1, 1, 0, 0, 0, 0, time.UTC), 329 }, 330 { 331 Type: NamesAccepted, 332 Status: ConditionTrue, 333 Reason: "NoConflicts", 334 Message: "no conflicts found", 335 LastTransitionTime: metav1.Date(2018, 1, 1, 0, 0, 0, 0, time.UTC), 336 }, 337 }, 338 conditionType: Terminating, 339 expectedcrdCondition: []CustomResourceDefinitionCondition{ 340 { 341 Type: Established, 342 Status: ConditionTrue, 343 Reason: "Accepted", 344 Message: "the initial names have been accepted", 345 LastTransitionTime: metav1.Date(2018, 1, 1, 0, 0, 0, 0, time.UTC), 346 }, 347 { 348 Type: NamesAccepted, 349 Status: ConditionTrue, 350 Reason: "NoConflicts", 351 Message: "no conflicts found", 352 LastTransitionTime: metav1.Date(2018, 1, 1, 0, 0, 0, 0, time.UTC), 353 }, 354 }, 355 }, 356 } 357 for _, tc := range tests { 358 crd := generateCRDwithCondition(tc.crdCondition) 359 RemoveCRDCondition(crd, tc.conditionType) 360 if len(tc.expectedcrdCondition) != len(crd.Status.Conditions) { 361 t.Errorf("%v expected %v, got %v", tc.name, tc.expectedcrdCondition, crd.Status.Conditions) 362 } 363 for i := range tc.expectedcrdCondition { 364 if !IsCRDConditionEquivalent(&tc.expectedcrdCondition[i], &crd.Status.Conditions[i]) { 365 t.Errorf("%v expected %v, got %v", tc.name, tc.expectedcrdCondition, crd.Status.Conditions) 366 } 367 } 368 } 369} 370 371func TestIsCRDConditionPresentAndEqual(t *testing.T) { 372 tests := []struct { 373 name string 374 crdCondition []CustomResourceDefinitionCondition 375 conditionType CustomResourceDefinitionConditionType 376 status ConditionStatus 377 expectresult bool 378 }{ 379 { 380 name: "test CRDCondition is not Present", 381 crdCondition: []CustomResourceDefinitionCondition{ 382 { 383 Type: Established, 384 Status: ConditionTrue, 385 Reason: "Accepted", 386 Message: "the initial names have been accepted", 387 LastTransitionTime: metav1.Date(2018, 1, 1, 0, 0, 0, 0, time.UTC), 388 }, 389 { 390 Type: NamesAccepted, 391 Status: ConditionTrue, 392 Reason: "NoConflicts", 393 Message: "no conflicts found", 394 LastTransitionTime: metav1.Date(2018, 1, 1, 0, 0, 0, 0, time.UTC), 395 }, 396 }, 397 conditionType: Terminating, 398 status: ConditionTrue, 399 expectresult: false, 400 }, 401 { 402 name: "test CRDCondition is Present but not Equal", 403 crdCondition: []CustomResourceDefinitionCondition{ 404 { 405 Type: Established, 406 Status: ConditionTrue, 407 Reason: "Accepted", 408 Message: "the initial names have been accepted", 409 LastTransitionTime: metav1.Date(2018, 1, 1, 0, 0, 0, 0, time.UTC), 410 }, 411 { 412 Type: NamesAccepted, 413 Status: ConditionTrue, 414 Reason: "NoConflicts", 415 Message: "no conflicts found", 416 LastTransitionTime: metav1.Date(2018, 1, 1, 0, 0, 0, 0, time.UTC), 417 }, 418 }, 419 conditionType: Established, 420 status: ConditionFalse, 421 expectresult: false, 422 }, 423 { 424 name: "test CRDCondition is Present and Equal", 425 crdCondition: []CustomResourceDefinitionCondition{ 426 { 427 Type: Established, 428 Status: ConditionTrue, 429 Reason: "Accepted", 430 Message: "the initial names have been accepted", 431 LastTransitionTime: metav1.Date(2018, 1, 1, 0, 0, 0, 0, time.UTC), 432 }, 433 { 434 Type: NamesAccepted, 435 Status: ConditionTrue, 436 Reason: "NoConflicts", 437 Message: "no conflicts found", 438 LastTransitionTime: metav1.Date(2018, 1, 1, 0, 0, 0, 0, time.UTC), 439 }, 440 }, 441 conditionType: NamesAccepted, 442 status: ConditionTrue, 443 expectresult: true, 444 }, 445 } 446 for _, tc := range tests { 447 crd := generateCRDwithCondition(tc.crdCondition) 448 res := IsCRDConditionPresentAndEqual(crd, tc.conditionType, tc.status) 449 if res != tc.expectresult { 450 t.Errorf("%v expected %t, got %t", tc.name, tc.expectresult, res) 451 } 452 } 453} 454 455func generateCRDwithCondition(conditions []CustomResourceDefinitionCondition) *CustomResourceDefinition { 456 testCRDObjectMeta := metav1.ObjectMeta{ 457 Name: "plural.group.com", 458 ResourceVersion: "12", 459 } 460 testCRDSpec := CustomResourceDefinitionSpec{ 461 Group: "group.com", 462 Version: "version", 463 Scope: ResourceScope("Cluster"), 464 Names: CustomResourceDefinitionNames{ 465 Plural: "plural", 466 Singular: "singular", 467 Kind: "kind", 468 ListKind: "listkind", 469 }, 470 } 471 testCRDAcceptedNames := CustomResourceDefinitionNames{ 472 Plural: "plural", 473 Singular: "singular", 474 Kind: "kind", 475 ListKind: "listkind", 476 } 477 return &CustomResourceDefinition{ 478 ObjectMeta: testCRDObjectMeta, 479 Spec: testCRDSpec, 480 Status: CustomResourceDefinitionStatus{ 481 AcceptedNames: testCRDAcceptedNames, 482 Conditions: conditions, 483 }, 484 } 485} 486