Sync all scripts from website downloads — 352 scripts total
Includes updated JS challenge scripts with Claude-User whitelist, same-site referer bypass, Blackbox-Exporter allowed bot, and all new exporters, cheat sheets, and automation scripts.
This commit is contained in:
Executable
+546
@@ -0,0 +1,546 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#####################################################################################
|
||||
#### docker-smoke-tests.sh — Verify Docker daemon and containers are healthy ####
|
||||
#### Checks daemon, API, lifecycle, networking, volumes, DNS, compose, images. ####
|
||||
#### ####
|
||||
#### Author: Phil Connor ####
|
||||
#### Contact: contact@mylinux.work ####
|
||||
#### License: MIT ####
|
||||
#### Version: 1.0 ####
|
||||
#### ####
|
||||
#### Usage: ./docker-smoke-tests.sh ####
|
||||
#### COMPOSE_FILE=/path/to/docker-compose.yml ./docker-smoke-tests.sh ####
|
||||
#### ####
|
||||
#### See --help for all options. ####
|
||||
#####################################################################################
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ── Defaults ──────────────────────────────────────────────────────────
|
||||
TEST_IMAGE="${TEST_IMAGE:-alpine:latest}"
|
||||
COMPOSE_FILE="${COMPOSE_FILE:-}"
|
||||
SKIP_LIFECYCLE="${SKIP_LIFECYCLE:-false}"
|
||||
SKIP_NETWORK="${SKIP_NETWORK:-false}"
|
||||
SKIP_VOLUME="${SKIP_VOLUME:-false}"
|
||||
SKIP_BUILD="${SKIP_BUILD:-false}"
|
||||
DNS_TEST_DOMAIN="${DNS_TEST_DOMAIN:-google.com}"
|
||||
OUTPUT_FORMAT="${OUTPUT_FORMAT:-text}"
|
||||
COLOR="${COLOR:-auto}"
|
||||
VERBOSE="${VERBOSE:-false}"
|
||||
|
||||
# ── State ─────────────────────────────────────────────────────────────
|
||||
PASS=0
|
||||
FAIL=0
|
||||
SKIP=0
|
||||
TOTAL=0
|
||||
RESULTS=()
|
||||
START_TIME=""
|
||||
|
||||
# ── Test artifact names ──────────────────────────────────────────────
|
||||
SMOKE_PREFIX="smoke-test-$$"
|
||||
SMOKE_CONTAINER="${SMOKE_PREFIX}-ctr"
|
||||
SMOKE_PORT_CONTAINER="${SMOKE_PREFIX}-port"
|
||||
SMOKE_DNS_CONTAINER="${SMOKE_PREFIX}-dns"
|
||||
SMOKE_VOL_CONTAINER="${SMOKE_PREFIX}-vol"
|
||||
SMOKE_NET_CONTAINER="${SMOKE_PREFIX}-net"
|
||||
SMOKE_MEM_CONTAINER="${SMOKE_PREFIX}-mem"
|
||||
SMOKE_VOLUME="${SMOKE_PREFIX}-vol"
|
||||
SMOKE_NETWORK="${SMOKE_PREFIX}-net"
|
||||
SMOKE_BUILD_TAG="${SMOKE_PREFIX}-img"
|
||||
SMOKE_PORT=$((47000 + (RANDOM % 1000)))
|
||||
|
||||
# ── Colors ────────────────────────────────────────────────────────────
|
||||
setup_colors() {
|
||||
if [[ "$COLOR" == "never" ]]; then
|
||||
RED="" GREEN="" YELLOW="" BLUE="" BOLD="" RESET=""
|
||||
return
|
||||
fi
|
||||
if [[ "$COLOR" == "always" ]] || [[ -t 1 ]]; then
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[0;33m'
|
||||
BLUE='\033[0;34m'
|
||||
BOLD='\033[1m'
|
||||
RESET='\033[0m'
|
||||
else
|
||||
RED="" GREEN="" YELLOW="" BLUE="" BOLD="" RESET=""
|
||||
fi
|
||||
}
|
||||
|
||||
# ── Logging ───────────────────────────────────────────────────────────
|
||||
log() { echo -e "${BLUE}[INFO]${RESET} $*"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${RESET} $*" >&2; }
|
||||
err() { echo -e "${RED}[ERROR]${RESET} $*" >&2; }
|
||||
verbose() { if [[ "$VERBOSE" == "true" ]]; then echo -e "${BLUE}[DEBUG]${RESET} $*"; fi; }
|
||||
|
||||
# ── Test Result Recording ─────────────────────────────────────────────
|
||||
record_pass() {
|
||||
local name="$1" detail="${2:-}"
|
||||
((PASS++)) || true; ((TOTAL++)) || true
|
||||
RESULTS+=("PASS|${name}|${detail}")
|
||||
if [[ "$OUTPUT_FORMAT" == "tap" ]]; then echo "ok ${TOTAL} - ${name}${detail:+ (${detail})}"
|
||||
else echo -e " ${GREEN}✓${RESET} ${name}${detail:+ — ${detail}}"; fi
|
||||
}
|
||||
|
||||
record_fail() {
|
||||
local name="$1" detail="${2:-}"
|
||||
((FAIL++)) || true; ((TOTAL++)) || true
|
||||
RESULTS+=("FAIL|${name}|${detail}")
|
||||
if [[ "$OUTPUT_FORMAT" == "tap" ]]; then
|
||||
echo "not ok ${TOTAL} - ${name}"
|
||||
[[ -n "$detail" ]] && echo " # ${detail}"
|
||||
else echo -e " ${RED}✗${RESET} ${name}${detail:+ — ${detail}}"; fi
|
||||
}
|
||||
|
||||
record_skip() {
|
||||
local name="$1" reason="${2:-}"
|
||||
((SKIP++)) || true; ((TOTAL++)) || true
|
||||
RESULTS+=("SKIP|${name}|${reason}")
|
||||
if [[ "$OUTPUT_FORMAT" == "tap" ]]; then echo "ok ${TOTAL} - ${name} # SKIP ${reason}"
|
||||
else echo -e " ${YELLOW}⊘${RESET} ${name}${reason:+ — ${reason}}"; fi
|
||||
}
|
||||
|
||||
# ── Helpers ───────────────────────────────────────────────────────────
|
||||
has_cmd() { command -v "$1" >/dev/null 2>&1; }
|
||||
|
||||
remove_container() {
|
||||
local name="$1"
|
||||
docker rm -f "$name" >/dev/null 2>&1 || true
|
||||
}
|
||||
|
||||
section() {
|
||||
if [[ "$OUTPUT_FORMAT" != "tap" ]]; then echo ""; echo -e "${BOLD}$1${RESET}"; fi
|
||||
}
|
||||
|
||||
# ── Cleanup ───────────────────────────────────────────────────────────
|
||||
# shellcheck disable=SC2317
|
||||
cleanup() {
|
||||
verbose "Cleaning up test artifacts..."
|
||||
remove_container "$SMOKE_CONTAINER"
|
||||
remove_container "$SMOKE_PORT_CONTAINER"
|
||||
remove_container "$SMOKE_DNS_CONTAINER"
|
||||
remove_container "$SMOKE_VOL_CONTAINER"
|
||||
remove_container "$SMOKE_NET_CONTAINER"
|
||||
remove_container "$SMOKE_MEM_CONTAINER"
|
||||
docker volume rm -f "$SMOKE_VOLUME" >/dev/null 2>&1 || true
|
||||
docker network rm "$SMOKE_NETWORK" >/dev/null 2>&1 || true
|
||||
docker rmi -f "$SMOKE_BUILD_TAG" >/dev/null 2>&1 || true
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# TEST FUNCTIONS
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
|
||||
# ── 1. Docker daemon running ─────────────────────────────────────────
|
||||
test_daemon_running() {
|
||||
if has_cmd systemctl; then
|
||||
if systemctl is-active --quiet docker 2>/dev/null; then record_pass "Docker daemon running" "systemctl active"
|
||||
else record_fail "Docker daemon running" "systemctl inactive"; fi
|
||||
elif has_cmd service; then
|
||||
if service docker status >/dev/null 2>&1; then record_pass "Docker daemon running" "service running"
|
||||
else record_fail "Docker daemon running" "service stopped"; fi
|
||||
elif docker info >/dev/null 2>&1; then record_pass "Docker daemon running" "docker info ok"
|
||||
else record_fail "Docker daemon running" "cannot determine status"; fi
|
||||
}
|
||||
|
||||
# ── 2. Docker API responsive ─────────────────────────────────────────
|
||||
test_api_responsive() {
|
||||
local output
|
||||
if output=$(timeout 10 docker info 2>&1); then
|
||||
local ver; ver=$(echo "$output" | grep -i "Server Version" | head -1 | awk '{print $NF}') || true
|
||||
record_pass "Docker API responsive" "server ${ver:-unknown}"
|
||||
else record_fail "Docker API responsive" "docker info timed out or failed"; fi
|
||||
}
|
||||
|
||||
# ── 3. Docker socket accessible ──────────────────────────────────────
|
||||
test_socket_accessible() {
|
||||
local socket="/var/run/docker.sock"
|
||||
if [[ -S "$socket" ]]; then
|
||||
if [[ -r "$socket" && -w "$socket" ]]; then record_pass "Docker socket accessible" "$socket"
|
||||
else record_fail "Docker socket accessible" "$socket not readable/writable"; fi
|
||||
elif docker info >/dev/null 2>&1; then record_pass "Docker socket accessible" "non-default socket"
|
||||
else record_fail "Docker socket accessible" "$socket not found"; fi
|
||||
}
|
||||
|
||||
# ── 4. Container lifecycle ───────────────────────────────────────────
|
||||
test_container_lifecycle() {
|
||||
if [[ "$SKIP_LIFECYCLE" == "true" ]]; then record_skip "Container lifecycle" "SKIP_LIFECYCLE=true"; return; fi
|
||||
remove_container "$SMOKE_CONTAINER"
|
||||
|
||||
if ! docker create --name "$SMOKE_CONTAINER" "$TEST_IMAGE" sleep 30 >/dev/null 2>&1; then
|
||||
record_fail "Container lifecycle" "docker create failed"
|
||||
return
|
||||
fi
|
||||
|
||||
if ! docker start "$SMOKE_CONTAINER" >/dev/null 2>&1; then
|
||||
record_fail "Container lifecycle" "docker start failed"
|
||||
return
|
||||
fi
|
||||
|
||||
local exec_output
|
||||
exec_output=$(docker exec "$SMOKE_CONTAINER" echo "smoke-ok" 2>&1) || true
|
||||
if [[ "$exec_output" != "smoke-ok" ]]; then
|
||||
record_fail "Container lifecycle" "docker exec failed"
|
||||
return
|
||||
fi
|
||||
|
||||
if ! docker stop -t 5 "$SMOKE_CONTAINER" >/dev/null 2>&1; then
|
||||
record_fail "Container lifecycle" "docker stop failed"
|
||||
return
|
||||
fi
|
||||
|
||||
if ! docker rm "$SMOKE_CONTAINER" >/dev/null 2>&1; then
|
||||
record_fail "Container lifecycle" "docker rm failed"
|
||||
return
|
||||
fi
|
||||
|
||||
record_pass "Container lifecycle" "create/start/exec/stop/rm"
|
||||
}
|
||||
|
||||
# ── 5. Port binding ──────────────────────────────────────────────────
|
||||
test_port_binding() {
|
||||
if [[ "$SKIP_LIFECYCLE" == "true" ]]; then record_skip "Port binding" "SKIP_LIFECYCLE=true"; return; fi
|
||||
if ! has_cmd curl; then record_skip "Port binding" "curl not installed"; return; fi
|
||||
remove_container "$SMOKE_PORT_CONTAINER"
|
||||
|
||||
if ! docker run -d --name "$SMOKE_PORT_CONTAINER" \
|
||||
-p "${SMOKE_PORT}:80" \
|
||||
"$TEST_IMAGE" sh -c 'mkdir -p /var/www && echo "smoke-ok" > /var/www/index.html && httpd -f -p 80 -h /var/www 2>/dev/null || { while true; do echo -e "HTTP/1.1 200 OK\r\nContent-Length: 9\r\n\r\nsmoke-ok\n" | nc -l -p 80 2>/dev/null || break; done; }' >/dev/null 2>&1; then
|
||||
record_fail "Port binding" "failed to start container with port mapping"
|
||||
return
|
||||
fi
|
||||
|
||||
sleep 2
|
||||
local response
|
||||
response=$(curl -sf --max-time 5 "http://localhost:${SMOKE_PORT}/" 2>/dev/null) || true
|
||||
remove_container "$SMOKE_PORT_CONTAINER"
|
||||
|
||||
if [[ "$response" == *"smoke-ok"* ]]; then
|
||||
record_pass "Port binding" "curl localhost:${SMOKE_PORT}"
|
||||
else
|
||||
record_fail "Port binding" "no response on localhost:${SMOKE_PORT}"
|
||||
fi
|
||||
}
|
||||
|
||||
# ── 6. Container DNS ─────────────────────────────────────────────────
|
||||
test_container_dns() {
|
||||
if [[ "$SKIP_LIFECYCLE" == "true" ]]; then record_skip "Container DNS" "SKIP_LIFECYCLE=true"; return; fi
|
||||
remove_container "$SMOKE_DNS_CONTAINER"
|
||||
|
||||
local dns_output
|
||||
dns_output=$(docker run --rm --name "$SMOKE_DNS_CONTAINER" "$TEST_IMAGE" \
|
||||
sh -c "nslookup ${DNS_TEST_DOMAIN} 2>/dev/null || getent hosts ${DNS_TEST_DOMAIN} 2>/dev/null || ping -c1 -W3 ${DNS_TEST_DOMAIN} 2>/dev/null" 2>&1) || true
|
||||
|
||||
if [[ -n "$dns_output" ]] && ! echo "$dns_output" | grep -qi "can't resolve\|not found\|failure\|NXDOMAIN"; then
|
||||
record_pass "Container DNS" "${DNS_TEST_DOMAIN}"
|
||||
else
|
||||
record_fail "Container DNS" "failed to resolve ${DNS_TEST_DOMAIN}"
|
||||
fi
|
||||
}
|
||||
|
||||
# ── 7. Volume mount ──────────────────────────────────────────────────
|
||||
test_volume_mount() {
|
||||
if [[ "$SKIP_VOLUME" == "true" ]]; then record_skip "Volume mount" "SKIP_VOLUME=true"; return; fi
|
||||
docker volume rm -f "$SMOKE_VOLUME" >/dev/null 2>&1 || true
|
||||
remove_container "$SMOKE_VOL_CONTAINER"
|
||||
|
||||
if ! docker volume create "$SMOKE_VOLUME" >/dev/null 2>&1; then
|
||||
record_fail "Volume mount" "docker volume create failed"
|
||||
return
|
||||
fi
|
||||
|
||||
local write_result
|
||||
write_result=$(docker run --rm --name "$SMOKE_VOL_CONTAINER" \
|
||||
-v "${SMOKE_VOLUME}:/data" "$TEST_IMAGE" \
|
||||
sh -c 'echo "smoke-vol-ok" > /data/test.txt && cat /data/test.txt' 2>&1) || true
|
||||
|
||||
docker volume rm -f "$SMOKE_VOLUME" >/dev/null 2>&1 || true
|
||||
|
||||
if [[ "$write_result" == "smoke-vol-ok" ]]; then
|
||||
record_pass "Volume mount" "write/read verified"
|
||||
else
|
||||
record_fail "Volume mount" "write/read mismatch"
|
||||
fi
|
||||
}
|
||||
|
||||
# ── 8. Network create/connect ────────────────────────────────────────
|
||||
test_network_create() {
|
||||
if [[ "$SKIP_NETWORK" == "true" ]]; then record_skip "Network create/connect" "SKIP_NETWORK=true"; return; fi
|
||||
docker network rm "$SMOKE_NETWORK" >/dev/null 2>&1 || true
|
||||
remove_container "$SMOKE_NET_CONTAINER"
|
||||
|
||||
if ! docker network create --driver bridge "$SMOKE_NETWORK" >/dev/null 2>&1; then
|
||||
record_fail "Network create/connect" "docker network create failed"
|
||||
return
|
||||
fi
|
||||
|
||||
local net_output
|
||||
net_output=$(docker run --rm --name "$SMOKE_NET_CONTAINER" \
|
||||
--network "$SMOKE_NETWORK" "$TEST_IMAGE" \
|
||||
sh -c 'ip addr show 2>/dev/null || ifconfig 2>/dev/null' 2>&1) || true
|
||||
|
||||
docker network rm "$SMOKE_NETWORK" >/dev/null 2>&1 || true
|
||||
|
||||
if [[ -n "$net_output" ]]; then
|
||||
record_pass "Network create/connect" "bridge network"
|
||||
else
|
||||
record_fail "Network create/connect" "container failed to attach to network"
|
||||
fi
|
||||
}
|
||||
|
||||
# ── 9. Image pull ────────────────────────────────────────────────────
|
||||
test_image_pull() {
|
||||
if docker pull "$TEST_IMAGE" >/dev/null 2>&1; then
|
||||
record_pass "Image pull" "$TEST_IMAGE"
|
||||
else
|
||||
record_fail "Image pull" "failed to pull $TEST_IMAGE"
|
||||
fi
|
||||
}
|
||||
|
||||
# ── 10. Image build ──────────────────────────────────────────────────
|
||||
test_image_build() {
|
||||
if [[ "$SKIP_BUILD" == "true" ]]; then record_skip "Image build" "SKIP_BUILD=true"; return; fi
|
||||
docker rmi -f "$SMOKE_BUILD_TAG" >/dev/null 2>&1 || true
|
||||
|
||||
if echo "FROM alpine:latest" | docker build -t "$SMOKE_BUILD_TAG" - >/dev/null 2>&1; then
|
||||
docker rmi -f "$SMOKE_BUILD_TAG" >/dev/null 2>&1 || true
|
||||
record_pass "Image build" "inline Dockerfile"
|
||||
else
|
||||
record_fail "Image build" "docker build failed"
|
||||
fi
|
||||
}
|
||||
|
||||
# ── 11. Docker Compose ───────────────────────────────────────────────
|
||||
test_compose_stack() {
|
||||
if [[ -z "$COMPOSE_FILE" ]]; then
|
||||
record_skip "Compose stack" "COMPOSE_FILE not set"
|
||||
return
|
||||
fi
|
||||
if [[ ! -f "$COMPOSE_FILE" ]]; then
|
||||
record_fail "Compose stack" "${COMPOSE_FILE} not found"
|
||||
return
|
||||
fi
|
||||
local compose_cmd=""
|
||||
if docker compose version >/dev/null 2>&1; then
|
||||
compose_cmd="docker compose"
|
||||
elif has_cmd docker-compose; then
|
||||
compose_cmd="docker-compose"
|
||||
else
|
||||
record_skip "Compose stack" "neither 'docker compose' nor 'docker-compose' available"
|
||||
return
|
||||
fi
|
||||
|
||||
local ps_output expected_count running_count
|
||||
ps_output=$($compose_cmd -f "$COMPOSE_FILE" ps --format json 2>/dev/null) || true
|
||||
|
||||
if [[ -z "$ps_output" ]]; then
|
||||
ps_output=$($compose_cmd -f "$COMPOSE_FILE" ps 2>/dev/null) || true
|
||||
if [[ -z "$ps_output" ]]; then
|
||||
record_fail "Compose stack" "could not read compose project status"
|
||||
return
|
||||
fi
|
||||
expected_count=$(echo "$ps_output" | tail -n +2 | wc -l)
|
||||
running_count=$(echo "$ps_output" | tail -n +2 | grep -ciE "up|running" || true)
|
||||
else
|
||||
expected_count=$(echo "$ps_output" | grep -c '"Service"' 2>/dev/null || echo "$ps_output" | wc -l)
|
||||
running_count=$(echo "$ps_output" | grep -ciE '"running"' 2>/dev/null || true)
|
||||
fi
|
||||
|
||||
if [[ "$expected_count" -eq 0 ]]; then
|
||||
record_fail "Compose stack" "no services found"
|
||||
elif [[ "$running_count" -ge "$expected_count" ]]; then
|
||||
record_pass "Compose stack" "${running_count}/${expected_count} services running"
|
||||
else
|
||||
record_fail "Compose stack" "${running_count}/${expected_count} services running"
|
||||
fi
|
||||
}
|
||||
|
||||
# ── 12. Resource limits ──────────────────────────────────────────────
|
||||
test_resource_limits() {
|
||||
if [[ "$SKIP_LIFECYCLE" == "true" ]]; then record_skip "Resource limits" "SKIP_LIFECYCLE=true"; return; fi
|
||||
remove_container "$SMOKE_MEM_CONTAINER"
|
||||
|
||||
local mem_limit
|
||||
mem_limit=$(docker run --rm --name "$SMOKE_MEM_CONTAINER" \
|
||||
--memory=64m "$TEST_IMAGE" \
|
||||
sh -c 'cat /sys/fs/cgroup/memory.max 2>/dev/null || cat /sys/fs/cgroup/memory/memory.limit_in_bytes 2>/dev/null' 2>&1) || true
|
||||
|
||||
if [[ -z "$mem_limit" ]]; then
|
||||
record_skip "Resource limits" "cgroup memory info not available"
|
||||
return
|
||||
fi
|
||||
|
||||
local limit_bytes=67108864 # 64 MiB
|
||||
if [[ "$mem_limit" =~ ^[0-9]+$ ]]; then
|
||||
if [[ "$mem_limit" -le $((limit_bytes + 1048576)) ]]; then
|
||||
local limit_mb=$((mem_limit / 1048576))
|
||||
record_pass "Resource limits" "memory cgroup enforced (${limit_mb}M)"
|
||||
else
|
||||
record_fail "Resource limits" "memory limit not enforced (got ${mem_limit})"
|
||||
fi
|
||||
else
|
||||
record_skip "Resource limits" "unexpected cgroup value: ${mem_limit}"
|
||||
fi
|
||||
}
|
||||
|
||||
# ── 13. Disk space ───────────────────────────────────────────────────
|
||||
test_disk_space() {
|
||||
local df_output
|
||||
df_output=$(docker system df 2>/dev/null) || true
|
||||
|
||||
if [[ -z "$df_output" ]]; then
|
||||
record_fail "Disk space" "docker system df failed"
|
||||
return
|
||||
fi
|
||||
|
||||
local docker_root used_pct
|
||||
docker_root=$(docker info --format '{{.DockerRootDir}}' 2>/dev/null) || docker_root="/var/lib/docker"
|
||||
used_pct=$(df "$docker_root" 2>/dev/null | tail -1 | awk '{print $5}' | tr -d '%') || used_pct=0
|
||||
|
||||
if [[ "$used_pct" -gt 80 ]]; then
|
||||
record_fail "Disk space" "${used_pct}% used (threshold 80%)"
|
||||
else
|
||||
record_pass "Disk space" "${used_pct}% used"
|
||||
fi
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# OUTPUT
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
|
||||
print_tap_header() {
|
||||
echo "TAP version 13"
|
||||
}
|
||||
|
||||
print_tap_footer() {
|
||||
echo "1..${TOTAL}"
|
||||
echo "# pass ${PASS}"
|
||||
echo "# fail ${FAIL}"
|
||||
echo "# skip ${SKIP}"
|
||||
}
|
||||
|
||||
print_summary() {
|
||||
local end_time; end_time=$(date +%s)
|
||||
local duration=$(( end_time - START_TIME ))
|
||||
echo ""
|
||||
echo -e "${BOLD}────────────────────────────────────────${RESET}"
|
||||
echo -e "${BOLD}Summary${RESET} Docker Smoke Tests"
|
||||
echo -e " ${GREEN}${PASS} passed${RESET} ${RED}${FAIL} failed${RESET} ${YELLOW}${SKIP} skipped${RESET} (${duration}s)"
|
||||
echo -e "${BOLD}────────────────────────────────────────${RESET}"
|
||||
if [[ $FAIL -eq 0 ]]; then echo -e "${GREEN}${BOLD}All tests passed.${RESET}"
|
||||
else echo -e "${RED}${BOLD}${FAIL} test(s) failed.${RESET}"; fi
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# MAIN
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $(basename "$0") [OPTIONS]
|
||||
|
||||
Smoke-test Docker daemon, containers, networking, volumes, images, and compose.
|
||||
|
||||
Environment variables (all optional):
|
||||
TEST_IMAGE Image for tests (default: alpine:latest)
|
||||
COMPOSE_FILE docker-compose.yml path (default: none)
|
||||
SKIP_LIFECYCLE Skip lifecycle tests (default: false)
|
||||
SKIP_NETWORK Skip network tests (default: false)
|
||||
SKIP_VOLUME Skip volume tests (default: false)
|
||||
SKIP_BUILD Skip build test (default: false)
|
||||
DNS_TEST_DOMAIN DNS domain to resolve (default: google.com)
|
||||
OUTPUT_FORMAT text or tap (default: text)
|
||||
COLOR auto, always, never (default: auto)
|
||||
VERBOSE Show debug output (default: false)
|
||||
|
||||
Options:
|
||||
--skip-lifecycle Skip container lifecycle tests
|
||||
--skip-network Skip network tests
|
||||
--skip-volume Skip volume tests
|
||||
--skip-build Skip image build test
|
||||
--format FORMAT Output format: text (default), tap
|
||||
--verbose Show debug output
|
||||
--no-color Disable colored output
|
||||
--help Show this help
|
||||
|
||||
Examples:
|
||||
./$(basename "$0")
|
||||
COMPOSE_FILE=/opt/stacks/web/docker-compose.yml ./$(basename "$0")
|
||||
OUTPUT_FORMAT=tap ./$(basename "$0") --skip-build
|
||||
EOF
|
||||
}
|
||||
|
||||
main() {
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--skip-lifecycle) SKIP_LIFECYCLE=true ;;
|
||||
--skip-network) SKIP_NETWORK=true ;;
|
||||
--skip-volume) SKIP_VOLUME=true ;;
|
||||
--skip-build) SKIP_BUILD=true ;;
|
||||
--format) OUTPUT_FORMAT="$2"; shift ;;
|
||||
--verbose) VERBOSE=true ;;
|
||||
--no-color) COLOR=never ;;
|
||||
--help|-h) usage; exit 0 ;;
|
||||
*) err "Unknown option: $1"; usage; exit 1 ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
setup_colors
|
||||
|
||||
if ! has_cmd docker; then
|
||||
err "docker CLI not found in PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
if [[ "$OUTPUT_FORMAT" == "tap" ]]; then
|
||||
print_tap_header
|
||||
else
|
||||
echo ""
|
||||
echo -e "${BOLD}Docker Smoke Tests${RESET}"
|
||||
echo -e "Image: ${TEST_IMAGE} Port: ${SMOKE_PORT}"
|
||||
echo -e "Time: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
fi
|
||||
|
||||
section "Daemon & Infrastructure"
|
||||
test_daemon_running
|
||||
test_api_responsive
|
||||
test_socket_accessible
|
||||
|
||||
section "Image Operations"
|
||||
test_image_pull
|
||||
test_image_build
|
||||
|
||||
section "Container Operations"
|
||||
test_container_lifecycle
|
||||
test_port_binding
|
||||
test_container_dns
|
||||
|
||||
section "Storage"
|
||||
test_volume_mount
|
||||
test_disk_space
|
||||
|
||||
section "Networking"
|
||||
test_network_create
|
||||
|
||||
section "Resource Limits"
|
||||
test_resource_limits
|
||||
|
||||
section "Compose"
|
||||
test_compose_stack
|
||||
|
||||
# ── Results ──
|
||||
if [[ "$OUTPUT_FORMAT" == "tap" ]]; then
|
||||
print_tap_footer
|
||||
else
|
||||
print_summary
|
||||
fi
|
||||
|
||||
[[ $FAIL -eq 0 ]] && exit 0 || exit 1
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user