From 348189e9115233d9f1a09c442c2def6c221c8cee Mon Sep 17 00:00:00 2001 From: rongxin Date: Wed, 18 Jun 2025 08:17:01 +0800 Subject: [PATCH] fix: consumer test for apisix-stanalone --- Dockerfile.dev | 2 +- api/adc/types.go | 10 +- api/adc/zz_generated.deepcopy.go | 8 +- internal/provider/adc/translator/consumer.go | 3 +- test/e2e/api7/gatewayproxy.go | 267 +++++++++++++++++++ test/e2e/crds/consumer.go | 2 +- test/e2e/e2e_test.go | 1 + 7 files changed, 278 insertions(+), 15 deletions(-) create mode 100644 test/e2e/api7/gatewayproxy.go diff --git a/Dockerfile.dev b/Dockerfile.dev index f06154106..bb0708ed3 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -8,7 +8,7 @@ WORKDIR /app RUN apt update \ && apt install -y git \ - && git clone --branch main https://github.com/api7/adc.git \ + && git clone --depth 1 --branch main https://github.com/api7/adc.git \ && cd adc \ && corepack enable pnpm \ && pnpm install \ diff --git a/api/adc/types.go b/api/adc/types.go index d9b0dab6a..211fa6006 100644 --- a/api/adc/types.go +++ b/api/adc/types.go @@ -128,11 +128,11 @@ type ConsumerGroup struct { // +k8s:deepcopy-gen=true type Consumer struct { - Credentials []Credential `json:"credentials,omitempty" yaml:"credentials,omitempty"` - Description string `json:"description,omitempty" yaml:"description,omitempty"` - Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"` - Plugins Plugins `json:"plugins,omitempty" yaml:"plugins,omitempty"` - Username string `json:"username" yaml:"username"` + Metadata `json:",inline" yaml:",inline"` + + Credentials []Credential `json:"credentials,omitempty" yaml:"credentials,omitempty"` + Plugins Plugins `json:"plugins,omitempty" yaml:"plugins,omitempty"` + Username string `json:"username" yaml:"username"` } // +k8s:deepcopy-gen=true diff --git a/api/adc/zz_generated.deepcopy.go b/api/adc/zz_generated.deepcopy.go index 8051a98bc..bd9250957 100644 --- a/api/adc/zz_generated.deepcopy.go +++ b/api/adc/zz_generated.deepcopy.go @@ -65,6 +65,7 @@ func (in *ClientClass) DeepCopy() *ClientClass { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Consumer) DeepCopyInto(out *Consumer) { *out = *in + in.Metadata.DeepCopyInto(&out.Metadata) if in.Credentials != nil { in, out := &in.Credentials, &out.Credentials *out = make([]Credential, len(*in)) @@ -72,13 +73,6 @@ func (in *Consumer) DeepCopyInto(out *Consumer) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - if in.Labels != nil { - in, out := &in.Labels, &out.Labels - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } out.Plugins = in.Plugins.DeepCopy() } diff --git a/internal/provider/adc/translator/consumer.go b/internal/provider/adc/translator/consumer.go index 2b5cb9641..fd1a4907b 100644 --- a/internal/provider/adc/translator/consumer.go +++ b/internal/provider/adc/translator/consumer.go @@ -19,6 +19,7 @@ import ( adctypes "github.com/apache/apisix-ingress-controller/api/adc" "github.com/apache/apisix-ingress-controller/api/v1alpha1" + "github.com/apache/apisix-ingress-controller/internal/controller/label" "github.com/apache/apisix-ingress-controller/internal/provider" ) @@ -65,7 +66,7 @@ func (t *Translator) TranslateConsumerV1alpha1(tctx *provider.TranslateContext, credentials = append(credentials, credential) } consumer.Credentials = credentials - + consumer.Labels = label.GenLabel(consumerV) plugins := adctypes.Plugins{} for _, plugin := range consumerV.Spec.Plugins { pluginName := plugin.Name diff --git a/test/e2e/api7/gatewayproxy.go b/test/e2e/api7/gatewayproxy.go new file mode 100644 index 000000000..6e589d9ad --- /dev/null +++ b/test/e2e/api7/gatewayproxy.go @@ -0,0 +1,267 @@ +// 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 gatewayapi + +import ( + "fmt" + "net/http" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "github.com/apache/apisix-ingress-controller/test/e2e/scaffold" +) + +var _ = Describe("Test GatewayProxy", func() { + s := scaffold.NewDefaultScaffold() + + var defaultGatewayClass = ` +apiVersion: gateway.networking.k8s.io/v1 +kind: GatewayClass +metadata: + name: %s +spec: + controllerName: %s +` + + var gatewayWithProxy = ` +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: apisix +spec: + gatewayClassName: %s + listeners: + - name: http + protocol: HTTP + port: 80 + infrastructure: + parametersRef: + group: apisix.apache.org + kind: GatewayProxy + name: apisix-proxy-config +` + + var gatewayProxyWithEnabledPlugin = ` +apiVersion: apisix.apache.org/v1alpha1 +kind: GatewayProxy +metadata: + name: apisix-proxy-config +spec: + provider: + type: ControlPlane + controlPlane: + endpoints: + - %s + auth: + type: AdminKey + adminKey: + value: "%s" + plugins: + - name: response-rewrite + enabled: true + config: + headers: + X-Proxy-Test: "enabled" +` + var ( + gatewayProxyWithPluginMetadata0 = ` +apiVersion: apisix.apache.org/v1alpha1 +kind: GatewayProxy +metadata: + name: apisix-proxy-config +spec: + provider: + type: ControlPlane + controlPlane: + endpoints: + - %s + auth: + type: AdminKey + adminKey: + value: "%s" + plugins: + - name: error-page + enabled: true + config: {} + pluginMetadata: + error-page: { + "enable": true, + "error_404": { + "body": "404 from plugin metadata", + "content-type": "text/plain" + } + } +` + gatewayProxyWithPluginMetadata1 = ` +apiVersion: apisix.apache.org/v1alpha1 +kind: GatewayProxy +metadata: + name: apisix-proxy-config +spec: + provider: + type: ControlPlane + controlPlane: + endpoints: + - %s + auth: + type: AdminKey + adminKey: + value: "%s" + plugins: + - name: error-page + enabled: true + config: {} + pluginMetadata: + error-page: { + "enable": false, + "error_404": { + "body": "404 from plugin metadata", + "content-type": "text/plain" + } + } +` + ) + + var httpRouteForTest = ` +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: test-route +spec: + parentRefs: + - name: %s + hostnames: + - example.com + rules: + - matches: + - path: + type: Exact + value: /get + backendRefs: + - name: httpbin-service-e2e-test + port: 80 +` + + var resourceApplied = func(resourceType, resourceName, resourceRaw string, observedGeneration int) { + Expect(s.CreateResourceFromString(resourceRaw)). + NotTo(HaveOccurred(), fmt.Sprintf("creating %s", resourceType)) + + Eventually(func() string { + hryaml, err := s.GetResourceYaml(resourceType, resourceName) + Expect(err).NotTo(HaveOccurred(), fmt.Sprintf("getting %s yaml", resourceType)) + return hryaml + }).WithTimeout(8*time.Second).ProbeEvery(2*time.Second). + Should( + SatisfyAll( + ContainSubstring(`status: "True"`), + ContainSubstring(fmt.Sprintf("observedGeneration: %d", observedGeneration)), + ), + fmt.Sprintf("checking %s condition status", resourceType), + ) + time.Sleep(3 * time.Second) + } + + var ( + gatewayClassName string + ) + + BeforeEach(func() { + By("Create GatewayClass") + gatewayClassName = fmt.Sprintf("apisix-%d", time.Now().Unix()) + err := s.CreateResourceFromStringWithNamespace(fmt.Sprintf(defaultGatewayClass, gatewayClassName, s.GetControllerName()), "") + Expect(err).NotTo(HaveOccurred(), "creating GatewayClass") + time.Sleep(5 * time.Second) + + By("Check GatewayClass condition") + gcYaml, err := s.GetResourceYaml("GatewayClass", gatewayClassName) + Expect(err).NotTo(HaveOccurred(), "getting GatewayClass yaml") + Expect(gcYaml).To(ContainSubstring(`status: "True"`), "checking GatewayClass condition status") + Expect(gcYaml).To(ContainSubstring("message: the gatewayclass has been accepted by the apisix-ingress-controller"), "checking GatewayClass condition message") + + By("Create GatewayProxy with enabled plugin") + err = s.CreateResourceFromString(fmt.Sprintf(gatewayProxyWithEnabledPlugin, s.Deployer.GetAdminEndpoint(), s.AdminKey())) + Expect(err).NotTo(HaveOccurred(), "creating GatewayProxy with enabled plugin") + time.Sleep(5 * time.Second) + + By("Create Gateway with GatewayProxy") + err = s.CreateResourceFromStringWithNamespace(fmt.Sprintf(gatewayWithProxy, gatewayClassName), s.Namespace()) + Expect(err).NotTo(HaveOccurred(), "creating Gateway with GatewayProxy") + time.Sleep(5 * time.Second) + + By("check Gateway condition") + gwyaml, err := s.GetResourceYaml("Gateway", "apisix") + Expect(err).NotTo(HaveOccurred(), "getting Gateway yaml") + Expect(gwyaml).To(ContainSubstring(`status: "True"`), "checking Gateway condition status") + Expect(gwyaml).To(ContainSubstring("message: the gateway has been accepted by the apisix-ingress-controller"), "checking Gateway condition message") + }) + + AfterEach(func() { + By("Clean up resources") + _ = s.DeleteResourceFromString(fmt.Sprintf(httpRouteForTest, "apisix")) + _ = s.DeleteResourceFromString(fmt.Sprintf(gatewayWithProxy, gatewayClassName)) + _ = s.DeleteResourceFromString(fmt.Sprintf(gatewayProxyWithEnabledPlugin, s.Deployer.GetAdminEndpoint(), s.AdminKey())) + }) + + Context("Test Gateway with PluginMetadata", func() { + var ( + err error + ) + + PIt("Should work OK with error-page", func() { + By("Update GatewayProxy with PluginMetadata") + err = s.CreateResourceFromString(fmt.Sprintf(gatewayProxyWithPluginMetadata0, s.Deployer.GetAdminEndpoint(), s.AdminKey())) + Expect(err).ShouldNot(HaveOccurred()) + time.Sleep(5 * time.Second) + + By("Create HTTPRoute for Gateway with GatewayProxy") + resourceApplied("HTTPRoute", "test-route", fmt.Sprintf(httpRouteForTest, "apisix"), 1) + + time.Sleep(5 * time.Second) + By("Check PluginMetadata working") + s.NewAPISIXClient(). + GET("/not-found"). + WithHost("example.com"). + Expect(). + Status(http.StatusNotFound). + Body().Contains("404 from plugin metadata") + + By("Update GatewayProxy with PluginMetadata") + err = s.CreateResourceFromString(fmt.Sprintf(gatewayProxyWithPluginMetadata1, s.Deployer.GetAdminEndpoint(), s.AdminKey())) + Expect(err).ShouldNot(HaveOccurred()) + time.Sleep(5 * time.Second) + + By("Check PluginMetadata working") + s.NewAPISIXClient(). + GET("/not-found"). + WithHost("example.com"). + Expect(). + Status(http.StatusNotFound). + Body().Contains(`{"error_msg":"404 Route Not Found"}`) + + By("Delete GatewayProxy") + err = s.DeleteResourceFromString(fmt.Sprintf(gatewayProxyWithPluginMetadata0, s.Deployer.GetAdminEndpoint(), s.AdminKey())) + Expect(err).ShouldNot(HaveOccurred()) + time.Sleep(5 * time.Second) + + By("Check PluginMetadata is not working") + s.NewAPISIXClient(). + GET("/not-found"). + WithHost("example.com"). + Expect(). + Status(http.StatusNotFound). + Body().Contains(`{"error_msg":"404 Route Not Found"}`) + }) + }) +}) diff --git a/test/e2e/crds/consumer.go b/test/e2e/crds/consumer.go index f87abb9a4..ae060e3fb 100644 --- a/test/e2e/crds/consumer.go +++ b/test/e2e/crds/consumer.go @@ -23,7 +23,7 @@ import ( "github.com/apache/apisix-ingress-controller/test/e2e/scaffold" ) -var _ = PDescribe("Test Consumer", func() { +var _ = Describe("Test Consumer", func() { s := scaffold.NewDefaultScaffold() var defaultGatewayProxy = ` diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index ae1503e4b..c756d75e2 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -19,6 +19,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + _ "github.com/apache/apisix-ingress-controller/test/e2e/api7" _ "github.com/apache/apisix-ingress-controller/test/e2e/crds" "github.com/apache/apisix-ingress-controller/test/e2e/framework" _ "github.com/apache/apisix-ingress-controller/test/e2e/gatewayapi"