run.sh 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. #!/bin/bash
  2. set -e
  3. dir="$(dirname "$(readlink -f "$BASH_SOURCE")")"
  4. self="$(basename "$0")"
  5. usage() {
  6. cat <<EOUSAGE
  7. usage: $self [-t test ...] image:tag [...]
  8. ie: $self debian:stretch
  9. $self -t utc python:3
  10. $self -t utc python:3 -t python-hy
  11. This script processes the specified Docker images to test their running
  12. environments.
  13. EOUSAGE
  14. }
  15. # arg handling
  16. opts="$(getopt -o 'ht:c:?' --long 'dry-run,help,test:,config:,keep-namespace' -- "$@" || { usage >&2 && false; })"
  17. eval set -- "$opts"
  18. declare -A argTests=()
  19. declare -a configs=()
  20. dryRun=
  21. keepNamespace=
  22. while true; do
  23. flag=$1
  24. shift
  25. case "$flag" in
  26. --dry-run) dryRun=1 ;;
  27. --help|-h|'-?') usage && exit 0 ;;
  28. --test|-t) argTests["$1"]=1 && shift ;;
  29. --config|-c) configs+=("$(readlink -f "$1")") && shift ;;
  30. --keep-namespace) keepNamespace=1 ;;
  31. --) break ;;
  32. *)
  33. {
  34. echo "error: unknown flag: $flag"
  35. usage
  36. } >&2
  37. exit 1
  38. ;;
  39. esac
  40. done
  41. if [ $# -eq 0 ]; then
  42. usage >&2
  43. exit 1
  44. fi
  45. # declare configuration variables
  46. declare -a globalTests=()
  47. declare -A testAlias=()
  48. declare -A imageTests=()
  49. declare -A globalExcludeTests=()
  50. declare -A explicitTests=()
  51. # if there are no user-specified configs, use the default config
  52. if [ ${#configs} -eq 0 ]; then
  53. configs+=("$dir/config.sh")
  54. fi
  55. # load the configs
  56. declare -A testPaths=()
  57. for conf in "${configs[@]}"; do
  58. . "$conf"
  59. # Determine the full path to any newly-declared tests
  60. confDir="$(dirname "$conf")"
  61. for testName in ${globalTests[@]} ${imageTests[@]}; do
  62. [ "${testPaths[$testName]}" ] && continue
  63. if [ -d "$confDir/tests/$testName" ]; then
  64. # Test directory found relative to the conf file
  65. testPaths[$testName]="$confDir/tests/$testName"
  66. elif [ -d "$dir/tests/$testName" ]; then
  67. # Test directory found in the main tests/ directory
  68. testPaths[$testName]="$dir/tests/$testName"
  69. fi
  70. done
  71. done
  72. didFail=
  73. for dockerImage in "$@"; do
  74. echo "testing $dockerImage"
  75. repo="${dockerImage%:*}"
  76. tagVar="${dockerImage#*:}"
  77. #version="${tagVar%-*}"
  78. variant="${tagVar##*-}"
  79. case "$tagVar" in
  80. *onbuild*)
  81. # "maven:onbuild-alpine" is still onbuild
  82. # ONCE ONBUILD, ALWAYS ONBUILD
  83. variant='onbuild'
  84. ;;
  85. *fpm-*)
  86. # lolPHP
  87. variant='fpm'
  88. ;;
  89. *alpine*)
  90. # "alpine3.4", "alpine3.6", "nginx:alpine-perl", etc are still "alpine" variants
  91. variant='alpine'
  92. ;;
  93. slim-*|*-slim-*)
  94. # "slim-jessie" is still "slim"
  95. variant='slim'
  96. ;;
  97. psmdb-*)
  98. # Percona Server for MongoDB is still "mongo"
  99. variant='psmdb'
  100. ;;
  101. *nanoserver*)
  102. # all nanoserver variants are windows and should have explict tests
  103. variant='nanoserver'
  104. ;;
  105. *windowsservercore*)
  106. # all servercore variants are windows and should have explict tests
  107. variant='windowsservercore'
  108. ;;
  109. esac
  110. testRepo="$repo"
  111. if [ -z "$keepNamespace" ]; then
  112. testRepo="${testRepo##*/}"
  113. fi
  114. for possibleAlias in \
  115. "${testAlias[$repo:$variant]}" \
  116. "${testAlias[$repo]}" \
  117. "${testAlias[$testRepo:$variant]}" \
  118. "${testAlias[$testRepo]}" \
  119. ; do
  120. if [ -n "$possibleAlias" ]; then
  121. testRepo="$possibleAlias"
  122. break
  123. fi
  124. done
  125. explicitVariant=
  126. if [ \
  127. "${explicitTests[:$variant]}" \
  128. -o "${explicitTests[$repo:$variant]}" \
  129. -o "${explicitTests[$testRepo:$variant]}" \
  130. ]; then
  131. explicitVariant=1
  132. fi
  133. testCandidates=()
  134. if [ -z "$explicitVariant" ]; then
  135. testCandidates+=( "${globalTests[@]}" )
  136. fi
  137. testCandidates+=(
  138. ${imageTests[:$variant]}
  139. )
  140. if [ -z "$explicitVariant" ]; then
  141. testCandidates+=(
  142. ${imageTests[$testRepo]}
  143. )
  144. fi
  145. testCandidates+=(
  146. ${imageTests[$testRepo:$variant]}
  147. )
  148. if [ "$testRepo" != "$repo" ]; then
  149. if [ -z "$explicitVariant" ]; then
  150. testCandidates+=(
  151. ${imageTests[$repo]}
  152. )
  153. fi
  154. testCandidates+=(
  155. ${imageTests[$repo:$variant]}
  156. )
  157. fi
  158. tests=()
  159. for t in "${testCandidates[@]}"; do
  160. if [ ${#argTests[@]} -gt 0 -a -z "${argTests[$t]}" ]; then
  161. # skipping due to -t
  162. continue
  163. fi
  164. if [ \
  165. ! -z "${globalExcludeTests[${testRepo}_$t]}" \
  166. -o ! -z "${globalExcludeTests[${testRepo}:${variant}_$t]}" \
  167. -o ! -z "${globalExcludeTests[:${variant}_$t]}" \
  168. -o ! -z "${globalExcludeTests[${repo}_$t]}" \
  169. -o ! -z "${globalExcludeTests[${repo}:${variant}_$t]}" \
  170. -o ! -z "${globalExcludeTests[:${variant}_$t]}" \
  171. ]; then
  172. # skipping due to exclude
  173. continue
  174. fi
  175. tests+=( "$t" )
  176. done
  177. # check for zero tests before checking for existing image
  178. # this will make windows variants no longer fail
  179. if [ "${#tests[@]}" -eq '0' ]; then
  180. echo $'\timage has no tests...skipping'
  181. continue
  182. fi
  183. if ! docker inspect "$dockerImage" &> /dev/null; then
  184. echo $'\timage does not exist!'
  185. didFail=1
  186. continue
  187. fi
  188. currentTest=0
  189. totalTest="${#tests[@]}"
  190. for t in "${tests[@]}"; do
  191. (( currentTest+=1 ))
  192. echo -ne "\t'$t' [$currentTest/$totalTest]..."
  193. # run test against dockerImage here
  194. # find the script for the test
  195. scriptDir="${testPaths[$t]}"
  196. if [ -d "$scriptDir" ]; then
  197. script="$scriptDir/run.sh"
  198. if [ -x "$script" -a ! -d "$script" ]; then
  199. # TODO dryRun logic
  200. if output="$("$script" $dockerImage)"; then
  201. if [ -f "$scriptDir/expected-std-out.txt" ] && ! d="$(echo "$output" | diff -u "$scriptDir/expected-std-out.txt" - 2>/dev/null)"; then
  202. echo 'failed; unexpected output:'
  203. echo "$d"
  204. didFail=1
  205. else
  206. echo 'passed'
  207. fi
  208. else
  209. echo 'failed'
  210. didFail=1
  211. fi
  212. else
  213. echo "skipping"
  214. echo >&2 "error: $script missing, not executable or is a directory"
  215. didFail=1
  216. continue
  217. fi
  218. else
  219. echo "skipping"
  220. echo >&2 "error: unable to locate test '$t'"
  221. didFail=1
  222. continue
  223. fi
  224. done
  225. done
  226. if [ "$didFail" ]; then
  227. exit 1
  228. fi