#!/usr/bin/env bash # # Source-level unit tests for export-runner.sh. The runner is written to be sourceable # (main runs only when executed directly), so we can load its functions, stub the parts # that would spawn containers, and assert pure logic. No Docker, no broker, no data dir. # # Run: scripts/test-export-runner.sh (exit 0 = all pass) set -uo pipefail HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" RUNNER="$HERE/export-runner.sh" # The runner sources runtime/export.env and hard-requires HOST_DATA_PATH/CTID/ACCOUNT. # Provide throwaway values so sourcing succeeds without the real deployment config. export ENV_FILE; ENV_FILE="$(mktemp)" cat > "$ENV_FILE" <<'ENV' HOST_DATA_PATH=/nonexistent CTID=test@example.com ACCOUNT=0 ENV trap 'rm -f "$ENV_FILE"' EXIT # shellcheck disable=SC1090 source "$RUNNER" PASS=0 FAIL=0 check() { # check NAME EXPECTED ACTUAL if [[ "$2" == "$3" ]]; then echo " ✓ $1"; PASS=$((PASS+1)) else echo " ✗ $1 — expected [$2], got [$3]"; FAIL=$((FAIL+1)); fi } # --- discover_start contamination regression ------------------------------------------- # run_one streams "[BOT] …" progress on STDOUT; discover_start's STDOUT is its result # channel (read via command substitution). A stub that mimics that noise must NOT leak # into the result. Pre-fix this returned garbage like "0-000-…" -> start_idx 0 -> the # year-0000 "--start=01/01/0" abort. CURRENT_YEAR/MONTH come from the host clock; pick a # data-start strictly before today so the assertion is stable regardless of the date. emit_noise() { echo " [BOT] Progress 50% | bla"; echo " [BOT] | Info | noise"; } # Scenario 1: data starts in a past December (yearly probe hits), Jan of that year empty, # Feb has data -> expect " 2". TARGET_YEAR=$(( CURRENT_YEAR - 1 )) probe_run() { emit_noise case "$3" in "01/12/$TARGET_YEAR") return 0 ;; # yearly probe: this December has data "01/02/$TARGET_YEAR") return 0 ;; # monthly probe: February is the first month *) return 1 ;; esac } got="$(discover_start FOO M1)" check "discover_start: result is clean (no [BOT] leakage)" "$TARGET_YEAR 2" "$got" # Scenario 2: no data in any past year, first data in an early month of the current year. probe_run() { emit_noise [[ "$3" == "01/0$(( CURRENT_MONTH > 1 ? CURRENT_MONTH - 1 : CURRENT_MONTH ))/$CURRENT_YEAR" ]] && return 0 return 1 } got="$(discover_start FOO M1)" # first month of the current year that the stub reports data for: want_m=$(( CURRENT_MONTH > 1 ? CURRENT_MONTH - 1 : CURRENT_MONTH )) check "discover_start: current-year fallback, clean result" "$CURRENT_YEAR $want_m" "$got" # Scenario 3: genuinely no data anywhere -> empty stdout, rc 1. probe_run() { emit_noise; return 1; } got="$(discover_start FOO M1)"; rc=$? check "discover_start: no data -> empty result" "" "$got" check "discover_start: no data -> rc 1" "1" "$rc" # --- month index round-trip (sanity on the arithmetic the resume loop depends on) ------ i=$(midx 2026 5) check "midx/idx_year round-trip" "2026" "$(idx_year "$i")" check "midx/idx_month round-trip" "5" "$(idx_month "$i")" # --- write_meta freshness guard (no Docker needed) ------------------------------------- # A recent sidecar must be skipped without spawning a container, so scheduled runs stay # short. Point HOST_DATA_PATH at a temp dir, drop a just-created meta file, and assert # write_meta classifies it as a fresh-skip. A docker stub fails loudly if it wrongly runs. TMPDATA="$(mktemp -d)"; HOST_DATA_PATH="$TMPDATA" : > "$TMPDATA/EURUSD.meta.json" # mtime = now -> inside any positive window META_OK=0; META_FAIL=0; META_SKIP=0; META_MAX_AGE_DAYS=7 docker() { echo "UNEXPECTED docker call" >&2; return 1; } # must NOT be reached on a fresh file write_meta EURUSD >/dev/null 2>&1 unset -f docker check "write_meta: fresh sidecar -> skipped" "1" "$META_SKIP" check "write_meta: fresh sidecar -> not produced" "0" "$META_OK" rm -rf "$TMPDATA" echo "-----" echo "$PASS passed, $FAIL failed" [[ $FAIL -eq 0 ]]