Skip to content
This repository has been archived by the owner on Dec 15, 2021. It is now read-only.

Commit

Permalink
rework tests to be run by 'bats'
Browse files Browse the repository at this point in the history
* moved all used functions to script/libtest.bash
  (renamed from libtest.sh as per bats requirement)

* created tests/integration-tests.bats, containing all
  tests to be run:
- cleanup integration-tests to mainly run above bats
  manifest
- removed integration-test-{functions,rbac}

* small mods to .travis.yaml to clone and use 'bats' repo
  • Loading branch information
jjo committed Aug 9, 2017
1 parent b67bf98 commit 04a36c3
Show file tree
Hide file tree
Showing 7 changed files with 242 additions and 257 deletions.
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ install:
- chmod +x $GOPATH/bin/kubecfg
- git clone --depth=1 https://github.com/ksonnet/ksonnet-lib.git
- export KUBECFG_JPATH=$PWD/ksonnet-lib
- git clone --depth=1 https://github.com/sstephenson/bats.git bats
- export PATH=$PATH:$PWD/bats/bin

script:
- make test
Expand Down
22 changes: 0 additions & 22 deletions script/integration-test-functions

This file was deleted.

76 changes: 0 additions & 76 deletions script/integration-test-rbac

This file was deleted.

25 changes: 18 additions & 7 deletions script/integration-tests
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,15 @@ test -d $PWD/ksonnet-lib && export KUBECFG_JPATH=$PWD/ksonnet-lib
# We require below env
: ${GOPATH:?} ${KUBECFG_JPATH:?}

# Default to "dind" for testing
# Default to "dind" kubernetes context
INTEGRATION_TESTS_CTX=${1:-dind}

set -xu
# ... and 'bats' installed
which bats > /dev/null || {
echo "ERROR: 'bats' is required to run these tests," \
"install it from https://github.com/sstephenson/bats"
exit 255
}

k8s_create_dind() {
# Bring up kubeadm-dind-cluster (docker-in-docker k8s cluster)
Expand All @@ -22,12 +27,18 @@ k8s_create_dind() {
sleep 5
}

kubectl get nodes --context=${INTEGRATION_TESTS_CTX} || k8s_create_${INTEGRATION_TESTS_CTX}
## main() ##
# Create k8s cluster (only "dind" supported atm) if missing:
kubectl get nodes --context=${INTEGRATION_TESTS_CTX:?} || k8s_create_${INTEGRATION_TESTS_CTX} || exit 255
export TEST_CONTEXT=${INTEGRATION_TESTS_CTX}

source script/libtest.bash
trap k8s_context_restore 0
k8s_context_save

# Run the tests thru bats:
kubectl create namespace kubeless
# TEST: kubeless and RBAC (will leave setup ready for next tests)
./script/integration-test-rbac ${INTEGRATION_TESTS_CTX} || exit 1
# TEST: some simple function calls
./script/integration-test-functions ${INTEGRATION_TESTS_CTX} || exit 1
bats tests/integration-tests.bats

# Just showing remaining k8s objects
kubectl get all --all-namespaces
185 changes: 185 additions & 0 deletions script/libtest.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
#!/bin/bash
# k8s and kubeless helpers, specially "wait"-ers on pod ready/deleted/etc

KUBELESS_JSONNET=kubeless.jsonnet
KUBELESS_JSONNET_RBAC=kubeless-rbac-novols.jsonnet

KUBECTL_BIN=$(which kubectl)
KUBECFG_BIN=$(which kubecfg)

export TEST_MAX_WAIT_SEC=120

# Workaround 'bats' lack of forced output support, dup() stderr fd
exec 9>&2
echo_info() {
test -z "$TEST_DEBUG" && return 0
echo "INFO: $*" >&9
}
export -f echo_info

kubectl() {
${KUBECTL_BIN:?} --context=${TEST_CONTEXT:?} "$@"
}
kubecfg() {
${KUBECFG_BIN:?} --context=${TEST_CONTEXT:?} "$@"
}

## k8s specific Helper functions
k8s_wait_for_pod_ready() {
echo_info "Waiting for pod '${@}' to be ready ... "
local -i cnt=${TEST_MAX_WAIT_SEC:?}
until kubectl get pod "${@}" |&grep -q Running; do
((cnt=cnt-1)) || return 1
sleep 1
done
}
k8s_wait_for_pod_gone() {
echo_info "Waiting for pod '${@}' to be gone ... "
local -i cnt=${TEST_MAX_WAIT_SEC:?}
until kubectl get pod "${@}" |&grep -q No.resources.found; do
((cnt=cnt-1)) || return 1
sleep 1
done
}
k8s_wait_for_pod_logline() {
local string="${1:?}"; shift
local -i cnt=${TEST_MAX_WAIT_SEC:?}
echo_info "Waiting for '${@}' to show logline '${string}' ..."
until kubectl logs --tail=10 "${@}"|&grep -q "${string}"; do
((cnt=cnt-1)) || return 1
sleep 1
done
}
k8s_context_save() {
TEST_CONTEXT_SAVED=$(${KUBECTL_BIN} config current-context)
# Kubeless doesn't support contexts yet, save+restore it
# Don't save current_context if it's the same already
[[ $TEST_CONTEXT_SAVED == $TEST_CONTEXT ]] && TEST_CONTEXT_SAVED=""

# Save current_context
[[ $TEST_CONTEXT_SAVED != "" ]] && \
echo_info "Saved context: '${TEST_CONTEXT_SAVED}'" && \
${KUBECTL_BIN} config use-context ${TEST_CONTEXT}
}
k8s_context_restore() {
# Restore saved context
[[ $TEST_CONTEXT_SAVED != "" ]] && \
echo_info "Restoring context: '${TEST_CONTEXT_SAVED}'" && \
${KUBECTL_BIN} config use-context ${TEST_CONTEXT_SAVED}
}
_wait_for_cmd_ok() {
local cmd="${*:?}"; shift
local -i cnt=${TEST_MAX_WAIT_SEC:?}
echo_info "Waiting for '${*}' to successfully exit ..."
until env ${cmd}; do
((cnt=cnt-1)) || return 1
sleep 1
done
}

## Specific for kubeless
kubeless_recreate() {
local jsonnet_del=${1:?missing jsonnet delete manifest} jsonnet_upd=${2:?missing jsonnet update manifest}
local -i cnt=${TEST_MAX_WAIT_SEC:?}
echo_info "Delete kubeless namespace, wait to be gone ... "
kubecfg delete ${jsonnet_del}
kubectl delete namespace kubeless >& /dev/null || true
while kubectl get namespace kubeless >& /dev/null; do
((cnt=cnt-1)) || return 1
sleep 1
done
kubectl create namespace kubeless
kubecfg update ${jsonnet_upd}
}
kubeless_function_delete() {
local func=${1:?}; shift
echo_info "Deleting function "${func}" in case still present ... "
kubeless function delete "${func}" >& /dev/null || true
kubectl delete all -l function="${func}" > /dev/null || true
k8s_wait_for_pod_gone -l function="${func}"
}
kubeless_function_deploy() {
local func=${1:?}; shift
echo_info "Deploying function ..."
kubeless function deploy ${func} ${@}
}
kubeless_function_exp_regex_call() {
local exp_rc=${1:?} regex=${2:?} func=${3:?}; shift 3
echo_info "Calling function ${func}, expecting rc=${exp_rc} "
kubeless function call ${func} "${@}"|&egrep ${regex}
}
_wait_for_kubeless_controller_ready() {
echo_info "Waiting for kubeless controller to be ready ... "
k8s_wait_for_pod_ready -n kubeless -l kubeless=controller
_wait_for_cmd_ok kubectl get functions 2>/dev/null
}
_wait_for_controller_logline() {
local string="${1:?}"
k8s_wait_for_pod_logline "${string}" -n kubeless -l kubeless=controller
}
_wait_for_simple_function_pod_ready() {
k8s_wait_for_pod_ready -l function=get-python
}
_deploy_simple_function() {
make -C examples get-python
}
_call_simple_function() {
# Artifact to dodge 'bats' lack of support for positively testing _for_ errors
case "${1:?}" in
1) make -C examples get-python-verify |& egrep Error.1;;
0) make -C examples get-python-verify;;
esac
}
_delete_simple_function() {
kubeless_function_delete get-python
}

## Entry points used by 'bats' tests:
verify_k8s_tools() {
local tools="kubectl kubecfg kubeless"
for exe in $tools; do
which ${exe} >/dev/null && continue
echo "ERROR: '${exe}' needs to be installed"
return 1
done
}
verify_minikube_running () {
[[ $TEST_CONTEXT == minikube ]] || return 0
minikube status | grep -q "minikube: Running" && return 0
echo "ERROR: minikube not running."
return 1
}
verify_rbac_mode() {
kubectl api-versions |&grep -q rbac && return 0
echo "ERROR: Please run w/RBAC, eg minikube as: minikube start --extra-config=apiserver.Authorization.Mode=RBAC"
return 1
}
test_must_fail_without_rbac_roles() {
echo_info "RBAC TEST: function deploy/call must fail without RBAC roles"
_delete_simple_function
kubeless_recreate $KUBELESS_JSONNET_RBAC $KUBELESS_JSONNET
_wait_for_kubeless_controller_ready
_deploy_simple_function
_wait_for_controller_logline "User.*cannot"
_call_simple_function 1
}
test_must_pass_with_rbac_roles() {
echo_info "RBAC TEST: function deploy/call must succeed with RBAC roles"
_delete_simple_function
kubeless_recreate $KUBELESS_JSONNET_RBAC $KUBELESS_JSONNET_RBAC
_wait_for_kubeless_controller_ready
_deploy_simple_function
_wait_for_controller_logline "controller synced and ready"
_wait_for_simple_function_pod_ready
_call_simple_function 0
}

test_kubeless_function() {
local func=${1:?}
echo_info "TEST: $func"
kubeless_function_delete ${func}
make -sC examples ${func}
k8s_wait_for_pod_ready -l function=${func}
make -sC examples ${func}-verify
}
# vim: sw=4 ts=4 et si
Loading

0 comments on commit 04a36c3

Please sign in to comment.