test: Start to migrate to docker's upstream tests
* Follow the upstream test suite's conventions. * More migration to follow.
This commit is contained in:
parent
e700aa1f9f
commit
ee5d6a6b8a
18
test/README.md
Normal file
18
test/README.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Tests
|
||||||
|
|
||||||
|
Philosophy is to not re-invent the wheel while allowing users to quickly test repository specific tests.
|
||||||
|
|
||||||
|
Example invocation from top-level of repository:
|
||||||
|
|
||||||
|
docker build -t openvpn .
|
||||||
|
tests/run.sh openvpn
|
||||||
|
|
||||||
|
More details: https://github.com/docker-library/official-images/tree/master/test
|
||||||
|
|
||||||
|
## Continuous Integration
|
||||||
|
|
||||||
|
The set of scripts defined by `config.sh` are run every time a pull request or push to the repository is made.
|
||||||
|
|
||||||
|
## Maintenance
|
||||||
|
|
||||||
|
Periodically these scripts may need to be synchronized with their upsteam source. Would be nice to be able to just use them from upstream if it such a feature is added later to avoid having to copy them in place.
|
12
test/config.sh
Normal file
12
test/config.sh
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
testAlias+=(
|
||||||
|
[kylemanna/openvpn]='openvpn'
|
||||||
|
)
|
||||||
|
|
||||||
|
imageTests+=(
|
||||||
|
[openvpn]='
|
||||||
|
paranoid
|
||||||
|
'
|
||||||
|
)
|
202
test/run.sh
Executable file
202
test/run.sh
Executable file
@ -0,0 +1,202 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
dir="$(dirname "$(readlink -f "$BASH_SOURCE")")"
|
||||||
|
|
||||||
|
self="$(basename "$0")"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<EOUSAGE
|
||||||
|
|
||||||
|
usage: $self [-t test ...] image:tag [...]
|
||||||
|
ie: $self debian:wheezy
|
||||||
|
$self -t utc python:3
|
||||||
|
$self -t utc python:3 -t python-hy
|
||||||
|
|
||||||
|
This script processes the specified Docker images to test their running
|
||||||
|
environments.
|
||||||
|
EOUSAGE
|
||||||
|
}
|
||||||
|
|
||||||
|
# arg handling
|
||||||
|
opts="$(getopt -o 'ht:c:?' --long 'dry-run,help,test:,config:' -- "$@" || { usage >&2 && false; })"
|
||||||
|
eval set -- "$opts"
|
||||||
|
|
||||||
|
declare -A argTests=()
|
||||||
|
declare -a configs=()
|
||||||
|
dryRun=
|
||||||
|
while true; do
|
||||||
|
flag=$1
|
||||||
|
shift
|
||||||
|
case "$flag" in
|
||||||
|
--dry-run) dryRun=1 ;;
|
||||||
|
--help|-h|'-?') usage && exit 0 ;;
|
||||||
|
--test|-t) argTests["$1"]=1 && shift ;;
|
||||||
|
--config|-c) configs+=("$(readlink -f "$1")") && shift ;;
|
||||||
|
--) break ;;
|
||||||
|
*)
|
||||||
|
{
|
||||||
|
echo "error: unknown flag: $flag"
|
||||||
|
usage
|
||||||
|
} >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
|
usage >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# declare configuration variables
|
||||||
|
declare -a globalTests=()
|
||||||
|
declare -A testAlias=()
|
||||||
|
declare -A imageTests=()
|
||||||
|
declare -A globalExcludeTests=()
|
||||||
|
declare -A explicitTests=()
|
||||||
|
|
||||||
|
# if there are no user-specified configs, use the default config
|
||||||
|
if [ ${#configs} -eq 0 ]; then
|
||||||
|
configs+=("$dir/config.sh")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# load the configs
|
||||||
|
declare -A testPaths=()
|
||||||
|
for conf in "${configs[@]}"; do
|
||||||
|
. "$conf"
|
||||||
|
|
||||||
|
# Determine the full path to any newly-declared tests
|
||||||
|
confDir="$(dirname "$conf")"
|
||||||
|
|
||||||
|
for testName in ${globalTests[@]} ${imageTests[@]}; do
|
||||||
|
[ "${testPaths[$testName]}" ] && continue
|
||||||
|
|
||||||
|
if [ -d "$confDir/tests/$testName" ]; then
|
||||||
|
# Test directory found relative to the conf file
|
||||||
|
testPaths[$testName]="$confDir/tests/$testName"
|
||||||
|
elif [ -d "$dir/tests/$testName" ]; then
|
||||||
|
# Test directory found in the main tests/ directory
|
||||||
|
testPaths[$testName]="$dir/tests/$testName"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
didFail=
|
||||||
|
for dockerImage in "$@"; do
|
||||||
|
echo "testing $dockerImage"
|
||||||
|
|
||||||
|
if ! docker inspect "$dockerImage" &> /dev/null; then
|
||||||
|
echo $'\timage does not exist!'
|
||||||
|
didFail=1
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
repo="${dockerImage%:*}"
|
||||||
|
tagVar="${dockerImage#*:}"
|
||||||
|
#version="${tagVar%-*}"
|
||||||
|
variant="${tagVar##*-}"
|
||||||
|
|
||||||
|
testRepo=$repo
|
||||||
|
[ -z "${testAlias[$repo]}" ] || testRepo="${testAlias[$repo]}"
|
||||||
|
|
||||||
|
explicitVariant=
|
||||||
|
if [ \
|
||||||
|
"${explicitTests[:$variant]}" \
|
||||||
|
-o "${explicitTests[$repo:$variant]}" \
|
||||||
|
-o "${explicitTests[$testRepo:$variant]}" \
|
||||||
|
]; then
|
||||||
|
explicitVariant=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
testCandidates=()
|
||||||
|
if [ -z "$explicitVariant" ]; then
|
||||||
|
testCandidates+=( "${globalTests[@]}" )
|
||||||
|
fi
|
||||||
|
testCandidates+=(
|
||||||
|
${imageTests[:$variant]}
|
||||||
|
)
|
||||||
|
if [ -z "$explicitVariant" ]; then
|
||||||
|
testCandidates+=(
|
||||||
|
${imageTests[$testRepo]}
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
testCandidates+=(
|
||||||
|
${imageTests[$testRepo:$variant]}
|
||||||
|
)
|
||||||
|
if [ "$testRepo" != "$repo" ]; then
|
||||||
|
if [ -z "$explicitVariant" ]; then
|
||||||
|
testCandidates+=(
|
||||||
|
${imageTests[$repo]}
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
testCandidates+=(
|
||||||
|
${imageTests[$repo:$variant]}
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
|
||||||
|
tests=()
|
||||||
|
for t in "${testCandidates[@]}"; do
|
||||||
|
if [ ${#argTests[@]} -gt 0 -a -z "${argTests[$t]}" ]; then
|
||||||
|
# skipping due to -t
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ \
|
||||||
|
! -z "${globalExcludeTests[${testRepo}_$t]}" \
|
||||||
|
-o ! -z "${globalExcludeTests[${testRepo}:${variant}_$t]}" \
|
||||||
|
-o ! -z "${globalExcludeTests[:${variant}_$t]}" \
|
||||||
|
-o ! -z "${globalExcludeTests[${repo}_$t]}" \
|
||||||
|
-o ! -z "${globalExcludeTests[${repo}:${variant}_$t]}" \
|
||||||
|
-o ! -z "${globalExcludeTests[:${variant}_$t]}" \
|
||||||
|
]; then
|
||||||
|
# skipping due to exclude
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
tests+=( "$t" )
|
||||||
|
done
|
||||||
|
|
||||||
|
currentTest=0
|
||||||
|
totalTest="${#tests[@]}"
|
||||||
|
for t in "${tests[@]}"; do
|
||||||
|
(( currentTest+=1 ))
|
||||||
|
echo -ne "\t'$t' [$currentTest/$totalTest]..."
|
||||||
|
|
||||||
|
# run test against dockerImage here
|
||||||
|
# find the script for the test
|
||||||
|
scriptDir="${testPaths[$t]}"
|
||||||
|
if [ -d "$scriptDir" ]; then
|
||||||
|
script="$scriptDir/run.sh"
|
||||||
|
if [ -x "$script" -a ! -d "$script" ]; then
|
||||||
|
# TODO dryRun logic
|
||||||
|
if output="$("$script" $dockerImage)"; then
|
||||||
|
if [ -f "$scriptDir/expected-std-out.txt" ] && ! d="$(echo "$output" | diff -u "$scriptDir/expected-std-out.txt" - 2>/dev/null)"; then
|
||||||
|
echo 'failed; unexpected output:'
|
||||||
|
echo "$d"
|
||||||
|
didFail=1
|
||||||
|
else
|
||||||
|
echo 'passed'
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo 'failed'
|
||||||
|
didFail=1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "skipping"
|
||||||
|
echo >&2 "error: $script missing, not executable or is a directory"
|
||||||
|
didFail=1
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "skipping"
|
||||||
|
echo >&2 "error: unable to locate test '$t'"
|
||||||
|
didFail=1
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$didFail" ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
39
test/tests/docker-build.sh
Executable file
39
test/tests/docker-build.sh
Executable file
@ -0,0 +1,39 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# wrapper around "docker build" that creates a temporary directory and copies files into it first so that arbitrary host directories can be copied into containers without bind mounts, but accepts a Dockerfile on stdin
|
||||||
|
|
||||||
|
# usage: ./docker-build.sh some-host-directory some-new-image:some-tag <<EOD
|
||||||
|
# FROM ...
|
||||||
|
# COPY dir/... /.../
|
||||||
|
# EOD
|
||||||
|
# ie: ./docker-build.sh .../hylang-hello-world librarytest/hylang <<EOD
|
||||||
|
# FROM hylang
|
||||||
|
# COPY dir/container.hy /dir/
|
||||||
|
# CMD ["hy", "/dir/container.hy"]
|
||||||
|
# EOD
|
||||||
|
|
||||||
|
dir="$1"; shift
|
||||||
|
[ -d "$dir" ]
|
||||||
|
|
||||||
|
imageTag="$1"; shift
|
||||||
|
|
||||||
|
tmp="$(mktemp -t -d docker-library-test-build-XXXXXXXXXX)"
|
||||||
|
trap "rm -rf '$tmp'" EXIT
|
||||||
|
|
||||||
|
cat > "$tmp/Dockerfile"
|
||||||
|
|
||||||
|
from="$(awk -F '[ \t]+' 'toupper($1) == "FROM" { print $2; exit }' "$tmp/Dockerfile")"
|
||||||
|
onbuilds="$(docker inspect -f '{{len .Config.OnBuild}}' "$from")"
|
||||||
|
if [ "$onbuilds" -gt 0 ]; then
|
||||||
|
# crap, the image we want to build has some ONBUILD instructions
|
||||||
|
# those are kind of going to ruin our day
|
||||||
|
# let's do some hacks to strip those bad boys out in a new fake layer
|
||||||
|
"$(dirname "$(readlink -f "$BASH_SOURCE")")/remove-onbuild.sh" "$from" "$imageTag"
|
||||||
|
awk -F '[ \t]+' 'toupper($1) == "FROM" { $2 = "'"$imageTag"'" } { print }' "$tmp/Dockerfile" > "$tmp/Dockerfile.new"
|
||||||
|
mv "$tmp/Dockerfile.new" "$tmp/Dockerfile"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cp -RL "$dir" "$tmp/dir"
|
||||||
|
|
||||||
|
docker build -t "$imageTag" "$tmp" > /dev/null
|
10
test/tests/image-name.sh
Executable file
10
test/tests/image-name.sh
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# usage: ./image-name.sh librarytest/something some/image:some-tag
|
||||||
|
# output: librarytest/something:some-image-some-tag
|
||||||
|
|
||||||
|
base="$1"; shift
|
||||||
|
tag="$1"; shift
|
||||||
|
|
||||||
|
echo "$base:$(echo "$tag" | sed 's![:/]!-!g')"
|
22
test/tests/paranoid/container.sh
Normal file
22
test/tests/paranoid/container.sh
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SERV_IP=$(ip -4 -o addr show scope global | awk '{print $4}' | sed -e 's:/.*::' | head -n1)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Generate a simple configuration, returns nonzero on error
|
||||||
|
#
|
||||||
|
ovpn_genconfig -u udp://$SERV_IP 2>/dev/null
|
||||||
|
|
||||||
|
export EASYRSA_BATCH=1
|
||||||
|
export EASYRSA_REQ_CN="Travis-CI Test CA"
|
||||||
|
|
||||||
|
#
|
||||||
|
# Initialize the certificate PKI state, returns nonzero on error
|
||||||
|
#
|
||||||
|
ovpn_initpki nopass 2>/dev/null
|
||||||
|
|
||||||
|
#
|
||||||
|
# Test back-up
|
||||||
|
#
|
||||||
|
ovpn_copy_server_files
|
1
test/tests/paranoid/run.sh
Symbolic link
1
test/tests/paranoid/run.sh
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../run-bash-in-container.sh
|
7
test/tests/run-bash-in-container.sh
Executable file
7
test/tests/run-bash-in-container.sh
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
testDir="$(readlink -f "$(dirname "$BASH_SOURCE")")"
|
||||||
|
runDir="$(dirname "$(readlink -f "$BASH_SOURCE")")"
|
||||||
|
|
||||||
|
source "$runDir/run-in-container.sh" "$testDir" "$1" bash ./container.sh
|
46
test/tests/run-in-container.sh
Executable file
46
test/tests/run-in-container.sh
Executable file
@ -0,0 +1,46 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# NOT INTENDED TO BE USED AS A TEST "run.sh" DIRECTLY
|
||||||
|
# SEE OTHER "run-*-in-container.sh" SCRIPTS FOR USAGE
|
||||||
|
|
||||||
|
testDir="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
image="$1"
|
||||||
|
shift
|
||||||
|
entrypoint="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
# do some fancy footwork so that if testDir is /a/b/c, we mount /a/b and use c as the working directory (so relative symlinks work one level up)
|
||||||
|
thisDir="$(dirname "$(readlink -f "$BASH_SOURCE")")"
|
||||||
|
testDir="$(readlink -f "$testDir")"
|
||||||
|
testBase="$(basename "$testDir")"
|
||||||
|
hostMount="$(dirname "$testDir")"
|
||||||
|
containerMount="/tmp/test-dir"
|
||||||
|
workdir="$containerMount/$testBase"
|
||||||
|
# TODO should we be doing something fancy with $BASH_SOURCE instead so we can be arbitrarily deep and mount the top level always?
|
||||||
|
|
||||||
|
newImage="$("$thisDir/image-name.sh" librarytest/run-in-container "$image--$testBase")"
|
||||||
|
"$thisDir/docker-build.sh" "$hostMount" "$newImage" <<EOD
|
||||||
|
FROM $image
|
||||||
|
COPY dir $containerMount
|
||||||
|
WORKDIR $workdir
|
||||||
|
ENTRYPOINT ["$entrypoint"]
|
||||||
|
EOD
|
||||||
|
|
||||||
|
args=( --rm )
|
||||||
|
|
||||||
|
# there is strong potential for nokogiri+overlayfs failure
|
||||||
|
# see https://github.com/docker-library/ruby/issues/55
|
||||||
|
gemHome="$(docker inspect -f '{{range .Config.Env}}{{println .}}{{end}}' "$newImage" | awk -F '=' '$1 == "GEM_HOME" { print $2; exit }')"
|
||||||
|
if [ "$gemHome" ]; then
|
||||||
|
# must be a Ruby image
|
||||||
|
driver="$(docker info | awk -F ': ' '$1 == "Storage Driver" { print $2; exit }')"
|
||||||
|
if [ "$driver" = 'overlay' ]; then
|
||||||
|
# let's add a volume (_not_ a bind mount) on GEM_HOME to work around nokogiri+overlayfs issues
|
||||||
|
args+=( -v "$gemHome" )
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec docker run "${args[@]}" "$newImage" "$@"
|
@ -1,22 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -ex
|
|
||||||
|
|
||||||
IMG=${IMG:-kylemanna/openvpn}
|
|
||||||
|
|
||||||
temp=$(mktemp -d)
|
|
||||||
|
|
||||||
pushd $temp
|
|
||||||
|
|
||||||
SERV_IP=$(ip -4 -o addr show scope global | awk '{print $4}' | sed -e 's:/.*::' | head -n1)
|
|
||||||
|
|
||||||
docker run --net=none --rm -t -i -v $PWD:/etc/openvpn $IMG ovpn_genconfig -u udp://$SERV_IP
|
|
||||||
|
|
||||||
docker run --net=none --rm -t -i -v $PWD:/etc/openvpn -e "EASYRSA_BATCH=1" -e "EASYRSA_REQ_CN=Travis-CI Test CA" kylemanna/openvpn ovpn_initpki nopass
|
|
||||||
|
|
||||||
docker run --net=none --rm -t -i -v $PWD:/etc/openvpn $IMG ovpn_copy_server_files
|
|
||||||
|
|
||||||
popd
|
|
||||||
# Can't delete the temp directory as docker creates some files as root.
|
|
||||||
# Just let it die with the test instance.
|
|
||||||
rm -rf $temp || true
|
|
Loading…
Reference in New Issue
Block a user