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, &notExistParentConfigMap)).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  })