From f0f2b1ac3e2ae9a691448f2c94e8aeaf87cd44da Mon Sep 17 00:00:00 2001 From: Rodolphe CHAIGNEAU Date: Wed, 18 Apr 2018 12:16:24 +0200 Subject: [PATCH] add travis file and smoke tests for CI --- .travis.yml | 53 ++++++++++ project.sh | 278 ++++++++++++++++++++++++++++++++++++++++++++++++++++ readme.md | 2 +- smoke.sh | 250 ++++++++++++++++++++++++++++++++++++++++++++++ test.sh | 45 +++++++++ util.sh | 22 +++++ 6 files changed, 649 insertions(+), 1 deletion(-) create mode 100644 .travis.yml create mode 100755 project.sh create mode 100644 smoke.sh create mode 100755 test.sh create mode 100644 util.sh diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..6f9581a --- /dev/null +++ b/.travis.yml @@ -0,0 +1,53 @@ +sudo: required + +language: bash + +services: + - docker + +env: + - CURRENT_VERSION=$(git describe --abbrev=0 --tags) WIREMOCK_LATEST_VERSION=$(git ls-remote --tags git://github.com/tomakehurst/wiremock.git | grep -e "refs/tags/[0-9]*\." | sort -t '/' -k 3 -V | tail -1 | cut -f3 -d '/') + +notifications: + email: false + slack: + secure: "a/Dj2bFQXq6UGTgirG61u9O3dA/2Zh18ckR4coBqn4/Nrutgf7XHGi66YgkHAkmvMDiY5m40n/zE7FmAYBLGzQBIE7D8FOa81qSb5WpP6lJSTAGitiPzidw1e/cZvP+rhr5Zoa0rp7hSOyGRNGJaDSF10CeZLkm2wNaSrbFreaRg972EEh7jWZhSa7YUJLdD2kdZVWYHoHEg8QKKyAag5pq/UPiwZ2uM2D6C5SxS0NpdE1MbLNE5VoU8NHGV7amX5L3sb2iK3+AvhxqoLEWdojB9DAZhuMl8s/mL8zok+xomM5i/WYidBe3GO3iRQyvs4DoHoS5/5UELNouLY/Clj/m+5OZTxbe52JpbPPPTK95S9xvVbYI9bXy1PTv3K33be9A6FKKXeAUgWvWL51TeTyAWhgO3ccTkQX4en2M1+g+WWVXxF9Zj8WbmwzXzx7q/fVTvxeZ39A/nYDz9oblOm3Ld9bpMJVfrr0vcFx5f0OZnvyB7badqWn26fskFAjlbN8K/6A6+vXv6KfxJLnUI8Nvpf49OPIxcnqTNogB0hW9ODDczr8CJMyfp5kFDENa3NDI/VCSEagQxRysURbkl7OaJyljRm21zk/kxv05homxE4cLeQpQkp7G3lIUNT7IO8RBOV/LYJOcndGN479RgkXA27hZhLgBy0l3/HSg5hvQ=" + +before_install: + - if [ "$CURRENT_VERSION" != "$WIREMOCK_LATEST_VERSION" ]; then git checkout master && ./project.sh release prepare $WIREMOCK_LATEST_VERSION ; fi + - docker build -t wiremock . + - docker build -t wiremock-alpine alpine + - docker build -t wiremock-hello samples/hello + - docker build -t wiremock-random samples/random + +install: + - docker run --name wiremock -d wiremock + - docker run --name wiremock-args -d wiremock --https-port 8443 --verbose + - docker run --name wiremock-hello -d wiremock-hello + - docker run --name wiremock-random -d wiremock-random + - docker run --name wiremock-alpine -d wiremock-alpine + +script: + - ./test.sh + +before_deploy: + - if [ "$CURRENT_VERSION" = "$WIREMOCK_LATEST_VERSION" ]; then travis_terminate; fi + - docker tag wiremock-alpine rodolpheche/wiremock:$WIREMOCK_LATEST_VERSION-alpine + - docker tag wiremock rodolpheche/wiremock:$WIREMOCK_LATEST_VERSION + - docker tag wiremock rodolpheche/wiremock:latest + - echo "$DOCKER_PASSWORD" | docker login -u "rodolpheche" --password-stdin + - docker push rodolpheche/wiremock:$WIREMOCK_LATEST_VERSION-alpine + - docker push rodolpheche/wiremock:$WIREMOCK_LATEST_VERSION + - docker push rodolpheche/wiremock:latest + - git config --local user.name "rodolpheche" + - git config --local user.email "$GIT_USER_EMAIL" + - git add . + - git commit -m "upgrade to version $WIREMOCK_LATEST_VERSION" + - git tag ${WIREMOCK_LATEST_VERSION} + - git remote set-url origin https://${GITHUB_API_KEY}@github.com/rodolpheche/wiremock-docker.git + - git push origin master + +deploy: + provider: releases + api_key: "${GITHUB_API_KEY}" + skip_cleanup: true diff --git a/project.sh b/project.sh new file mode 100755 index 0000000..b89011a --- /dev/null +++ b/project.sh @@ -0,0 +1,278 @@ +#!/bin/bash + +. util.sh + +EXECUTION_OUTPUT=/dev/null + +usage() { +cat << EOF +Usage: $0 COMMAND [-v] + +Wiremock Docker image project + +Commands: + build Build classic & alpine images + test Test classic & alpine images + release clean Clean workspace (revert readme & Dockerfiles) + release prepare Prepare release (update version in readme.md, Dockerfile & alpine/Dockerfile files) + release perform Perform release (docker push & git tag/push) + +Args: + -v verbose mode + -y force yes +EOF +exit +} + +build() { + ################# + # classic image # + ################# + + CURRENT_VERSION=$(cat Dockerfile | grep "ENV WIREMOCK_VERSION" | cut -d ' ' -f 3) + title "Build Wiremock Docker image $CURRENT_VERSION" + + message "Build classic image" + docker build -t ${IMAGE_NAME} . > ${EXECUTION_OUTPUT} + assert_bash_ok $? + + ################ + # alpine image # + ################ + + CURRENT_VERSION=$(cat alpine/Dockerfile | grep "ENV WIREMOCK_VERSION" | cut -d ' ' -f 3) + title "Build Wiremock Docker alpine image $CURRENT_VERSION" + + message "Build alpine image" + docker build -t ${IMAGE_NAME}-alpine alpine > ${EXECUTION_OUTPUT} + assert_bash_ok $? +} + +test() { + # remove running container + docker rm -f wiremock-container > ${EXECUTION_OUTPUT} 2>&1 + + ################# + # classic image # + ################# + + # version message + eval $(docker run --rm ${IMAGE_NAME}-alpine env | grep WIREMOCK_VERSION) + title "Test Wiremock Docker image $WIREMOCK_VERSION" + + # default + message "Test default run" + CONTAINER_ID=$(docker run -d ${IMAGE_NAME}) + CONTAINER_IP=$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" ${CONTAINER_ID}) + sleep 1 + smoke_url_ok "http://$CONTAINER_IP:8080/__admin" + smoke_assert_body "mappings" + docker rm -f ${CONTAINER_ID} > ${EXECUTION_OUTPUT} + + # wiremock args + message "Test Wiremock args" + CONTAINER_ID=$(docker run -d ${IMAGE_NAME} --https-port 8443) + CONTAINER_IP=$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" ${CONTAINER_ID}) + sleep 1 + smoke_url_ok "https://$CONTAINER_IP:8443/__admin" + smoke_assert_body "mappings" + docker rm -f ${CONTAINER_ID} > ${EXECUTION_OUTPUT} + + # helloworld sample + message "Test helloworld sample" + docker build -t wiremock-hello samples/hello > ${EXECUTION_OUTPUT} + CONTAINER_ID=$(docker run -d wiremock-hello) + CONTAINER_IP=$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" ${CONTAINER_ID}) + sleep 1 + smoke_url_ok "http://$CONTAINER_IP:8080/hello" + smoke_assert_body "Hello World !" + docker rm -f ${CONTAINER_ID} > ${EXECUTION_OUTPUT} + + # extension + message "Test Wiremock extension" + docker build -t wiremock-random samples/random > ${EXECUTION_OUTPUT} + CONTAINER_ID=$(docker run -d wiremock-random) + CONTAINER_IP=$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" ${CONTAINER_ID}) + sleep 1 + smoke_url_ok "http://$CONTAINER_IP:8080/random" + smoke_assert_body "randomInteger" + docker rm -f ${CONTAINER_ID} > ${EXECUTION_OUTPUT} + + # file permission + # TODO + + ################ + # alpine image # + ################ + + # version message + eval $(docker run --rm ${IMAGE_NAME}-alpine env | grep WIREMOCK_VERSION) + title "Test Wiremock Docker alpine image $WIREMOCK_VERSION" + + # default + message "Test default run" + CONTAINER_ID=$(docker run -d ${IMAGE_NAME}-alpine) + CONTAINER_IP=$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" ${CONTAINER_ID}) + sleep 1 + smoke_url_ok "http://$CONTAINER_IP:8080/__admin" + smoke_assert_body "mappings" + docker rm -f ${CONTAINER_ID} > ${EXECUTION_OUTPUT} + + # wiremock args + message "Test Wiremock args" + CONTAINER_ID=$(docker run -d ${IMAGE_NAME}-alpine --https-port 8443) + CONTAINER_IP=$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" ${CONTAINER_ID}) + sleep 1 + smoke_url_ok "https://$CONTAINER_IP:8443/__admin" + smoke_assert_body "mappings" + docker rm -f ${CONTAINER_ID} > ${EXECUTION_OUTPUT} + + # file permission + # TODO +} + +release_clean() { + title "Clean workspace" + + message "Revert readme.md, Dockerfile & alpine/Dockerfile files" + git checkout readme.md Dockerfile alpine/Dockerfile + assert_bash_ok $? +} + +release_prepare() { + title "Prepare release" + + if [ "$1" = "" ] + then + echo "You must specify a version" + exit 1 + fi + + message "Revert readme.md, Dockerfile & alpine/Dockerfile files" + git checkout readme.md Dockerfile alpine/Dockerfile + assert_bash_ok $? + + message "Fetch tags from Github" + git fetch -q origin -t + assert_bash_ok $? + + message "Fetch last git tag" + LAST_VERSION=$(git describe --tag --abbrev=0) + LAST_MINOR_VERSION=${LAST_VERSION%.*} + NEW_VERSION=$1 + NEW_MINOR_VERSION=${1%.*} + assert_bash_ok $? + + message "Sed version in readme.md, Dockerfile & alpine/Dockerfile files" + sed -i s/${LAST_VERSION}/${NEW_VERSION}/g readme.md Dockerfile alpine/Dockerfile + assert_bash_ok $? + + message "Sed minor version in readme.md file" + sed -i s/${LAST_MINOR_VERSION}/${NEW_MINOR_VERSION}/g readme.md + assert_bash_ok $? +} + +release_perform() { + title "Perform release" + + if [ "$FORCE_YES" != "true" ] + then + message "${red}The Docker image will be pushed to the HUB" + message "The project code will be commit, tagged & pushed to GitHub${normal}" + echo + read -p " Are you sure? [Y/n] "œœ -n 1 -r + echo + if [[ $REPLY =~ ^[^Yy]$ ]] + then + exit 0 + fi + fi + + # docker build + + build + + # functionnal tests + + test + + # docker tag + + title "Tag Wiremock Docker image $CURRENT_VERSION" + message "Tag classic image" + docker tag ${IMAGE_NAME} ${IMAGE_NAME}:${CURRENT_VERSION} + assert_bash_ok $? + + title "Tag Wiremock Docker alpine image $CURRENT_VERSION" + message "Tag alpine image" + docker tag ${IMAGE_NAME}-alpine ${IMAGE_NAME}-alpine:${CURRENT_VERSION} + assert_bash_ok $? + +# # docker push +# +# title "Push Wiremock Docker image $CURRENT_VERSION" +# message "Push classic image" +# docker push ${IMAGE_NAME}:${CURRENT_VERSION} +# assert_bash_ok $? +# +# title "Push Wiremock Docker alpine image $CURRENT_VERSION" +# message "Push alpine image" +# docker push ${IMAGE_NAME}-alpine:${CURRENT_VERSION} +# assert_bash_ok $? +# +# # git commit +# +# # git tag +# +# # git push (with tags) +} + +release() { + case $1 in + clean|prepare|perform) + release_$1 $2 + ;; + *) + usage + ;; + esac +} + +# args extract + +SHORT_OPTS="vyh" +LONG_OPTS="verbose,,help" +ARGS=$(getopt -o ${SHORT_OPTS} -l ${LONG_OPTS} -n "$0" -- "$@") +eval set -- "${ARGS}" +while true +do + case $1 in + -y) + FORCE_YES="true" + ;; + -v|--verbose) + EXECUTION_OUTPUT=/dev/stdout + ;; + -h|--help) + usage + exit + ;; + --) + break + ;; + esac + shift +done +shift + +# process + +case $1 in + build|test|release) + $@ + smoke_report + ;; + *) + usage + ;; +esac diff --git a/readme.md b/readme.md index b871d5f..c8d5ac2 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,4 @@ -# Wiremock Docker +# Wiremock Docker [![Build Status](https://travis-ci.org/rodolpheche/wiremock-docker.svg?branch=master)](https://travis-ci.org/rodolpheche/wiremock-docker) > [Wiremock](http://wiremock.org) standalone HTTP server Docker image diff --git a/smoke.sh b/smoke.sh new file mode 100644 index 0000000..5ae3f28 --- /dev/null +++ b/smoke.sh @@ -0,0 +1,250 @@ +#!/bin/bash +SMOKE_TMP_DIR=$(mktemp -d) + +SMOKE_AFTER_RESPONSE="" + +SMOKE_CURL_CODE="$SMOKE_TMP_DIR/smoke_curl_code" +SMOKE_CURL_HEADERS="$SMOKE_TMP_DIR/smoke_curl_headers" +SMOKE_CURL_BODY="$SMOKE_TMP_DIR/smoke_curl_body" +SMOKE_CURL_COOKIE_JAR="$SMOKE_TMP_DIR/smoke_curl_cookie_jar" + +SMOKE_CSRF_TOKEN="" +SMOKE_CSRF_FORM_DATA="$SMOKE_TMP_DIR/smoke_csrf_form_data" + +SMOKE_TESTS_FAILED=0 +SMOKE_TESTS_RUN=0 +SMOKE_URL_PREFIX="" +SMOKE_HEADER_HOST="" + +## "Public API" + +smoke_csrf() { + SMOKE_CSRF_TOKEN="$1" +} + +smoke_form() { + URL="$1" + FORMDATA="$2" + + if [[ ! -f "$FORMDATA" ]]; then + _smoke_print_failure "No formdata file" + _smoke_cleanup + exit 1 + fi + + _curl_post $URL $FORMDATA +} + +smoke_form_ok() { + URL="$1" + FORMDATA="$2" + + smoke_form "$URL" "$FORMDATA" + smoke_assert_code_ok +} + +smoke_report() { + _smoke_cleanup + if [[ $SMOKE_TESTS_FAILED -ne 0 ]]; then + _smoke_print_report_failure "FAIL ($SMOKE_TESTS_FAILED/$SMOKE_TESTS_RUN)" + exit 1 + fi + _smoke_print_report_success "OK ($SMOKE_TESTS_RUN/$SMOKE_TESTS_RUN)" +} + +smoke_response_code() { + cat $SMOKE_CURL_CODE +} + +smoke_response_body() { + cat $SMOKE_CURL_BODY +} + +smoke_response_headers() { + cat $SMOKE_CURL_HEADERS +} + +smoke_tcp_ok() { + URL="$1 $2" + _smoke_print_url "$URL" + echo EOF | telnet $URL > $SMOKE_CURL_BODY + smoke_assert_body "Connected" +} + +smoke_url() { + URL="$1" + _curl_get $URL +} + +smoke_url_ok() { + URL="$1" + smoke_url "$URL" + smoke_assert_code_ok +} + +smoke_url_prefix() { + SMOKE_URL_PREFIX="$1" +} + +smoke_host() { + SMOKE_HEADER_HOST="$1" +} + +## Assertions + +smoke_assert_code() { + EXPECTED="$1" + CODE=$(cat $SMOKE_CURL_CODE) + + if [[ $CODE == $1 ]]; then + _smoke_success "$1 Response code" + else + _smoke_fail "$1 Response code" + fi +} + +smoke_assert_code_ok() { + CODE=$(cat $SMOKE_CURL_CODE) + + if [[ $CODE == 2* ]]; then + _smoke_success "2xx Response code" + else + _smoke_fail "2xx Response code" + fi +} + +smoke_assert_body() { + STRING="$1" + + smoke_response_body | grep --quiet "$STRING" + + if [[ $? -eq 0 ]]; then + _smoke_success "Body contains \"$STRING\"" + else + _smoke_fail "Body does not contain \"$STRING\"" + fi +} + +smoke_assert_headers() { + STRING="$1" + + smoke_response_headers | grep --quiet "$STRING" + + if [[ $? -eq 0 ]]; then + _smoke_success "Headers contain \"$STRING\"" + else + _smoke_fail "Headers do not contain \"$STRING\"" + fi +} + +## Smoke "private" functions + +_smoke_after_response() { + $SMOKE_AFTER_RESPONSE +} + +_smoke_cleanup() { + rm -rf $SMOKE_TMP_DIR +} + +_smoke_fail() { + REASON="$1" + (( SMOKE_TESTS_FAILED++ )) + (( SMOKE_TESTS_RUN++ )) + _smoke_print_failure "$REASON" +} + +_smoke_prepare_formdata() { + FORMDATA="$1" + + if [[ "" != $SMOKE_CSRF_TOKEN ]]; then + cat $FORMDATA | sed "s/__SMOKE_CSRF_TOKEN__/$SMOKE_CSRF_TOKEN/" > $SMOKE_CSRF_FORM_DATA + echo $SMOKE_CSRF_FORM_DATA + else + echo $FORMDATA + fi +} + +_smoke_success() { + REASON="$1" + _smoke_print_success "$REASON" + (( SMOKE_TESTS_RUN++ )) +} + +## Curl helpers +_curl() { + local opt=(--cookie $SMOKE_CURL_COOKIE_JAR --cookie-jar $SMOKE_CURL_COOKIE_JAR --location --dump-header $SMOKE_CURL_HEADERS --insecure --silent) + if [[ -n "$SMOKE_HEADER_HOST" ]] + then + opt+=(-H "Host: $SMOKE_HEADER_HOST") + fi + curl "${opt[@]}" "$@" > $SMOKE_CURL_BODY +} + +_curl_get() { + URL="$1" + + SMOKE_URL="$SMOKE_URL_PREFIX$URL" + _smoke_print_url "$SMOKE_URL" + + _curl $SMOKE_URL + + grep -oE 'HTTP[^ ]+ [0-9]{3}' $SMOKE_CURL_HEADERS | tail -n1 | grep -oE '[0-9]{3}' > $SMOKE_CURL_CODE + + $SMOKE_AFTER_RESPONSE +} + +_curl_post() { + URL="$1" + FORMDATA="$2" + FORMDATA_FILE="@"$(_smoke_prepare_formdata $FORMDATA) + + SMOKE_URL="$SMOKE_URL_PREFIX$URL" + _smoke_print_url "$SMOKE_URL" + + _curl --data "$FORMDATA_FILE" $SMOKE_URL + + grep -oE 'HTTP[^ ]+ [0-9]{3}' $SMOKE_CURL_HEADERS | tail -n1 | grep -oE '[0-9]{3}' > $SMOKE_CURL_CODE + + $SMOKE_AFTER_RESPONSE +} + +## Print helpers + +# test for color support, inspired by: +# http://unix.stackexchange.com/questions/9957/how-to-check-if-bash-can-print-colors +if [ -t 1 ]; then + ncolors=$(tput colors) + if test -n "$ncolors" && test $ncolors -ge 8; then + bold="$(tput bold)" + normal="$(tput sgr0)" + red="$(tput setaf 1)" + redbg="$(tput setab 1)" + green="$(tput setaf 2)" + greenbg="$(tput setab 2)" + fi +fi + +_smoke_print_failure() { + TEXT="$1" + echo " [${red}${bold}FAIL${normal}] $TEXT" +} + +_smoke_print_report_failure() { + TEXT="$1" + echo -e "${redbg}$TEXT${normal}" +} +_smoke_print_report_success() { + TEXT="$1" + echo -e "${greenbg}$TEXT${normal}" +} + +_smoke_print_success() { + TEXT="$1" + echo " [ ${green}${bold}OK${normal} ] $TEXT" +} + +_smoke_print_url() { + TEXT="$1" + echo "> $TEXT" +} diff --git a/test.sh b/test.sh new file mode 100755 index 0000000..e8d4aac --- /dev/null +++ b/test.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +. smoke.sh + +message() { + echo + echo "${bold}$1${normal}" + echo +} + +sleep 5 + +# default +message "Test default run" +CONTAINER_IP=$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" wiremock) +smoke_url_ok "http://$CONTAINER_IP:8080/__admin" +smoke_assert_body "mappings" + +# wiremock args +message "Test Wiremock args" +CONTAINER_IP=$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" wiremock-args) +smoke_url_ok "https://$CONTAINER_IP:8443/__admin" +smoke_assert_body "mappings" + +# helloworld sample +message "Test helloworld sample" +CONTAINER_IP=$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" wiremock-hello) +smoke_url_ok "http://$CONTAINER_IP:8080/hello" +smoke_assert_body "Hello World !" + +# extension +message "Test Wiremock extension" +CONTAINER_IP=$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" wiremock-random) +smoke_url_ok "http://$CONTAINER_IP:8080/random" +smoke_assert_body "randomInteger" + +# alpine +message "Test alpine image" +CONTAINER_IP=$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" wiremock-alpine) +smoke_url_ok "http://$CONTAINER_IP:8080/__admin" +smoke_assert_body "mappings" + +# final report +echo +smoke_report diff --git a/util.sh b/util.sh new file mode 100644 index 0000000..e14f9cb --- /dev/null +++ b/util.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +. smoke.sh + +assert_bash_ok() { + if [[ $1 -eq 0 ]]; then + _smoke_success "Bash return ok" + else + _smoke_fail "Bash return error" + fi +} + +title() { + echo "" + message "${bold}$1${normal}" + echo "" +} + +message() { + TEXT="$1" + echo "$TEXT" +}