sigs.k8s.io/kueue@v0.6.2/pkg/controller/admissionchecks/multikueue/indexer_test.go (about)

     1  /*
     2  Copyright 2024 The Kubernetes 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 multikueue
    18  
    19  import (
    20  	"context"
    21  	"testing"
    22  
    23  	"github.com/google/go-cmp/cmp"
    24  	"github.com/google/go-cmp/cmp/cmpopts"
    25  	corev1 "k8s.io/api/core/v1"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/apimachinery/pkg/runtime"
    28  	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
    29  	"sigs.k8s.io/controller-runtime/pkg/client"
    30  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    31  	jobset "sigs.k8s.io/jobset/api/jobset/v1alpha2"
    32  
    33  	kueuealpha "sigs.k8s.io/kueue/apis/kueue/v1alpha1"
    34  	kueue "sigs.k8s.io/kueue/apis/kueue/v1beta1"
    35  	"sigs.k8s.io/kueue/pkg/util/slices"
    36  	utiltesting "sigs.k8s.io/kueue/pkg/util/testing"
    37  )
    38  
    39  const (
    40  	TestNamespace = "ns"
    41  )
    42  
    43  func getClientBuilder() (*fake.ClientBuilder, context.Context) {
    44  	scheme := runtime.NewScheme()
    45  	if err := clientgoscheme.AddToScheme(scheme); err != nil {
    46  		panic(err)
    47  	}
    48  	if err := kueue.AddToScheme(scheme); err != nil {
    49  		panic(err)
    50  	}
    51  	if err := kueuealpha.AddToScheme(scheme); err != nil {
    52  		panic(err)
    53  	}
    54  	if err := jobset.AddToScheme(scheme); err != nil {
    55  		panic(err)
    56  	}
    57  
    58  	ctx := context.Background()
    59  	builder := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&corev1.Namespace{
    60  		ObjectMeta: metav1.ObjectMeta{
    61  			Name: TestNamespace,
    62  		},
    63  	})
    64  	_ = SetupIndexer(ctx, utiltesting.AsIndexer(builder), TestNamespace)
    65  	return builder, ctx
    66  }
    67  
    68  func TestListMultiKueueClustersUsingKubeConfig(t *testing.T) {
    69  	cases := map[string]struct {
    70  		clusters      []*kueuealpha.MultiKueueCluster
    71  		filter        client.ListOption
    72  		wantListError error
    73  		wantList      []string
    74  	}{
    75  		"no clusters": {
    76  			filter: client.MatchingFields{UsingKubeConfigs: TestNamespace + "/secret1"},
    77  		},
    78  		"single cluster, single match": {
    79  			clusters: []*kueuealpha.MultiKueueCluster{
    80  				utiltesting.MakeMultiKueueCluster("cluster1").KubeConfig(kueuealpha.SecretLocationType, "secret1").Obj(),
    81  			},
    82  			filter:   client.MatchingFields{UsingKubeConfigs: TestNamespace + "/secret1"},
    83  			wantList: []string{"cluster1"},
    84  		},
    85  		"single cluster, no match": {
    86  			clusters: []*kueuealpha.MultiKueueCluster{
    87  				utiltesting.MakeMultiKueueCluster("cluster2").KubeConfig(kueuealpha.SecretLocationType, "secret2").Obj(),
    88  			},
    89  			filter: client.MatchingFields{UsingKubeConfigs: TestNamespace + "/secret1"},
    90  		},
    91  		"multiple clusters, single match": {
    92  			clusters: []*kueuealpha.MultiKueueCluster{
    93  				utiltesting.MakeMultiKueueCluster("cluster1").KubeConfig(kueuealpha.SecretLocationType, "secret1").Obj(),
    94  				utiltesting.MakeMultiKueueCluster("cluster2").KubeConfig(kueuealpha.SecretLocationType, "secret2").Obj(),
    95  			},
    96  			filter:   client.MatchingFields{UsingKubeConfigs: TestNamespace + "/secret1"},
    97  			wantList: []string{"cluster1"},
    98  		},
    99  	}
   100  	for name, tc := range cases {
   101  		t.Run(name, func(t *testing.T) {
   102  			builder, ctx := getClientBuilder()
   103  			k8sclient := builder.Build()
   104  			for _, req := range tc.clusters {
   105  				if err := k8sclient.Create(ctx, req); err != nil {
   106  					t.Fatalf("Unable to create %q cluster: %v", client.ObjectKeyFromObject(req), err)
   107  				}
   108  			}
   109  
   110  			lst := &kueuealpha.MultiKueueClusterList{}
   111  
   112  			gotListErr := k8sclient.List(ctx, lst, tc.filter)
   113  			if diff := cmp.Diff(tc.wantListError, gotListErr); diff != "" {
   114  				t.Errorf("unexpected list error (-want/+got):\n%s", diff)
   115  			}
   116  
   117  			gotList := slices.Map(lst.Items, func(mkc *kueuealpha.MultiKueueCluster) string { return mkc.Name })
   118  			if diff := cmp.Diff(tc.wantList, gotList, cmpopts.EquateEmpty(), cmpopts.SortSlices(func(a, b string) bool { return a < b })); diff != "" {
   119  				t.Errorf("unexpected list (-want/+got):\n%s", diff)
   120  			}
   121  		})
   122  	}
   123  }
   124  
   125  func TestListMultiKueueConfigsUsingMultiKueueClusters(t *testing.T) {
   126  	cases := map[string]struct {
   127  		configs       []*kueuealpha.MultiKueueConfig
   128  		filter        client.ListOption
   129  		wantListError error
   130  		wantList      []string
   131  	}{
   132  		"no configs": {
   133  			filter: client.MatchingFields{UsingMultiKueueClusters: "cluster1"},
   134  		},
   135  		"single config, single match": {
   136  			configs: []*kueuealpha.MultiKueueConfig{
   137  				utiltesting.MakeMultiKueueConfig("config1").Clusters("cluster1", "cluster2").Obj(),
   138  			},
   139  			filter:   client.MatchingFields{UsingMultiKueueClusters: "cluster2"},
   140  			wantList: []string{"config1"},
   141  		},
   142  		"single config, no match": {
   143  			configs: []*kueuealpha.MultiKueueConfig{
   144  				utiltesting.MakeMultiKueueConfig("config2").Clusters("cluster2").Obj(),
   145  			},
   146  			filter: client.MatchingFields{UsingMultiKueueClusters: "cluster1"},
   147  		},
   148  		"multiple configs, single match": {
   149  			configs: []*kueuealpha.MultiKueueConfig{
   150  				utiltesting.MakeMultiKueueConfig("config1").Clusters("cluster1", "cluster2").Obj(),
   151  				utiltesting.MakeMultiKueueConfig("config2").Clusters("cluster2").Obj(),
   152  			},
   153  			filter:   client.MatchingFields{UsingMultiKueueClusters: "cluster1"},
   154  			wantList: []string{"config1"},
   155  		},
   156  	}
   157  	for name, tc := range cases {
   158  		t.Run(name, func(t *testing.T) {
   159  			builder, ctx := getClientBuilder()
   160  			k8sclient := builder.Build()
   161  			for _, config := range tc.configs {
   162  				if err := k8sclient.Create(ctx, config); err != nil {
   163  					t.Fatalf("Unable to create %q config: %v", client.ObjectKeyFromObject(config), err)
   164  				}
   165  			}
   166  
   167  			lst := &kueuealpha.MultiKueueConfigList{}
   168  
   169  			gotListErr := k8sclient.List(ctx, lst, tc.filter)
   170  			if diff := cmp.Diff(tc.wantListError, gotListErr); diff != "" {
   171  				t.Errorf("unexpected list error (-want/+got):\n%s", diff)
   172  			}
   173  
   174  			gotList := slices.Map(lst.Items, func(mkc *kueuealpha.MultiKueueConfig) string { return mkc.Name })
   175  			if diff := cmp.Diff(tc.wantList, gotList, cmpopts.EquateEmpty(), cmpopts.SortSlices(func(a, b string) bool { return a < b })); diff != "" {
   176  				t.Errorf("unexpected list (-want/+got):\n%s", diff)
   177  			}
   178  		})
   179  	}
   180  }