diff --git a/run.sh b/run.sh index 868d338..d1cae51 100755 --- a/run.sh +++ b/run.sh @@ -14,15 +14,34 @@ reload_crond() { watch_config() { local file="$1" if command -v inotifywait >/dev/null 2>&1; then - inotifywait -m -e close_write,move,delete "$file" | - while read -r _; do - generate_cron - reload_crond + local dir="$(dirname "$file")" + local base="$(basename "$file")" + inotifywait -m -e close_write,move,create,delete "$dir" --format '%e %f' | + while read -r events fname; do + [ "$fname" = "$base" ] || continue + if echo "$events" | grep -qE 'DELETE|MOVED_FROM'; then + echo "Warning: configuration file '$file' missing, skipping cron generation" >&2 + elif [ -f "$file" ]; then + generate_cron + reload_crond + fi done || true else local prev - prev="$(md5sum "$file" 2>/dev/null | awk '{print $1}' || true)" + if [ -f "$file" ]; then + prev="$(md5sum "$file" 2>/dev/null | awk '{print $1}' || true)" + else + prev="missing" + echo "Warning: configuration file '$file' missing, skipping cron generation" >&2 + fi while sleep 5; do + if [ ! -f "$file" ]; then + if [ "$prev" != "missing" ]; then + prev="missing" + echo "Warning: configuration file '$file' missing, skipping cron generation" >&2 + fi + continue + fi local curr curr="$(md5sum "$file" 2>/dev/null | awk '{print $1}' || true)" if [ "$curr" != "$prev" ]; then @@ -35,7 +54,15 @@ watch_config() { } # Generate cron entries from environment/config -generate_cron +if [ -n "${CONFIG_FILE:-}" ]; then + if [ -f "$CONFIG_FILE" ]; then + generate_cron + else + echo "Warning: configuration file '$CONFIG_FILE' missing, skipping cron generation" >&2 + fi +else + generate_cron +fi crond -f -l 2 & CROND_PID=$! diff --git a/test.sh b/test.sh index 772d64b..9a3a7fe 100755 --- a/test.sh +++ b/test.sh @@ -1,31 +1,7 @@ #!/usr/bin/env bash set -euo pipefail -IMAGE_NAME=docker-cron-test -LOG_FILE=test.log -TEMP_CONFIG=config.json +bash tests/config_parser_test.sh +bash tests/watch_config_test.sh -cleanup() { - rm -f "$TEMP_CONFIG" "$LOG_FILE" -} -trap cleanup EXIT - -# Build docker image - docker build -t "$IMAGE_NAME" . - -# Create temporary config file -cat > "$TEMP_CONFIG" <<'CFG' -{ - "jobs": [ - {"cmd": "echo hello from cron", "interval": "* * * * *"} - ] -} -CFG - -# Run config parser inside container and display generated crontab - docker run --rm -v "$(pwd)/$TEMP_CONFIG:/config.json" -e CONFIG_FILE=/config.json --entrypoint /bin/sh "$IMAGE_NAME" -c '/app/config_parser.sh; cat /etc/crontabs/root' | tee "$LOG_FILE" - -# Verify expected command is present in log -grep -q "echo hello from cron" "$LOG_FILE" - -echo "Test completed successfully" +echo "All tests passed" diff --git a/tests/watch_config_test.sh b/tests/watch_config_test.sh new file mode 100755 index 0000000..a4162e2 --- /dev/null +++ b/tests/watch_config_test.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Ensure crond is available +if ! command -v crond >/dev/null 2>&1; then + if command -v apt-get >/dev/null 2>&1; then + apt-get update >/dev/null + apt-get install -y busybox >/dev/null + ln -sf /bin/busybox /usr/bin/crond + else + echo "crond not available, skipping watch_config test" >&2 + exit 0 + fi +fi + +# Ensure config parser is accessible at /app +if [ ! -e /app ]; then + ln -s "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/app" /app +fi + +# busybox crond expects /var/spool/cron/crontabs; map it to /etc/crontabs +if [ ! -e /var/spool/cron/crontabs ]; then + mkdir -p /var/spool/cron + mkdir -p /etc/crontabs + ln -s /etc/crontabs /var/spool/cron/crontabs +fi + +TMPDIR=$(mktemp -d) +CONFIG="$TMPDIR/config.json" +LOG="$TMPDIR/run.log" +RUN_PID=0 + +cleanup() { + if [ "$RUN_PID" -ne 0 ]; then + pkill -P "$RUN_PID" >/dev/null 2>&1 || true + kill "$RUN_PID" >/dev/null 2>&1 || true + fi + rm -rf "$TMPDIR" +} +trap cleanup EXIT + +cat >"$CONFIG" <<'CFG' +{ + "jobs": [ + {"cmd": "/bin/echo first", "interval": "* * * * *"} + ] +} +CFG + +CONFIG_FILE="$CONFIG" bash ./run.sh >"$LOG" 2>&1 & +RUN_PID=$! + +# Allow initial generation +sleep 2 + +grep -q "echo first" /etc/crontabs/root + +# Remove config file and ensure watcher keeps running +rm "$CONFIG" + +sleep 7 + +kill -0 "$RUN_PID" + +grep -q "configuration file.*missing" "$LOG" + +# Recreate config file with different command +cat >"$CONFIG" <<'CFG' +{ + "jobs": [ + {"cmd": "/bin/echo second", "interval": "* * * * *"} + ] +} +CFG + +sleep 7 + +grep -q "echo second" /etc/crontabs/root + +echo "watch_config test passed"