Refactoring of test scripts
This commit is contained in:
parent
8db5788c34
commit
1bde95aba5
10 changed files with 304 additions and 18 deletions
8
Makefile
8
Makefile
|
@ -38,8 +38,8 @@ test:
|
||||||
@go test -v -race -tags "$(BUILDTAGS) cgo" ${GO_LIST_FILES}
|
@go test -v -race -tags "$(BUILDTAGS) cgo" ${GO_LIST_FILES}
|
||||||
|
|
||||||
.PHONY: test-e2e
|
.PHONY: test-e2e
|
||||||
test-e2e: ginkgo
|
test-e2e:
|
||||||
@go run hack/e2e.go -v --up --test --down
|
@go run hack/e2e.go --verbose --up --test --down --files="hack/nginx-ingress-controller.yaml,hack/default-backend.yaml"
|
||||||
|
|
||||||
.PHONY: cover
|
.PHONY: cover
|
||||||
cover:
|
cover:
|
||||||
|
@ -66,7 +66,3 @@ docker-build:
|
||||||
.PHONY: docker-push
|
.PHONY: docker-push
|
||||||
docker-push:
|
docker-push:
|
||||||
make -C controllers/nginx push
|
make -C controllers/nginx push
|
||||||
|
|
||||||
.PHONY: ginkgo
|
|
||||||
ginkgo:
|
|
||||||
go get github.com/onsi/ginkgo/ginkgo
|
|
||||||
|
|
51
hack/default-backend.yaml
Normal file
51
hack/default-backend.yaml
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
apiVersion: extensions/v1beta1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: default-http-backend
|
||||||
|
labels:
|
||||||
|
k8s-app: default-http-backend
|
||||||
|
namespace: kube-system
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
k8s-app: default-http-backend
|
||||||
|
spec:
|
||||||
|
terminationGracePeriodSeconds: 60
|
||||||
|
containers:
|
||||||
|
- name: default-http-backend
|
||||||
|
# Any image is permissable as long as:
|
||||||
|
# 1. It serves a 404 page at /
|
||||||
|
# 2. It serves 200 on a /healthz endpoint
|
||||||
|
image: gcr.io/google_containers/defaultbackend:1.0
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: 8080
|
||||||
|
scheme: HTTP
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
timeoutSeconds: 5
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 10m
|
||||||
|
memory: 20Mi
|
||||||
|
requests:
|
||||||
|
cpu: 10m
|
||||||
|
memory: 20Mi
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: default-http-backend
|
||||||
|
namespace: kube-system
|
||||||
|
labels:
|
||||||
|
k8s-app: default-http-backend
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 8080
|
||||||
|
selector:
|
||||||
|
k8s-app: default-http-backend
|
|
@ -18,7 +18,7 @@ if [ ! -e ${KUBECTL} ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -e ${MINIKUBE} ]; then
|
if [ ! -e ${MINIKUBE} ]; then
|
||||||
echo "kubectl binary is missing. downloading..."
|
echo "minikube binary is missing. downloading..."
|
||||||
curl -sSLo ${MINIKUBE} https://storage.googleapis.com/minikube/releases/v${MINIKUBE_VERSION}/minikube-linux-amd64
|
curl -sSLo ${MINIKUBE} https://storage.googleapis.com/minikube/releases/v${MINIKUBE_VERSION}/minikube-linux-amd64
|
||||||
chmod +x ${MINIKUBE}
|
chmod +x ${MINIKUBE}
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
echo "running ginkgo"
|
|
3
hack/e2e-internal/run-e2e.sh
Executable file
3
hack/e2e-internal/run-e2e.sh
Executable file
|
@ -0,0 +1,3 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
go test -v k8s.io/ingress/hack/... -tags -run ^TestIngressSuite$ --args --alsologtostderr --v=10
|
35
hack/e2e.go
35
hack/e2e.go
|
@ -34,11 +34,12 @@ var (
|
||||||
build = flag.Bool("build", true, "Build the backends images indicated by the env var BACKENDS required to run e2e tests.")
|
build = flag.Bool("build", true, "Build the backends images indicated by the env var BACKENDS required to run e2e tests.")
|
||||||
up = flag.Bool("up", true, "Creates a kubernetes cluster using hyperkube (containerized kubelet).")
|
up = flag.Bool("up", true, "Creates a kubernetes cluster using hyperkube (containerized kubelet).")
|
||||||
down = flag.Bool("down", true, "destroys the created cluster.")
|
down = flag.Bool("down", true, "destroys the created cluster.")
|
||||||
test = flag.Bool("test", true, "Run Ginkgo tests.")
|
test = flag.Bool("test", true, "Run tests.")
|
||||||
dump = flag.String("dump", "", "If set, dump cluster logs to this location on test or cluster-up failure")
|
dump = flag.String("dump", "", "If set, dump cluster logs to this location on test or cluster-up failure")
|
||||||
testArgs = flag.String("test-args", "", "Space-separated list of arguments to pass to Ginkgo test runner.")
|
testArgs = flag.String("test-args", "", "Space-separated list of arguments to pass to the test runner.")
|
||||||
deployment = flag.String("deployment", "bash", "up/down mechanism")
|
deployment = flag.String("deployment", "bash", "up/down mechanism")
|
||||||
verbose = flag.Bool("v", false, "If true, print all command output.")
|
verbose = flag.Bool("verbose", false, "If true, print all command output.")
|
||||||
|
files = flag.String("files", "", "Path to a file/S descriptor that will create an Ingress controller")
|
||||||
)
|
)
|
||||||
|
|
||||||
func appendError(errs []error, err error) []error {
|
func appendError(errs []error, err error) []error {
|
||||||
|
@ -139,6 +140,10 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func run(deploy deployer) error {
|
func run(deploy deployer) error {
|
||||||
|
if *files == "" {
|
||||||
|
return fmt.Errorf("missing required flag --files")
|
||||||
|
}
|
||||||
|
|
||||||
if *dump != "" {
|
if *dump != "" {
|
||||||
defer writeXML(time.Now())
|
defer writeXML(time.Now())
|
||||||
}
|
}
|
||||||
|
@ -172,7 +177,7 @@ func run(deploy deployer) error {
|
||||||
return fmt.Errorf("starting e2e cluster: %s", err)
|
return fmt.Errorf("starting e2e cluster: %s", err)
|
||||||
}
|
}
|
||||||
if *dump != "" {
|
if *dump != "" {
|
||||||
cmd := exec.Command("./cluster/kubectl.sh", "--match-server-version=false", "get", "nodes", "-oyaml")
|
cmd := exec.Command("./hack/e2e-internal/kubectl", "get", "nodes", "-oyaml")
|
||||||
b, err := cmd.CombinedOutput()
|
b, err := cmd.CombinedOutput()
|
||||||
if *verbose {
|
if *verbose {
|
||||||
log.Printf("kubectl get nodes:\n%s", string(b))
|
log.Printf("kubectl get nodes:\n%s", string(b))
|
||||||
|
@ -187,6 +192,10 @@ func run(deploy deployer) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := deploy.SetupController(*files); err != nil {
|
||||||
|
errs = appendError(errs, err)
|
||||||
|
}
|
||||||
|
|
||||||
if *test {
|
if *test {
|
||||||
if err := xmlWrap("IsUp", deploy.IsUp); err != nil {
|
if err := xmlWrap("IsUp", deploy.IsUp); err != nil {
|
||||||
errs = appendError(errs, err)
|
errs = appendError(errs, err)
|
||||||
|
@ -226,6 +235,7 @@ type deployer interface {
|
||||||
Up() error
|
Up() error
|
||||||
IsUp() error
|
IsUp() error
|
||||||
SetupKubecfg() error
|
SetupKubecfg() error
|
||||||
|
SetupController(p string) error
|
||||||
Down() error
|
Down() error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,6 +262,18 @@ func (b bash) SetupKubecfg() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b bash) SetupController(p string) error {
|
||||||
|
files := strings.Split(p, ",")
|
||||||
|
for _, f := range files {
|
||||||
|
err := finishRunning("setup controller", exec.Command("./hack/e2e-internal/kubectl", "create", "-f", f))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (b bash) Down() error {
|
func (b bash) Down() error {
|
||||||
return finishRunning("teardown", exec.Command("./hack/e2e-internal/e2e-down.sh"))
|
return finishRunning("teardown", exec.Command("./hack/e2e-internal/e2e-down.sh"))
|
||||||
}
|
}
|
||||||
|
@ -262,10 +284,7 @@ func DumpClusterLogs(location string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test() error {
|
func Test() error {
|
||||||
if *testArgs == "" {
|
return finishRunning("Ingress tests", exec.Command("./hack/e2e-internal/run-e2e.sh", strings.Fields(*testArgs)...))
|
||||||
*testArgs = "--ginkgo.focus=\\[Feature:Ingress\\]"
|
|
||||||
}
|
|
||||||
return finishRunning("Ginkgo tests", exec.Command("./hack/e2e-internal/ginkgo-e2e.sh", strings.Fields(*testArgs)...))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func finishRunning(stepName string, cmd *exec.Cmd) error {
|
func finishRunning(stepName string, cmd *exec.Cmd) error {
|
||||||
|
|
61
hack/e2e_types.go
Normal file
61
hack/e2e_types.go
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
Copyright 2017 The Kubernetes 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"k8s.io/client-go/pkg/api"
|
||||||
|
extensions "k8s.io/client-go/pkg/apis/extensions/v1beta1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IngressTestCase defines a test case for Ingress
|
||||||
|
type IngressTestCase struct {
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
Description string `yaml:"description"`
|
||||||
|
Pod *api.Pod `yaml:"pod"`
|
||||||
|
ReplicationController *api.ReplicationController `yaml:"replicationController"`
|
||||||
|
Deployment *extensions.Deployment `yaml:"deployment"`
|
||||||
|
Assert []*Assert `yaml:"tests"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assert defines a verification over the
|
||||||
|
type Assert struct {
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
Request Request `yaml:"request"`
|
||||||
|
Expect []*Expect `yaml:"expect"`
|
||||||
|
Timeout time.Duration `yaml:"timeout"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request defines a HTTP/s request to be executed against an Ingress
|
||||||
|
type Request struct {
|
||||||
|
Method string `yaml:"method"`
|
||||||
|
URL string `yaml:"url"`
|
||||||
|
Query map[string]interface{} `yaml:"query"`
|
||||||
|
Form map[string]interface{} `yaml:"form"`
|
||||||
|
Body interface{} `yaml:"body"`
|
||||||
|
Headers map[string]string `yaml:"headers"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expect defines the required conditions that must be true from a request response
|
||||||
|
type Expect struct {
|
||||||
|
Body []byte `yaml:"body"`
|
||||||
|
ContentType string `yaml:"contentType"`
|
||||||
|
Header []string `yaml:"header"`
|
||||||
|
HeaderAndValue map[string]string `yaml:"headerAndValue"`
|
||||||
|
Statuscode int `yaml:"statucDode"`
|
||||||
|
}
|
111
hack/ingress_test.go
Normal file
111
hack/ingress_test.go
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
/*
|
||||||
|
Copyright 2017 The Kubernetes 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIngressSuite(t *testing.T) {
|
||||||
|
pwd, _ := os.Getwd()
|
||||||
|
filepath.Walk(path.Join(pwd, "/suite"),
|
||||||
|
func(path string, info os.FileInfo, err error) error {
|
||||||
|
if strings.HasSuffix(path, ".yaml") {
|
||||||
|
t.Log(path)
|
||||||
|
runTestCase(path, t)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func runTestCase(rawtc string, t *testing.T) {
|
||||||
|
tc, err := parseTestCase(rawtc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error reading Ingress test case file %v: %v", rawtc, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run(tc.Name, func(t *testing.T) {
|
||||||
|
t.Logf("starting deploy of requirements for test case '%v'", tc.Name)
|
||||||
|
err := tc.deploy()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error in test case deploy process: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.Assert == nil {
|
||||||
|
t.Fatalf("test case %v does not contains tests", tc.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, assert := range tc.Assert {
|
||||||
|
t.Logf("running assert %v", assert.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = tc.undeploy()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error in test case deploy process: %v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseTestCase parses a test case from a yaml file
|
||||||
|
func parseTestCase(p string) (IngressTestCase, error) {
|
||||||
|
return IngressTestCase{
|
||||||
|
Name: "basic test",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// deploy creates the kubernetes object specified in the test case
|
||||||
|
func (tc IngressTestCase) deploy() error {
|
||||||
|
if tc.Pod != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.ReplicationController != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.Deployment != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("invalid deployment option. Please check the test case")
|
||||||
|
}
|
||||||
|
|
||||||
|
// undeploy removes the kubernetes object created by the test case
|
||||||
|
func (tc IngressTestCase) undeploy() error {
|
||||||
|
if tc.Pod != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.ReplicationController != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.Deployment != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deployIngressController() error {
|
||||||
|
return nil
|
||||||
|
}
|
47
hack/nginx-ingress-controller.yaml
Normal file
47
hack/nginx-ingress-controller.yaml
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
apiVersion: extensions/v1beta1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: nginx-ingress-controller
|
||||||
|
labels:
|
||||||
|
k8s-app: nginx-ingress-controller
|
||||||
|
namespace: kube-system
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
k8s-app: nginx-ingress-controller
|
||||||
|
spec:
|
||||||
|
terminationGracePeriodSeconds: 60
|
||||||
|
containers:
|
||||||
|
- image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.7
|
||||||
|
name: nginx-ingress-controller
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: 10254
|
||||||
|
scheme: HTTP
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: 10254
|
||||||
|
scheme: HTTP
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
timeoutSeconds: 1
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
hostPort: 80
|
||||||
|
- containerPort: 443
|
||||||
|
hostPort: 443
|
||||||
|
env:
|
||||||
|
- name: POD_NAME
|
||||||
|
valueFrom:
|
||||||
|
fieldRef:
|
||||||
|
fieldPath: metadata.name
|
||||||
|
- name: POD_NAMESPACE
|
||||||
|
valueFrom:
|
||||||
|
fieldRef:
|
||||||
|
fieldPath: metadata.namespace
|
||||||
|
args:
|
||||||
|
- /nginx-ingress-controller
|
||||||
|
- --default-backend-service=$(POD_NAMESPACE)/default-http-backend
|
1
hack/suite/0001.yaml
Normal file
1
hack/suite/0001.yaml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
-
|
Loading…
Reference in a new issue