mirror of https://github.com/kubevela/kubevela.git
				
				
				
			
		
			
				
	
	
		
			1530 lines
		
	
	
		
			41 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			1530 lines
		
	
	
		
			41 KiB
		
	
	
	
		
			Go
		
	
	
	
| /*
 | |
| Copyright 2021 The KubeVela Authors.
 | |
| 
 | |
| Licensed under the Apache License, Version 2.0 (the "License");
 | |
| you may not use this file except in compliance with the License.
 | |
| You may obtain a copy of the License at
 | |
| 
 | |
|     http://www.apache.org/licenses/LICENSE-2.0
 | |
| 
 | |
| Unless required by applicable law or agreed to in writing, software
 | |
| distributed under the License is distributed on an "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| See the License for the specific language governing permissions and
 | |
| limitations under the License.
 | |
| */
 | |
| 
 | |
| package query
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"testing"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
 | |
| 	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
 | |
| 	types3 "github.com/oam-dev/kubevela/apis/types"
 | |
| 	"github.com/oam-dev/kubevela/pkg/cue/model/value"
 | |
| 	"github.com/oam-dev/kubevela/pkg/oam"
 | |
| 	"github.com/oam-dev/kubevela/pkg/oam/util"
 | |
| 	"github.com/oam-dev/kubevela/pkg/velaql/providers/query/types"
 | |
| 
 | |
| 	. "github.com/onsi/ginkgo"
 | |
| 	. "github.com/onsi/gomega"
 | |
| 
 | |
| 	v12 "k8s.io/api/apps/v1"
 | |
| 	v1 "k8s.io/api/core/v1"
 | |
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | |
| 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 | |
| 	"k8s.io/apimachinery/pkg/runtime"
 | |
| 	types2 "k8s.io/apimachinery/pkg/types"
 | |
| 	"k8s.io/utils/pointer"
 | |
| 
 | |
| 	"sigs.k8s.io/controller-runtime/pkg/client"
 | |
| 
 | |
| 	"github.com/fluxcd/helm-controller/api/v2beta1"
 | |
| 	"github.com/fluxcd/source-controller/api/v1beta2"
 | |
| 	"github.com/stretchr/testify/assert"
 | |
| )
 | |
| 
 | |
| func TestPodStatus(t *testing.T) {
 | |
| 	succeedPod := v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "Pod"}, Status: v1.PodStatus{
 | |
| 		Phase: v1.PodSucceeded,
 | |
| 	}}
 | |
| 
 | |
| 	runningReadyPod := v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "Pod"},
 | |
| 		Spec: v1.PodSpec{
 | |
| 			RestartPolicy: v1.RestartPolicyAlways,
 | |
| 		},
 | |
| 		Status: v1.PodStatus{
 | |
| 			Conditions: []v1.PodCondition{
 | |
| 				{
 | |
| 					Type:   v1.PodReady,
 | |
| 					Status: v1.ConditionTrue,
 | |
| 				},
 | |
| 			},
 | |
| 			Phase: v1.PodRunning,
 | |
| 		}}
 | |
| 
 | |
| 	runningUnHealthyPod := v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "Pod"},
 | |
| 		Spec: v1.PodSpec{
 | |
| 			RestartPolicy: v1.RestartPolicyAlways,
 | |
| 		},
 | |
| 		Status: v1.PodStatus{
 | |
| 			ContainerStatuses: []v1.ContainerStatus{
 | |
| 				{
 | |
| 					LastTerminationState: v1.ContainerState{
 | |
| 						Terminated: &v1.ContainerStateTerminated{
 | |
| 							ExitCode: 127,
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			Phase: v1.PodRunning,
 | |
| 		}}
 | |
| 
 | |
| 	runningProgressingPod := v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "Pod"},
 | |
| 		Spec: v1.PodSpec{
 | |
| 			RestartPolicy: v1.RestartPolicyAlways,
 | |
| 		},
 | |
| 		Status: v1.PodStatus{
 | |
| 			Phase:  v1.PodRunning,
 | |
| 			Reason: "ContainerCreating",
 | |
| 		}}
 | |
| 
 | |
| 	restartNeverPod := v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "Pod"},
 | |
| 		Spec: v1.PodSpec{
 | |
| 			RestartPolicy: v1.RestartPolicyNever,
 | |
| 		},
 | |
| 		Status: v1.PodStatus{
 | |
| 			Phase: v1.PodRunning,
 | |
| 		}}
 | |
| 
 | |
| 	pendingPod := v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "Pod"},
 | |
| 		Spec: v1.PodSpec{
 | |
| 			RestartPolicy: v1.RestartPolicyNever,
 | |
| 		}, Status: v1.PodStatus{Phase: v1.PodPending},
 | |
| 	}
 | |
| 
 | |
| 	failedWithMessagePod := v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "Pod"},
 | |
| 		Status: v1.PodStatus{Phase: v1.PodFailed, Message: "some message"},
 | |
| 	}
 | |
| 
 | |
| 	failedWithOOMKillPod := v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "Pod"},
 | |
| 		Status: v1.PodStatus{Phase: v1.PodFailed, ContainerStatuses: []v1.ContainerStatus{
 | |
| 			{
 | |
| 				State: v1.ContainerState{
 | |
| 					Terminated: &v1.ContainerStateTerminated{
 | |
| 						Reason: "OOMKilled",
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		}},
 | |
| 	}
 | |
| 
 | |
| 	failedWithExistCodePod := v1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "Pod"},
 | |
| 		Status: v1.PodStatus{Phase: v1.PodFailed, ContainerStatuses: []v1.ContainerStatus{
 | |
| 			{
 | |
| 				Name: "nginx",
 | |
| 				State: v1.ContainerState{
 | |
| 					Terminated: &v1.ContainerStateTerminated{
 | |
| 						ExitCode: 189,
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		}},
 | |
| 	}
 | |
| 
 | |
| 	testCases := map[string]struct {
 | |
| 		intput v1.Pod
 | |
| 		result types.HealthStatus
 | |
| 	}{
 | |
| 		"succeedPod": {
 | |
| 			intput: succeedPod,
 | |
| 			result: types.HealthStatus{Status: types.HealthStatusHealthy},
 | |
| 		},
 | |
| 		"runningReadyPod": {
 | |
| 			intput: runningReadyPod,
 | |
| 			result: types.HealthStatus{Status: types.HealthStatusHealthy, Reason: "all containers are ready"},
 | |
| 		},
 | |
| 		"runningUnHealthyPod": {
 | |
| 			intput: runningUnHealthyPod,
 | |
| 			result: types.HealthStatus{Status: types.HealthStatusUnHealthy},
 | |
| 		},
 | |
| 		"runningProgressingPod": {
 | |
| 			intput: runningProgressingPod,
 | |
| 			result: types.HealthStatus{Status: types.HealthStatusProgressing, Reason: "ContainerCreating"},
 | |
| 		},
 | |
| 		"restartNeverPod": {
 | |
| 			intput: restartNeverPod,
 | |
| 			result: types.HealthStatus{Status: types.HealthStatusProgressing},
 | |
| 		},
 | |
| 		"pendingPod": {
 | |
| 			intput: pendingPod,
 | |
| 			result: types.HealthStatus{Status: types.HealthStatusProgressing},
 | |
| 		},
 | |
| 		"failedWithMessagePod": {
 | |
| 			intput: failedWithMessagePod,
 | |
| 			result: types.HealthStatus{Status: types.HealthStatusUnHealthy, Message: "some message"},
 | |
| 		},
 | |
| 		"failedWithOOMKillPod": {
 | |
| 			intput: failedWithOOMKillPod,
 | |
| 			result: types.HealthStatus{Status: types.HealthStatusUnHealthy, Message: "OOMKilled"},
 | |
| 		},
 | |
| 		"failedWithExistCodePod": {
 | |
| 			intput: failedWithExistCodePod,
 | |
| 			result: types.HealthStatus{Status: types.HealthStatusUnHealthy, Message: "container \"nginx\" failed with exit code 189"},
 | |
| 		},
 | |
| 	}
 | |
| 	for _, s := range testCases {
 | |
| 		pod := s.intput.DeepCopy()
 | |
| 		p, err := runtime.DefaultUnstructuredConverter.ToUnstructured(pod)
 | |
| 		assert.NoError(t, err)
 | |
| 		res, err := checkPodStatus(unstructured.Unstructured{Object: p})
 | |
| 		assert.NoError(t, err)
 | |
| 		assert.NotNil(t, res)
 | |
| 		assert.Equal(t, *res, s.result)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestService2EndpointOption(t *testing.T) {
 | |
| 	labels := map[string]string{
 | |
| 		"service-name": "test",
 | |
| 		"uid":          "test-uid",
 | |
| 	}
 | |
| 	u := unstructured.Unstructured{}
 | |
| 	u.SetAPIVersion("v1")
 | |
| 	u.SetKind("Service")
 | |
| 	u.SetLabels(labels)
 | |
| 	l, err := service2EndpointListOption(u)
 | |
| 	assert.NoError(t, err)
 | |
| 	assert.Equal(t, "service-name=test,uid=test-uid", l.LabelSelector.String())
 | |
| }
 | |
| 
 | |
| func TestServiceStatus(t *testing.T) {
 | |
| 	lbHealthSvc := v1.Service{Spec: v1.ServiceSpec{Type: v1.ServiceTypeLoadBalancer}, Status: v1.ServiceStatus{
 | |
| 		LoadBalancer: v1.LoadBalancerStatus{
 | |
| 			Ingress: []v1.LoadBalancerIngress{
 | |
| 				{
 | |
| 					IP: "198.1.1.1",
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}}
 | |
| 	lbProgressingSvc := v1.Service{Spec: v1.ServiceSpec{Type: v1.ServiceTypeLoadBalancer}, Status: v1.ServiceStatus{}}
 | |
| 	testCases := map[string]struct {
 | |
| 		input v1.Service
 | |
| 		res   types.HealthStatus
 | |
| 	}{
 | |
| 		"health": {
 | |
| 			input: lbHealthSvc,
 | |
| 			res:   types.HealthStatus{Status: types.HealthStatusHealthy},
 | |
| 		},
 | |
| 		"progressing": {
 | |
| 			input: lbProgressingSvc,
 | |
| 			res:   types.HealthStatus{Status: types.HealthStatusProgressing},
 | |
| 		},
 | |
| 	}
 | |
| 	for _, s := range testCases {
 | |
| 		svc := s.input.DeepCopy()
 | |
| 		u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&svc)
 | |
| 		assert.NoError(t, err)
 | |
| 		res, err := checkServiceStatus(unstructured.Unstructured{Object: u})
 | |
| 		assert.NoError(t, err)
 | |
| 		assert.NotNil(t, res)
 | |
| 		assert.Equal(t, s.res, *res)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestPVCStatus(t *testing.T) {
 | |
| 	heathyPVC := v1.PersistentVolumeClaim{Status: v1.PersistentVolumeClaimStatus{Phase: v1.ClaimBound}}
 | |
| 	unHeathyPVC := v1.PersistentVolumeClaim{Status: v1.PersistentVolumeClaimStatus{Phase: v1.ClaimLost}}
 | |
| 	progressingPVC := v1.PersistentVolumeClaim{Status: v1.PersistentVolumeClaimStatus{Phase: v1.ClaimPending}}
 | |
| 	heathyUnkown := v1.PersistentVolumeClaim{Status: v1.PersistentVolumeClaimStatus{}}
 | |
| 	testCases := map[string]struct {
 | |
| 		input v1.PersistentVolumeClaim
 | |
| 		res   types.HealthStatus
 | |
| 	}{
 | |
| 		"health": {
 | |
| 			input: heathyPVC,
 | |
| 			res:   types.HealthStatus{Status: types.HealthStatusHealthy},
 | |
| 		},
 | |
| 		"progressing": {
 | |
| 			input: progressingPVC,
 | |
| 			res:   types.HealthStatus{Status: types.HealthStatusProgressing},
 | |
| 		},
 | |
| 		"unHealthy": {
 | |
| 			input: unHeathyPVC,
 | |
| 			res:   types.HealthStatus{Status: types.HealthStatusUnHealthy},
 | |
| 		},
 | |
| 		"unknown": {
 | |
| 			input: heathyUnkown,
 | |
| 			res:   types.HealthStatus{Status: types.HealthStatusUnKnown},
 | |
| 		},
 | |
| 	}
 | |
| 	for _, s := range testCases {
 | |
| 		pvc := s.input.DeepCopy()
 | |
| 		u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&pvc)
 | |
| 		assert.NoError(t, err)
 | |
| 		res, err := checkPVCHealthStatus(unstructured.Unstructured{Object: u})
 | |
| 		assert.NoError(t, err)
 | |
| 		assert.NotNil(t, res)
 | |
| 		assert.Equal(t, s.res, *res)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestGetReplicaSetCondition(t *testing.T) {
 | |
| 	rs := v12.ReplicaSet{Status: v12.ReplicaSetStatus{
 | |
| 		Conditions: []v12.ReplicaSetCondition{{
 | |
| 			Type: v12.ReplicaSetReplicaFailure,
 | |
| 		}},
 | |
| 	}}
 | |
| 	c := getAppsv1ReplicaSetCondition(rs.Status, v12.ReplicaSetReplicaFailure)
 | |
| 	assert.NotNil(t, c)
 | |
| }
 | |
| 
 | |
| func TestReplicaSetStatus(t *testing.T) {
 | |
| 	unhealthyReplicaSet := v12.ReplicaSet{
 | |
| 		ObjectMeta: metav1.ObjectMeta{
 | |
| 			Generation: 2,
 | |
| 		},
 | |
| 		Status: v12.ReplicaSetStatus{ObservedGeneration: 2,
 | |
| 			Conditions: []v12.ReplicaSetCondition{{
 | |
| 				Type:   v12.ReplicaSetReplicaFailure,
 | |
| 				Status: v1.ConditionTrue,
 | |
| 			}}},
 | |
| 	}
 | |
| 	progressingPodReplicaSet := v12.ReplicaSet{
 | |
| 		ObjectMeta: metav1.ObjectMeta{
 | |
| 			Generation: 2,
 | |
| 		},
 | |
| 		Spec: v12.ReplicaSetSpec{Replicas: pointer.Int32(3)},
 | |
| 		Status: v12.ReplicaSetStatus{
 | |
| 			ObservedGeneration: 2,
 | |
| 			ReadyReplicas:      2,
 | |
| 			AvailableReplicas:  2,
 | |
| 		},
 | |
| 	}
 | |
| 	progressingRollingReplicaSet := v12.ReplicaSet{
 | |
| 		ObjectMeta: metav1.ObjectMeta{
 | |
| 			Generation: 2,
 | |
| 		},
 | |
| 		Spec: v12.ReplicaSetSpec{Replicas: pointer.Int32(3)},
 | |
| 		Status: v12.ReplicaSetStatus{
 | |
| 			ObservedGeneration: 1,
 | |
| 		},
 | |
| 	}
 | |
| 	testCases := map[string]struct {
 | |
| 		input v12.ReplicaSet
 | |
| 		res   types.HealthStatus
 | |
| 	}{
 | |
| 		"unHealth": {
 | |
| 			input: unhealthyReplicaSet,
 | |
| 			res:   types.HealthStatus{Status: types.HealthStatusUnHealthy},
 | |
| 		},
 | |
| 		"progressing": {
 | |
| 			input: progressingPodReplicaSet,
 | |
| 			res:   types.HealthStatus{Status: types.HealthStatusProgressing, Message: "Waiting for rollout to finish: 2 out of 3 new replicas are available..."},
 | |
| 		},
 | |
| 		"rolling": {
 | |
| 			input: progressingRollingReplicaSet,
 | |
| 			res:   types.HealthStatus{Status: types.HealthStatusProgressing, Message: "Waiting for rollout to finish: observed replica set generation less then desired generation"},
 | |
| 		},
 | |
| 	}
 | |
| 	for d, s := range testCases {
 | |
| 		fmt.Println(d)
 | |
| 		rs := s.input.DeepCopy()
 | |
| 		u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&rs)
 | |
| 		assert.NoError(t, err)
 | |
| 		res, err := checkReplicaSetStatus(unstructured.Unstructured{Object: u})
 | |
| 		assert.NoError(t, err)
 | |
| 		assert.NotNil(t, res)
 | |
| 		assert.Equal(t, s.res, *res)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestHelmResourceStatus(t *testing.T) {
 | |
| 	tm := metav1.TypeMeta{APIVersion: "helm.toolkit.fluxcd.io/v2beta1", Kind: "HelmRelease"}
 | |
| 	healthHr := v2beta1.HelmRelease{TypeMeta: tm, Status: v2beta1.HelmReleaseStatus{Conditions: []metav1.Condition{
 | |
| 		{
 | |
| 			Type:   "Ready",
 | |
| 			Status: metav1.ConditionTrue,
 | |
| 		},
 | |
| 	}}}
 | |
| 	unHealthyHr := v2beta1.HelmRelease{TypeMeta: tm, Status: v2beta1.HelmReleaseStatus{Conditions: []metav1.Condition{
 | |
| 		{
 | |
| 			Type:    "Ready",
 | |
| 			Status:  metav1.ConditionFalse,
 | |
| 			Message: "some reason",
 | |
| 		},
 | |
| 	}}}
 | |
| 	unKnowHealthyHr := v2beta1.HelmRelease{TypeMeta: tm, Status: v2beta1.HelmReleaseStatus{Conditions: []metav1.Condition{
 | |
| 		{
 | |
| 			Type:   "OtherType",
 | |
| 			Status: metav1.ConditionFalse,
 | |
| 		},
 | |
| 	}}}
 | |
| 	testCases := map[string]struct {
 | |
| 		hr  v2beta1.HelmRelease
 | |
| 		res *types.HealthStatus
 | |
| 	}{
 | |
| 		"healthHr": {
 | |
| 			hr:  healthHr,
 | |
| 			res: &types.HealthStatus{Status: types.HealthStatusHealthy},
 | |
| 		},
 | |
| 		"unHealthyHr": {
 | |
| 			hr:  unHealthyHr,
 | |
| 			res: &types.HealthStatus{Status: types.HealthStatusUnHealthy, Message: "some reason"},
 | |
| 		},
 | |
| 		"unKnowHealthyHr": {
 | |
| 			hr:  unKnowHealthyHr,
 | |
| 			res: &types.HealthStatus{Status: types.HealthStatusUnKnown},
 | |
| 		},
 | |
| 	}
 | |
| 	for _, s := range testCases {
 | |
| 		obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(s.hr.DeepCopy())
 | |
| 		assert.NoError(t, err)
 | |
| 		res, err := checkResourceStatus(unstructured.Unstructured{Object: obj})
 | |
| 		assert.NoError(t, err)
 | |
| 		assert.Equal(t, res, s.res)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestHelmRepoResourceStatus(t *testing.T) {
 | |
| 	tm := metav1.TypeMeta{APIVersion: "source.toolkit.fluxcd.io/v1beta2", Kind: "HelmRepository"}
 | |
| 	healthHr := v1beta2.HelmRepository{TypeMeta: tm, Status: v1beta2.HelmRepositoryStatus{Conditions: []metav1.Condition{
 | |
| 		{
 | |
| 			Type:   "Ready",
 | |
| 			Status: metav1.ConditionTrue,
 | |
| 		},
 | |
| 	}}}
 | |
| 	unHealthyHr := v1beta2.HelmRepository{TypeMeta: tm, Status: v1beta2.HelmRepositoryStatus{Conditions: []metav1.Condition{
 | |
| 		{
 | |
| 			Type:    "Ready",
 | |
| 			Status:  metav1.ConditionFalse,
 | |
| 			Message: "some reason",
 | |
| 		},
 | |
| 	}}}
 | |
| 	unKnowHealthyHr := v1beta2.HelmRepository{TypeMeta: tm, Status: v1beta2.HelmRepositoryStatus{Conditions: []metav1.Condition{
 | |
| 		{
 | |
| 			Type:   "OtherType",
 | |
| 			Status: metav1.ConditionFalse,
 | |
| 		},
 | |
| 	}}}
 | |
| 	testCases := map[string]struct {
 | |
| 		hr  v1beta2.HelmRepository
 | |
| 		res *types.HealthStatus
 | |
| 	}{
 | |
| 		"healthHr": {
 | |
| 			hr:  healthHr,
 | |
| 			res: &types.HealthStatus{Status: types.HealthStatusHealthy},
 | |
| 		},
 | |
| 		"unHealthyHr": {
 | |
| 			hr:  unHealthyHr,
 | |
| 			res: &types.HealthStatus{Status: types.HealthStatusUnHealthy, Message: "some reason"},
 | |
| 		},
 | |
| 		"unKnowHealthyHr": {
 | |
| 			hr:  unKnowHealthyHr,
 | |
| 			res: &types.HealthStatus{Status: types.HealthStatusUnKnown},
 | |
| 		},
 | |
| 	}
 | |
| 	for _, s := range testCases {
 | |
| 		obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(s.hr.DeepCopy())
 | |
| 		assert.NoError(t, err)
 | |
| 		res, err := checkResourceStatus(unstructured.Unstructured{Object: obj})
 | |
| 		assert.NoError(t, err)
 | |
| 		assert.Equal(t, res, s.res)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestGenListOption(t *testing.T) {
 | |
| 	resLabel, err := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{MatchLabels: map[string]string{"testKey": "testVal"}})
 | |
| 	assert.NoError(t, err)
 | |
| 	listOption := client.ListOptions{LabelSelector: resLabel, Namespace: "test"}
 | |
| 
 | |
| 	deploy := v12.Deployment{ObjectMeta: metav1.ObjectMeta{Namespace: "test"}, Spec: v12.DeploymentSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"testKey": "testVal"}}}}
 | |
| 	du, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&deploy)
 | |
| 	assert.NoError(t, err)
 | |
| 	assert.NotNil(t, du)
 | |
| 	dls, err := deploy2RsLabelListOption(unstructured.Unstructured{Object: du})
 | |
| 	assert.NoError(t, err)
 | |
| 	assert.Equal(t, listOption, dls)
 | |
| 
 | |
| 	rs := v12.ReplicaSet{ObjectMeta: metav1.ObjectMeta{Namespace: "test"}, Spec: v12.ReplicaSetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"testKey": "testVal"}}}}
 | |
| 	rsu, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&rs)
 | |
| 	assert.NoError(t, err)
 | |
| 	assert.NotNil(t, du)
 | |
| 	rsls, err := rs2PodLabelListOption(unstructured.Unstructured{Object: rsu})
 | |
| 	assert.NoError(t, err)
 | |
| 	assert.Equal(t, listOption, rsls)
 | |
| 
 | |
| 	sts := v12.StatefulSet{ObjectMeta: metav1.ObjectMeta{Namespace: "test"}, Spec: v12.StatefulSetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"testKey": "testVal"}}}}
 | |
| 	stsu, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&sts)
 | |
| 	assert.NoError(t, err)
 | |
| 	assert.NotNil(t, stsu)
 | |
| 	stsls, err := statefulSet2PodListOption(unstructured.Unstructured{Object: stsu})
 | |
| 	assert.NoError(t, err)
 | |
| 	assert.Equal(t, listOption, stsls)
 | |
| 
 | |
| 	helmRelease := unstructured.Unstructured{}
 | |
| 	helmRelease.SetName("test-helm")
 | |
| 	helmRelease.SetNamespace("test-ns")
 | |
| 	hrll, err := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{MatchLabels: map[string]string{"helm.toolkit.fluxcd.io/name": "test-helm", "helm.toolkit.fluxcd.io/namespace": "test-ns"}})
 | |
| 	assert.NoError(t, err)
 | |
| 
 | |
| 	hrls, err := helmRelease2AnyListOption(helmRelease)
 | |
| 	assert.NoError(t, err)
 | |
| 	assert.Equal(t, hrls, client.ListOptions{LabelSelector: hrll})
 | |
| }
 | |
| 
 | |
| func TestPodAdditionalInfo(t *testing.T) {
 | |
| 	typeMeta := metav1.TypeMeta{APIVersion: "v1", Kind: "Pod"}
 | |
| 
 | |
| 	type testCase struct {
 | |
| 		pod v1.Pod
 | |
| 		res map[string]interface{}
 | |
| 	}
 | |
| 
 | |
| 	case1 := testCase{
 | |
| 		pod: v1.Pod{TypeMeta: typeMeta,
 | |
| 			ObjectMeta: metav1.ObjectMeta{DeletionTimestamp: &metav1.Time{Time: time.Now()}},
 | |
| 			Status: v1.PodStatus{
 | |
| 				InitContainerStatuses: []v1.ContainerStatus{
 | |
| 					{
 | |
| 						State: v1.ContainerState{
 | |
| 							Terminated: &v1.ContainerStateTerminated{
 | |
| 								ExitCode: 0,
 | |
| 							},
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 				Reason: "NodeLost"},
 | |
| 		},
 | |
| 		res: map[string]interface{}{
 | |
| 			"Ready":    "0/0",
 | |
| 			"Status":   "Unknown",
 | |
| 			"Restarts": 0,
 | |
| 			"Age":      "<unknown>",
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	case2 := testCase{
 | |
| 		pod: v1.Pod{TypeMeta: typeMeta,
 | |
| 			Status: v1.PodStatus{
 | |
| 				InitContainerStatuses: []v1.ContainerStatus{
 | |
| 					{
 | |
| 						State: v1.ContainerState{
 | |
| 							Terminated: &v1.ContainerStateTerminated{
 | |
| 								ExitCode: 127,
 | |
| 							},
 | |
| 						},
 | |
| 					},
 | |
| 				}},
 | |
| 		},
 | |
| 		res: map[string]interface{}{
 | |
| 			"Ready":    "0/0",
 | |
| 			"Status":   "Init:ExitCode:127",
 | |
| 			"Restarts": 0,
 | |
| 			"Age":      "<unknown>",
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	case3 := testCase{
 | |
| 		pod: v1.Pod{TypeMeta: typeMeta,
 | |
| 			Status: v1.PodStatus{
 | |
| 				InitContainerStatuses: []v1.ContainerStatus{
 | |
| 					{
 | |
| 						State: v1.ContainerState{
 | |
| 							Terminated: &v1.ContainerStateTerminated{
 | |
| 								ExitCode: 127,
 | |
| 								Signal:   32,
 | |
| 							},
 | |
| 						},
 | |
| 					},
 | |
| 				}},
 | |
| 		},
 | |
| 		res: map[string]interface{}{
 | |
| 			"Ready":    "0/0",
 | |
| 			"Status":   "Init:Signal:32",
 | |
| 			"Restarts": 0,
 | |
| 			"Age":      "<unknown>",
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	case4 := testCase{
 | |
| 		pod: v1.Pod{TypeMeta: typeMeta,
 | |
| 			Status: v1.PodStatus{
 | |
| 				InitContainerStatuses: []v1.ContainerStatus{
 | |
| 					{
 | |
| 						State: v1.ContainerState{
 | |
| 							Terminated: &v1.ContainerStateTerminated{
 | |
| 								Reason:   "OOMKill",
 | |
| 								ExitCode: 127,
 | |
| 							},
 | |
| 						},
 | |
| 					},
 | |
| 				}},
 | |
| 		},
 | |
| 		res: map[string]interface{}{
 | |
| 			"Ready":    "0/0",
 | |
| 			"Status":   "Init:OOMKill",
 | |
| 			"Restarts": 0,
 | |
| 			"Age":      "<unknown>",
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	case5 := testCase{
 | |
| 		pod: v1.Pod{TypeMeta: typeMeta,
 | |
| 			Status: v1.PodStatus{
 | |
| 				InitContainerStatuses: []v1.ContainerStatus{
 | |
| 					{
 | |
| 						State: v1.ContainerState{
 | |
| 							Terminated: &v1.ContainerStateTerminated{
 | |
| 								Reason:   "OOMKill",
 | |
| 								ExitCode: 127,
 | |
| 							},
 | |
| 						},
 | |
| 					},
 | |
| 				}},
 | |
| 		},
 | |
| 		res: map[string]interface{}{
 | |
| 			"Ready":    "0/0",
 | |
| 			"Status":   "Init:OOMKill",
 | |
| 			"Restarts": 0,
 | |
| 			"Age":      "<unknown>",
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	case6 := testCase{
 | |
| 		pod: v1.Pod{TypeMeta: typeMeta,
 | |
| 			Status: v1.PodStatus{
 | |
| 				InitContainerStatuses: []v1.ContainerStatus{
 | |
| 					{
 | |
| 						State: v1.ContainerState{
 | |
| 							Waiting: &v1.ContainerStateWaiting{
 | |
| 								Reason: "ContainerCreating",
 | |
| 							},
 | |
| 						},
 | |
| 					},
 | |
| 				}},
 | |
| 		},
 | |
| 		res: map[string]interface{}{
 | |
| 			"Ready":    "0/0",
 | |
| 			"Status":   "Init:ContainerCreating",
 | |
| 			"Restarts": 0,
 | |
| 			"Age":      "<unknown>",
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	case7 := testCase{
 | |
| 		pod: v1.Pod{TypeMeta: typeMeta,
 | |
| 			Spec: v1.PodSpec{
 | |
| 				InitContainers: []v1.Container{
 | |
| 					{Name: "test"},
 | |
| 				}},
 | |
| 			Status: v1.PodStatus{
 | |
| 				InitContainerStatuses: []v1.ContainerStatus{
 | |
| 					{
 | |
| 						State: v1.ContainerState{
 | |
| 							Waiting: &v1.ContainerStateWaiting{},
 | |
| 						},
 | |
| 					},
 | |
| 				}},
 | |
| 		},
 | |
| 		res: map[string]interface{}{
 | |
| 			"Ready":    "0/0",
 | |
| 			"Status":   "Init:0/1",
 | |
| 			"Restarts": 0,
 | |
| 			"Age":      "<unknown>",
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	case8 := testCase{
 | |
| 		pod: v1.Pod{TypeMeta: typeMeta,
 | |
| 			Status: v1.PodStatus{
 | |
| 				ContainerStatuses: []v1.ContainerStatus{
 | |
| 					{
 | |
| 						State: v1.ContainerState{
 | |
| 							Waiting: &v1.ContainerStateWaiting{
 | |
| 								Reason: "ContainerCreating",
 | |
| 							},
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		res: map[string]interface{}{
 | |
| 			"Ready":    "0/0",
 | |
| 			"Status":   "ContainerCreating",
 | |
| 			"Restarts": 0,
 | |
| 			"Age":      "<unknown>",
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	case9 := testCase{
 | |
| 		pod: v1.Pod{TypeMeta: typeMeta,
 | |
| 			Status: v1.PodStatus{
 | |
| 				ContainerStatuses: []v1.ContainerStatus{
 | |
| 					{
 | |
| 						State: v1.ContainerState{
 | |
| 							Terminated: &v1.ContainerStateTerminated{
 | |
| 								Reason: "OOMKilled",
 | |
| 							},
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		res: map[string]interface{}{
 | |
| 			"Ready":    "0/0",
 | |
| 			"Status":   "OOMKilled",
 | |
| 			"Restarts": 0,
 | |
| 			"Age":      "<unknown>",
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	case10 := testCase{
 | |
| 		pod: v1.Pod{TypeMeta: typeMeta,
 | |
| 			Status: v1.PodStatus{
 | |
| 				ContainerStatuses: []v1.ContainerStatus{
 | |
| 					{
 | |
| 						State: v1.ContainerState{
 | |
| 							Terminated: &v1.ContainerStateTerminated{
 | |
| 								Signal: 2,
 | |
| 							},
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		res: map[string]interface{}{
 | |
| 			"Ready":    "0/0",
 | |
| 			"Status":   "Signal:2",
 | |
| 			"Restarts": 0,
 | |
| 			"Age":      "<unknown>",
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	case11 := testCase{
 | |
| 		pod: v1.Pod{TypeMeta: typeMeta,
 | |
| 			Status: v1.PodStatus{
 | |
| 				ContainerStatuses: []v1.ContainerStatus{
 | |
| 					{
 | |
| 						State: v1.ContainerState{
 | |
| 							Terminated: &v1.ContainerStateTerminated{
 | |
| 								ExitCode: 127,
 | |
| 							},
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		res: map[string]interface{}{
 | |
| 			"Ready":    "0/0",
 | |
| 			"Status":   "ExitCode:127",
 | |
| 			"Restarts": 0,
 | |
| 			"Age":      "<unknown>",
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	case12 := testCase{
 | |
| 		pod: v1.Pod{TypeMeta: typeMeta,
 | |
| 			Spec: v1.PodSpec{
 | |
| 				Containers: []v1.Container{{
 | |
| 					Name: "nginx",
 | |
| 				}},
 | |
| 			},
 | |
| 			Status: v1.PodStatus{
 | |
| 				ContainerStatuses: []v1.ContainerStatus{
 | |
| 					{
 | |
| 						State: v1.ContainerState{
 | |
| 							Running: &v1.ContainerStateRunning{
 | |
| 								StartedAt: metav1.Now(),
 | |
| 							},
 | |
| 						},
 | |
| 						Ready: true,
 | |
| 					},
 | |
| 				},
 | |
| 				Phase: "Running",
 | |
| 			},
 | |
| 		},
 | |
| 		res: map[string]interface{}{
 | |
| 			"Ready":    "1/1",
 | |
| 			"Status":   "Running",
 | |
| 			"Restarts": 0,
 | |
| 			"Age":      "<unknown>",
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	case13 := testCase{
 | |
| 		pod: v1.Pod{TypeMeta: typeMeta,
 | |
| 			Spec: v1.PodSpec{
 | |
| 				Containers: []v1.Container{{
 | |
| 					Name: "nginx",
 | |
| 				}},
 | |
| 			},
 | |
| 			Status: v1.PodStatus{
 | |
| 				ContainerStatuses: []v1.ContainerStatus{
 | |
| 					{
 | |
| 						State: v1.ContainerState{
 | |
| 							Running: &v1.ContainerStateRunning{
 | |
| 								StartedAt: metav1.Now(),
 | |
| 							},
 | |
| 						},
 | |
| 						Ready: true,
 | |
| 					},
 | |
| 				},
 | |
| 				Phase: "Completed",
 | |
| 				Conditions: []v1.PodCondition{
 | |
| 					{
 | |
| 						Type:   v1.PodReady,
 | |
| 						Status: v1.ConditionTrue,
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		res: map[string]interface{}{
 | |
| 			"Ready":    "1/1",
 | |
| 			"Status":   "Running",
 | |
| 			"Restarts": 0,
 | |
| 			"Age":      "<unknown>",
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	case14 := testCase{
 | |
| 		pod: v1.Pod{TypeMeta: typeMeta,
 | |
| 			Spec: v1.PodSpec{
 | |
| 				Containers: []v1.Container{{
 | |
| 					Name: "nginx",
 | |
| 				}},
 | |
| 			},
 | |
| 			Status: v1.PodStatus{
 | |
| 				ContainerStatuses: []v1.ContainerStatus{
 | |
| 					{
 | |
| 						State: v1.ContainerState{
 | |
| 							Running: &v1.ContainerStateRunning{
 | |
| 								StartedAt: metav1.Now(),
 | |
| 							},
 | |
| 						},
 | |
| 						Ready: true,
 | |
| 					},
 | |
| 				},
 | |
| 				Phase: "Completed",
 | |
| 			},
 | |
| 		},
 | |
| 		res: map[string]interface{}{
 | |
| 			"Ready":    "1/1",
 | |
| 			"Status":   "NotReady",
 | |
| 			"Restarts": 0,
 | |
| 			"Age":      "<unknown>",
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	case15 := testCase{
 | |
| 		pod: v1.Pod{TypeMeta: typeMeta,
 | |
| 			ObjectMeta: metav1.ObjectMeta{
 | |
| 				DeletionTimestamp: &metav1.Time{Time: time.Now()},
 | |
| 			},
 | |
| 		},
 | |
| 		res: map[string]interface{}{
 | |
| 			"Ready":    "0/0",
 | |
| 			"Status":   "Terminating",
 | |
| 			"Restarts": 0,
 | |
| 			"Age":      "<unknown>",
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	testCases := map[string]testCase{
 | |
| 		"pod1":  case1,
 | |
| 		"pod2":  case2,
 | |
| 		"pod3":  case3,
 | |
| 		"pod4":  case4,
 | |
| 		"pod5":  case5,
 | |
| 		"pod6":  case6,
 | |
| 		"pod7":  case7,
 | |
| 		"pod8":  case8,
 | |
| 		"pod9":  case9,
 | |
| 		"pod10": case10,
 | |
| 		"pod11": case11,
 | |
| 		"pod12": case12,
 | |
| 		"pod13": case13,
 | |
| 		"pod14": case14,
 | |
| 		"pod15": case15,
 | |
| 	}
 | |
| 
 | |
| 	for des, t2 := range testCases {
 | |
| 		fmt.Println(des)
 | |
| 		u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(t2.pod.DeepCopy())
 | |
| 		assert.NoError(t, err)
 | |
| 		res, err := additionalInfo(unstructured.Unstructured{Object: u})
 | |
| 		assert.NoError(t, err)
 | |
| 		assert.Equal(t, t2.res, res)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestSvcAdditionalInfo(t *testing.T) {
 | |
| 	typeMeta := metav1.TypeMeta{APIVersion: "v1", Kind: "Service"}
 | |
| 
 | |
| 	type testCase struct {
 | |
| 		svc v1.Service
 | |
| 		res map[string]interface{}
 | |
| 	}
 | |
| 
 | |
| 	case1 := testCase{
 | |
| 		svc: v1.Service{TypeMeta: typeMeta, Spec: v1.ServiceSpec{
 | |
| 			Type: v1.ServiceTypeLoadBalancer,
 | |
| 		},
 | |
| 			Status: v1.ServiceStatus{LoadBalancer: v1.LoadBalancerStatus{Ingress: []v1.LoadBalancerIngress{{IP: "145.2.2.1"}}}}},
 | |
| 		res: map[string]interface{}{
 | |
| 			"EIP": "145.2.2.1",
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	case2 := testCase{
 | |
| 		svc: v1.Service{TypeMeta: typeMeta, Spec: v1.ServiceSpec{
 | |
| 			Type: v1.ServiceTypeLoadBalancer,
 | |
| 		},
 | |
| 			Status: v1.ServiceStatus{}},
 | |
| 		res: map[string]interface{}{
 | |
| 			"EIP": "pending",
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	testCases := map[string]testCase{
 | |
| 		"svc1": case1,
 | |
| 		"svc2": case2,
 | |
| 	}
 | |
| 
 | |
| 	for des, t2 := range testCases {
 | |
| 		fmt.Println(des)
 | |
| 		u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(t2.svc.DeepCopy())
 | |
| 		assert.NoError(t, err)
 | |
| 		res, err := additionalInfo(unstructured.Unstructured{Object: u})
 | |
| 		assert.NoError(t, err)
 | |
| 		assert.Equal(t, t2.res, res)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| var _ = Describe("unit-test to e2e test", func() {
 | |
| 	deploy1 := v12.Deployment{
 | |
| 		TypeMeta: metav1.TypeMeta{
 | |
| 			APIVersion: "apps/v1",
 | |
| 			Kind:       "Deployment",
 | |
| 		},
 | |
| 		ObjectMeta: metav1.ObjectMeta{
 | |
| 			Name:      "deploy1",
 | |
| 			Namespace: "test-namespace",
 | |
| 		},
 | |
| 		Spec: v12.DeploymentSpec{
 | |
| 			Selector: &metav1.LabelSelector{
 | |
| 				MatchLabels: map[string]string{
 | |
| 					"app": "deploy1",
 | |
| 				},
 | |
| 			},
 | |
| 			Template: v1.PodTemplateSpec{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Labels: map[string]string{
 | |
| 						"app": "deploy1",
 | |
| 					},
 | |
| 				},
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Image: "nginx",
 | |
| 							Name:  "nginx",
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	deploy2 := v12.Deployment{
 | |
| 		TypeMeta: metav1.TypeMeta{
 | |
| 			APIVersion: "apps/v1",
 | |
| 			Kind:       "Deployment",
 | |
| 		},
 | |
| 		ObjectMeta: metav1.ObjectMeta{
 | |
| 			Name:      "deploy2",
 | |
| 			Namespace: "test-namespace",
 | |
| 		},
 | |
| 		Spec: v12.DeploymentSpec{
 | |
| 			Selector: &metav1.LabelSelector{
 | |
| 				MatchLabels: map[string]string{
 | |
| 					"app": "deploy2",
 | |
| 				},
 | |
| 			},
 | |
| 			Template: v1.PodTemplateSpec{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Labels: map[string]string{
 | |
| 						"app": "deploy2",
 | |
| 					},
 | |
| 				},
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Image: "nginx",
 | |
| 							Name:  "nginx",
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	rs1 := v12.ReplicaSet{
 | |
| 		TypeMeta: metav1.TypeMeta{
 | |
| 			APIVersion: "apps/v1",
 | |
| 			Kind:       "ReplicaSet",
 | |
| 		},
 | |
| 		ObjectMeta: metav1.ObjectMeta{
 | |
| 			Name:      "rs1",
 | |
| 			Namespace: "test-namespace",
 | |
| 			Labels: map[string]string{
 | |
| 				"app": "deploy1",
 | |
| 			},
 | |
| 		},
 | |
| 		Spec: v12.ReplicaSetSpec{
 | |
| 			Selector: &metav1.LabelSelector{
 | |
| 				MatchLabels: map[string]string{
 | |
| 					"app": "deploy1",
 | |
| 					"rs":  "rs1",
 | |
| 				},
 | |
| 			},
 | |
| 			Template: v1.PodTemplateSpec{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Labels: map[string]string{
 | |
| 						"app": "deploy1",
 | |
| 						"rs":  "rs1",
 | |
| 					},
 | |
| 				},
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Image: "nginx",
 | |
| 							Name:  "nginx",
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	rs2 := v12.ReplicaSet{
 | |
| 		TypeMeta: metav1.TypeMeta{
 | |
| 			APIVersion: "apps/v1",
 | |
| 			Kind:       "ReplicaSet",
 | |
| 		},
 | |
| 		ObjectMeta: metav1.ObjectMeta{
 | |
| 			Name:      "rs2",
 | |
| 			Namespace: "test-namespace",
 | |
| 			Labels: map[string]string{
 | |
| 				"app": "deploy1",
 | |
| 			},
 | |
| 		},
 | |
| 		Spec: v12.ReplicaSetSpec{
 | |
| 			Selector: &metav1.LabelSelector{
 | |
| 				MatchLabels: map[string]string{
 | |
| 					"app": "deploy1",
 | |
| 					"rs":  "rs2",
 | |
| 				},
 | |
| 			},
 | |
| 			Template: v1.PodTemplateSpec{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Labels: map[string]string{
 | |
| 						"app": "deploy1",
 | |
| 						"rs":  "rs2",
 | |
| 					},
 | |
| 				},
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Image: "nginx",
 | |
| 							Name:  "nginx",
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	rs3 := v12.ReplicaSet{
 | |
| 		TypeMeta: metav1.TypeMeta{
 | |
| 			APIVersion: "apps/v1",
 | |
| 			Kind:       "ReplicaSet",
 | |
| 		},
 | |
| 		ObjectMeta: metav1.ObjectMeta{
 | |
| 			Name:      "rs3",
 | |
| 			Namespace: "test-namespace",
 | |
| 			Labels: map[string]string{
 | |
| 				"app": "deploy2",
 | |
| 			},
 | |
| 		},
 | |
| 		Spec: v12.ReplicaSetSpec{
 | |
| 			Selector: &metav1.LabelSelector{
 | |
| 				MatchLabels: map[string]string{
 | |
| 					"app": "deploy2",
 | |
| 					"rs":  "rs3",
 | |
| 				},
 | |
| 			},
 | |
| 			Template: v1.PodTemplateSpec{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Labels: map[string]string{
 | |
| 						"app": "deploy2",
 | |
| 						"rs":  "rs3",
 | |
| 					},
 | |
| 				},
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Image: "nginx",
 | |
| 							Name:  "nginx",
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	pod1 := v1.Pod{
 | |
| 		TypeMeta: metav1.TypeMeta{
 | |
| 			APIVersion: "v1",
 | |
| 			Kind:       "Pod",
 | |
| 		},
 | |
| 		ObjectMeta: metav1.ObjectMeta{
 | |
| 			Name:      "pod1",
 | |
| 			Namespace: "test-namespace",
 | |
| 			Labels: map[string]string{
 | |
| 				"app": "deploy1",
 | |
| 				"rs":  "rs1",
 | |
| 			},
 | |
| 		},
 | |
| 		Spec: v1.PodSpec{
 | |
| 			Containers: []v1.Container{
 | |
| 				{
 | |
| 					Image: "nginx",
 | |
| 					Name:  "nginx",
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	pod2 := v1.Pod{
 | |
| 		TypeMeta: metav1.TypeMeta{
 | |
| 			APIVersion: "v1",
 | |
| 			Kind:       "Pod",
 | |
| 		},
 | |
| 		ObjectMeta: metav1.ObjectMeta{
 | |
| 			Name:      "pod2",
 | |
| 			Namespace: "test-namespace",
 | |
| 			Labels: map[string]string{
 | |
| 				"app": "deploy1",
 | |
| 				"rs":  "rs2",
 | |
| 			},
 | |
| 		},
 | |
| 		Spec: v1.PodSpec{
 | |
| 			Containers: []v1.Container{
 | |
| 				{
 | |
| 					Image: "nginx",
 | |
| 					Name:  "nginx",
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	pod3 := v1.Pod{
 | |
| 		TypeMeta: metav1.TypeMeta{
 | |
| 			APIVersion: "v1",
 | |
| 			Kind:       "Pod",
 | |
| 		},
 | |
| 		ObjectMeta: metav1.ObjectMeta{
 | |
| 			Name:      "pod3",
 | |
| 			Namespace: "test-namespace",
 | |
| 			Labels: map[string]string{
 | |
| 				"app": "deploy2",
 | |
| 				"rs":  "rs3",
 | |
| 			},
 | |
| 		},
 | |
| 		Spec: v1.PodSpec{
 | |
| 			Containers: []v1.Container{
 | |
| 				{
 | |
| 					Image: "nginx",
 | |
| 					Name:  "nginx",
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	rs4 := v12.ReplicaSet{
 | |
| 		TypeMeta: metav1.TypeMeta{
 | |
| 			APIVersion: "apps/v1",
 | |
| 			Kind:       "ReplicaSet",
 | |
| 		},
 | |
| 		ObjectMeta: metav1.ObjectMeta{
 | |
| 			Name:      "rs4",
 | |
| 			Namespace: "test-namespace",
 | |
| 			Labels: map[string]string{
 | |
| 				"app": "deploy3",
 | |
| 			},
 | |
| 		},
 | |
| 		Spec: v12.ReplicaSetSpec{
 | |
| 			Selector: &metav1.LabelSelector{
 | |
| 				MatchLabels: map[string]string{
 | |
| 					"app": "deploy3",
 | |
| 					"rs":  "rs4",
 | |
| 				},
 | |
| 			},
 | |
| 			Template: v1.PodTemplateSpec{
 | |
| 				ObjectMeta: metav1.ObjectMeta{
 | |
| 					Labels: map[string]string{
 | |
| 						"app": "deploy3",
 | |
| 						"rs":  "rs4",
 | |
| 					},
 | |
| 				},
 | |
| 				Spec: v1.PodSpec{
 | |
| 					Containers: []v1.Container{
 | |
| 						{
 | |
| 							Image: "nginx",
 | |
| 							Name:  "nginx",
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	pod4 := v1.Pod{
 | |
| 		TypeMeta: metav1.TypeMeta{
 | |
| 			APIVersion: "v1",
 | |
| 			Kind:       "Pod",
 | |
| 		},
 | |
| 		ObjectMeta: metav1.ObjectMeta{
 | |
| 			Name:      "pod4",
 | |
| 			Namespace: "test-namespace",
 | |
| 			Labels: map[string]string{
 | |
| 				"app": "deploy3",
 | |
| 				"rs":  "rs4",
 | |
| 			},
 | |
| 		},
 | |
| 		Spec: v1.PodSpec{
 | |
| 			Containers: []v1.Container{
 | |
| 				{
 | |
| 					Image: "nginx",
 | |
| 					Name:  "nginx",
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	var objectList []client.Object
 | |
| 	objectList = append(objectList, &deploy1, &deploy1, &rs1, &rs2, &rs3, &rs4, &pod1, &pod2, &pod3, &rs4, &pod4)
 | |
| 	BeforeEach(func() {
 | |
| 		Expect(k8sClient.Create(ctx, &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace"}})).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{}))
 | |
| 		Expect(k8sClient.Create(ctx, deploy1.DeepCopy())).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{}))
 | |
| 		Expect(k8sClient.Create(ctx, deploy2.DeepCopy())).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{}))
 | |
| 		Expect(k8sClient.Create(ctx, rs1.DeepCopy())).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{}))
 | |
| 		Expect(k8sClient.Create(ctx, rs2.DeepCopy())).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{}))
 | |
| 		Expect(k8sClient.Create(ctx, rs3.DeepCopy())).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{}))
 | |
| 		Expect(k8sClient.Create(ctx, pod1.DeepCopy())).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{}))
 | |
| 		Expect(k8sClient.Create(ctx, pod2.DeepCopy())).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{}))
 | |
| 		Expect(k8sClient.Create(ctx, pod3.DeepCopy())).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{}))
 | |
| 
 | |
| 		cRs4 := rs4.DeepCopy()
 | |
| 		Expect(k8sClient.Create(ctx, cRs4)).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{}))
 | |
| 		cPod4 := pod4.DeepCopy()
 | |
| 		cPod4.SetOwnerReferences([]metav1.OwnerReference{
 | |
| 			{
 | |
| 				APIVersion: "apps/v1",
 | |
| 				Kind:       "ReplicaSet",
 | |
| 				Name:       cRs4.Name,
 | |
| 				UID:        cRs4.UID,
 | |
| 			},
 | |
| 		})
 | |
| 		Expect(k8sClient.Create(ctx, cPod4)).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{}))
 | |
| 	})
 | |
| 
 | |
| 	AfterEach(func() {
 | |
| 		for _, object := range objectList {
 | |
| 			Expect(k8sClient.Delete(ctx, object))
 | |
| 		}
 | |
| 	})
 | |
| 
 | |
| 	It("test fetchObjectWithResourceTreeNode func", func() {
 | |
| 		rtn := types.ResourceTreeNode{
 | |
| 			Name:       "deploy1",
 | |
| 			Namespace:  "test-namespace",
 | |
| 			APIVersion: "apps/v1",
 | |
| 			Kind:       "Deployment",
 | |
| 		}
 | |
| 		u, err := fetchObjectWithResourceTreeNode(ctx, "", k8sClient, rtn)
 | |
| 		Expect(err).Should(BeNil())
 | |
| 		Expect(u).ShouldNot(BeNil())
 | |
| 		Expect(u.GetName()).Should(BeEquivalentTo("deploy1"))
 | |
| 	})
 | |
| 
 | |
| 	It("test list item by rule", func() {
 | |
| 		u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(deploy1.DeepCopy())
 | |
| 		Expect(err).Should(BeNil())
 | |
| 		items, err := listItemByRule(ctx, k8sClient, ResourceType{APIVersion: "apps/v1", Kind: "ReplicaSet"}, unstructured.Unstructured{Object: u},
 | |
| 			deploy2RsLabelListOption, nil, true)
 | |
| 		Expect(err).Should(BeNil())
 | |
| 		Expect(len(items)).Should(BeEquivalentTo(2))
 | |
| 
 | |
| 		u2, err := runtime.DefaultUnstructuredConverter.ToUnstructured(deploy2.DeepCopy())
 | |
| 		Expect(err).Should(BeNil())
 | |
| 		items2, err := listItemByRule(ctx, k8sClient, ResourceType{APIVersion: "apps/v1", Kind: "ReplicaSet"}, unstructured.Unstructured{Object: u2},
 | |
| 			nil, deploy2RsLabelListOption, true)
 | |
| 		Expect(len(items2)).Should(BeEquivalentTo(1))
 | |
| 
 | |
| 		// test use ownerReference UId to filter
 | |
| 		u3 := unstructured.Unstructured{}
 | |
| 		u3.SetNamespace(rs4.Namespace)
 | |
| 		u3.SetName(rs4.Name)
 | |
| 		u3.SetAPIVersion("apps/v1")
 | |
| 		u3.SetKind("ReplicaSet")
 | |
| 		Expect(k8sClient.Get(ctx, types2.NamespacedName{Namespace: u3.GetNamespace(), Name: u3.GetName()}, &u3))
 | |
| 		Expect(err).Should(BeNil())
 | |
| 		items3, err := listItemByRule(ctx, k8sClient, ResourceType{APIVersion: "v1", Kind: "Pod"}, u3,
 | |
| 			nil, nil, true)
 | |
| 		Expect(err).Should(BeNil())
 | |
| 		Expect(len(items3)).Should(BeEquivalentTo(1))
 | |
| 	})
 | |
| 
 | |
| 	It("iterate resource", func() {
 | |
| 		tn, err := iteratorChildResources(ctx, "", k8sClient, types.ResourceTreeNode{
 | |
| 			Cluster:    "",
 | |
| 			Namespace:  "test-namespace",
 | |
| 			Name:       "deploy1",
 | |
| 			APIVersion: "apps/v1",
 | |
| 			Kind:       "Deployment",
 | |
| 		}, 1)
 | |
| 		Expect(err).Should(BeNil())
 | |
| 		Expect(len(tn)).Should(BeEquivalentTo(2))
 | |
| 		Expect(len(tn[0].LeafNodes)).Should(BeEquivalentTo(1))
 | |
| 		Expect(len(tn[1].LeafNodes)).Should(BeEquivalentTo(1))
 | |
| 	})
 | |
| 
 | |
| 	It("test provider handler func", func() {
 | |
| 		app := v1beta1.Application{
 | |
| 			ObjectMeta: metav1.ObjectMeta{
 | |
| 				Name:      "app",
 | |
| 				Namespace: "test-namespace",
 | |
| 			},
 | |
| 			Spec: v1beta1.ApplicationSpec{
 | |
| 				Components: []common.ApplicationComponent{},
 | |
| 			},
 | |
| 		}
 | |
| 
 | |
| 		rt := v1beta1.ResourceTracker{
 | |
| 			ObjectMeta: metav1.ObjectMeta{
 | |
| 				Name: "app-test-v1-namespace",
 | |
| 				Labels: map[string]string{
 | |
| 					oam.LabelAppName:      "app",
 | |
| 					oam.LabelAppNamespace: "test-namespace",
 | |
| 				},
 | |
| 				Annotations: map[string]string{
 | |
| 					oam.AnnotationPublishVersion: "v1",
 | |
| 				},
 | |
| 			},
 | |
| 			Spec: v1beta1.ResourceTrackerSpec{
 | |
| 				Type: v1beta1.ResourceTrackerTypeVersioned,
 | |
| 				ManagedResources: []v1beta1.ManagedResource{
 | |
| 					{
 | |
| 						ClusterObjectReference: common.ClusterObjectReference{
 | |
| 							Cluster: "",
 | |
| 							ObjectReference: v1.ObjectReference{
 | |
| 								APIVersion: "apps/v1",
 | |
| 								Kind:       "Deployment",
 | |
| 								Namespace:  "test-namespace",
 | |
| 								Name:       "deploy1",
 | |
| 							},
 | |
| 						},
 | |
| 						OAMObjectReference: common.OAMObjectReference{
 | |
| 							Component: "deploy1",
 | |
| 						},
 | |
| 					},
 | |
| 					{
 | |
| 						ClusterObjectReference: common.ClusterObjectReference{
 | |
| 							Cluster: "",
 | |
| 							ObjectReference: v1.ObjectReference{
 | |
| 								APIVersion: "apps/v1",
 | |
| 								Kind:       "Deployment",
 | |
| 								Namespace:  "test-namespace",
 | |
| 								Name:       "deploy2",
 | |
| 							},
 | |
| 						},
 | |
| 						OAMObjectReference: common.OAMObjectReference{
 | |
| 							Component: "deploy2",
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		}
 | |
| 
 | |
| 		Expect(k8sClient.Create(ctx, &app)).Should(BeNil())
 | |
| 		Expect(k8sClient.Create(ctx, &rt)).Should(BeNil())
 | |
| 
 | |
| 		prd := provider{cli: k8sClient}
 | |
| 		opt := `app: {
 | |
| 				name: "app"
 | |
| 				namespace: "test-namespace"
 | |
| 			}`
 | |
| 		v, err := value.NewValue(opt, nil, "")
 | |
| 		Expect(err).Should(BeNil())
 | |
| 		Expect(prd.GetApplicationResourceTree(nil, v, nil)).Should(BeNil())
 | |
| 		type Res struct {
 | |
| 			List []types.AppliedResource `json:"list"`
 | |
| 		}
 | |
| 		var res Res
 | |
| 		err = v.UnmarshalTo(&res)
 | |
| 		Expect(err).Should(BeNil())
 | |
| 		Expect(len(res.List)).Should(Equal(2))
 | |
| 	})
 | |
| 
 | |
| 	It("Test not exist api don't break whole process", func() {
 | |
| 		notExistRuleStr := `
 | |
| - parentResourceType:
 | |
|     group: apps
 | |
|     kind: Deployment
 | |
|   childrenResourceType:
 | |
|     - apiVersion: v2
 | |
|       kind: Pod
 | |
| `
 | |
| 		notExistParentResourceStr := `
 | |
| - parentResourceType:
 | |
|     group: badgroup
 | |
|     kind: Deployment
 | |
|   childrenResourceType:
 | |
|     - apiVersion: v2
 | |
|       kind: Pod
 | |
| `
 | |
| 		Expect(k8sClient.Create(ctx, &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "vela-system"}})).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{}))
 | |
| 		badRuleConfigMap := v1.ConfigMap{TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "ConfigMap"},
 | |
| 			ObjectMeta: metav1.ObjectMeta{Namespace: types3.DefaultKubeVelaNS, Name: "bad-rule", Labels: map[string]string{oam.LabelResourceRules: "true"}},
 | |
| 			Data:       map[string]string{relationshipKey: notExistRuleStr},
 | |
| 		}
 | |
| 		Expect(k8sClient.Create(ctx, &badRuleConfigMap)).Should(BeNil())
 | |
| 
 | |
| 		notExistParentConfigMap := v1.ConfigMap{TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "ConfigMap"},
 | |
| 			ObjectMeta: metav1.ObjectMeta{Namespace: types3.DefaultKubeVelaNS, Name: "not-exist-parent", Labels: map[string]string{oam.LabelResourceRules: "true"}},
 | |
| 			Data:       map[string]string{relationshipKey: notExistParentResourceStr},
 | |
| 		}
 | |
| 		Expect(k8sClient.Create(ctx, ¬ExistParentConfigMap)).Should(BeNil())
 | |
| 
 | |
| 		prd := provider{cli: k8sClient}
 | |
| 		opt := `app: {
 | |
| 				name: "app"
 | |
| 				namespace: "test-namespace"
 | |
| 			}`
 | |
| 		v, err := value.NewValue(opt, nil, "")
 | |
| 
 | |
| 		Expect(err).Should(BeNil())
 | |
| 		Expect(prd.GetApplicationResourceTree(nil, v, nil)).Should(BeNil())
 | |
| 		type Res struct {
 | |
| 			List []types.AppliedResource `json:"list"`
 | |
| 		}
 | |
| 		var res Res
 | |
| 		err = v.UnmarshalTo(&res)
 | |
| 		Expect(err).Should(BeNil())
 | |
| 		Expect(len(res.List)).Should(Equal(2))
 | |
| 	})
 | |
| })
 | |
| 
 | |
| var _ = Describe("test merge globalRules", func() {
 | |
| 	cloneSetStr := `
 | |
| - parentResourceType:
 | |
|     group: apps.kruise.io
 | |
|     kind: CloneSet
 | |
|   childrenResourceType:
 | |
|     - apiVersion: v1
 | |
|       kind: Pod
 | |
|     - apiVersion: apps/v1
 | |
|       kind: ControllerRevision
 | |
| `
 | |
| 	daemonSetStr := `
 | |
| - parentResourceType:
 | |
|     group: apps
 | |
|     kind: DaemonSet
 | |
|   childrenResourceType:
 | |
|     - apiVersion: v1
 | |
|       kind: Pod
 | |
|     - apiVersion: apps/v1
 | |
|       kind: ControllerRevision
 | |
| `
 | |
| 	stsStr := `
 | |
| - parentResourceType:
 | |
|     group: apps
 | |
|     kind: StatefulSet
 | |
|   childrenResourceType:
 | |
|     - apiVersion: v1
 | |
|       kind: Pod
 | |
|     - apiVersion: apps/v1
 | |
|       kind: ControllerRevision
 | |
| `
 | |
| 	missConfigedStr := `
 | |
| - parentResourceType:
 | |
|     group: apps
 | |
|     kind: StatefulSet
 | |
| childrenResourceType:
 | |
|     - apiVersion: v1
 | |
|       kind: Pod
 | |
|     - apiVersion: apps/v1
 | |
|       kind: ControllerRevision
 | |
| `
 | |
| 
 | |
| 	It("test merge rules", func() {
 | |
| 		Expect(k8sClient.Create(ctx, &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "vela-system"}})).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{}))
 | |
| 		cloneSetConfigMap := v1.ConfigMap{TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "ConfigMap"},
 | |
| 			ObjectMeta: metav1.ObjectMeta{Namespace: types3.DefaultKubeVelaNS, Name: "cloneset", Labels: map[string]string{oam.LabelResourceRules: "true"}},
 | |
| 			Data:       map[string]string{relationshipKey: cloneSetStr},
 | |
| 		}
 | |
| 		Expect(k8sClient.Create(ctx, &cloneSetConfigMap)).Should(BeNil())
 | |
| 
 | |
| 		daemonSetConfigMap := v1.ConfigMap{TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "ConfigMap"},
 | |
| 			ObjectMeta: metav1.ObjectMeta{Namespace: types3.DefaultKubeVelaNS, Name: "daemonset", Labels: map[string]string{oam.LabelResourceRules: "true"}},
 | |
| 			Data:       map[string]string{relationshipKey: daemonSetStr},
 | |
| 		}
 | |
| 		Expect(k8sClient.Create(ctx, &daemonSetConfigMap)).Should(BeNil())
 | |
| 
 | |
| 		stsConfigMap := v1.ConfigMap{TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "ConfigMap"},
 | |
| 			ObjectMeta: metav1.ObjectMeta{Namespace: types3.DefaultKubeVelaNS, Name: "sts", Labels: map[string]string{oam.LabelResourceRules: "true"}},
 | |
| 			Data:       map[string]string{relationshipKey: stsStr},
 | |
| 		}
 | |
| 		Expect(k8sClient.Create(ctx, &stsConfigMap)).Should(BeNil())
 | |
| 
 | |
| 		missConfigedCm := v1.ConfigMap{TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "ConfigMap"},
 | |
| 			ObjectMeta: metav1.ObjectMeta{Namespace: types3.DefaultKubeVelaNS, Name: "miss-configed", Labels: map[string]string{oam.LabelResourceRules: "true"}},
 | |
| 			Data:       map[string]string{relationshipKey: missConfigedStr},
 | |
| 		}
 | |
| 		Expect(k8sClient.Create(ctx, &missConfigedCm)).Should(BeNil())
 | |
| 
 | |
| 		Expect(mergeCustomRules(ctx, k8sClient)).Should(BeNil())
 | |
| 		childrenResources, ok := globalRule[GroupResourceType{Group: "apps.kruise.io", Kind: "CloneSet"}]
 | |
| 		Expect(ok).Should(BeTrue())
 | |
| 		Expect(childrenResources.DefaultGenListOptionFunc).Should(BeNil())
 | |
| 		Expect(len(childrenResources.CareResource)).Should(BeEquivalentTo(2))
 | |
| 		specifyFunc, ok := childrenResources.CareResource[ResourceType{APIVersion: "v1", Kind: "Pod"}]
 | |
| 		Expect(ok).Should(BeTrue())
 | |
| 		Expect(specifyFunc).Should(BeNil())
 | |
| 
 | |
| 		dsChildrenResources, ok := globalRule[GroupResourceType{Group: "apps", Kind: "DaemonSet"}]
 | |
| 		Expect(ok).Should(BeTrue())
 | |
| 		Expect(dsChildrenResources.DefaultGenListOptionFunc).Should(BeNil())
 | |
| 		Expect(len(dsChildrenResources.CareResource)).Should(BeEquivalentTo(2))
 | |
| 		dsSpecifyFunc, ok := dsChildrenResources.CareResource[ResourceType{APIVersion: "v1", Kind: "Pod"}]
 | |
| 		Expect(ok).Should(BeTrue())
 | |
| 		Expect(dsSpecifyFunc).Should(BeNil())
 | |
| 		crSpecifyFunc, ok := dsChildrenResources.CareResource[ResourceType{APIVersion: "apps/v1", Kind: "ControllerRevision"}]
 | |
| 		Expect(ok).Should(BeTrue())
 | |
| 		Expect(crSpecifyFunc).Should(BeNil())
 | |
| 
 | |
| 		stsChildrenResources, ok := globalRule[GroupResourceType{Group: "apps", Kind: "StatefulSet"}]
 | |
| 		Expect(ok).Should(BeTrue())
 | |
| 		Expect(stsChildrenResources.DefaultGenListOptionFunc).Should(BeNil())
 | |
| 		Expect(len(stsChildrenResources.CareResource)).Should(BeEquivalentTo(2))
 | |
| 		stsCrSpecifyFunc, ok := stsChildrenResources.CareResource[ResourceType{APIVersion: "apps/v1", Kind: "ControllerRevision"}]
 | |
| 		Expect(ok).Should(BeTrue())
 | |
| 		Expect(stsCrSpecifyFunc).Should(BeNil())
 | |
| 	})
 | |
| })
 |