github.com/oam-dev/kubevela@v1.9.11/pkg/policy/topology_test.go (about)

     1  /*
     2  Copyright 2022 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 policy
    18  
    19  import (
    20  	"context"
    21  	"testing"
    22  
    23  	"github.com/stretchr/testify/require"
    24  	corev1 "k8s.io/api/core/v1"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/runtime"
    27  	utilfeature "k8s.io/apiserver/pkg/util/feature"
    28  	featuregatetesting "k8s.io/component-base/featuregate/testing"
    29  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    30  
    31  	clusterv1alpha1 "github.com/oam-dev/cluster-gateway/pkg/apis/cluster/v1alpha1"
    32  	clustercommon "github.com/oam-dev/cluster-gateway/pkg/common"
    33  
    34  	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha1"
    35  	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
    36  	"github.com/oam-dev/kubevela/apis/types"
    37  	"github.com/oam-dev/kubevela/pkg/features"
    38  	"github.com/oam-dev/kubevela/pkg/multicluster"
    39  	"github.com/oam-dev/kubevela/pkg/utils/common"
    40  )
    41  
    42  func TestGetClusterLabelSelectorInTopology(t *testing.T) {
    43  	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.DeprecatedPolicySpec, true)()
    44  	multicluster.ClusterGatewaySecretNamespace = types.DefaultKubeVelaNS
    45  	cli := fake.NewClientBuilder().WithScheme(common.Scheme).WithObjects(&corev1.Secret{
    46  		ObjectMeta: metav1.ObjectMeta{
    47  			Name:      "cluster-a",
    48  			Namespace: multicluster.ClusterGatewaySecretNamespace,
    49  			Labels: map[string]string{
    50  				clustercommon.LabelKeyClusterEndpointType:   string(clusterv1alpha1.ClusterEndpointTypeConst),
    51  				clustercommon.LabelKeyClusterCredentialType: string(clusterv1alpha1.CredentialTypeX509Certificate),
    52  				"key": "value",
    53  			},
    54  		},
    55  	}, &corev1.Secret{
    56  		ObjectMeta: metav1.ObjectMeta{
    57  			Name:      "cluster-b",
    58  			Namespace: multicluster.ClusterGatewaySecretNamespace,
    59  			Labels: map[string]string{
    60  				clustercommon.LabelKeyClusterEndpointType:   string(clusterv1alpha1.ClusterEndpointTypeConst),
    61  				clustercommon.LabelKeyClusterCredentialType: string(clusterv1alpha1.CredentialTypeX509Certificate),
    62  				"key": "value",
    63  			},
    64  		},
    65  	}, &corev1.Secret{
    66  		ObjectMeta: metav1.ObjectMeta{
    67  			Name:      "cluster-c",
    68  			Namespace: multicluster.ClusterGatewaySecretNamespace,
    69  			Labels: map[string]string{
    70  				clustercommon.LabelKeyClusterEndpointType:   string(clusterv1alpha1.ClusterEndpointTypeConst),
    71  				clustercommon.LabelKeyClusterCredentialType: string(clusterv1alpha1.CredentialTypeX509Certificate),
    72  				"key": "none",
    73  			},
    74  		},
    75  	}).Build()
    76  	appNs := "test"
    77  	testCases := map[string]struct {
    78  		Inputs              []v1beta1.AppPolicy
    79  		Outputs             []v1alpha1.PlacementDecision
    80  		Error               string
    81  		AllowCrossNamespace bool
    82  	}{
    83  		"invalid-topology-policy": {
    84  			Inputs: []v1beta1.AppPolicy{{
    85  				Name:       "topology-policy",
    86  				Type:       "topology",
    87  				Properties: &runtime.RawExtension{Raw: []byte(`{"cluster":"x"}`)},
    88  			}},
    89  			Error: "failed to parse topology policy",
    90  		},
    91  		"cluster-not-found": {
    92  			Inputs: []v1beta1.AppPolicy{{
    93  				Name:       "topology-policy",
    94  				Type:       "topology",
    95  				Properties: &runtime.RawExtension{Raw: []byte(`{"clusters":["cluster-x"]}`)},
    96  			}},
    97  			Error: "failed to get cluster",
    98  		},
    99  		"topology-by-clusters": {
   100  			Inputs: []v1beta1.AppPolicy{{
   101  				Name:       "topology-policy",
   102  				Type:       "topology",
   103  				Properties: &runtime.RawExtension{Raw: []byte(`{"clusters":["cluster-a"]}`)},
   104  			}},
   105  			Outputs: []v1alpha1.PlacementDecision{{Cluster: "cluster-a", Namespace: ""}},
   106  		},
   107  		"topology-by-cluster-selector-404": {
   108  			Inputs: []v1beta1.AppPolicy{{
   109  				Name:       "topology-policy",
   110  				Type:       "topology",
   111  				Properties: &runtime.RawExtension{Raw: []byte(`{"clusterSelector":{"key":"bad-value"}}`)},
   112  			}},
   113  			Error: "failed to find any cluster matches given labels",
   114  		},
   115  		"topology-by-cluster-selector-ignore-404": {
   116  			Inputs: []v1beta1.AppPolicy{{
   117  				Name:       "topology-policy",
   118  				Type:       "topology",
   119  				Properties: &runtime.RawExtension{Raw: []byte(`{"clusterSelector":{"key":"bad-value"},"allowEmpty":true}`)},
   120  			}},
   121  			Outputs: []v1alpha1.PlacementDecision{},
   122  		},
   123  		"topology-by-cluster-selector": {
   124  			Inputs: []v1beta1.AppPolicy{{
   125  				Name:       "topology-policy",
   126  				Type:       "topology",
   127  				Properties: &runtime.RawExtension{Raw: []byte(`{"clusterSelector":{"key":"value"}}`)},
   128  			}},
   129  			Outputs: []v1alpha1.PlacementDecision{{Cluster: "cluster-a", Namespace: ""}, {Cluster: "cluster-b", Namespace: ""}},
   130  		},
   131  		"topology-by-cluster-label-selector": {
   132  			Inputs: []v1beta1.AppPolicy{{
   133  				Name:       "topology-policy",
   134  				Type:       "topology",
   135  				Properties: &runtime.RawExtension{Raw: []byte(`{"clusterLabelSelector":{"key":"value"}}`)},
   136  			}},
   137  			Outputs: []v1alpha1.PlacementDecision{{Cluster: "cluster-a", Namespace: ""}, {Cluster: "cluster-b", Namespace: ""}},
   138  		},
   139  		"topology-by-cluster-selector-and-namespace-invalid": {
   140  			Inputs: []v1beta1.AppPolicy{{
   141  				Name:       "topology-policy",
   142  				Type:       "topology",
   143  				Properties: &runtime.RawExtension{Raw: []byte(`{"clusterSelector":{"key":"value"},"namespace":"override"}`)},
   144  			}},
   145  			Error: "cannot cross namespace",
   146  		},
   147  		"topology-by-cluster-selector-and-namespace": {
   148  			Inputs: []v1beta1.AppPolicy{{
   149  				Name:       "topology-policy",
   150  				Type:       "topology",
   151  				Properties: &runtime.RawExtension{Raw: []byte(`{"clusterSelector":{"key":"value"},"namespace":"override"}`)},
   152  			}},
   153  			Outputs:             []v1alpha1.PlacementDecision{{Cluster: "cluster-a", Namespace: "override"}, {Cluster: "cluster-b", Namespace: "override"}},
   154  			AllowCrossNamespace: true,
   155  		},
   156  		"topology-no-clusters-and-cluster-label-selector": {
   157  			Inputs: []v1beta1.AppPolicy{{
   158  				Name:       "topology-policy",
   159  				Type:       "topology",
   160  				Properties: &runtime.RawExtension{Raw: []byte(`{"namespace":"override"}`)},
   161  			}},
   162  			Outputs:             []v1alpha1.PlacementDecision{{Cluster: "local", Namespace: "override"}},
   163  			AllowCrossNamespace: true,
   164  		},
   165  		"no-topology-policy": {
   166  			Inputs:  []v1beta1.AppPolicy{},
   167  			Outputs: []v1alpha1.PlacementDecision{{Cluster: "local", Namespace: ""}},
   168  		},
   169  		"empty-topology-policy": {
   170  			Inputs: []v1beta1.AppPolicy{{Type: "topology", Name: "some-name", Properties: nil}},
   171  			Error:  "have empty properties",
   172  		},
   173  	}
   174  	for name, tt := range testCases {
   175  		t.Run(name, func(t *testing.T) {
   176  			r := require.New(t)
   177  			pds, err := GetPlacementsFromTopologyPolicies(context.Background(), cli, appNs, tt.Inputs, tt.AllowCrossNamespace)
   178  			if tt.Error != "" {
   179  				r.NotNil(err)
   180  				r.Contains(err.Error(), tt.Error)
   181  			} else {
   182  				r.NoError(err)
   183  				r.Equal(tt.Outputs, pds)
   184  			}
   185  		})
   186  	}
   187  }