github.com/oam-dev/kubevela@v1.9.11/pkg/velaql/providers/query/tree_test.go (about) 1 /* 2 Copyright 2021 The KubeVela 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 query 18 19 import ( 20 "context" 21 "testing" 22 "time" 23 24 . "github.com/onsi/ginkgo/v2" 25 . "github.com/onsi/gomega" 26 27 "github.com/fluxcd/helm-controller/api/v2beta1" 28 "github.com/fluxcd/source-controller/api/v1beta2" 29 "github.com/stretchr/testify/assert" 30 v12 "k8s.io/api/apps/v1" 31 batchv1 "k8s.io/api/batch/v1" 32 v1 "k8s.io/api/core/v1" 33 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 34 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 35 "k8s.io/apimachinery/pkg/labels" 36 "k8s.io/apimachinery/pkg/runtime" 37 "k8s.io/apimachinery/pkg/runtime/serializer/yaml" 38 types2 "k8s.io/apimachinery/pkg/types" 39 "k8s.io/utils/pointer" 40 "sigs.k8s.io/controller-runtime/pkg/client" 41 42 monitorContext "github.com/kubevela/pkg/monitor/context" 43 "github.com/kubevela/workflow/pkg/cue/model/value" 44 45 "github.com/oam-dev/kubevela/apis/core.oam.dev/common" 46 "github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1" 47 types3 "github.com/oam-dev/kubevela/apis/types" 48 "github.com/oam-dev/kubevela/pkg/oam" 49 "github.com/oam-dev/kubevela/pkg/oam/util" 50 "github.com/oam-dev/kubevela/pkg/velaql/providers/query/types" 51 ) 52 53 func TestPodStatus(t *testing.T) { 54 succeedPod := v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "Pod"}, Status: v1.PodStatus{ 55 Phase: v1.PodSucceeded, 56 }} 57 58 runningReadyPod := v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "Pod"}, 59 Spec: v1.PodSpec{ 60 RestartPolicy: v1.RestartPolicyAlways, 61 }, 62 Status: v1.PodStatus{ 63 Conditions: []v1.PodCondition{ 64 { 65 Type: v1.PodReady, 66 Status: v1.ConditionTrue, 67 }, 68 }, 69 Phase: v1.PodRunning, 70 }} 71 72 runningUnHealthyPod := v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "Pod"}, 73 Spec: v1.PodSpec{ 74 RestartPolicy: v1.RestartPolicyAlways, 75 }, 76 Status: v1.PodStatus{ 77 ContainerStatuses: []v1.ContainerStatus{ 78 { 79 LastTerminationState: v1.ContainerState{ 80 Terminated: &v1.ContainerStateTerminated{ 81 ExitCode: 127, 82 }, 83 }, 84 }, 85 }, 86 Phase: v1.PodRunning, 87 }} 88 89 runningProgressingPod := v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "Pod"}, 90 Spec: v1.PodSpec{ 91 RestartPolicy: v1.RestartPolicyAlways, 92 }, 93 Status: v1.PodStatus{ 94 Phase: v1.PodRunning, 95 Reason: "ContainerCreating", 96 }} 97 98 restartNeverPod := v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "Pod"}, 99 Spec: v1.PodSpec{ 100 RestartPolicy: v1.RestartPolicyNever, 101 }, 102 Status: v1.PodStatus{ 103 Phase: v1.PodRunning, 104 }} 105 106 pendingPod := v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "Pod"}, 107 Spec: v1.PodSpec{ 108 RestartPolicy: v1.RestartPolicyNever, 109 }, Status: v1.PodStatus{Phase: v1.PodPending}, 110 } 111 112 failedWithMessagePod := v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "Pod"}, 113 Status: v1.PodStatus{Phase: v1.PodFailed, Message: "some message"}, 114 } 115 116 failedWithOOMKillPod := v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "Pod"}, 117 Status: v1.PodStatus{Phase: v1.PodFailed, ContainerStatuses: []v1.ContainerStatus{ 118 { 119 State: v1.ContainerState{ 120 Terminated: &v1.ContainerStateTerminated{ 121 Reason: "OOMKilled", 122 }, 123 }, 124 }, 125 }}, 126 } 127 128 failedWithExistCodePod := v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "Pod"}, 129 Status: v1.PodStatus{Phase: v1.PodFailed, ContainerStatuses: []v1.ContainerStatus{ 130 { 131 Name: "nginx", 132 State: v1.ContainerState{ 133 Terminated: &v1.ContainerStateTerminated{ 134 ExitCode: 189, 135 }, 136 }, 137 }, 138 }}, 139 } 140 141 testCases := map[string]struct { 142 intput v1.Pod 143 result types.HealthStatus 144 }{ 145 "succeedPod": { 146 intput: succeedPod, 147 result: types.HealthStatus{Status: types.HealthStatusHealthy}, 148 }, 149 "runningReadyPod": { 150 intput: runningReadyPod, 151 result: types.HealthStatus{Status: types.HealthStatusHealthy, Reason: "all containers are ready"}, 152 }, 153 "runningUnHealthyPod": { 154 intput: runningUnHealthyPod, 155 result: types.HealthStatus{Status: types.HealthStatusUnHealthy}, 156 }, 157 "runningProgressingPod": { 158 intput: runningProgressingPod, 159 result: types.HealthStatus{Status: types.HealthStatusProgressing, Reason: "ContainerCreating"}, 160 }, 161 "restartNeverPod": { 162 intput: restartNeverPod, 163 result: types.HealthStatus{Status: types.HealthStatusProgressing}, 164 }, 165 "pendingPod": { 166 intput: pendingPod, 167 result: types.HealthStatus{Status: types.HealthStatusProgressing}, 168 }, 169 "failedWithMessagePod": { 170 intput: failedWithMessagePod, 171 result: types.HealthStatus{Status: types.HealthStatusUnHealthy, Message: "some message"}, 172 }, 173 "failedWithOOMKillPod": { 174 intput: failedWithOOMKillPod, 175 result: types.HealthStatus{Status: types.HealthStatusUnHealthy, Message: "OOMKilled"}, 176 }, 177 "failedWithExistCodePod": { 178 intput: failedWithExistCodePod, 179 result: types.HealthStatus{Status: types.HealthStatusUnHealthy, Message: "container \"nginx\" failed with exit code 189"}, 180 }, 181 } 182 for _, s := range testCases { 183 pod := s.intput.DeepCopy() 184 p, err := runtime.DefaultUnstructuredConverter.ToUnstructured(pod) 185 assert.NoError(t, err) 186 res, err := checkPodStatus(unstructured.Unstructured{Object: p}) 187 assert.NoError(t, err) 188 assert.NotNil(t, res) 189 assert.Equal(t, *res, s.result) 190 } 191 } 192 193 func TestService2EndpointOption(t *testing.T) { 194 labels := map[string]string{ 195 "service-name": "test", 196 "uid": "test-uid", 197 } 198 u := unstructured.Unstructured{} 199 u.SetAPIVersion("v1") 200 u.SetKind("Service") 201 u.SetLabels(labels) 202 l, err := service2EndpointListOption(u) 203 assert.NoError(t, err) 204 assert.Equal(t, "service-name=test,uid=test-uid", l.LabelSelector.String()) 205 } 206 207 func TestConvertLabel2Selector(t *testing.T) { 208 cronJob1 := ` 209 apiVersion: batch/v1 210 kind: CronJob 211 metadata: 212 name: cronjob1 213 labels: 214 app: cronjob1 215 spec: 216 schedule: "* * * * *" 217 jobTemplate: 218 metadata: 219 labels: 220 app: cronJob1 221 spec: 222 template: 223 spec: 224 containers: 225 - name: cronjob 226 image: busybox 227 command: ["/bin/sh","-c","date"] 228 restartPolicy: Never 229 ` 230 obj := unstructured.Unstructured{} 231 dec := yaml.NewDecodingSerializer(unstructured.UnstructuredJSONScheme) 232 _, _, err := dec.Decode([]byte(cronJob1), nil, &obj) 233 assert.NoError(t, err) 234 workload1 := WorkloadUnstructured{obj} 235 selector1, err := workload1.convertLabel2Selector("not", "exist") 236 assert.Equal(t, selector1, labels.Everything()) 237 assert.NoError(t, err) 238 239 selector2, err := workload1.convertLabel2Selector() 240 assert.Equal(t, selector2, nil) 241 assert.Error(t, err) 242 243 _, _, err = dec.Decode([]byte(cronJob1), nil, &obj) 244 assert.NoError(t, err) 245 workload2 := WorkloadUnstructured{obj} 246 selector3, err := workload2.convertLabel2Selector("apiVersion") 247 assert.Equal(t, selector3, labels.Everything()) 248 assert.NoError(t, err) 249 250 _, _, err = dec.Decode([]byte(cronJob1), nil, &obj) 251 assert.NoError(t, err) 252 workload3 := WorkloadUnstructured{obj} 253 selector4, err := workload3.convertLabel2Selector("spec", "jobTemplate", "metadata", "labels") 254 assert.Equal(t, selector4.String(), "app=cronJob1") 255 assert.NoError(t, err) 256 } 257 258 func TestCronJobLabelListOption(t *testing.T) { 259 cronJob := ` 260 apiVersion: batch/v1 261 kind: CronJob 262 metadata: 263 name: cronjob1 264 labels: 265 app: cronjob1 266 spec: 267 schedule: "* * * * *" 268 jobTemplate: 269 metadata: 270 labels: 271 app: cronJob1 272 spec: 273 template: 274 spec: 275 containers: 276 - name: cronjob 277 image: busybox 278 command: ["/bin/sh","-c","date"] 279 restartPolicy: Never 280 ` 281 282 // convert yaml to unstructured 283 obj := unstructured.Unstructured{} 284 dec := yaml.NewDecodingSerializer(unstructured.UnstructuredJSONScheme) 285 _, _, err := dec.Decode([]byte(cronJob), nil, &obj) 286 assert.NoError(t, err) 287 l, err := cronJobLabelListOption(obj) 288 assert.NoError(t, err) 289 assert.Equal(t, "app=cronJob1", l.LabelSelector.String()) 290 } 291 292 func TestServiceStatus(t *testing.T) { 293 lbHealthSvc := v1.Service{Spec: v1.ServiceSpec{Type: v1.ServiceTypeLoadBalancer}, Status: v1.ServiceStatus{ 294 LoadBalancer: v1.LoadBalancerStatus{ 295 Ingress: []v1.LoadBalancerIngress{ 296 { 297 IP: "198.1.1.1", 298 }, 299 }, 300 }, 301 }} 302 lbProgressingSvc := v1.Service{Spec: v1.ServiceSpec{Type: v1.ServiceTypeLoadBalancer}, Status: v1.ServiceStatus{}} 303 testCases := map[string]struct { 304 input v1.Service 305 res types.HealthStatus 306 }{ 307 "health": { 308 input: lbHealthSvc, 309 res: types.HealthStatus{Status: types.HealthStatusHealthy}, 310 }, 311 "progressing": { 312 input: lbProgressingSvc, 313 res: types.HealthStatus{Status: types.HealthStatusProgressing}, 314 }, 315 } 316 for _, s := range testCases { 317 svc := s.input.DeepCopy() 318 u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&svc) 319 assert.NoError(t, err) 320 res, err := checkServiceStatus(unstructured.Unstructured{Object: u}) 321 assert.NoError(t, err) 322 assert.NotNil(t, res) 323 assert.Equal(t, s.res, *res) 324 } 325 } 326 327 func TestPVCStatus(t *testing.T) { 328 heathyPVC := v1.PersistentVolumeClaim{Status: v1.PersistentVolumeClaimStatus{Phase: v1.ClaimBound}} 329 unHeathyPVC := v1.PersistentVolumeClaim{Status: v1.PersistentVolumeClaimStatus{Phase: v1.ClaimLost}} 330 progressingPVC := v1.PersistentVolumeClaim{Status: v1.PersistentVolumeClaimStatus{Phase: v1.ClaimPending}} 331 heathyUnkown := v1.PersistentVolumeClaim{Status: v1.PersistentVolumeClaimStatus{}} 332 testCases := map[string]struct { 333 input v1.PersistentVolumeClaim 334 res types.HealthStatus 335 }{ 336 "health": { 337 input: heathyPVC, 338 res: types.HealthStatus{Status: types.HealthStatusHealthy}, 339 }, 340 "progressing": { 341 input: progressingPVC, 342 res: types.HealthStatus{Status: types.HealthStatusProgressing}, 343 }, 344 "unHealthy": { 345 input: unHeathyPVC, 346 res: types.HealthStatus{Status: types.HealthStatusUnHealthy}, 347 }, 348 "unknown": { 349 input: heathyUnkown, 350 res: types.HealthStatus{Status: types.HealthStatusUnKnown}, 351 }, 352 } 353 for _, s := range testCases { 354 pvc := s.input.DeepCopy() 355 u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&pvc) 356 assert.NoError(t, err) 357 res, err := checkPVCHealthStatus(unstructured.Unstructured{Object: u}) 358 assert.NoError(t, err) 359 assert.NotNil(t, res) 360 assert.Equal(t, s.res, *res) 361 } 362 } 363 364 func TestGetReplicaSetCondition(t *testing.T) { 365 rs := v12.ReplicaSet{Status: v12.ReplicaSetStatus{ 366 Conditions: []v12.ReplicaSetCondition{{ 367 Type: v12.ReplicaSetReplicaFailure, 368 }}, 369 }} 370 c := getAppsv1ReplicaSetCondition(rs.Status, v12.ReplicaSetReplicaFailure) 371 assert.NotNil(t, c) 372 } 373 374 func TestReplicaSetStatus(t *testing.T) { 375 unhealthyReplicaSet := v12.ReplicaSet{ 376 ObjectMeta: metav1.ObjectMeta{ 377 Generation: 2, 378 }, 379 Status: v12.ReplicaSetStatus{ObservedGeneration: 2, 380 Conditions: []v12.ReplicaSetCondition{{ 381 Type: v12.ReplicaSetReplicaFailure, 382 Status: v1.ConditionTrue, 383 }}}, 384 } 385 progressingPodReplicaSet := v12.ReplicaSet{ 386 ObjectMeta: metav1.ObjectMeta{ 387 Generation: 2, 388 }, 389 Spec: v12.ReplicaSetSpec{Replicas: pointer.Int32(3)}, 390 Status: v12.ReplicaSetStatus{ 391 ObservedGeneration: 2, 392 ReadyReplicas: 2, 393 AvailableReplicas: 2, 394 }, 395 } 396 progressingRollingReplicaSet := v12.ReplicaSet{ 397 ObjectMeta: metav1.ObjectMeta{ 398 Generation: 2, 399 }, 400 Spec: v12.ReplicaSetSpec{Replicas: pointer.Int32(3)}, 401 Status: v12.ReplicaSetStatus{ 402 ObservedGeneration: 1, 403 }, 404 } 405 testCases := map[string]struct { 406 input v12.ReplicaSet 407 res types.HealthStatus 408 }{ 409 "unHealth": { 410 input: unhealthyReplicaSet, 411 res: types.HealthStatus{Status: types.HealthStatusUnHealthy}, 412 }, 413 "progressing": { 414 input: progressingPodReplicaSet, 415 res: types.HealthStatus{Status: types.HealthStatusProgressing, Message: "Waiting for rollout to finish: 2 out of 3 new replicas are available..."}, 416 }, 417 "rolling": { 418 input: progressingRollingReplicaSet, 419 res: types.HealthStatus{Status: types.HealthStatusProgressing, Message: "Waiting for rollout to finish: observed replica set generation less then desired generation"}, 420 }, 421 } 422 for _, s := range testCases { 423 rs := s.input.DeepCopy() 424 u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&rs) 425 assert.NoError(t, err) 426 res, err := checkReplicaSetStatus(unstructured.Unstructured{Object: u}) 427 assert.NoError(t, err) 428 assert.NotNil(t, res) 429 assert.Equal(t, s.res, *res) 430 } 431 } 432 433 func TestHelmResourceStatus(t *testing.T) { 434 tm := metav1.TypeMeta{APIVersion: "helm.toolkit.fluxcd.io/v2beta1", Kind: "HelmRelease"} 435 healthHr := v2beta1.HelmRelease{TypeMeta: tm, Status: v2beta1.HelmReleaseStatus{Conditions: []metav1.Condition{ 436 { 437 Type: "Ready", 438 Status: metav1.ConditionTrue, 439 }, 440 }}} 441 unHealthyHr := v2beta1.HelmRelease{TypeMeta: tm, Status: v2beta1.HelmReleaseStatus{Conditions: []metav1.Condition{ 442 { 443 Type: "Ready", 444 Status: metav1.ConditionFalse, 445 Message: "some reason", 446 }, 447 }}} 448 unKnowHealthyHr := v2beta1.HelmRelease{TypeMeta: tm, Status: v2beta1.HelmReleaseStatus{Conditions: []metav1.Condition{ 449 { 450 Type: "OtherType", 451 Status: metav1.ConditionFalse, 452 }, 453 }}} 454 testCases := map[string]struct { 455 hr v2beta1.HelmRelease 456 res *types.HealthStatus 457 }{ 458 "healthHr": { 459 hr: healthHr, 460 res: &types.HealthStatus{Status: types.HealthStatusHealthy}, 461 }, 462 "unHealthyHr": { 463 hr: unHealthyHr, 464 res: &types.HealthStatus{Status: types.HealthStatusUnHealthy, Message: "some reason"}, 465 }, 466 "unKnowHealthyHr": { 467 hr: unKnowHealthyHr, 468 res: &types.HealthStatus{Status: types.HealthStatusUnKnown}, 469 }, 470 } 471 for _, s := range testCases { 472 obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(s.hr.DeepCopy()) 473 assert.NoError(t, err) 474 res, err := CheckResourceStatus(unstructured.Unstructured{Object: obj}) 475 assert.NoError(t, err) 476 assert.Equal(t, res, s.res) 477 } 478 } 479 480 func TestHelmRepoResourceStatus(t *testing.T) { 481 tm := metav1.TypeMeta{APIVersion: "source.toolkit.fluxcd.io/v1beta2", Kind: "HelmRepository"} 482 healthHr := v1beta2.HelmRepository{TypeMeta: tm, Status: v1beta2.HelmRepositoryStatus{Conditions: []metav1.Condition{ 483 { 484 Type: "Ready", 485 Status: metav1.ConditionTrue, 486 }, 487 }}} 488 unHealthyHr := v1beta2.HelmRepository{TypeMeta: tm, Status: v1beta2.HelmRepositoryStatus{Conditions: []metav1.Condition{ 489 { 490 Type: "Ready", 491 Status: metav1.ConditionFalse, 492 Message: "some reason", 493 }, 494 }}} 495 unKnowHealthyHr := v1beta2.HelmRepository{TypeMeta: tm, Status: v1beta2.HelmRepositoryStatus{Conditions: []metav1.Condition{ 496 { 497 Type: "OtherType", 498 Status: metav1.ConditionFalse, 499 }, 500 }}} 501 testCases := map[string]struct { 502 hr v1beta2.HelmRepository 503 res *types.HealthStatus 504 }{ 505 "healthHr": { 506 hr: healthHr, 507 res: &types.HealthStatus{Status: types.HealthStatusHealthy}, 508 }, 509 "unHealthyHr": { 510 hr: unHealthyHr, 511 res: &types.HealthStatus{Status: types.HealthStatusUnHealthy, Message: "some reason"}, 512 }, 513 "unKnowHealthyHr": { 514 hr: unKnowHealthyHr, 515 res: &types.HealthStatus{Status: types.HealthStatusUnKnown}, 516 }, 517 } 518 for _, s := range testCases { 519 obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(s.hr.DeepCopy()) 520 assert.NoError(t, err) 521 res, err := CheckResourceStatus(unstructured.Unstructured{Object: obj}) 522 assert.NoError(t, err) 523 assert.Equal(t, res, s.res) 524 } 525 } 526 527 func TestGenListOption(t *testing.T) { 528 resLabel, err := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{MatchLabels: map[string]string{"testKey": "testVal"}}) 529 assert.NoError(t, err) 530 listOption := client.ListOptions{LabelSelector: resLabel, Namespace: "test"} 531 532 deploy := v12.Deployment{ObjectMeta: metav1.ObjectMeta{Namespace: "test"}, Spec: v12.DeploymentSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"testKey": "testVal"}}}} 533 du, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&deploy) 534 assert.NoError(t, err) 535 assert.NotNil(t, du) 536 dls, err := defaultWorkloadLabelListOption(unstructured.Unstructured{Object: du}) 537 assert.NoError(t, err) 538 assert.Equal(t, listOption, dls) 539 540 rs := v12.ReplicaSet{ObjectMeta: metav1.ObjectMeta{Namespace: "test"}, Spec: v12.ReplicaSetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"testKey": "testVal"}}}} 541 rsu, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&rs) 542 assert.NoError(t, err) 543 assert.NotNil(t, du) 544 rsls, err := defaultWorkloadLabelListOption(unstructured.Unstructured{Object: rsu}) 545 assert.NoError(t, err) 546 assert.Equal(t, listOption, rsls) 547 548 sts := v12.StatefulSet{ObjectMeta: metav1.ObjectMeta{Namespace: "test"}, Spec: v12.StatefulSetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"testKey": "testVal"}}}} 549 stsu, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&sts) 550 assert.NoError(t, err) 551 assert.NotNil(t, stsu) 552 stsls, err := defaultWorkloadLabelListOption(unstructured.Unstructured{Object: stsu}) 553 assert.NoError(t, err) 554 assert.Equal(t, listOption, stsls) 555 556 helmRelease := unstructured.Unstructured{} 557 helmRelease.SetName("test-helm") 558 helmRelease.SetNamespace("test-ns") 559 hrll, err := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{MatchLabels: map[string]string{"helm.toolkit.fluxcd.io/name": "test-helm", "helm.toolkit.fluxcd.io/namespace": "test-ns"}}) 560 assert.NoError(t, err) 561 562 hrls, err := helmRelease2AnyListOption(helmRelease) 563 assert.NoError(t, err) 564 assert.Equal(t, hrls, client.ListOptions{LabelSelector: hrll}) 565 } 566 567 func TestPodAdditionalInfo(t *testing.T) { 568 typeMeta := metav1.TypeMeta{APIVersion: "v1", Kind: "Pod"} 569 570 type testCase struct { 571 pod v1.Pod 572 res map[string]interface{} 573 } 574 575 case1 := testCase{ 576 pod: v1.Pod{TypeMeta: typeMeta, 577 ObjectMeta: metav1.ObjectMeta{DeletionTimestamp: &metav1.Time{Time: time.Now()}}, 578 Status: v1.PodStatus{ 579 InitContainerStatuses: []v1.ContainerStatus{ 580 { 581 State: v1.ContainerState{ 582 Terminated: &v1.ContainerStateTerminated{ 583 ExitCode: 0, 584 }, 585 }, 586 }, 587 }, 588 Reason: "NodeLost"}, 589 }, 590 res: map[string]interface{}{ 591 "Ready": "0/0", 592 "Status": "Unknown", 593 "Restarts": 0, 594 "Age": "<unknown>", 595 }, 596 } 597 598 case2 := testCase{ 599 pod: v1.Pod{TypeMeta: typeMeta, 600 Status: v1.PodStatus{ 601 InitContainerStatuses: []v1.ContainerStatus{ 602 { 603 State: v1.ContainerState{ 604 Terminated: &v1.ContainerStateTerminated{ 605 ExitCode: 127, 606 }, 607 }, 608 }, 609 }}, 610 }, 611 res: map[string]interface{}{ 612 "Ready": "0/0", 613 "Status": "Init:ExitCode:127", 614 "Restarts": 0, 615 "Age": "<unknown>", 616 }, 617 } 618 619 case3 := testCase{ 620 pod: v1.Pod{TypeMeta: typeMeta, 621 Status: v1.PodStatus{ 622 InitContainerStatuses: []v1.ContainerStatus{ 623 { 624 State: v1.ContainerState{ 625 Terminated: &v1.ContainerStateTerminated{ 626 ExitCode: 127, 627 Signal: 32, 628 }, 629 }, 630 }, 631 }}, 632 }, 633 res: map[string]interface{}{ 634 "Ready": "0/0", 635 "Status": "Init:Signal:32", 636 "Restarts": 0, 637 "Age": "<unknown>", 638 }, 639 } 640 641 case4 := testCase{ 642 pod: v1.Pod{TypeMeta: typeMeta, 643 Status: v1.PodStatus{ 644 InitContainerStatuses: []v1.ContainerStatus{ 645 { 646 State: v1.ContainerState{ 647 Terminated: &v1.ContainerStateTerminated{ 648 Reason: "OOMKill", 649 ExitCode: 127, 650 }, 651 }, 652 }, 653 }}, 654 }, 655 res: map[string]interface{}{ 656 "Ready": "0/0", 657 "Status": "Init:OOMKill", 658 "Restarts": 0, 659 "Age": "<unknown>", 660 }, 661 } 662 663 case5 := testCase{ 664 pod: v1.Pod{TypeMeta: typeMeta, 665 Status: v1.PodStatus{ 666 InitContainerStatuses: []v1.ContainerStatus{ 667 { 668 State: v1.ContainerState{ 669 Terminated: &v1.ContainerStateTerminated{ 670 Reason: "OOMKill", 671 ExitCode: 127, 672 }, 673 }, 674 }, 675 }}, 676 }, 677 res: map[string]interface{}{ 678 "Ready": "0/0", 679 "Status": "Init:OOMKill", 680 "Restarts": 0, 681 "Age": "<unknown>", 682 }, 683 } 684 685 case6 := testCase{ 686 pod: v1.Pod{TypeMeta: typeMeta, 687 Status: v1.PodStatus{ 688 InitContainerStatuses: []v1.ContainerStatus{ 689 { 690 State: v1.ContainerState{ 691 Waiting: &v1.ContainerStateWaiting{ 692 Reason: "ContainerCreating", 693 }, 694 }, 695 }, 696 }}, 697 }, 698 res: map[string]interface{}{ 699 "Ready": "0/0", 700 "Status": "Init:ContainerCreating", 701 "Restarts": 0, 702 "Age": "<unknown>", 703 }, 704 } 705 706 case7 := testCase{ 707 pod: v1.Pod{TypeMeta: typeMeta, 708 Spec: v1.PodSpec{ 709 InitContainers: []v1.Container{ 710 {Name: "test"}, 711 }}, 712 Status: v1.PodStatus{ 713 InitContainerStatuses: []v1.ContainerStatus{ 714 { 715 State: v1.ContainerState{ 716 Waiting: &v1.ContainerStateWaiting{}, 717 }, 718 }, 719 }}, 720 }, 721 res: map[string]interface{}{ 722 "Ready": "0/0", 723 "Status": "Init:0/1", 724 "Restarts": 0, 725 "Age": "<unknown>", 726 }, 727 } 728 729 case8 := testCase{ 730 pod: v1.Pod{TypeMeta: typeMeta, 731 Status: v1.PodStatus{ 732 ContainerStatuses: []v1.ContainerStatus{ 733 { 734 State: v1.ContainerState{ 735 Waiting: &v1.ContainerStateWaiting{ 736 Reason: "ContainerCreating", 737 }, 738 }, 739 }, 740 }, 741 }, 742 }, 743 res: map[string]interface{}{ 744 "Ready": "0/0", 745 "Status": "ContainerCreating", 746 "Restarts": 0, 747 "Age": "<unknown>", 748 }, 749 } 750 751 case9 := testCase{ 752 pod: v1.Pod{TypeMeta: typeMeta, 753 Status: v1.PodStatus{ 754 ContainerStatuses: []v1.ContainerStatus{ 755 { 756 State: v1.ContainerState{ 757 Terminated: &v1.ContainerStateTerminated{ 758 Reason: "OOMKilled", 759 }, 760 }, 761 }, 762 }, 763 }, 764 }, 765 res: map[string]interface{}{ 766 "Ready": "0/0", 767 "Status": "OOMKilled", 768 "Restarts": 0, 769 "Age": "<unknown>", 770 }, 771 } 772 773 case10 := testCase{ 774 pod: v1.Pod{TypeMeta: typeMeta, 775 Status: v1.PodStatus{ 776 ContainerStatuses: []v1.ContainerStatus{ 777 { 778 State: v1.ContainerState{ 779 Terminated: &v1.ContainerStateTerminated{ 780 Signal: 2, 781 }, 782 }, 783 }, 784 }, 785 }, 786 }, 787 res: map[string]interface{}{ 788 "Ready": "0/0", 789 "Status": "Signal:2", 790 "Restarts": 0, 791 "Age": "<unknown>", 792 }, 793 } 794 795 case11 := testCase{ 796 pod: v1.Pod{TypeMeta: typeMeta, 797 Status: v1.PodStatus{ 798 ContainerStatuses: []v1.ContainerStatus{ 799 { 800 State: v1.ContainerState{ 801 Terminated: &v1.ContainerStateTerminated{ 802 ExitCode: 127, 803 }, 804 }, 805 }, 806 }, 807 }, 808 }, 809 res: map[string]interface{}{ 810 "Ready": "0/0", 811 "Status": "ExitCode:127", 812 "Restarts": 0, 813 "Age": "<unknown>", 814 }, 815 } 816 817 case12 := testCase{ 818 pod: v1.Pod{TypeMeta: typeMeta, 819 Spec: v1.PodSpec{ 820 Containers: []v1.Container{{ 821 Name: "nginx", 822 }}, 823 }, 824 Status: v1.PodStatus{ 825 ContainerStatuses: []v1.ContainerStatus{ 826 { 827 State: v1.ContainerState{ 828 Running: &v1.ContainerStateRunning{ 829 StartedAt: metav1.Now(), 830 }, 831 }, 832 Ready: true, 833 }, 834 }, 835 Phase: "Running", 836 }, 837 }, 838 res: map[string]interface{}{ 839 "Ready": "1/1", 840 "Status": "Running", 841 "Restarts": 0, 842 "Age": "<unknown>", 843 }, 844 } 845 846 case13 := testCase{ 847 pod: v1.Pod{TypeMeta: typeMeta, 848 Spec: v1.PodSpec{ 849 Containers: []v1.Container{{ 850 Name: "nginx", 851 }}, 852 }, 853 Status: v1.PodStatus{ 854 ContainerStatuses: []v1.ContainerStatus{ 855 { 856 State: v1.ContainerState{ 857 Running: &v1.ContainerStateRunning{ 858 StartedAt: metav1.Now(), 859 }, 860 }, 861 Ready: true, 862 }, 863 }, 864 Phase: "Completed", 865 Conditions: []v1.PodCondition{ 866 { 867 Type: v1.PodReady, 868 Status: v1.ConditionTrue, 869 }, 870 }, 871 }, 872 }, 873 res: map[string]interface{}{ 874 "Ready": "1/1", 875 "Status": "Running", 876 "Restarts": 0, 877 "Age": "<unknown>", 878 }, 879 } 880 881 case14 := testCase{ 882 pod: v1.Pod{TypeMeta: typeMeta, 883 Spec: v1.PodSpec{ 884 Containers: []v1.Container{{ 885 Name: "nginx", 886 }}, 887 }, 888 Status: v1.PodStatus{ 889 ContainerStatuses: []v1.ContainerStatus{ 890 { 891 State: v1.ContainerState{ 892 Running: &v1.ContainerStateRunning{ 893 StartedAt: metav1.Now(), 894 }, 895 }, 896 Ready: true, 897 }, 898 }, 899 Phase: "Completed", 900 }, 901 }, 902 res: map[string]interface{}{ 903 "Ready": "1/1", 904 "Status": "NotReady", 905 "Restarts": 0, 906 "Age": "<unknown>", 907 }, 908 } 909 910 case15 := testCase{ 911 pod: v1.Pod{TypeMeta: typeMeta, 912 ObjectMeta: metav1.ObjectMeta{ 913 DeletionTimestamp: &metav1.Time{Time: time.Now()}, 914 }, 915 }, 916 res: map[string]interface{}{ 917 "Ready": "0/0", 918 "Status": "Terminating", 919 "Restarts": 0, 920 "Age": "<unknown>", 921 }, 922 } 923 924 testCases := map[string]testCase{ 925 "pod1": case1, 926 "pod2": case2, 927 "pod3": case3, 928 "pod4": case4, 929 "pod5": case5, 930 "pod6": case6, 931 "pod7": case7, 932 "pod8": case8, 933 "pod9": case9, 934 "pod10": case10, 935 "pod11": case11, 936 "pod12": case12, 937 "pod13": case13, 938 "pod14": case14, 939 "pod15": case15, 940 } 941 942 for _, t2 := range testCases { 943 u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(t2.pod.DeepCopy()) 944 assert.NoError(t, err) 945 res, err := additionalInfo(unstructured.Unstructured{Object: u}) 946 assert.NoError(t, err) 947 assert.Equal(t, t2.res, res) 948 } 949 } 950 951 func TestDeploymentAdditionalInfo(t *testing.T) { 952 typeMeta := metav1.TypeMeta{APIVersion: "apps/v1", Kind: "Deployment"} 953 954 type testCase struct { 955 Deployment v12.Deployment 956 res map[string]interface{} 957 } 958 959 case1 := testCase{ 960 Deployment: v12.Deployment{ 961 TypeMeta: typeMeta, 962 Spec: v12.DeploymentSpec{Replicas: pointer.Int32(1)}, 963 Status: v12.DeploymentStatus{ 964 ReadyReplicas: 1, 965 UpdatedReplicas: 1, 966 AvailableReplicas: 1, 967 }, 968 }, 969 res: map[string]interface{}{ 970 "Ready": "1/1", 971 "Update": int32(1), 972 "Available": int32(1), 973 "Age": "<unknown>", 974 }, 975 } 976 977 testCases := map[string]testCase{ 978 "deployment1": case1, 979 } 980 981 for _, t2 := range testCases { 982 u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(t2.Deployment.DeepCopy()) 983 assert.NoError(t, err) 984 res, err := additionalInfo(unstructured.Unstructured{Object: u}) 985 assert.NoError(t, err) 986 assert.Equal(t, t2.res, res) 987 } 988 } 989 990 func TestStatefulSetAdditionalInfo(t *testing.T) { 991 typeMeta := metav1.TypeMeta{APIVersion: "apps/v1", Kind: "StatefulSet"} 992 993 type testCase struct { 994 StatefulSet v12.StatefulSet 995 res map[string]interface{} 996 } 997 998 case1 := testCase{ 999 StatefulSet: v12.StatefulSet{ 1000 TypeMeta: typeMeta, 1001 Spec: v12.StatefulSetSpec{Replicas: pointer.Int32(1)}, 1002 Status: v12.StatefulSetStatus{ 1003 ReadyReplicas: 1, 1004 }, 1005 }, 1006 res: map[string]interface{}{ 1007 "Ready": "1/1", 1008 "Age": "<unknown>", 1009 }, 1010 } 1011 1012 testCases := map[string]testCase{ 1013 "statefulSet1": case1, 1014 } 1015 1016 for _, t2 := range testCases { 1017 u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(t2.StatefulSet.DeepCopy()) 1018 assert.NoError(t, err) 1019 res, err := additionalInfo(unstructured.Unstructured{Object: u}) 1020 assert.NoError(t, err) 1021 assert.Equal(t, t2.res, res) 1022 } 1023 } 1024 1025 func TestSvcAdditionalInfo(t *testing.T) { 1026 typeMeta := metav1.TypeMeta{APIVersion: "v1", Kind: "Service"} 1027 1028 type testCase struct { 1029 svc v1.Service 1030 res map[string]interface{} 1031 } 1032 1033 case1 := testCase{ 1034 svc: v1.Service{TypeMeta: typeMeta, Spec: v1.ServiceSpec{ 1035 Type: v1.ServiceTypeLoadBalancer, 1036 }, 1037 Status: v1.ServiceStatus{LoadBalancer: v1.LoadBalancerStatus{Ingress: []v1.LoadBalancerIngress{{IP: "145.2.2.1"}}}}}, 1038 res: map[string]interface{}{ 1039 "EIP": "145.2.2.1", 1040 }, 1041 } 1042 1043 case2 := testCase{ 1044 svc: v1.Service{TypeMeta: typeMeta, Spec: v1.ServiceSpec{ 1045 Type: v1.ServiceTypeLoadBalancer, 1046 }, 1047 Status: v1.ServiceStatus{}}, 1048 res: map[string]interface{}{ 1049 "EIP": "pending", 1050 }, 1051 } 1052 1053 testCases := map[string]testCase{ 1054 "svc1": case1, 1055 "svc2": case2, 1056 } 1057 1058 for _, t2 := range testCases { 1059 u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(t2.svc.DeepCopy()) 1060 assert.NoError(t, err) 1061 res, err := additionalInfo(unstructured.Unstructured{Object: u}) 1062 assert.NoError(t, err) 1063 assert.Equal(t, t2.res, res) 1064 } 1065 } 1066 1067 var _ = Describe("unit-test to e2e test", func() { 1068 deploy1 := v12.Deployment{ 1069 TypeMeta: metav1.TypeMeta{ 1070 APIVersion: "apps/v1", 1071 Kind: "Deployment", 1072 }, 1073 ObjectMeta: metav1.ObjectMeta{ 1074 Name: "deploy1", 1075 Namespace: "test-namespace", 1076 }, 1077 Spec: v12.DeploymentSpec{ 1078 Selector: &metav1.LabelSelector{ 1079 MatchLabels: map[string]string{ 1080 "app": "deploy1", 1081 }, 1082 }, 1083 Template: v1.PodTemplateSpec{ 1084 ObjectMeta: metav1.ObjectMeta{ 1085 Labels: map[string]string{ 1086 "app": "deploy1", 1087 }, 1088 }, 1089 Spec: v1.PodSpec{ 1090 Containers: []v1.Container{ 1091 { 1092 Image: "nginx", 1093 Name: "nginx", 1094 }, 1095 }, 1096 }, 1097 }, 1098 }, 1099 } 1100 1101 deploy2 := v12.Deployment{ 1102 TypeMeta: metav1.TypeMeta{ 1103 APIVersion: "apps/v1", 1104 Kind: "Deployment", 1105 }, 1106 ObjectMeta: metav1.ObjectMeta{ 1107 Name: "deploy2", 1108 Namespace: "test-namespace", 1109 }, 1110 Spec: v12.DeploymentSpec{ 1111 Selector: &metav1.LabelSelector{ 1112 MatchLabels: map[string]string{ 1113 "app": "deploy2", 1114 }, 1115 }, 1116 Template: v1.PodTemplateSpec{ 1117 ObjectMeta: metav1.ObjectMeta{ 1118 Labels: map[string]string{ 1119 "app": "deploy2", 1120 }, 1121 }, 1122 Spec: v1.PodSpec{ 1123 Containers: []v1.Container{ 1124 { 1125 Image: "nginx", 1126 Name: "nginx", 1127 }, 1128 }, 1129 }, 1130 }, 1131 }, 1132 } 1133 1134 rs1 := v12.ReplicaSet{ 1135 TypeMeta: metav1.TypeMeta{ 1136 APIVersion: "apps/v1", 1137 Kind: "ReplicaSet", 1138 }, 1139 ObjectMeta: metav1.ObjectMeta{ 1140 Name: "rs1", 1141 Namespace: "test-namespace", 1142 Labels: map[string]string{ 1143 "app": "deploy1", 1144 }, 1145 }, 1146 Spec: v12.ReplicaSetSpec{ 1147 Selector: &metav1.LabelSelector{ 1148 MatchLabels: map[string]string{ 1149 "app": "deploy1", 1150 "rs": "rs1", 1151 }, 1152 }, 1153 Template: v1.PodTemplateSpec{ 1154 ObjectMeta: metav1.ObjectMeta{ 1155 Labels: map[string]string{ 1156 "app": "deploy1", 1157 "rs": "rs1", 1158 }, 1159 }, 1160 Spec: v1.PodSpec{ 1161 Containers: []v1.Container{ 1162 { 1163 Image: "nginx", 1164 Name: "nginx", 1165 }, 1166 }, 1167 }, 1168 }, 1169 }, 1170 } 1171 1172 rs2 := v12.ReplicaSet{ 1173 TypeMeta: metav1.TypeMeta{ 1174 APIVersion: "apps/v1", 1175 Kind: "ReplicaSet", 1176 }, 1177 ObjectMeta: metav1.ObjectMeta{ 1178 Name: "rs2", 1179 Namespace: "test-namespace", 1180 Labels: map[string]string{ 1181 "app": "deploy1", 1182 }, 1183 }, 1184 Spec: v12.ReplicaSetSpec{ 1185 Selector: &metav1.LabelSelector{ 1186 MatchLabels: map[string]string{ 1187 "app": "deploy1", 1188 "rs": "rs2", 1189 }, 1190 }, 1191 Template: v1.PodTemplateSpec{ 1192 ObjectMeta: metav1.ObjectMeta{ 1193 Labels: map[string]string{ 1194 "app": "deploy1", 1195 "rs": "rs2", 1196 }, 1197 }, 1198 Spec: v1.PodSpec{ 1199 Containers: []v1.Container{ 1200 { 1201 Image: "nginx", 1202 Name: "nginx", 1203 }, 1204 }, 1205 }, 1206 }, 1207 }, 1208 } 1209 1210 rs3 := v12.ReplicaSet{ 1211 TypeMeta: metav1.TypeMeta{ 1212 APIVersion: "apps/v1", 1213 Kind: "ReplicaSet", 1214 }, 1215 ObjectMeta: metav1.ObjectMeta{ 1216 Name: "rs3", 1217 Namespace: "test-namespace", 1218 Labels: map[string]string{ 1219 "app": "deploy2", 1220 }, 1221 }, 1222 Spec: v12.ReplicaSetSpec{ 1223 Selector: &metav1.LabelSelector{ 1224 MatchLabels: map[string]string{ 1225 "app": "deploy2", 1226 "rs": "rs3", 1227 }, 1228 }, 1229 Template: v1.PodTemplateSpec{ 1230 ObjectMeta: metav1.ObjectMeta{ 1231 Labels: map[string]string{ 1232 "app": "deploy2", 1233 "rs": "rs3", 1234 }, 1235 }, 1236 Spec: v1.PodSpec{ 1237 Containers: []v1.Container{ 1238 { 1239 Image: "nginx", 1240 Name: "nginx", 1241 }, 1242 }, 1243 }, 1244 }, 1245 }, 1246 } 1247 1248 pod1 := v1.Pod{ 1249 TypeMeta: metav1.TypeMeta{ 1250 APIVersion: "v1", 1251 Kind: "Pod", 1252 }, 1253 ObjectMeta: metav1.ObjectMeta{ 1254 Name: "pod1", 1255 Namespace: "test-namespace", 1256 Labels: map[string]string{ 1257 "app": "deploy1", 1258 "rs": "rs1", 1259 }, 1260 }, 1261 Spec: v1.PodSpec{ 1262 Containers: []v1.Container{ 1263 { 1264 Image: "nginx", 1265 Name: "nginx", 1266 }, 1267 }, 1268 }, 1269 } 1270 1271 pod2 := v1.Pod{ 1272 TypeMeta: metav1.TypeMeta{ 1273 APIVersion: "v1", 1274 Kind: "Pod", 1275 }, 1276 ObjectMeta: metav1.ObjectMeta{ 1277 Name: "pod2", 1278 Namespace: "test-namespace", 1279 Labels: map[string]string{ 1280 "app": "deploy1", 1281 "rs": "rs2", 1282 }, 1283 }, 1284 Spec: v1.PodSpec{ 1285 Containers: []v1.Container{ 1286 { 1287 Image: "nginx", 1288 Name: "nginx", 1289 }, 1290 }, 1291 }, 1292 } 1293 1294 pod3 := v1.Pod{ 1295 TypeMeta: metav1.TypeMeta{ 1296 APIVersion: "v1", 1297 Kind: "Pod", 1298 }, 1299 ObjectMeta: metav1.ObjectMeta{ 1300 Name: "pod3", 1301 Namespace: "test-namespace", 1302 Labels: map[string]string{ 1303 "app": "deploy2", 1304 "rs": "rs3", 1305 }, 1306 }, 1307 Spec: v1.PodSpec{ 1308 Containers: []v1.Container{ 1309 { 1310 Image: "nginx", 1311 Name: "nginx", 1312 }, 1313 }, 1314 }, 1315 } 1316 1317 rs4 := v12.ReplicaSet{ 1318 TypeMeta: metav1.TypeMeta{ 1319 APIVersion: "apps/v1", 1320 Kind: "ReplicaSet", 1321 }, 1322 ObjectMeta: metav1.ObjectMeta{ 1323 Name: "rs4", 1324 Namespace: "test-namespace", 1325 Labels: map[string]string{ 1326 "app": "deploy3", 1327 }, 1328 }, 1329 Spec: v12.ReplicaSetSpec{ 1330 Selector: &metav1.LabelSelector{ 1331 MatchLabels: map[string]string{ 1332 "app": "deploy3", 1333 "rs": "rs4", 1334 }, 1335 }, 1336 Template: v1.PodTemplateSpec{ 1337 ObjectMeta: metav1.ObjectMeta{ 1338 Labels: map[string]string{ 1339 "app": "deploy3", 1340 "rs": "rs4", 1341 }, 1342 }, 1343 Spec: v1.PodSpec{ 1344 Containers: []v1.Container{ 1345 { 1346 Image: "nginx", 1347 Name: "nginx", 1348 }, 1349 }, 1350 }, 1351 }, 1352 }, 1353 } 1354 1355 pod4 := v1.Pod{ 1356 TypeMeta: metav1.TypeMeta{ 1357 APIVersion: "v1", 1358 Kind: "Pod", 1359 }, 1360 ObjectMeta: metav1.ObjectMeta{ 1361 Name: "pod4", 1362 Namespace: "test-namespace", 1363 Labels: map[string]string{ 1364 "app": "deploy3", 1365 "rs": "rs4", 1366 }, 1367 }, 1368 Spec: v1.PodSpec{ 1369 Containers: []v1.Container{ 1370 { 1371 Image: "nginx", 1372 Name: "nginx", 1373 }, 1374 }, 1375 }, 1376 } 1377 pod5 := v1.Pod{ 1378 TypeMeta: metav1.TypeMeta{ 1379 APIVersion: "v1", 1380 Kind: "Pod", 1381 }, 1382 ObjectMeta: metav1.ObjectMeta{ 1383 Name: "pod5", 1384 Namespace: "test-namespace", 1385 Labels: map[string]string{ 1386 "job-name": "job2", 1387 }, 1388 }, 1389 Spec: v1.PodSpec{ 1390 Containers: []v1.Container{ 1391 { 1392 Image: "nginx", 1393 Name: "nginx", 1394 }, 1395 }, 1396 }, 1397 } 1398 1399 job1 := batchv1.Job{ 1400 TypeMeta: metav1.TypeMeta{ 1401 APIVersion: "batch/v1", 1402 Kind: "Job", 1403 }, 1404 ObjectMeta: metav1.ObjectMeta{ 1405 Name: "job1", 1406 Namespace: "test-namespace", 1407 Labels: map[string]string{ 1408 "app": "cronJob1", 1409 }, 1410 }, 1411 Spec: batchv1.JobSpec{ 1412 Template: v1.PodTemplateSpec{ 1413 Spec: v1.PodSpec{ 1414 RestartPolicy: "OnFailure", 1415 Containers: []v1.Container{ 1416 { 1417 Image: "nginx", 1418 Name: "nginx", 1419 }, 1420 }, 1421 }, 1422 }, 1423 }, 1424 } 1425 1426 manualSelector := true 1427 job2 := batchv1.Job{ 1428 TypeMeta: metav1.TypeMeta{ 1429 APIVersion: "batch/v1", 1430 Kind: "Job", 1431 }, 1432 ObjectMeta: metav1.ObjectMeta{ 1433 Name: "job2", 1434 Namespace: "test-namespace", 1435 Labels: map[string]string{ 1436 "job-name": "job2", 1437 }, 1438 }, 1439 Spec: batchv1.JobSpec{ 1440 ManualSelector: &manualSelector, 1441 Selector: &metav1.LabelSelector{ 1442 MatchLabels: map[string]string{ 1443 "job-name": "job2", 1444 }, 1445 }, 1446 Template: v1.PodTemplateSpec{ 1447 ObjectMeta: metav1.ObjectMeta{ 1448 Labels: map[string]string{ 1449 "job-name": "job2", 1450 }, 1451 }, 1452 Spec: v1.PodSpec{ 1453 RestartPolicy: "OnFailure", 1454 Containers: []v1.Container{ 1455 { 1456 Image: "nginx", 1457 Name: "nginx", 1458 }, 1459 }, 1460 }, 1461 }, 1462 }, 1463 } 1464 1465 cronJob1 := batchv1.CronJob{ 1466 TypeMeta: metav1.TypeMeta{ 1467 APIVersion: "batch/v1", 1468 Kind: "CronJob", 1469 }, 1470 ObjectMeta: metav1.ObjectMeta{ 1471 Name: "cronjob1", 1472 Namespace: "test-namespace", 1473 Labels: map[string]string{ 1474 "app": "cronJob1", 1475 }, 1476 }, 1477 Spec: batchv1.CronJobSpec{ 1478 Schedule: "* * * * *", 1479 JobTemplate: batchv1.JobTemplateSpec{ 1480 ObjectMeta: metav1.ObjectMeta{ 1481 Labels: map[string]string{ 1482 "app": "cronJob1", 1483 }, 1484 }, 1485 Spec: batchv1.JobSpec{ 1486 Template: v1.PodTemplateSpec{ 1487 Spec: v1.PodSpec{ 1488 RestartPolicy: "OnFailure", 1489 Containers: []v1.Container{ 1490 { 1491 Image: "nginx", 1492 Name: "nginx", 1493 }, 1494 }, 1495 }, 1496 }, 1497 }, 1498 }, 1499 }, 1500 } 1501 1502 var objectList []client.Object 1503 objectList = append(objectList, &deploy1, &deploy1, &rs1, &rs2, &rs3, &rs4, &pod1, &pod2, &pod3, &rs4, &pod4, &pod5, &job1, &job2, &cronJob1) 1504 BeforeEach(func() { 1505 Expect(k8sClient.Create(ctx, &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace"}})).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{})) 1506 Expect(k8sClient.Create(ctx, deploy1.DeepCopy())).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{})) 1507 Expect(k8sClient.Create(ctx, deploy2.DeepCopy())).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{})) 1508 Expect(k8sClient.Create(ctx, rs1.DeepCopy())).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{})) 1509 Expect(k8sClient.Create(ctx, rs2.DeepCopy())).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{})) 1510 Expect(k8sClient.Create(ctx, rs3.DeepCopy())).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{})) 1511 Expect(k8sClient.Create(ctx, pod1.DeepCopy())).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{})) 1512 Expect(k8sClient.Create(ctx, pod2.DeepCopy())).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{})) 1513 Expect(k8sClient.Create(ctx, pod3.DeepCopy())).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{})) 1514 cRs4 := rs4.DeepCopy() 1515 Expect(k8sClient.Create(ctx, cRs4)).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{})) 1516 cPod4 := pod4.DeepCopy() 1517 cPod4.SetOwnerReferences([]metav1.OwnerReference{ 1518 { 1519 APIVersion: "apps/v1", 1520 Kind: "ReplicaSet", 1521 Name: cRs4.Name, 1522 UID: cRs4.UID, 1523 }, 1524 }) 1525 Expect(k8sClient.Create(ctx, cPod4)).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{})) 1526 cCronJob1 := cronJob1.DeepCopy() 1527 Expect(k8sClient.Create(ctx, cCronJob1)).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{})) 1528 cJob1 := job1.DeepCopy() 1529 Expect(k8sClient.Create(ctx, cJob1)).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{})) 1530 cJob2 := job2.DeepCopy() 1531 Expect(k8sClient.Create(ctx, cJob2)).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{})) 1532 cPod5 := pod5.DeepCopy() 1533 Expect(k8sClient.Create(ctx, cPod5)).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{})) 1534 }) 1535 1536 AfterEach(func() { 1537 for _, object := range objectList { 1538 Expect(k8sClient.Delete(ctx, object)) 1539 } 1540 }) 1541 1542 It("test fetchObjectWithResourceTreeNode func", func() { 1543 rtn := types.ResourceTreeNode{ 1544 Name: "deploy1", 1545 Namespace: "test-namespace", 1546 APIVersion: "apps/v1", 1547 Kind: "Deployment", 1548 } 1549 u, err := fetchObjectWithResourceTreeNode(ctx, "", k8sClient, rtn) 1550 Expect(err).Should(BeNil()) 1551 Expect(u).ShouldNot(BeNil()) 1552 Expect(u.GetName()).Should(BeEquivalentTo("deploy1")) 1553 }) 1554 1555 It("test list item by rule", func() { 1556 u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(deploy1.DeepCopy()) 1557 Expect(err).Should(BeNil()) 1558 items, err := listItemByRule(ctx, k8sClient, ResourceType{APIVersion: "apps/v1", Kind: "ReplicaSet"}, unstructured.Unstructured{Object: u}, 1559 defaultWorkloadLabelListOption, nil, true) 1560 Expect(err).Should(BeNil()) 1561 Expect(len(items)).Should(BeEquivalentTo(2)) 1562 1563 u2, err := runtime.DefaultUnstructuredConverter.ToUnstructured(deploy2.DeepCopy()) 1564 Expect(err).Should(BeNil()) 1565 items2, err := listItemByRule(ctx, k8sClient, ResourceType{APIVersion: "apps/v1", Kind: "ReplicaSet"}, unstructured.Unstructured{Object: u2}, 1566 nil, defaultWorkloadLabelListOption, true) 1567 Expect(len(items2)).Should(BeEquivalentTo(1)) 1568 1569 // test use ownerReference UId to filter 1570 u3 := unstructured.Unstructured{} 1571 u3.SetNamespace(rs4.Namespace) 1572 u3.SetName(rs4.Name) 1573 u3.SetAPIVersion("apps/v1") 1574 u3.SetKind("ReplicaSet") 1575 Expect(k8sClient.Get(ctx, types2.NamespacedName{Namespace: u3.GetNamespace(), Name: u3.GetName()}, &u3)) 1576 Expect(err).Should(BeNil()) 1577 items3, err := listItemByRule(ctx, k8sClient, ResourceType{APIVersion: "v1", Kind: "Pod"}, u3, 1578 nil, nil, true) 1579 Expect(err).Should(BeNil()) 1580 Expect(len(items3)).Should(BeEquivalentTo(1)) 1581 1582 u4 := unstructured.Unstructured{} 1583 u4.SetNamespace(cronJob1.Namespace) 1584 u4.SetName(cronJob1.Name) 1585 u4.SetAPIVersion("batch/v1") 1586 u4.SetKind("CronJob") 1587 Expect(k8sClient.Get(ctx, types2.NamespacedName{Namespace: u4.GetNamespace(), Name: u4.GetName()}, &u4)) 1588 Expect(err).Should(BeNil()) 1589 item4, err := listItemByRule(ctx, k8sClient, ResourceType{APIVersion: "batch/v1", Kind: "Job"}, u4, 1590 cronJobLabelListOption, nil, true) 1591 Expect(err).Should(BeNil()) 1592 Expect(len(item4)).Should(BeEquivalentTo(1)) 1593 }) 1594 1595 It("iterate resource", func() { 1596 tn, err := iterateListSubResources(ctx, "", k8sClient, types.ResourceTreeNode{ 1597 Cluster: "", 1598 Namespace: "test-namespace", 1599 Name: "deploy1", 1600 APIVersion: "apps/v1", 1601 Kind: "Deployment", 1602 }, 1, func(node types.ResourceTreeNode) bool { 1603 return true 1604 }) 1605 Expect(err).Should(BeNil()) 1606 Expect(len(tn)).Should(BeEquivalentTo(2)) 1607 Expect(len(tn[0].LeafNodes)).Should(BeEquivalentTo(1)) 1608 Expect(len(tn[1].LeafNodes)).Should(BeEquivalentTo(1)) 1609 1610 tn, err = iterateListSubResources(ctx, "", k8sClient, types.ResourceTreeNode{ 1611 Cluster: "", 1612 Namespace: "test-namespace", 1613 Name: "cronjob1", 1614 APIVersion: "batch/v1", 1615 Kind: "CronJob", 1616 }, 1, func(node types.ResourceTreeNode) bool { 1617 return true 1618 }) 1619 Expect(err).Should(BeNil()) 1620 Expect(len(tn)).Should(BeEquivalentTo(1)) 1621 1622 tn, err = iterateListSubResources(ctx, "", k8sClient, types.ResourceTreeNode{ 1623 Cluster: "", 1624 Namespace: "test-namespace", 1625 Name: "job2", 1626 APIVersion: "batch/v1", 1627 Kind: "Job", 1628 }, 1, func(node types.ResourceTreeNode) bool { 1629 return true 1630 }) 1631 Expect(err).Should(BeNil()) 1632 Expect(len(tn)).Should(BeEquivalentTo(1)) 1633 }) 1634 1635 It("test provider handler func", func() { 1636 app := v1beta1.Application{ 1637 ObjectMeta: metav1.ObjectMeta{ 1638 Name: "app", 1639 Namespace: "test-namespace", 1640 }, 1641 Spec: v1beta1.ApplicationSpec{ 1642 Components: []common.ApplicationComponent{}, 1643 }, 1644 } 1645 1646 rt := v1beta1.ResourceTracker{ 1647 ObjectMeta: metav1.ObjectMeta{ 1648 Name: "app-test-v1-namespace", 1649 Labels: map[string]string{ 1650 oam.LabelAppName: "app", 1651 oam.LabelAppNamespace: "test-namespace", 1652 }, 1653 Annotations: map[string]string{ 1654 oam.AnnotationPublishVersion: "v1", 1655 }, 1656 }, 1657 Spec: v1beta1.ResourceTrackerSpec{ 1658 Type: v1beta1.ResourceTrackerTypeVersioned, 1659 ManagedResources: []v1beta1.ManagedResource{ 1660 { 1661 ClusterObjectReference: common.ClusterObjectReference{ 1662 Cluster: "", 1663 ObjectReference: v1.ObjectReference{ 1664 APIVersion: "apps/v1", 1665 Kind: "Deployment", 1666 Namespace: "test-namespace", 1667 Name: "deploy1", 1668 }, 1669 }, 1670 OAMObjectReference: common.OAMObjectReference{ 1671 Component: "deploy1", 1672 }, 1673 }, 1674 { 1675 ClusterObjectReference: common.ClusterObjectReference{ 1676 Cluster: "", 1677 ObjectReference: v1.ObjectReference{ 1678 APIVersion: "apps/v1", 1679 Kind: "Deployment", 1680 Namespace: "test-namespace", 1681 Name: "deploy2", 1682 }, 1683 }, 1684 OAMObjectReference: common.OAMObjectReference{ 1685 Component: "deploy2", 1686 }, 1687 }, 1688 }, 1689 }, 1690 } 1691 1692 Expect(k8sClient.Create(ctx, &app)).Should(BeNil()) 1693 Expect(k8sClient.Create(ctx, &rt)).Should(BeNil()) 1694 1695 prd := provider{cli: k8sClient} 1696 opt := `app: { 1697 name: "app" 1698 namespace: "test-namespace" 1699 withTree: true 1700 }` 1701 v, err := value.NewValue(opt, nil, "") 1702 Expect(err).Should(BeNil()) 1703 logCtx := monitorContext.NewTraceContext(ctx, "") 1704 Expect(prd.ListAppliedResources(logCtx, nil, v, nil)).Should(BeNil()) 1705 type Res struct { 1706 List []types.AppliedResource `json:"list"` 1707 } 1708 var res Res 1709 err = v.UnmarshalTo(&res) 1710 Expect(err).Should(BeNil()) 1711 Expect(len(res.List)).Should(Equal(2)) 1712 }) 1713 1714 It("Test not exist api don't break whole process", func() { 1715 notExistRuleStr := ` 1716 - parentResourceType: 1717 group: apps 1718 kind: Deployment 1719 childrenResourceType: 1720 - apiVersion: v2 1721 kind: Pod 1722 ` 1723 notExistParentResourceStr := ` 1724 - parentResourceType: 1725 group: badgroup 1726 kind: Deployment 1727 childrenResourceType: 1728 - apiVersion: v2 1729 kind: Pod 1730 ` 1731 Expect(k8sClient.Create(ctx, &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "vela-system"}})).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{})) 1732 badRuleConfigMap := v1.ConfigMap{TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "ConfigMap"}, 1733 ObjectMeta: metav1.ObjectMeta{Namespace: types3.DefaultKubeVelaNS, Name: "bad-rule", Labels: map[string]string{oam.LabelResourceRules: "true"}}, 1734 Data: map[string]string{relationshipKey: notExistRuleStr}, 1735 } 1736 Expect(k8sClient.Create(ctx, &badRuleConfigMap)).Should(BeNil()) 1737 1738 // clear after test 1739 objectList = append(objectList, &badRuleConfigMap) 1740 1741 notExistParentConfigMap := v1.ConfigMap{TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "ConfigMap"}, 1742 ObjectMeta: metav1.ObjectMeta{Namespace: types3.DefaultKubeVelaNS, Name: "not-exist-parent", Labels: map[string]string{oam.LabelResourceRules: "true"}}, 1743 Data: map[string]string{relationshipKey: notExistParentResourceStr}, 1744 } 1745 Expect(k8sClient.Create(ctx, ¬ExistParentConfigMap)).Should(BeNil()) 1746 1747 // clear after test 1748 objectList = append(objectList, &badRuleConfigMap) 1749 1750 prd := provider{cli: k8sClient} 1751 opt := `app: { 1752 name: "app" 1753 namespace: "test-namespace" 1754 withTree: true 1755 }` 1756 v, err := value.NewValue(opt, nil, "") 1757 1758 Expect(err).Should(BeNil()) 1759 logCtx := monitorContext.NewTraceContext(ctx, "") 1760 Expect(prd.ListAppliedResources(logCtx, nil, v, nil)).Should(BeNil()) 1761 type Res struct { 1762 List []types.AppliedResource `json:"list"` 1763 } 1764 var res Res 1765 err = v.UnmarshalTo(&res) 1766 Expect(err).Should(BeNil()) 1767 Expect(len(res.List)).Should(Equal(2)) 1768 }) 1769 }) 1770 1771 var _ = Describe("test merge globalRules", func() { 1772 cloneSetStr := ` 1773 - parentResourceType: 1774 group: apps.kruise.io 1775 kind: CloneSet 1776 childrenResourceType: 1777 - apiVersion: v1 1778 kind: Pod 1779 defaultLabelSelector: true 1780 - apiVersion: apps/v1 1781 kind: ControllerRevision 1782 ` 1783 clickhouseJsonStr := ` 1784 [ 1785 { 1786 "parentResourceType": { 1787 "group": "clickhouse.altinity.com", 1788 "kind": "ClickHouseInstallation" 1789 }, 1790 "childrenResourceType": [ 1791 { 1792 "apiVersion": "apps/v1", 1793 "kind": "StatefulSet" 1794 }, 1795 { 1796 "apiVersion": "v1", 1797 "kind": "Service" 1798 } 1799 ] 1800 } 1801 ] 1802 ` 1803 daemonSetStr := ` 1804 - parentResourceType: 1805 group: apps 1806 kind: DaemonSet 1807 childrenResourceType: 1808 - apiVersion: apps/v1 1809 kind: ControllerRevision 1810 ` 1811 stsStr := ` 1812 - parentResourceType: 1813 group: apps 1814 kind: StatefulSet 1815 childrenResourceType: 1816 - apiVersion: v1 1817 kind: Pod 1818 - apiVersion: apps/v1 1819 kind: ControllerRevision 1820 ` 1821 missConfigedStr := ` 1822 - parentResourceType: 1823 group: apps 1824 kind: StatefulSet 1825 childrenResourceType: 1826 - apiVersion: v1 1827 kind: Pod 1828 - apiVersion: apps/v1 1829 kind: ControllerRevision 1830 ` 1831 1832 It("test merge rules", func() { 1833 Expect(k8sClient.Create(ctx, &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "vela-system"}})).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{})) 1834 cloneSetConfigMap := v1.ConfigMap{TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "ConfigMap"}, 1835 ObjectMeta: metav1.ObjectMeta{Namespace: types3.DefaultKubeVelaNS, Name: "cloneset", Labels: map[string]string{ 1836 oam.LabelResourceRules: "true", 1837 oam.LabelResourceRuleFormat: oam.ResourceTopologyFormatYAML, 1838 }}, 1839 Data: map[string]string{relationshipKey: cloneSetStr}, 1840 } 1841 Expect(k8sClient.Create(ctx, &cloneSetConfigMap)).Should(BeNil()) 1842 1843 daemonSetConfigMap := v1.ConfigMap{TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "ConfigMap"}, 1844 ObjectMeta: metav1.ObjectMeta{Namespace: types3.DefaultKubeVelaNS, Name: "daemonset", Labels: map[string]string{ 1845 oam.LabelResourceRules: "true", 1846 oam.LabelResourceRuleFormat: oam.ResourceTopologyFormatYAML, 1847 }}, 1848 Data: map[string]string{relationshipKey: daemonSetStr}, 1849 } 1850 Expect(k8sClient.Create(ctx, &daemonSetConfigMap)).Should(BeNil()) 1851 1852 stsConfigMap := v1.ConfigMap{TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "ConfigMap"}, 1853 ObjectMeta: metav1.ObjectMeta{Namespace: types3.DefaultKubeVelaNS, Name: "sts", Labels: map[string]string{ 1854 oam.LabelResourceRules: "true", 1855 oam.LabelResourceRuleFormat: oam.ResourceTopologyFormatYAML, 1856 }}, 1857 Data: map[string]string{relationshipKey: stsStr}, 1858 } 1859 Expect(k8sClient.Create(ctx, &stsConfigMap)).Should(BeNil()) 1860 1861 missConfigedCm := v1.ConfigMap{TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "ConfigMap"}, 1862 ObjectMeta: metav1.ObjectMeta{Namespace: types3.DefaultKubeVelaNS, Name: "miss-configed", Labels: map[string]string{oam.LabelResourceRules: "true"}}, 1863 Data: map[string]string{relationshipKey: missConfigedStr}, 1864 } 1865 Expect(k8sClient.Create(ctx, &missConfigedCm)).Should(BeNil()) 1866 1867 clickhouseJsonCm := v1.ConfigMap{TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "ConfigMap"}, 1868 ObjectMeta: metav1.ObjectMeta{Namespace: types3.DefaultKubeVelaNS, Name: "clickhouse", Labels: map[string]string{ 1869 oam.LabelResourceRules: "true", 1870 oam.LabelResourceRuleFormat: oam.ResourceTopologyFormatJSON, 1871 }}, 1872 Data: map[string]string{relationshipKey: clickhouseJsonStr}, 1873 } 1874 Expect(k8sClient.Create(ctx, &clickhouseJsonCm)).Should(BeNil()) 1875 1876 Expect(mergeCustomRules(ctx, k8sClient)).Should(BeNil()) 1877 childrenResources, ok := globalRule.GetRule(GroupResourceType{Group: "apps.kruise.io", Kind: "CloneSet"}) 1878 Expect(ok).Should(BeTrue()) 1879 Expect(childrenResources.DefaultGenListOptionFunc).Should(BeNil()) 1880 Expect(len(*childrenResources.SubResources)).Should(BeEquivalentTo(2)) 1881 1882 crPod := childrenResources.SubResources.Get(ResourceType{APIVersion: "v1", Kind: "Pod"}) 1883 Expect(crPod).ShouldNot(BeNil()) 1884 Expect(crPod.listOptions).ShouldNot(BeNil()) 1885 1886 dsChildrenResources, ok := globalRule.GetRule(GroupResourceType{Group: "apps", Kind: "DaemonSet"}) 1887 Expect(ok).Should(BeTrue()) 1888 Expect(dsChildrenResources.DefaultGenListOptionFunc).Should(BeNil()) 1889 Expect(len(*dsChildrenResources.SubResources)).Should(BeEquivalentTo(2)) 1890 1891 // with the error version 1892 crPod2 := dsChildrenResources.SubResources.Get(ResourceType{APIVersion: "v1", Kind: "ControllerRevision"}) 1893 Expect(crPod2).Should(BeNil()) 1894 1895 crPod3 := dsChildrenResources.SubResources.Get(ResourceType{APIVersion: "v1", Kind: "Pod"}) 1896 Expect(crPod3).ShouldNot(BeNil()) 1897 Expect(crPod3.listOptions).ShouldNot(BeNil()) 1898 1899 cr := dsChildrenResources.SubResources.Get(ResourceType{APIVersion: "apps/v1", Kind: "ControllerRevision"}) 1900 Expect(cr).ShouldNot(BeNil()) 1901 Expect(cr.listOptions).Should(BeNil()) 1902 1903 stsChildrenResources, ok := globalRule.GetRule(GroupResourceType{Group: "apps", Kind: "StatefulSet"}) 1904 Expect(ok).Should(BeTrue()) 1905 Expect(stsChildrenResources.DefaultGenListOptionFunc).Should(BeNil()) 1906 Expect(len(*stsChildrenResources.SubResources)).Should(BeEquivalentTo(2)) 1907 revisionCR := stsChildrenResources.SubResources.Get(ResourceType{APIVersion: "apps/v1", Kind: "ControllerRevision"}) 1908 Expect(revisionCR).ShouldNot(BeNil()) 1909 Expect(revisionCR.listOptions).Should(BeNil()) 1910 1911 chChildrenResources, ok := globalRule.GetRule(GroupResourceType{Group: "clickhouse.altinity.com", Kind: "ClickHouseInstallation"}) 1912 Expect(ok).Should(BeTrue()) 1913 Expect(chChildrenResources.DefaultGenListOptionFunc).Should(BeNil()) 1914 Expect(len(*chChildrenResources.SubResources)).Should(BeEquivalentTo(2)) 1915 1916 chSts := chChildrenResources.SubResources.Get(ResourceType{APIVersion: "apps/v1", Kind: "StatefulSet"}) 1917 Expect(chSts).ShouldNot(BeNil()) 1918 Expect(chSts.listOptions).Should(BeNil()) 1919 1920 chSvc := chChildrenResources.SubResources.Get(ResourceType{APIVersion: "v1", Kind: "Service"}) 1921 Expect(chSvc).ShouldNot(BeNil()) 1922 Expect(chSvc.listOptions).Should(BeNil()) 1923 1924 // clear data 1925 Expect(k8sClient.Delete(context.TODO(), &missConfigedCm)).Should(BeNil()) 1926 Expect(k8sClient.Delete(context.TODO(), &stsConfigMap)).Should(BeNil()) 1927 Expect(k8sClient.Delete(context.TODO(), &daemonSetConfigMap)).Should(BeNil()) 1928 Expect(k8sClient.Delete(context.TODO(), &cloneSetConfigMap)).Should(BeNil()) 1929 }) 1930 })