From 8bcdeed43245a3bcf06dd3ad10344228d2071e6d Mon Sep 17 00:00:00 2001 From: Cedric Meury Date: Tue, 3 Apr 2018 00:00:56 +0200 Subject: [PATCH] run an integration test script against minikube --- Makefile | 8 +++ test/integration/charts/httpbin/.helmignore | 21 +++++++ test/integration/charts/httpbin/Chart.yaml | 5 ++ .../charts/httpbin/templates/_helpers.tpl | 16 ++++++ .../charts/httpbin/templates/deployment.yaml | 38 +++++++++++++ .../charts/httpbin/templates/ingress.yaml | 33 +++++++++++ .../charts/httpbin/templates/service.yaml | 19 +++++++ test/integration/charts/httpbin/values.yaml | 14 +++++ test/integration/happypath.yaml | 13 +++++ test/integration/lib/ensure.sh | 28 +++++++++ test/integration/lib/output.sh | 24 ++++++++ test/integration/run.sh | 57 +++++++++++++++++++ 12 files changed, 276 insertions(+) create mode 100644 test/integration/charts/httpbin/.helmignore create mode 100644 test/integration/charts/httpbin/Chart.yaml create mode 100644 test/integration/charts/httpbin/templates/_helpers.tpl create mode 100644 test/integration/charts/httpbin/templates/deployment.yaml create mode 100644 test/integration/charts/httpbin/templates/ingress.yaml create mode 100644 test/integration/charts/httpbin/templates/service.yaml create mode 100644 test/integration/charts/httpbin/values.yaml create mode 100644 test/integration/happypath.yaml create mode 100644 test/integration/lib/ensure.sh create mode 100644 test/integration/lib/output.sh create mode 100755 test/integration/run.sh diff --git a/Makefile b/Makefile index 63c2a314..9ad1ed53 100644 --- a/Makefile +++ b/Makefile @@ -21,10 +21,18 @@ test: go test -v ${PKGS} -cover -race -p=1 .PHONY: test +integration: + bash test/integration/run.sh +.PHONY: integration + cross: gox -os '!freebsd !netbsd' -arch '!arm' -output "dist/{{.Dir}}_{{.OS}}_{{.Arch}}" -ldflags '-X main.Version=${TAG}' ${TARGETS} .PHONY: cross +clean: + rm dist/helmfile_* +.PHONY: clean + pristine: generate fmt git ls-files --exclude-standard --modified --deleted --others | diff /dev/null - .PHONY: pristine diff --git a/test/integration/charts/httpbin/.helmignore b/test/integration/charts/httpbin/.helmignore new file mode 100644 index 00000000..f0c13194 --- /dev/null +++ b/test/integration/charts/httpbin/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/test/integration/charts/httpbin/Chart.yaml b/test/integration/charts/httpbin/Chart.yaml new file mode 100644 index 00000000..f4e846c3 --- /dev/null +++ b/test/integration/charts/httpbin/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: HTTP Request & Response Service, written in Python + Flask. https://httpbin.org +name: httpbin +version: 0.1.0 + diff --git a/test/integration/charts/httpbin/templates/_helpers.tpl b/test/integration/charts/httpbin/templates/_helpers.tpl new file mode 100644 index 00000000..cf15b710 --- /dev/null +++ b/test/integration/charts/httpbin/templates/_helpers.tpl @@ -0,0 +1,16 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "httpbin.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "httpbin.fullname" -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/test/integration/charts/httpbin/templates/deployment.yaml b/test/integration/charts/httpbin/templates/deployment.yaml new file mode 100644 index 00000000..d24b7ed9 --- /dev/null +++ b/test/integration/charts/httpbin/templates/deployment.yaml @@ -0,0 +1,38 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: +metadata: + name: {{ template "httpbin.fullname" . }} + labels: + app: {{ template "httpbin.name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: 1 + strategy: {} + template: + metadata: + labels: + app: {{ template "httpbin.name" . }} + release: {{ .Release.Name }} + spec: + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + livenessProbe: + httpGet: + path: / + port: {{ .Values.service.internalPort }} + readinessProbe: + httpGet: + path: / + port: {{ .Values.service.internalPort }} + ports: + - containerPort: {{ .Values.service.internalPort }} + resources: +{{ toYaml .Values.resources | indent 10 }} + +status: {} +--- diff --git a/test/integration/charts/httpbin/templates/ingress.yaml b/test/integration/charts/httpbin/templates/ingress.yaml new file mode 100644 index 00000000..bcd4311f --- /dev/null +++ b/test/integration/charts/httpbin/templates/ingress.yaml @@ -0,0 +1,33 @@ +{{- if .Values.ingress.enabled -}} +{{- $serviceName := include "httpbin.fullname" . -}} +{{- $servicePort := .Values.service.externalPort -}} +{{- $prefix := .Values.ingress.prefix -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: {{ template "httpbin.fullname" . }} + labels: + app: {{ template "httpbin.name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + annotations: + {{- range $key, $value := .Values.ingress.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} +spec: + rules: + {{- range $host := .Values.ingress.hosts }} + - host: {{ $host }} + http: + paths: + - path: / + backend: + serviceName: {{ $serviceName }} + servicePort: {{ $servicePort }} + {{- end -}} + {{- if .Values.ingress.tls }} + tls: +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end -}} +{{- end -}} diff --git a/test/integration/charts/httpbin/templates/service.yaml b/test/integration/charts/httpbin/templates/service.yaml new file mode 100644 index 00000000..cc71903d --- /dev/null +++ b/test/integration/charts/httpbin/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "httpbin.fullname" . }} + labels: + app: {{ template "httpbin.name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.externalPort }} + targetPort: {{ .Values.service.internalPort }} + protocol: TCP + name: {{ .Values.service.name }} + selector: + app: {{ template "httpbin.name" . }} + release: {{ .Release.Name }} diff --git a/test/integration/charts/httpbin/values.yaml b/test/integration/charts/httpbin/values.yaml new file mode 100644 index 00000000..34fe6360 --- /dev/null +++ b/test/integration/charts/httpbin/values.yaml @@ -0,0 +1,14 @@ +image: + repository: docker.io/citizenstig/httpbin + tag: latest + pullPolicy: IfNotPresent +service: + name: httpbin + type: LoadBalancer + externalPort: 8000 + internalPort: 8000 +ingress: + enabled: false + hosts: + - httpbin.local +resources: {} diff --git a/test/integration/happypath.yaml b/test/integration/happypath.yaml new file mode 100644 index 00000000..5dac162e --- /dev/null +++ b/test/integration/happypath.yaml @@ -0,0 +1,13 @@ +repositories: + - name: stable + url: https://kubernetes-charts.storage.googleapis.com/ + +context: minikube + +releases: + + - name: httpbin + chart: ./charts/httpbin + set: + - name: ingress.enabled + value: false diff --git a/test/integration/lib/ensure.sh b/test/integration/lib/ensure.sh new file mode 100644 index 00000000..bf3e1798 --- /dev/null +++ b/test/integration/lib/ensure.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +# Check environment is correctly setup + +if ! hash minikube 2>/dev/null; then + fail "Minikube needs to be installed." +fi +if [ ! $(minikube status --format '{{.MinikubeStatus}}') == "Running" ]; then + fail "Minikube is not running." +fi +if [ ! $(minikube status --format '{{.ClusterStatus}}') == "Running" ]; then + fail "Minikube Cluster is not running." +fi +if ! kubectl version --short 1> /dev/null; then + fail "Could not connect to minikube apiserver" +fi +if ! hash curl 1>/dev/null; then + fail "curl needs to be installed." +fi +if ! hash docker 1>/dev/null; then + fail "Docker needs to be installed." +fi +if ! docker version 1> /dev/null; then + fail "Could not connect to Docker daemon" +fi +if ! hash helm 1>/dev/null; then + fail "Helm needs to be installed." +fi diff --git a/test/integration/lib/output.sh b/test/integration/lib/output.sh new file mode 100644 index 00000000..05db3d5b --- /dev/null +++ b/test/integration/lib/output.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +declare -i tests_total=0 + +function info () { + tput bold; tput setaf 4; echo -n "INFO: "; tput sgr0; echo "${@}" +} +function warn () { + tput bold; tput setaf 3; echo -n "WARN: "; tput sgr0; echo "${@}" +} +function fail () { + tput bold; tput setaf 1; echo -n "FAIL: "; tput sgr0; echo "${@}" + exit 1 +} +function test_start () { + tput bold; tput setaf 6; echo -n "TEST: "; tput sgr0; echo "${@}" +} +function test_pass () { + tests_total=$((tests_total+1)) + tput bold; tput setaf 2; echo -n "PASS: "; tput sgr0; echo "${@}" +} +function all_tests_passed () { + tput bold; tput setaf 2; echo -n "PASS: "; tput sgr0; echo "${tests_total} tests passed" +} diff --git a/test/integration/run.sh b/test/integration/run.sh new file mode 100755 index 00000000..e7dfe550 --- /dev/null +++ b/test/integration/run.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash + +# IMPORTS ----------------------------------------------------------------------------------------------------------- + +# determine working directory to use to relative paths irrespective of starting directory +dir="${BASH_SOURCE%/*}" +if [[ ! -d "${dir}" ]]; then dir="${PWD}"; fi + +. "${dir}/lib/output.sh" +. "${dir}/lib/ensure.sh" + + +# GLOBALS ----------------------------------------------------------------------------------------------------------- + +test_ns="helmfile-tests-$(date +"%Y%m%d-%H%M%S")" +helmfile="./helmfile --namespace=${test_ns}" +helm="helm --kube-context=minikube" +kubectl="kubectl --context=minikube --namespace=${test_ns}" + +# FUNCTIONS ---------------------------------------------------------------------------------------------------------- + +function wait_deploy_ready() { + $kubectl rollout status deployment ${1} + while [ "$($kubectl get deploy ${1} -o=jsonpath='{.status.readyReplicas}')" == "0" ]; do + info "Waiting for deployment ${1} to be ready" + sleep 1 + done +} + +# RUN BUILD & SETUP -------------------------------------------------------------------------------------------------- + +set -e +$helm init 1> /dev/null +make build 1> /dev/null +$helmfile -v 1> /dev/null +$kubectl get namespace ${test_ns} &> /dev/null && warn "Namespace ${test_ns} exists, from a previous test run?" +trap "{ $kubectl delete namespace ${test_ns}; }" EXIT # remove namespace whenever we exit this script + +info "Using namespace: ${test_ns}" +info "Using Helm version: $(helm version --short --client | grep -o v.*$)" + +# TEST CASES---------------------------------------------------------------------------------------------------------- + +test_start "happypath - simple rollout of httpbin chart" +$helmfile -f ${dir}/happypath.yaml sync +wait_deploy_ready httpbin-httpbin +curl --fail $(minikube service --url --namespace=${test_ns} httpbin-httpbin)/status/200 \ + || fail "httpbin failed to return 200 OK" +$helmfile -f ${dir}/happypath.yaml delete +$helm status --namespace=${test_ns} httpbin &> /dev/null \ + && fail "release should not exist anymore after a delete" +test_pass "happypath" + + +# ALL DONE ----------------------------------------------------------------------------------------------------------- + +all_tests_passed \ No newline at end of file