From 4f20691a23260450ae1de5bce105d773a1ab60a9 Mon Sep 17 00:00:00 2001 From: Alex Zhang Date: Mon, 29 Mar 2021 17:08:44 +0800 Subject: [PATCH 1/5] test: add e2e test cases for redirect and fault-injection plugins --- pkg/kube/apisix/apis/config/v2alpha1/types.go | 2 +- pkg/seven/state/solver.go | 15 ++ test/e2e/README.md | 12 +- test/e2e/e2e.go | 1 + test/e2e/plugins/fault_injection.go | 175 ++++++++++++++++++ test/e2e/plugins/redirect.go | 152 +++++++++++++++ test/e2e/scaffold/scaffold.go | 3 + 7 files changed, 358 insertions(+), 2 deletions(-) create mode 100644 test/e2e/plugins/fault_injection.go create mode 100644 test/e2e/plugins/redirect.go diff --git a/pkg/kube/apisix/apis/config/v2alpha1/types.go b/pkg/kube/apisix/apis/config/v2alpha1/types.go index 303bd04aa6..5b7de57b43 100644 --- a/pkg/kube/apisix/apis/config/v2alpha1/types.go +++ b/pkg/kube/apisix/apis/config/v2alpha1/types.go @@ -174,7 +174,7 @@ type ApisixRouteHTTPPlugin struct { Enable bool `json:"enable" yaml:"enable"` // Plugin configuration. // TODO we may use protobuf to define it. - Config ApisixRouteHTTPPluginConfig + Config ApisixRouteHTTPPluginConfig `json:"config" yaml:"enable"` } // ApisixRouteHTTPPluginConfig is the configuration for diff --git a/pkg/seven/state/solver.go b/pkg/seven/state/solver.go index 7d4974643c..4b3105b8a9 100644 --- a/pkg/seven/state/solver.go +++ b/pkg/seven/state/solver.go @@ -1,3 +1,18 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You 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. + // Licensed to the Apache Software Foundation (ASF) under one or more // contributor license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright ownership. diff --git a/test/e2e/README.md b/test/e2e/README.md index 5f508a87c3..bc35f93050 100644 --- a/test/e2e/README.md +++ b/test/e2e/README.md @@ -20,7 +20,7 @@ apisix ingress controller e2e test suites ========================================= -For running e2e test cases, a Kubernetes cluster is needed, [minikube](https://minikube.sigs.k8s.io/docs/start/) is a good choice to build k8s cluster in development environment. +For running e2e test cases, a Kubernetes cluster is required, [minikube](https://minikube.sigs.k8s.io/docs/start/) is a good choice to build k8s cluster in development environment. Scaffold --------- @@ -34,3 +34,13 @@ a e2e test scaffold is prepared to run test cases easily. The source codes are i * Create a http server with [kennethreitz/httpbin](https://hub.docker.com/r/kennethreitz/httpbin/) as the upstream. The above mentioned steps are run before each case starts and all resources will be destroyed after the case finishes. + +Plugins +------- + +Test cases inside `plugins` directory test the availability about APISIX plugins. + +Features +-------- + +Test caes inside `features` directory test some features about APISIX, such as traffic-split, health check and so on. diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go index 8c5052d124..d2ea114a3e 100644 --- a/test/e2e/e2e.go +++ b/test/e2e/e2e.go @@ -18,6 +18,7 @@ import ( _ "github.com/apache/apisix-ingress-controller/test/e2e/endpoints" _ "github.com/apache/apisix-ingress-controller/test/e2e/features" _ "github.com/apache/apisix-ingress-controller/test/e2e/ingress" + _ "github.com/apache/apisix-ingress-controller/test/e2e/plugins" ) func runE2E() {} diff --git a/test/e2e/plugins/fault_injection.go b/test/e2e/plugins/fault_injection.go new file mode 100644 index 0000000000..6dd3b52a36 --- /dev/null +++ b/test/e2e/plugins/fault_injection.go @@ -0,0 +1,175 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You 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 plugins + +import ( + "fmt" + "net/http" + "time" + + "github.com/apache/apisix-ingress-controller/test/e2e/scaffold" + "github.com/onsi/ginkgo" + "github.com/stretchr/testify/assert" +) + +var _ = ginkgo.Describe("fault-injection plugin", func() { + opts := &scaffold.Options{ + Name: "default", + Kubeconfig: scaffold.GetKubeconfig(), + APISIXConfigPath: "testdata/apisix-gw-config.yaml", + APISIXDefaultConfigPath: "testdata/apisix-gw-config-default.yaml", + IngressAPISIXReplicas: 1, + HTTPBinServicePort: 80, + APISIXRouteVersion: "apisix.apache.org/v2alpha1", + } + s := scaffold.NewScaffold(opts) + ginkgo.It("inject code and body to abort request", func() { + backendSvc, backendPorts := s.DefaultHTTPBackend() + ar := fmt.Sprintf(` +apiVersion: apisix.apache.org/v2alpha1 +kind: ApisixRoute +metadata: + name: httpbin-route +spec: + http: + - name: rule1 + match: + hosts: + - httpbin.org + paths: + - /ip + backends: + - serviceName: %s + servicePort: %d + weight: 10 + plugins: + - name: fault-injection + enable: true + config: + abort: + http_status: 500 + body: "internal server error" + vars: + - [ ["http_x_foo", "==", "bar"], ["arg_name", "==", "bob"] ] +`, backendSvc, backendPorts[0]) + + assert.Nil(ginkgo.GinkgoT(), s.CreateResourceFromString(ar)) + + err := s.EnsureNumApisixUpstreamsCreated(1) + assert.Nil(ginkgo.GinkgoT(), err, "Checking number of upstreams") + err = s.EnsureNumApisixRoutesCreated(1) + assert.Nil(ginkgo.GinkgoT(), err, "Checking number of routes") + + // vars unsatisfied + resp := s.NewAPISIXClient().GET("/ip").WithHeader("Host", "httpbin.org").Expect() + resp.Status(http.StatusOK) + + resp = s.NewAPISIXClient().GET("/ip").WithQuery("name", "bob").WithHeader("Host", "httpbin.org").WithHeader("X-Foo", "bar").Expect() + resp.Status(http.StatusInternalServerError) + resp.Body().Equal("internal server error") + }) + + ginkgo.It("delay request", func() { + backendSvc, backendPorts := s.DefaultHTTPBackend() + ar := fmt.Sprintf(` +apiVersion: apisix.apache.org/v2alpha1 +kind: ApisixRoute +metadata: + name: httpbin-route +spec: + http: + - name: rule1 + match: + hosts: + - httpbin.org + paths: + - /ip + backends: + - serviceName: %s + servicePort: %d + weight: 10 + plugins: + - name: fault-injection + enable: true + config: + delay: + duration: 3 + vars: + - [ ["http_x_foo", "==", "bar"], ["arg_name", "==", "bob"] ] +`, backendSvc, backendPorts[0]) + + assert.Nil(ginkgo.GinkgoT(), s.CreateResourceFromString(ar)) + + err := s.EnsureNumApisixUpstreamsCreated(1) + assert.Nil(ginkgo.GinkgoT(), err, "Checking number of upstreams") + err = s.EnsureNumApisixRoutesCreated(1) + assert.Nil(ginkgo.GinkgoT(), err, "Checking number of routes") + + // vars unsatisfied + resp := s.NewAPISIXClient().GET("/ip").WithHeader("Host", "httpbin.org").Expect() + resp.Status(http.StatusOK) + + now := time.Now() + resp = s.NewAPISIXClient().GET("/ip").WithQuery("name", "bob").WithHeader("Host", "httpbin.org").WithHeader("X-Foo", "bar").Expect() + resp.Status(http.StatusOK) + assert.Less(ginkgo.GinkgoT(), float64((3 * time.Second).Nanoseconds()), float64(time.Since(now).Nanoseconds())) + }) + + ginkgo.It("disable plugin", func() { + backendSvc, backendPorts := s.DefaultHTTPBackend() + + ar := fmt.Sprintf(` +apiVersion: apisix.apache.org/v2alpha1 +kind: ApisixRoute +metadata: + name: httpbin-route +spec: + http: + - name: rule1 + match: + hosts: + - httpbin.org + paths: + - /ip + backends: + - serviceName: %s + servicePort: %d + weight: 10 + plugins: + - name: fault-injection + enable: false + config: + abort: + http_status: 500 + body: "internal server error" + vars: + - [ ["http_x_foo", "==", "bar"], ["arg_name", "==", "bob"] ] +`, backendSvc, backendPorts[0]) + + assert.Nil(ginkgo.GinkgoT(), s.CreateResourceFromString(ar)) + + err := s.EnsureNumApisixUpstreamsCreated(1) + assert.Nil(ginkgo.GinkgoT(), err, "Checking number of upstreams") + err = s.EnsureNumApisixRoutesCreated(1) + assert.Nil(ginkgo.GinkgoT(), err, "Checking number of routes") + + // vars unsatisfied + resp := s.NewAPISIXClient().GET("/ip").WithHeader("Host", "httpbin.org").Expect() + resp.Status(http.StatusOK) + + resp = s.NewAPISIXClient().GET("/ip").WithQuery("name", "bob").WithHeader("Host", "httpbin.org").WithHeader("X-Foo", "bar").Expect() + resp.Status(http.StatusOK) + }) +}) diff --git a/test/e2e/plugins/redirect.go b/test/e2e/plugins/redirect.go new file mode 100644 index 0000000000..8d432a8b30 --- /dev/null +++ b/test/e2e/plugins/redirect.go @@ -0,0 +1,152 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You 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 plugins + +import ( + "fmt" + "net/http" + + "github.com/stretchr/testify/assert" + + "github.com/onsi/ginkgo" + + "github.com/apache/apisix-ingress-controller/test/e2e/scaffold" +) + +var _ = ginkgo.Describe("redirect plugin", func() { + opts := &scaffold.Options{ + Name: "default", + Kubeconfig: scaffold.GetKubeconfig(), + APISIXConfigPath: "testdata/apisix-gw-config.yaml", + APISIXDefaultConfigPath: "testdata/apisix-gw-config-default.yaml", + IngressAPISIXReplicas: 1, + HTTPBinServicePort: 80, + APISIXRouteVersion: "apisix.apache.org/v2alpha1", + } + s := scaffold.NewScaffold(opts) + ginkgo.It("http_to_https", func() { + backendSvc, backendPorts := s.DefaultHTTPBackend() + ar := fmt.Sprintf(` +apiVersion: apisix.apache.org/v2alpha1 +kind: ApisixRoute +metadata: + name: httpbin-route +spec: + http: + - name: rule1 + match: + hosts: + - httpbin.org + paths: + - /ip + backends: + - serviceName: %s + servicePort: %d + weight: 10 + plugins: + - name: redirect + enable: true + config: + http_to_https: true +`, backendSvc, backendPorts[0]) + + assert.Nil(ginkgo.GinkgoT(), s.CreateResourceFromString(ar)) + + err := s.EnsureNumApisixUpstreamsCreated(1) + assert.Nil(ginkgo.GinkgoT(), err, "Checking number of upstreams") + err = s.EnsureNumApisixRoutesCreated(1) + assert.Nil(ginkgo.GinkgoT(), err, "Checking number of routes") + + resp := s.NewAPISIXClient().GET("/ip").WithHeader("Host", "httpbin.org").Expect() + resp.Status(http.StatusMovedPermanently) + resp.Header("Location").Equal("https://httpbin.org/ip") + }) + ginkgo.It("redirect to specific uri", func() { + backendSvc, backendPorts := s.DefaultHTTPBackend() + ar := fmt.Sprintf(` +apiVersion: apisix.apache.org/v2alpha1 +kind: ApisixRoute +metadata: + name: httpbin-route +spec: + http: + - name: rule1 + match: + hosts: + - httpbin.org + paths: + - /ip + backends: + - serviceName: %s + servicePort: %d + weight: 10 + plugins: + - name: redirect + enable: true + config: + uri: "$uri/ipip" + ret_code: 308 +`, backendSvc, backendPorts[0]) + + assert.Nil(ginkgo.GinkgoT(), s.CreateResourceFromString(ar)) + + err := s.EnsureNumApisixUpstreamsCreated(1) + assert.Nil(ginkgo.GinkgoT(), err, "Checking number of upstreams") + err = s.EnsureNumApisixRoutesCreated(1) + assert.Nil(ginkgo.GinkgoT(), err, "Checking number of routes") + + resp := s.NewAPISIXClient().GET("/ip").WithHeader("Host", "httpbin.org").Expect() + resp.Status(http.StatusPermanentRedirect) + resp.Header("Location").Equal("/ip/ipip") + }) + ginkgo.It("disable plugin", func() { + backendSvc, backendPorts := s.DefaultHTTPBackend() + ar := fmt.Sprintf(` +apiVersion: apisix.apache.org/v2alpha1 +kind: ApisixRoute +metadata: + name: httpbin-route +spec: + http: + - name: rule1 + match: + hosts: + - httpbin.org + paths: + - /ip + backends: + - serviceName: %s + servicePort: %d + weight: 10 + plugins: + - name: redirect + enable: false + config: + http_to_https: true + uri: "$uri/ipip" + ret_code: 308 +`, backendSvc, backendPorts[0]) + + assert.Nil(ginkgo.GinkgoT(), s.CreateResourceFromString(ar)) + + err := s.EnsureNumApisixUpstreamsCreated(1) + assert.Nil(ginkgo.GinkgoT(), err, "Checking number of upstreams") + err = s.EnsureNumApisixRoutesCreated(1) + assert.Nil(ginkgo.GinkgoT(), err, "Checking number of routes") + + resp := s.NewAPISIXClient().GET("/ip").WithHeader("Host", "httpbin.org").Expect() + resp.Status(http.StatusOK) + }) +}) diff --git a/test/e2e/scaffold/scaffold.go b/test/e2e/scaffold/scaffold.go index ed2979a2ed..7a9da7e6ef 100644 --- a/test/e2e/scaffold/scaffold.go +++ b/test/e2e/scaffold/scaffold.go @@ -154,6 +154,9 @@ func (s *Scaffold) NewAPISIXClient() *httpexpect.Expect { BaseURL: u.String(), Client: &http.Client{ Transport: &http.Transport{}, + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, }, Reporter: httpexpect.NewAssertReporter( httpexpect.NewAssertReporter(ginkgo.GinkgoT()), From 2486c0f5cce43c3554d61b88f2aa97db35e6c70c Mon Sep 17 00:00:00 2001 From: Alex Zhang Date: Mon, 29 Mar 2021 17:10:51 +0800 Subject: [PATCH 2/5] fix --- pkg/seven/state/solver.go | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/pkg/seven/state/solver.go b/pkg/seven/state/solver.go index 4b3105b8a9..7d4974643c 100644 --- a/pkg/seven/state/solver.go +++ b/pkg/seven/state/solver.go @@ -1,18 +1,3 @@ -// Licensed to the Apache Software Foundation (ASF) under one or more -// contributor license agreements. See the NOTICE file distributed with -// this work for additional information regarding copyright ownership. -// The ASF licenses this file to You 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. - // Licensed to the Apache Software Foundation (ASF) under one or more // contributor license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright ownership. From 11f81d1ecad4f7740952d250bd7d17d5f11d1504 Mon Sep 17 00:00:00 2001 From: Alex Zhang Date: Mon, 29 Mar 2021 17:31:54 +0800 Subject: [PATCH 3/5] fix --- test/e2e/plugins/redirect.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/e2e/plugins/redirect.go b/test/e2e/plugins/redirect.go index 8d432a8b30..cb094d0078 100644 --- a/test/e2e/plugins/redirect.go +++ b/test/e2e/plugins/redirect.go @@ -18,9 +18,8 @@ import ( "fmt" "net/http" - "github.com/stretchr/testify/assert" - "github.com/onsi/ginkgo" + "github.com/stretchr/testify/assert" "github.com/apache/apisix-ingress-controller/test/e2e/scaffold" ) From 3db26af27c73431fae656c12e84e9eb69e4b409c Mon Sep 17 00:00:00 2001 From: Alex Zhang Date: Wed, 31 Mar 2021 15:21:55 +0800 Subject: [PATCH 4/5] test: add test cases for uri-blocker plugin --- test/e2e/plugins/uri_blocker.go | 150 ++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 test/e2e/plugins/uri_blocker.go diff --git a/test/e2e/plugins/uri_blocker.go b/test/e2e/plugins/uri_blocker.go new file mode 100644 index 0000000000..8f1c8f9afe --- /dev/null +++ b/test/e2e/plugins/uri_blocker.go @@ -0,0 +1,150 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You 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 plugins + +import ( + "fmt" + + "github.com/stretchr/testify/assert" + + "github.com/apache/apisix-ingress-controller/test/e2e/scaffold" + "github.com/onsi/ginkgo" +) + +var _ = ginkgo.Describe("uri-blocker plugin", func() { + opts := &scaffold.Options{ + Name: "default", + Kubeconfig: scaffold.GetKubeconfig(), + APISIXConfigPath: "testdata/apisix-gw-config.yaml", + APISIXDefaultConfigPath: "testdata/apisix-gw-config-default.yaml", + IngressAPISIXReplicas: 1, + HTTPBinServicePort: 80, + APISIXRouteVersion: "apisix.apache.org/v2alpha1", + } + s := scaffold.NewScaffold(opts) + ginkgo.It("sanity", func() { + backendSvc, backendPorts := s.DefaultHTTPBackend() + ar := fmt.Sprintf(` +apiVersion: apisix.apache.org/v2alpha1 +kind: ApisixRoute +metadata: + name: httpbin-route +spec: + http: + - name: rule1 + match: + hosts: + - httpbin.org + paths: + - /ip + - /status/200 + - /headers + backends: + - serviceName: %s + servicePort: %d + weight: 10 + plugins: + - name: uri-blocker + enable: true + config: + rejected_code: 403 + block_rules: + - /status/200 + - /headers +`, backendSvc, backendPorts[0]) + + assert.Nil(ginkgo.GinkgoT(), s.CreateResourceFromString(ar)) + + err := s.EnsureNumApisixUpstreamsCreated(1) + assert.Nil(ginkgo.GinkgoT(), err, "Checking number of upstreams") + err = s.EnsureNumApisixRoutesCreated(1) + assert.Nil(ginkgo.GinkgoT(), err, "Checking number of routes") + + s.NewAPISIXClient().GET("/status/200").WithHeader("Host", "httpbin.org"). + Expect(). + Status(403) + s.NewAPISIXClient().GET("/headers").WithHeader("Host", "httpbin.org"). + Expect(). + Status(403) + s.NewAPISIXClient().GET("/status/206").WithHeader("Host", "httpbin.org"). + Expect(). + Status(404). + Body(). + Contains("404 Route Not Found") + s.NewAPISIXClient().GET("/ip").WithHeader("Host", "httpbin.org"). + Expect(). + Status(200). + Body(). + Contains("origin") + }) + + ginkgo.It("disable plugin", func() { + backendSvc, backendPorts := s.DefaultHTTPBackend() + ar := fmt.Sprintf(` +apiVersion: apisix.apache.org/v2alpha1 +kind: ApisixRoute +metadata: + name: httpbin-route +spec: + http: + - name: rule1 + match: + hosts: + - httpbin.org + paths: + - /ip + - /status/200 + - /headers + backends: + - serviceName: %s + servicePort: %d + weight: 10 + plugins: + - name: uri-blocker + enable: false + config: + rejected_code: 403 + block_rules: + - /status/200 + - /headers +`, backendSvc, backendPorts[0]) + + assert.Nil(ginkgo.GinkgoT(), s.CreateResourceFromString(ar)) + + err := s.EnsureNumApisixUpstreamsCreated(1) + assert.Nil(ginkgo.GinkgoT(), err, "Checking number of upstreams") + err = s.EnsureNumApisixRoutesCreated(1) + assert.Nil(ginkgo.GinkgoT(), err, "Checking number of routes") + + s.NewAPISIXClient().GET("/status/200").WithHeader("Host", "httpbin.org"). + Expect(). + Status(200) + s.NewAPISIXClient().GET("/headers").WithHeader("Host", "httpbin.org"). + Expect(). + Status(200). + Body(). + Contains("httpbin.org") + s.NewAPISIXClient().GET("/status/206").WithHeader("Host", "httpbin.org"). + Expect(). + Status(404). + Body(). + Contains("404 Route Not Found") + s.NewAPISIXClient().GET("/ip").WithHeader("Host", "httpbin.org"). + Expect(). + Status(200). + Body(). + Contains("origin") + }) +}) From 643f0da72953b77a4f7c1c454d97fea3cee63e86 Mon Sep 17 00:00:00 2001 From: Alex Zhang Date: Thu, 1 Apr 2021 09:33:48 +0800 Subject: [PATCH 5/5] fix --- pkg/kube/apisix/apis/config/v2alpha1/types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/kube/apisix/apis/config/v2alpha1/types.go b/pkg/kube/apisix/apis/config/v2alpha1/types.go index 5b7de57b43..bc4232b32e 100644 --- a/pkg/kube/apisix/apis/config/v2alpha1/types.go +++ b/pkg/kube/apisix/apis/config/v2alpha1/types.go @@ -174,7 +174,7 @@ type ApisixRouteHTTPPlugin struct { Enable bool `json:"enable" yaml:"enable"` // Plugin configuration. // TODO we may use protobuf to define it. - Config ApisixRouteHTTPPluginConfig `json:"config" yaml:"enable"` + Config ApisixRouteHTTPPluginConfig `json:"config" yaml:"config"` } // ApisixRouteHTTPPluginConfig is the configuration for