From ef1d0fdf1d0765ead78791e008050c318c46a494 Mon Sep 17 00:00:00 2001 From: johnniang Date: Wed, 23 Feb 2022 16:03:16 +0800 Subject: [PATCH 1/4] Proxy DevOps APIs with version v1alpha1 Signed-off-by: johnniang --- pkg/apiserver/apiserver.go | 6 +- pkg/kapis/devops/group.go | 17 --- pkg/kapis/devops/{v1alpha2 => }/register.go | 27 ++--- pkg/kapis/devops/register_test.go | 112 ++++++++++++++++++++ pkg/kapis/devops/v1alpha2/OWNERS | 12 --- pkg/kapis/devops/v1alpha3/register.go | 41 ------- tools/cmd/doc-gen/main.go | 6 +- 7 files changed, 130 insertions(+), 91 deletions(-) delete mode 100644 pkg/kapis/devops/group.go rename pkg/kapis/devops/{v1alpha2 => }/register.go (61%) create mode 100644 pkg/kapis/devops/register_test.go delete mode 100644 pkg/kapis/devops/v1alpha2/OWNERS delete mode 100644 pkg/kapis/devops/v1alpha3/register.go diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index a75a662ae..dca47a55e 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -65,8 +65,7 @@ import ( clusterkapisv1alpha1 "kubesphere.io/kubesphere/pkg/kapis/cluster/v1alpha1" configv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/config/v1alpha2" crd "kubesphere.io/kubesphere/pkg/kapis/crd" - devopsv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/devops/v1alpha2" - devopsv1alpha3 "kubesphere.io/kubesphere/pkg/kapis/devops/v1alpha3" + kapisdevops "kubesphere.io/kubesphere/pkg/kapis/devops" edgeruntimev1alpha1 "kubesphere.io/kubesphere/pkg/kapis/edgeruntime/v1alpha1" gatewayv1alpha1 "kubesphere.io/kubesphere/pkg/kapis/gateway/v1alpha1" iamapi "kubesphere.io/kubesphere/pkg/kapis/iam/v1alpha2" @@ -244,8 +243,7 @@ func (s *APIServer) installKubeSphereAPIs() { s.Config.AuthenticationOptions)) urlruntime.Must(servicemeshv1alpha2.AddToContainer(s.Config.ServiceMeshOptions, s.container, s.KubernetesClient.Kubernetes(), s.CacheClient)) urlruntime.Must(networkv1alpha2.AddToContainer(s.container, s.Config.NetworkOptions.WeaveScopeHost)) - urlruntime.Must(devopsv1alpha2.AddToContainer(s.container, s.Config.DevopsOptions.Endpoint)) - urlruntime.Must(devopsv1alpha3.AddToContainer(s.container, s.Config.DevopsOptions.Endpoint)) + urlruntime.Must(kapisdevops.AddToContainer(s.container, s.Config.DevopsOptions.Endpoint)) urlruntime.Must(notificationv1.AddToContainer(s.container, s.Config.NotificationOptions.Endpoint)) urlruntime.Must(alertingv1.AddToContainer(s.container, s.Config.AlertingOptions.Endpoint)) urlruntime.Must(alertingv2alpha1.AddToContainer(s.container, s.InformerFactory, diff --git a/pkg/kapis/devops/group.go b/pkg/kapis/devops/group.go deleted file mode 100644 index 3324fdbdc..000000000 --- a/pkg/kapis/devops/group.go +++ /dev/null @@ -1,17 +0,0 @@ -/* -Copyright 2020 The KubeSphere 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 devops diff --git a/pkg/kapis/devops/v1alpha2/register.go b/pkg/kapis/devops/register.go similarity index 61% rename from pkg/kapis/devops/v1alpha2/register.go rename to pkg/kapis/devops/register.go index 3bc472f9c..c9ed10470 100644 --- a/pkg/kapis/devops/v1alpha2/register.go +++ b/pkg/kapis/devops/register.go @@ -1,5 +1,5 @@ /* -Copyright 2020 The KubeSphere Authors. +Copyright 2022 The KubeSphere Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,26 +14,27 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha2 +package devops import ( "github.com/emicklei/go-restful" - "k8s.io/apimachinery/pkg/runtime/schema" - "kubesphere.io/kubesphere/pkg/kapis/generic" ) -const ( - GroupName = "devops.kubesphere.io" -) +const groupName = "devops.kubesphere.io" -var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"} +var versions = []string{"v1alpha1", "v1alpha2", "v1alpha3"} +// AddToContainer registers DevOps proxies to the container. func AddToContainer(container *restful.Container, endpoint string) error { - proxy, err := generic.NewGenericProxy(endpoint, GroupVersion.Group, GroupVersion.Version) - if err != nil { - return err + for _, version := range versions { + proxy, err := generic.NewGenericProxy(endpoint, groupName, version) + if err != nil { + return err + } + if err = proxy.AddToContainer(container); err != nil { + return err + } } - - return proxy.AddToContainer(container) + return nil } diff --git a/pkg/kapis/devops/register_test.go b/pkg/kapis/devops/register_test.go new file mode 100644 index 000000000..94059db58 --- /dev/null +++ b/pkg/kapis/devops/register_test.go @@ -0,0 +1,112 @@ +/* +Copyright 2022 The KubeSphere 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 devops + +import ( + "github.com/emicklei/go-restful" + "github.com/stretchr/testify/assert" + "net/http" + "net/http/httptest" + "testing" +) + +func TestAddToContainer(t *testing.T) { + fakeResponse := "fake DevOps APIServer response" + type args struct { + target string + mockAPIPattern string + mockResponse string + } + tests := []struct { + name string + args args + wantErr bool + wantResponse string + }{{ + name: "Should proxy v1alpha1 API properly", + args: args{ + target: "/kapis/devops.kubesphere.io/v1alpha1/resources", + mockAPIPattern: "/v1alpha1/resources", + }, + wantResponse: fakeResponse, + }, { + name: "Should proxy v1alpha2 API properly", + args: args{ + target: "/kapis/devops.kubesphere.io/v1alpha2/resources", + mockAPIPattern: "/v1alpha2/resources", + }, + wantResponse: fakeResponse, + }, { + name: "Should proxy v1alpha3 API properly", + args: args{ + target: "/kapis/devops.kubesphere.io/v1alpha3/resources", + mockAPIPattern: "/v1alpha3/resources", + }, + wantResponse: fakeResponse, + }, { + name: "Should return 404 if no pattern matches", + args: args{ + target: "/kapis/devops.kubesphere.io/v1alpha3/resources", + mockAPIPattern: "/v1alpha4/resources", + }, + wantResponse: "404 page not found\n", + }, { + name: "Should not proxy v1alpha123 API properly event if pattern matched", + args: args{ + target: "/kapis/devops.kubesphere.io/v1alpha123/resources", + mockAPIPattern: "/v1alpha123/resources", + }, + wantResponse: "404 page not found\n", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // create a fresh mock DevOps APIServer. + server := mockDevOpsAPIServer(tt.args.mockAPIPattern, 200, tt.args.mockResponse) + defer server.Close() + + // mock to request DevOps API from KubeSphere APIServer + container := restful.NewContainer() + if err := AddToContainer(container, server.URL); (err != nil) != tt.wantErr { + t.Errorf("AddToContainer() error = %v, wantErr %v", err, tt.wantErr) + } + request := httptest.NewRequest(http.MethodGet, tt.args.target, nil) + recorder := &responseRecorder{*httptest.NewRecorder()} + container.ServeHTTP(restful.NewResponse(recorder), request) + + assert.Equal(t, tt.wantResponse, recorder.Body.String()) + }) + } +} + +func mockDevOpsAPIServer(pattern string, fakeCode int, fakeResp string) *httptest.Server { + mux := http.NewServeMux() + mux.HandleFunc(pattern, func(writer http.ResponseWriter, request *http.Request) { + writer.WriteHeader(fakeCode) + _, _ = writer.Write([]byte(fakeResp)) + }) + return httptest.NewServer(mux) +} + +// responseRecorder extends httptest.ResponseRecorder and implements CloseNotifier interface for generic proxy. +type responseRecorder struct { + httptest.ResponseRecorder +} + +func (*responseRecorder) CloseNotify() <-chan bool { + return nil +} diff --git a/pkg/kapis/devops/v1alpha2/OWNERS b/pkg/kapis/devops/v1alpha2/OWNERS deleted file mode 100644 index d616f1051..000000000 --- a/pkg/kapis/devops/v1alpha2/OWNERS +++ /dev/null @@ -1,12 +0,0 @@ -approvers: - - shaowenchen - - linuxsuren - -reviewers: - - runzexia - - soulseen - - shaowenchen - - linuxsuren - -labels: - - area/devops diff --git a/pkg/kapis/devops/v1alpha3/register.go b/pkg/kapis/devops/v1alpha3/register.go deleted file mode 100644 index f496be6ba..000000000 --- a/pkg/kapis/devops/v1alpha3/register.go +++ /dev/null @@ -1,41 +0,0 @@ -/* - - Copyright 2020 The KubeSphere 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 v1alpha3 - -import ( - "github.com/emicklei/go-restful" - "k8s.io/apimachinery/pkg/runtime/schema" - - "kubesphere.io/kubesphere/pkg/kapis/generic" -) - -const ( - GroupName = "devops.kubesphere.io" -) - -var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha3"} - -func AddToContainer(container *restful.Container, endpoint string) error { - proxy, err := generic.NewGenericProxy(endpoint, GroupVersion.Group, GroupVersion.Version) - if err != nil { - return err - } - - return proxy.AddToContainer(container) -} diff --git a/tools/cmd/doc-gen/main.go b/tools/cmd/doc-gen/main.go index 3d1744bf8..f87e8af27 100644 --- a/tools/cmd/doc-gen/main.go +++ b/tools/cmd/doc-gen/main.go @@ -22,6 +22,7 @@ import ( "flag" "fmt" "io/ioutil" + kapisdevops "kubesphere.io/kubesphere/pkg/kapis/devops" "log" "kubesphere.io/kubesphere/pkg/client/clientset/versioned/fake" @@ -43,8 +44,6 @@ import ( "kubesphere.io/kubesphere/pkg/informers" alertingv2alpha1 "kubesphere.io/kubesphere/pkg/kapis/alerting/v2alpha1" clusterkapisv1alpha1 "kubesphere.io/kubesphere/pkg/kapis/cluster/v1alpha1" - devopsv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/devops/v1alpha2" - devopsv1alpha3 "kubesphere.io/kubesphere/pkg/kapis/devops/v1alpha3" iamv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/iam/v1alpha2" monitoringv1alpha3 "kubesphere.io/kubesphere/pkg/kapis/monitoring/v1alpha3" networkv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/network/v1alpha2" @@ -120,8 +119,7 @@ func generateSwaggerJson() []byte { urlruntime.Must(oauth.AddToContainer(container, nil, nil, nil, nil, nil, nil)) urlruntime.Must(clusterkapisv1alpha1.AddToContainer(container, clientsets.KubeSphere(), informerFactory.KubernetesSharedInformerFactory(), informerFactory.KubeSphereSharedInformerFactory(), "", "", "")) - urlruntime.Must(devopsv1alpha2.AddToContainer(container, "")) - urlruntime.Must(devopsv1alpha3.AddToContainer(container, "")) + urlruntime.Must(kapisdevops.AddToContainer(container, "")) urlruntime.Must(iamv1alpha2.AddToContainer(container, nil, nil, group.New(informerFactory, clientsets.KubeSphere(), clientsets.Kubernetes()), nil)) urlruntime.Must(monitoringv1alpha3.AddToContainer(container, clientsets.Kubernetes(), nil, nil, informerFactory, nil, nil, nil)) urlruntime.Must(openpitrixv1.AddToContainer(container, informerFactory, fake.NewSimpleClientset(), nil)) From 35cf45a0b7a8e6b157aacfe4a3f266af869a3e64 Mon Sep 17 00:00:00 2001 From: johnniang Date: Wed, 23 Feb 2022 17:04:11 +0800 Subject: [PATCH 2/4] Fix verification error and failing tests Signed-off-by: johnniang --- pkg/kapis/devops/register.go | 1 + pkg/kapis/devops/register_test.go | 8 ++++++-- tools/cmd/doc-gen/main.go | 3 ++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/pkg/kapis/devops/register.go b/pkg/kapis/devops/register.go index c9ed10470..95ad1fe05 100644 --- a/pkg/kapis/devops/register.go +++ b/pkg/kapis/devops/register.go @@ -18,6 +18,7 @@ package devops import ( "github.com/emicklei/go-restful" + "kubesphere.io/kubesphere/pkg/kapis/generic" ) diff --git a/pkg/kapis/devops/register_test.go b/pkg/kapis/devops/register_test.go index 94059db58..253864fbe 100644 --- a/pkg/kapis/devops/register_test.go +++ b/pkg/kapis/devops/register_test.go @@ -17,11 +17,12 @@ limitations under the License. package devops import ( - "github.com/emicklei/go-restful" - "github.com/stretchr/testify/assert" "net/http" "net/http/httptest" "testing" + + "github.com/emicklei/go-restful" + "github.com/stretchr/testify/assert" ) func TestAddToContainer(t *testing.T) { @@ -41,6 +42,7 @@ func TestAddToContainer(t *testing.T) { args: args{ target: "/kapis/devops.kubesphere.io/v1alpha1/resources", mockAPIPattern: "/v1alpha1/resources", + mockResponse: fakeResponse, }, wantResponse: fakeResponse, }, { @@ -48,6 +50,7 @@ func TestAddToContainer(t *testing.T) { args: args{ target: "/kapis/devops.kubesphere.io/v1alpha2/resources", mockAPIPattern: "/v1alpha2/resources", + mockResponse: fakeResponse, }, wantResponse: fakeResponse, }, { @@ -55,6 +58,7 @@ func TestAddToContainer(t *testing.T) { args: args{ target: "/kapis/devops.kubesphere.io/v1alpha3/resources", mockAPIPattern: "/v1alpha3/resources", + mockResponse: fakeResponse, }, wantResponse: fakeResponse, }, { diff --git a/tools/cmd/doc-gen/main.go b/tools/cmd/doc-gen/main.go index f87e8af27..bbdb37362 100644 --- a/tools/cmd/doc-gen/main.go +++ b/tools/cmd/doc-gen/main.go @@ -22,9 +22,10 @@ import ( "flag" "fmt" "io/ioutil" - kapisdevops "kubesphere.io/kubesphere/pkg/kapis/devops" "log" + kapisdevops "kubesphere.io/kubesphere/pkg/kapis/devops" + "kubesphere.io/kubesphere/pkg/client/clientset/versioned/fake" "kubesphere.io/kubesphere/pkg/version" From 291d35cf937a1d6b22aebe649388bc20178cf25c Mon Sep 17 00:00:00 2001 From: johnniang Date: Thu, 24 Feb 2022 17:31:55 +0800 Subject: [PATCH 3/4] Refactor DevOps API proxy Signed-off-by: johnniang --- pkg/kapis/devops/register.go | 13 ++++++++----- pkg/kapis/devops/register_test.go | 7 ++++--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/pkg/kapis/devops/register.go b/pkg/kapis/devops/register.go index 95ad1fe05..e7adf48ed 100644 --- a/pkg/kapis/devops/register.go +++ b/pkg/kapis/devops/register.go @@ -18,18 +18,21 @@ package devops import ( "github.com/emicklei/go-restful" + "k8s.io/apimachinery/pkg/runtime/schema" "kubesphere.io/kubesphere/pkg/kapis/generic" ) -const groupName = "devops.kubesphere.io" - -var versions = []string{"v1alpha1", "v1alpha2", "v1alpha3"} +var devopsGroupVersions = []schema.GroupVersion{ + {Group: "devops.kubesphere.io", Version: "v1alpha2"}, + {Group: "devops.kubesphere.io", Version: "v1alpha3"}, + // TODO Add other group versions here, like cd.devops.kubesphere.io +} // AddToContainer registers DevOps proxies to the container. func AddToContainer(container *restful.Container, endpoint string) error { - for _, version := range versions { - proxy, err := generic.NewGenericProxy(endpoint, groupName, version) + for _, groupVersion := range devopsGroupVersions { + proxy, err := generic.NewGenericProxy(endpoint, groupVersion.Group, groupVersion.Version) if err != nil { return err } diff --git a/pkg/kapis/devops/register_test.go b/pkg/kapis/devops/register_test.go index 253864fbe..d289d7869 100644 --- a/pkg/kapis/devops/register_test.go +++ b/pkg/kapis/devops/register_test.go @@ -27,6 +27,7 @@ import ( func TestAddToContainer(t *testing.T) { fakeResponse := "fake DevOps APIServer response" + notFoundResponse := "404 page not found\n" type args struct { target string mockAPIPattern string @@ -44,7 +45,7 @@ func TestAddToContainer(t *testing.T) { mockAPIPattern: "/v1alpha1/resources", mockResponse: fakeResponse, }, - wantResponse: fakeResponse, + wantResponse: notFoundResponse, }, { name: "Should proxy v1alpha2 API properly", args: args{ @@ -67,14 +68,14 @@ func TestAddToContainer(t *testing.T) { target: "/kapis/devops.kubesphere.io/v1alpha3/resources", mockAPIPattern: "/v1alpha4/resources", }, - wantResponse: "404 page not found\n", + wantResponse: notFoundResponse, }, { name: "Should not proxy v1alpha123 API properly event if pattern matched", args: args{ target: "/kapis/devops.kubesphere.io/v1alpha123/resources", mockAPIPattern: "/v1alpha123/resources", }, - wantResponse: "404 page not found\n", + wantResponse: notFoundResponse, }, } for _, tt := range tests { From 0e9d30ffe4fa372499f39d2a04a855a1fb3e0021 Mon Sep 17 00:00:00 2001 From: johnniang Date: Mon, 28 Feb 2022 11:06:20 +0800 Subject: [PATCH 4/4] Add gitops.kubesphere.io group proxy --- pkg/kapis/devops/register.go | 8 ++++++- pkg/kapis/devops/register_test.go | 38 ++++++++++++++++++++++--------- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/pkg/kapis/devops/register.go b/pkg/kapis/devops/register.go index e7adf48ed..d40f16b5f 100644 --- a/pkg/kapis/devops/register.go +++ b/pkg/kapis/devops/register.go @@ -17,6 +17,8 @@ limitations under the License. package devops import ( + "strings" + "github.com/emicklei/go-restful" "k8s.io/apimachinery/pkg/runtime/schema" @@ -26,13 +28,17 @@ import ( var devopsGroupVersions = []schema.GroupVersion{ {Group: "devops.kubesphere.io", Version: "v1alpha2"}, {Group: "devops.kubesphere.io", Version: "v1alpha3"}, + {Group: "gitops.kubesphere.io", Version: "v1alpha1"}, // TODO Add other group versions here, like cd.devops.kubesphere.io } // AddToContainer registers DevOps proxies to the container. func AddToContainer(container *restful.Container, endpoint string) error { + endpoint = strings.TrimSuffix(endpoint, "/") for _, groupVersion := range devopsGroupVersions { - proxy, err := generic.NewGenericProxy(endpoint, groupVersion.Group, groupVersion.Version) + // Ensure that we proxy with different group here due to trimming of "/kapis/group_name". + // TODO: We could add a flag to decide to trim "/kapis/group_name" or not when creating a new GenericProxy. + proxy, err := generic.NewGenericProxy(endpoint+"/kapis/"+groupVersion.Group, groupVersion.Group, groupVersion.Version) if err != nil { return err } diff --git a/pkg/kapis/devops/register_test.go b/pkg/kapis/devops/register_test.go index d289d7869..7fa8106dd 100644 --- a/pkg/kapis/devops/register_test.go +++ b/pkg/kapis/devops/register_test.go @@ -39,44 +39,60 @@ func TestAddToContainer(t *testing.T) { wantErr bool wantResponse string }{{ - name: "Should proxy v1alpha1 API properly", + name: "Should proxy devops.kubesphere.io/v1alpha1 API properly", args: args{ target: "/kapis/devops.kubesphere.io/v1alpha1/resources", - mockAPIPattern: "/v1alpha1/resources", + mockAPIPattern: "/kapis/devops.kubesphere.io/v1alpha1/resources", mockResponse: fakeResponse, }, wantResponse: notFoundResponse, }, { - name: "Should proxy v1alpha2 API properly", + name: "Should proxy devops.kubesphere.io/v1alpha2 API properly", args: args{ target: "/kapis/devops.kubesphere.io/v1alpha2/resources", - mockAPIPattern: "/v1alpha2/resources", + mockAPIPattern: "/kapis/devops.kubesphere.io/v1alpha2/resources", mockResponse: fakeResponse, }, wantResponse: fakeResponse, }, { - name: "Should proxy v1alpha3 API properly", + name: "Should proxy devops.kubesphere.io/v1alpha3 API properly", args: args{ target: "/kapis/devops.kubesphere.io/v1alpha3/resources", - mockAPIPattern: "/v1alpha3/resources", + mockAPIPattern: "/kapis/devops.kubesphere.io/v1alpha3/resources", mockResponse: fakeResponse, }, wantResponse: fakeResponse, }, { - name: "Should return 404 if no pattern matches", + name: "Should proxy gitops.kubesphere.io/v1alpha1 API properly", + args: args{ + target: "/kapis/gitops.kubesphere.io/v1alpha1/resources", + mockAPIPattern: "/kapis/gitops.kubesphere.io/v1alpha1/resources", + mockResponse: fakeResponse, + }, + wantResponse: fakeResponse, + }, { + name: "Should return 404 if versions miss match", args: args{ target: "/kapis/devops.kubesphere.io/v1alpha3/resources", - mockAPIPattern: "/v1alpha4/resources", + mockAPIPattern: "/kapis/devops.kubesphere.io/v1alpha1/resources", }, wantResponse: notFoundResponse, }, { - name: "Should not proxy v1alpha123 API properly event if pattern matched", + name: "Should return 404 if groups miss match", args: args{ - target: "/kapis/devops.kubesphere.io/v1alpha123/resources", - mockAPIPattern: "/v1alpha123/resources", + target: "/kapis/devops.kubesphere.io/v1alpha3/resources", + mockAPIPattern: "/kapis/gitops.kubesphere.io/v1alpha3/resources", }, wantResponse: notFoundResponse, }, + { + name: "Should not proxy v1alpha123 API properly event if pattern matched", + args: args{ + target: "/kapis/devops.kubesphere.io/v1alpha123/resources", + mockAPIPattern: "/kapis/devops.kubesphere.io/v1alpha123/resources", + }, + wantResponse: notFoundResponse, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {