123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- #!/usr/bin/env bash
- set -Eeuo pipefail
- dir="$(dirname "$(readlink -f "$BASH_SOURCE")")"
- self="$(basename "$0")"
- usage() {
- cat <<EOUSAGE
- usage: $self [-t test ...] image:tag [...]
- ie: $self debian:trixie
- $self -t utc python:3
- $self -t utc python:3 -t python-imports
- 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:,keep-namespace' -- "$@" || { usage >&2 && false; })"
- eval set -- "$opts"
- declare -A argTests=()
- declare -a configs=()
- dryRun=
- keepNamespace=
- 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 ;;
- --keep-namespace) keepNamespace=1 ;;
- --) 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
- case "$(uname -o)" in
- Msys)
- # https://stackoverflow.com/a/34386471/433558
- # https://github.com/docker/toolbox/blob/6960f28d5b01857d69b2095a02949264f09d3e57/windows/start.sh#L104-L107
- docker() {
- MSYS_NO_PATHCONV=1 command docker "$@"
- }
- export -f docker
- ;;
- esac
- # 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
- [ -n "${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"
-
- repo="${dockerImage%:*}"
- tagVar="${dockerImage#*:}"
- #version="${tagVar%-*}"
- variant="${tagVar##*-}"
-
- case "$tagVar" in
- *onbuild*)
- # "maven:onbuild-alpine" is still onbuild
- # ONCE ONBUILD, ALWAYS ONBUILD
- variant='onbuild'
- ;;
- *apache-*)
- # lolPHP
- variant='apache'
- ;;
- *fpm-*)
- # lolPHP
- variant='fpm'
- ;;
- *alpine*)
- # "alpine3.4", "alpine3.6", "nginx:alpine-perl", etc are still "alpine" variants
- variant='alpine'
- ;;
- slim-*|*-slim-*)
- # "slim-trixie" is still "slim"
- variant='slim'
- ;;
- psmdb-*)
- # Percona Server for MongoDB is still "mongo"
- variant='psmdb'
- ;;
- *nanoserver*)
- # all nanoserver variants are windows
- variant='nanoserver'
- ;;
- *windowsservercore*)
- # all servercore variants are windows
- variant='windowsservercore'
- ;;
- esac
-
- testRepo="$repo"
- if [ -z "$keepNamespace" ]; then
- testRepo="${testRepo##*/}"
- fi
-
- for possibleAlias in \
- "${testAlias[$repo:$variant]:-}" \
- "${testAlias[$repo]:-}" \
- "${testAlias[$testRepo:$variant]:-}" \
- "${testAlias[$testRepo]:-}" \
- ; do
- if [ -n "$possibleAlias" ]; then
- testRepo="$possibleAlias"
- break
- fi
- done
-
- explicitVariant=
- for possibleExplicit in \
- "${explicitTests[:$variant]:-}" \
- "${explicitTests[$repo:$variant]:-}" \
- "${explicitTests[$repo]:-}" \
- "${explicitTests[$testRepo:$variant]:-}" \
- "${explicitTests[$testRepo]:-}" \
- ; do
- if [ -n "$possibleExplicit" ]; then
- explicitVariant=1
- break
- fi
- done
-
- 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 ] && [ -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
-
- # check for zero tests before checking for existing image
- # this will make windows variants no longer fail
- if [ "${#tests[@]}" -eq '0' ]; then
- echo $'\timage has no tests...skipping'
- continue
- fi
-
- if ! docker inspect "$dockerImage" &> /dev/null; then
- echo $'\timage does not exist!'
- didFail=1
- continue
- fi
-
- 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" ] && [ ! -d "$script" ]; then
- # TODO dryRun logic
- if output="$("$script" "$dockerImage")"; then
- output="$(tr -d '\r' <<<"$output")" # Windows gives us \r\n ... :D
- if [ -f "$scriptDir/expected-std-out.txt" ] && ! d="$(diff -u "$scriptDir/expected-std-out.txt" - <<<"$output" 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 [ -n "$didFail" ]; then
- exit 1
- fi
|