You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by kv...@apache.org on 2021/04/01 03:27:35 UTC

[apisix-ingress-controller] branch master updated: test: add e2e test cases for redirect, uri-blocker and fault-injection plugins (#320)

This is an automated email from the ASF dual-hosted git repository.

kvn pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-ingress-controller.git


The following commit(s) were added to refs/heads/master by this push:
     new 06e2b35  test: add e2e test cases for redirect, uri-blocker and fault-injection plugins (#320)
06e2b35 is described below

commit 06e2b35bccbf62a9d7a1d0e2680eb9a71be78cae
Author: Alex Zhang <to...@apache.org>
AuthorDate: Thu Apr 1 11:27:25 2021 +0800

    test: add e2e test cases for redirect, uri-blocker and fault-injection plugins (#320)
    
    * test: add e2e test cases for redirect and fault-injection plugins
    
    * fix
    
    * fix
    
    * test: add test cases for uri-blocker plugin
    
    * fix
---
 pkg/kube/apisix/apis/config/v2alpha1/types.go |   2 +-
 test/e2e/README.md                            |  12 +-
 test/e2e/e2e.go                               |   1 +
 test/e2e/plugins/fault_injection.go           | 175 ++++++++++++++++++++++++++
 test/e2e/plugins/redirect.go                  | 151 ++++++++++++++++++++++
 test/e2e/plugins/uri_blocker.go               | 150 ++++++++++++++++++++++
 test/e2e/scaffold/scaffold.go                 |   3 +
 7 files changed, 492 insertions(+), 2 deletions(-)

diff --git a/pkg/kube/apisix/apis/config/v2alpha1/types.go b/pkg/kube/apisix/apis/config/v2alpha1/types.go
index 303bd04..bc4232b 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:"config"`
 }
 
 // ApisixRouteHTTPPluginConfig is the configuration for
diff --git a/test/e2e/README.md b/test/e2e/README.md
index 5f508a8..bc35f93 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 8c5052d..d2ea114 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 0000000..6dd3b52
--- /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 0000000..cb094d0
--- /dev/null
+++ b/test/e2e/plugins/redirect.go
@@ -0,0 +1,151 @@
+// 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/onsi/ginkgo"
+	"github.com/stretchr/testify/assert"
+
+	"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/plugins/uri_blocker.go b/test/e2e/plugins/uri_blocker.go
new file mode 100644
index 0000000..8f1c8f9
--- /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")
+	})
+})
diff --git a/test/e2e/scaffold/scaffold.go b/test/e2e/scaffold/scaffold.go
index ed2979a..7a9da7e 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()),