diff --git a/pkg/controller/storageversionmigrator/resourceversion.go b/pkg/controller/storageversionmigrator/resourceversion.go index 7ce40ba4113..f872038c360 100644 --- a/pkg/controller/storageversionmigrator/resourceversion.go +++ b/pkg/controller/storageversionmigrator/resourceversion.go @@ -50,7 +50,7 @@ const ( // to the SVM status before the migration is initiated. This resource version is utilized for checking // freshness of GC cache before the migration is initiated. type ResourceVersionController struct { - discoveryClient *discovery.DiscoveryClient + discoveryClient discovery.DiscoveryInterface metadataClient metadata.Interface svmListers svmlisters.StorageVersionMigrationLister svmSynced cache.InformerSynced @@ -62,7 +62,7 @@ type ResourceVersionController struct { func NewResourceVersionController( ctx context.Context, kubeClient clientset.Interface, - discoveryClient *discovery.DiscoveryClient, + discoveryClient discovery.DiscoveryInterface, metadataClient metadata.Interface, svmInformer svminformers.StorageVersionMigrationInformer, mapper meta.ResettableRESTMapper, diff --git a/pkg/controller/storageversionmigrator/storageversionmigrator.go b/pkg/controller/storageversionmigrator/storageversionmigrator.go index 0dfbee995c2..937d31f17a3 100644 --- a/pkg/controller/storageversionmigrator/storageversionmigrator.go +++ b/pkg/controller/storageversionmigrator/storageversionmigrator.go @@ -56,7 +56,7 @@ type SVMController struct { controllerName string kubeClient kubernetes.Interface dynamicClient *dynamic.DynamicClient - discoveryClient *discovery.DiscoveryClient + discoveryClient discovery.DiscoveryInterface svmListers svmlisters.StorageVersionMigrationLister svmSynced cache.InformerSynced queue workqueue.TypedRateLimitingInterface[string] @@ -68,7 +68,7 @@ func NewSVMController( ctx context.Context, kubeClient kubernetes.Interface, dynamicClient *dynamic.DynamicClient, - discoveryClient *discovery.DiscoveryClient, + discoveryClient discovery.DiscoveryInterface, svmInformer svminformers.StorageVersionMigrationInformer, controllerName string, mapper meta.ResettableRESTMapper, @@ -368,7 +368,7 @@ func (sv *SVMController) isResourceUpdatable(gvr schema.GroupVersionResource) (b if resource.Verbs != nil && sets.NewString(resource.Verbs...).Has("update") { return true, nil } - return false, fmt.Errorf("resource %q does not support update verb", gvr.String()) + return false, nil } } diff --git a/pkg/controller/storageversionmigrator/storageversionmigrator_test.go b/pkg/controller/storageversionmigrator/storageversionmigrator_test.go new file mode 100644 index 00000000000..a20e2a310d7 --- /dev/null +++ b/pkg/controller/storageversionmigrator/storageversionmigrator_test.go @@ -0,0 +1,105 @@ +/* +Copyright 2025 The Kubernetes 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 storageversionmigrator + +import ( + "net/http" + "net/http/httptest" + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + fakediscovery "k8s.io/client-go/discovery/fake" + kubetesting "k8s.io/client-go/testing" +) + +func TestIsResourceUpdatable(t *testing.T) { + tcs := []struct { + name string + resources []*metav1.APIResourceList + resource schema.GroupVersionResource + want bool + wantErr bool + }{ + { + name: "updatable resource", + resources: []*metav1.APIResourceList{ + { + GroupVersion: "v1", + APIResources: []metav1.APIResource{ + {Name: "pods", Namespaced: true, Kind: "Pod", Verbs: []string{"get", "list", "watch", "create", "update", "patch", "delete"}}, + {Name: "events", Namespaced: true, Kind: "Event", Verbs: []string{"get", "list", "watch", "create", "delete"}}, + }, + }, + }, + resource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}, + want: true, + }, + { + name: "non-updatable resource", + resources: []*metav1.APIResourceList{ + { + GroupVersion: "v1", + APIResources: []metav1.APIResource{ + {Name: "pods", Namespaced: true, Kind: "Pod", Verbs: []string{"get", "list", "watch", "create", "update", "patch", "delete"}}, + {Name: "events", Namespaced: true, Kind: "Event", Verbs: []string{"get", "list", "watch", "create", "delete"}}, + }, + }, + }, + resource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "events"}, + want: false, + }, + { + name: "unknown resource", + resources: []*metav1.APIResourceList{ + { + GroupVersion: "v1", + APIResources: []metav1.APIResource{ + {Name: "pods", Namespaced: true, Kind: "Pod", Verbs: []string{"get", "list", "watch", "create", "update", "patch", "delete"}}, + {Name: "events", Namespaced: true, Kind: "Event", Verbs: []string{"get", "list", "watch", "create", "delete"}}, + }, + }, + }, + resource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "foo"}, + wantErr: true, + }, + } + + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {})) + defer server.Close() + discoveryClient := fakediscovery.FakeDiscovery{Fake: &kubetesting.Fake{}} + discoveryClient.Resources = tc.resources + svmController := &SVMController{ + discoveryClient: &discoveryClient, + } + + isUpdatable, err := svmController.isResourceUpdatable(tc.resource) + if err != nil { + if !tc.wantErr { + t.Errorf("Unexpected error: %v", err) + } + return + } + if isUpdatable != tc.want { + t.Errorf("Expected %v, got %v", tc.want, isUpdatable) + } + }) + } + +}