295 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			295 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			Go
		
	
	
	
/*
 | 
						|
Copyright 2024 The Karmada 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 federatedresourcequota
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"testing"
 | 
						|
 | 
						|
	"github.com/stretchr/testify/assert"
 | 
						|
	corev1 "k8s.io/api/core/v1"
 | 
						|
	"k8s.io/apimachinery/pkg/api/resource"
 | 
						|
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						|
	"k8s.io/apimachinery/pkg/runtime"
 | 
						|
	"k8s.io/client-go/tools/record"
 | 
						|
	"sigs.k8s.io/controller-runtime/pkg/client"
 | 
						|
	"sigs.k8s.io/controller-runtime/pkg/client/fake"
 | 
						|
 | 
						|
	clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1"
 | 
						|
	policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
 | 
						|
	workv1alpha1 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha1"
 | 
						|
	"github.com/karmada-io/karmada/pkg/util"
 | 
						|
)
 | 
						|
 | 
						|
// setupTest initializes a test environment with the given runtime objects
 | 
						|
// It returns a fake client and a SyncController for use in tests
 | 
						|
func setupTest(t *testing.T, objs ...runtime.Object) (client.Client, *SyncController) {
 | 
						|
	scheme := runtime.NewScheme()
 | 
						|
	assert.NoError(t, policyv1alpha1.Install(scheme))
 | 
						|
	assert.NoError(t, workv1alpha1.Install(scheme))
 | 
						|
	assert.NoError(t, clusterv1alpha1.Install(scheme))
 | 
						|
	assert.NoError(t, corev1.AddToScheme(scheme))
 | 
						|
 | 
						|
	fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(objs...).Build()
 | 
						|
	controller := &SyncController{
 | 
						|
		Client:        fakeClient,
 | 
						|
		EventRecorder: record.NewFakeRecorder(100),
 | 
						|
	}
 | 
						|
	return fakeClient, controller
 | 
						|
}
 | 
						|
 | 
						|
// TestCleanUpWorks tests the cleanUpWorks function of the SyncController
 | 
						|
func TestCleanUpWorks(t *testing.T) {
 | 
						|
	tests := []struct {
 | 
						|
		name          string
 | 
						|
		existingWorks []runtime.Object
 | 
						|
		namespace     string
 | 
						|
		quotaName     string
 | 
						|
		expectedError bool
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name: "Successfully delete works",
 | 
						|
			existingWorks: []runtime.Object{
 | 
						|
				&workv1alpha1.Work{
 | 
						|
					ObjectMeta: metav1.ObjectMeta{
 | 
						|
						Name:      "work-1",
 | 
						|
						Namespace: "default",
 | 
						|
						Labels: map[string]string{
 | 
						|
							util.FederatedResourceQuotaNamespaceLabel: "default",
 | 
						|
							util.FederatedResourceQuotaNameLabel:      "test-quota",
 | 
						|
						},
 | 
						|
					},
 | 
						|
				},
 | 
						|
				&workv1alpha1.Work{
 | 
						|
					ObjectMeta: metav1.ObjectMeta{
 | 
						|
						Name:      "work-2",
 | 
						|
						Namespace: "default",
 | 
						|
						Labels: map[string]string{
 | 
						|
							util.FederatedResourceQuotaNamespaceLabel: "default",
 | 
						|
							util.FederatedResourceQuotaNameLabel:      "test-quota",
 | 
						|
						},
 | 
						|
					},
 | 
						|
				},
 | 
						|
			},
 | 
						|
			namespace:     "default",
 | 
						|
			quotaName:     "test-quota",
 | 
						|
			expectedError: false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:          "No works to delete",
 | 
						|
			existingWorks: []runtime.Object{},
 | 
						|
			namespace:     "default",
 | 
						|
			quotaName:     "test-quota",
 | 
						|
			expectedError: false,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, tt := range tests {
 | 
						|
		t.Run(tt.name, func(t *testing.T) {
 | 
						|
			fakeClient, controller := setupTest(t, tt.existingWorks...)
 | 
						|
 | 
						|
			err := controller.cleanUpWorks(context.Background(), tt.namespace, tt.quotaName)
 | 
						|
 | 
						|
			if tt.expectedError {
 | 
						|
				assert.Error(t, err)
 | 
						|
			} else {
 | 
						|
				assert.NoError(t, err)
 | 
						|
			}
 | 
						|
 | 
						|
			// Verify that works are deleted
 | 
						|
			workList := &workv1alpha1.WorkList{}
 | 
						|
			err = fakeClient.List(context.Background(), workList, client.MatchingLabels{
 | 
						|
				util.FederatedResourceQuotaNamespaceLabel: tt.namespace,
 | 
						|
				util.FederatedResourceQuotaNameLabel:      tt.quotaName,
 | 
						|
			})
 | 
						|
			assert.NoError(t, err)
 | 
						|
			assert.Empty(t, workList.Items)
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// It verifies that works are correctly created for the given FederatedResourceQuota and clusters
 | 
						|
func TestBuildWorks(t *testing.T) {
 | 
						|
	tests := []struct {
 | 
						|
		name          string
 | 
						|
		quota         *policyv1alpha1.FederatedResourceQuota
 | 
						|
		clusters      []clusterv1alpha1.Cluster
 | 
						|
		expectedError bool
 | 
						|
		expectedWorks int
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name: "Successfully build works for all clusters",
 | 
						|
			quota: &policyv1alpha1.FederatedResourceQuota{
 | 
						|
				ObjectMeta: metav1.ObjectMeta{
 | 
						|
					Name:      "test-quota",
 | 
						|
					Namespace: "default",
 | 
						|
				},
 | 
						|
				Spec: policyv1alpha1.FederatedResourceQuotaSpec{
 | 
						|
					StaticAssignments: []policyv1alpha1.StaticClusterAssignment{
 | 
						|
						{
 | 
						|
							ClusterName: "cluster1",
 | 
						|
							Hard: corev1.ResourceList{
 | 
						|
								corev1.ResourceCPU: resource.MustParse("1"),
 | 
						|
							},
 | 
						|
						},
 | 
						|
						{
 | 
						|
							ClusterName: "cluster2",
 | 
						|
							Hard: corev1.ResourceList{
 | 
						|
								corev1.ResourceCPU: resource.MustParse("2"),
 | 
						|
							},
 | 
						|
						},
 | 
						|
					},
 | 
						|
				},
 | 
						|
			},
 | 
						|
			clusters: []clusterv1alpha1.Cluster{
 | 
						|
				{ObjectMeta: metav1.ObjectMeta{Name: "cluster1"}},
 | 
						|
				{ObjectMeta: metav1.ObjectMeta{Name: "cluster2"}},
 | 
						|
			},
 | 
						|
			expectedError: false,
 | 
						|
			expectedWorks: 2,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "No clusters available",
 | 
						|
			quota: &policyv1alpha1.FederatedResourceQuota{
 | 
						|
				ObjectMeta: metav1.ObjectMeta{
 | 
						|
					Name:      "test-quota",
 | 
						|
					Namespace: "default",
 | 
						|
				},
 | 
						|
				Spec: policyv1alpha1.FederatedResourceQuotaSpec{
 | 
						|
					StaticAssignments: []policyv1alpha1.StaticClusterAssignment{
 | 
						|
						{
 | 
						|
							ClusterName: "cluster1",
 | 
						|
							Hard: corev1.ResourceList{
 | 
						|
								corev1.ResourceCPU: resource.MustParse("1"),
 | 
						|
							},
 | 
						|
						},
 | 
						|
					},
 | 
						|
				},
 | 
						|
			},
 | 
						|
			clusters:      []clusterv1alpha1.Cluster{},
 | 
						|
			expectedError: false,
 | 
						|
			expectedWorks: 0,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, tt := range tests {
 | 
						|
		t.Run(tt.name, func(t *testing.T) {
 | 
						|
			fakeClient, controller := setupTest(t)
 | 
						|
 | 
						|
			err := controller.buildWorks(context.Background(), tt.quota, tt.clusters)
 | 
						|
 | 
						|
			if tt.expectedError {
 | 
						|
				assert.Error(t, err)
 | 
						|
			} else {
 | 
						|
				assert.NoError(t, err)
 | 
						|
			}
 | 
						|
 | 
						|
			// Verify the number of created works
 | 
						|
			workList := &workv1alpha1.WorkList{}
 | 
						|
			err = fakeClient.List(context.Background(), workList, client.MatchingLabels{
 | 
						|
				util.FederatedResourceQuotaNamespaceLabel: tt.quota.Namespace,
 | 
						|
				util.FederatedResourceQuotaNameLabel:      tt.quota.Name,
 | 
						|
			})
 | 
						|
			assert.NoError(t, err)
 | 
						|
			assert.Len(t, workList.Items, tt.expectedWorks)
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// TestExtractClusterHardResourceList tests the extractClusterHardResourceList function
 | 
						|
func TestExtractClusterHardResourceList(t *testing.T) {
 | 
						|
	tests := []struct {
 | 
						|
		name           string
 | 
						|
		spec           policyv1alpha1.FederatedResourceQuotaSpec
 | 
						|
		clusterName    string
 | 
						|
		expectedResult corev1.ResourceList
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name: "Cluster found in static assignments",
 | 
						|
			spec: policyv1alpha1.FederatedResourceQuotaSpec{
 | 
						|
				StaticAssignments: []policyv1alpha1.StaticClusterAssignment{
 | 
						|
					{
 | 
						|
						ClusterName: "cluster1",
 | 
						|
						Hard: corev1.ResourceList{
 | 
						|
							corev1.ResourceCPU:    resource.MustParse("1"),
 | 
						|
							corev1.ResourceMemory: resource.MustParse("1Gi"),
 | 
						|
						},
 | 
						|
					},
 | 
						|
				},
 | 
						|
			},
 | 
						|
			clusterName: "cluster1",
 | 
						|
			expectedResult: corev1.ResourceList{
 | 
						|
				corev1.ResourceCPU:    resource.MustParse("1"),
 | 
						|
				corev1.ResourceMemory: resource.MustParse("1Gi"),
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "Cluster not found in static assignments",
 | 
						|
			spec: policyv1alpha1.FederatedResourceQuotaSpec{
 | 
						|
				StaticAssignments: []policyv1alpha1.StaticClusterAssignment{
 | 
						|
					{
 | 
						|
						ClusterName: "cluster1",
 | 
						|
						Hard: corev1.ResourceList{
 | 
						|
							corev1.ResourceCPU: resource.MustParse("1"),
 | 
						|
						},
 | 
						|
					},
 | 
						|
				},
 | 
						|
			},
 | 
						|
			clusterName:    "cluster2",
 | 
						|
			expectedResult: nil,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "Empty static assignments",
 | 
						|
			spec: policyv1alpha1.FederatedResourceQuotaSpec{
 | 
						|
				StaticAssignments: []policyv1alpha1.StaticClusterAssignment{},
 | 
						|
			},
 | 
						|
			clusterName:    "cluster1",
 | 
						|
			expectedResult: nil,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "Multiple static assignments",
 | 
						|
			spec: policyv1alpha1.FederatedResourceQuotaSpec{
 | 
						|
				StaticAssignments: []policyv1alpha1.StaticClusterAssignment{
 | 
						|
					{
 | 
						|
						ClusterName: "cluster1",
 | 
						|
						Hard: corev1.ResourceList{
 | 
						|
							corev1.ResourceCPU: resource.MustParse("1"),
 | 
						|
						},
 | 
						|
					},
 | 
						|
					{
 | 
						|
						ClusterName: "cluster2",
 | 
						|
						Hard: corev1.ResourceList{
 | 
						|
							corev1.ResourceCPU: resource.MustParse("2"),
 | 
						|
						},
 | 
						|
					},
 | 
						|
				},
 | 
						|
			},
 | 
						|
			clusterName: "cluster2",
 | 
						|
			expectedResult: corev1.ResourceList{
 | 
						|
				corev1.ResourceCPU: resource.MustParse("2"),
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, tt := range tests {
 | 
						|
		t.Run(tt.name, func(t *testing.T) {
 | 
						|
			result := extractClusterHardResourceList(tt.spec, tt.clusterName)
 | 
						|
			assert.Equal(t, tt.expectedResult, result)
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 |