Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: add e2e test cases for redirect, uri-blocker and fault-injection plugins #320

Merged
merged 5 commits into from Apr 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/kube/apisix/apis/config/v2alpha1/types.go
Expand Up @@ -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
Expand Down
12 changes: 11 additions & 1 deletion test/e2e/README.md
Expand Up @@ -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
---------
Expand All @@ -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.
1 change: 1 addition & 0 deletions test/e2e/e2e.go
Expand Up @@ -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() {}
175 changes: 175 additions & 0 deletions 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)
})
})
151 changes: 151 additions & 0 deletions 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)
})
})