|
| 1 | +#!/usr/bin/env bats |
| 2 | +# E2E tests for direct TCP listener mode (no controller) |
| 3 | + |
| 4 | +SCRIPT_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")" && pwd)" |
| 5 | +EXPORTER_CONFIG="${SCRIPT_DIR}/exporters/exporter-direct-listener.yaml" |
| 6 | +LISTENER_PORT=19090 |
| 7 | +LISTENER_PID="" |
| 8 | + |
| 9 | +setup() { |
| 10 | + bats_load_library bats-support |
| 11 | + bats_load_library bats-assert |
| 12 | + |
| 13 | + bats_require_minimum_version 1.5.0 |
| 14 | +} |
| 15 | + |
| 16 | +# Start the exporter in the background. |
| 17 | +# $1 - config file (default: $EXPORTER_CONFIG) |
| 18 | +# $2 - readiness: "grpc" waits via jmp shell (drains LogStream), |
| 19 | +# "port" waits via nc -z (preserves LogStream queue) |
| 20 | +# $3 - if set, redirect stderr to ${BATS_TEST_TMPDIR}/exporter.log |
| 21 | +# $4 - passphrase (optional) |
| 22 | +_start_exporter() { |
| 23 | + local config="${1:-$EXPORTER_CONFIG}" |
| 24 | + local readiness="${2:-grpc}" |
| 25 | + local capture_logs="${3:-}" |
| 26 | + local passphrase="${4:-}" |
| 27 | + |
| 28 | + local extra_args=() |
| 29 | + if [ -n "$passphrase" ]; then |
| 30 | + extra_args+=(--passphrase "$passphrase") |
| 31 | + fi |
| 32 | + |
| 33 | + if [ -n "$capture_logs" ]; then |
| 34 | + jmp run --exporter-config "$config" \ |
| 35 | + --tls-grpc-listener "$LISTENER_PORT" \ |
| 36 | + --tls-grpc-insecure "${extra_args[@]}" 2>"${BATS_TEST_TMPDIR}/exporter.log" & |
| 37 | + else |
| 38 | + jmp run --exporter-config "$config" \ |
| 39 | + --tls-grpc-listener "$LISTENER_PORT" \ |
| 40 | + --tls-grpc-insecure "${extra_args[@]}" & |
| 41 | + fi |
| 42 | + LISTENER_PID=$! |
| 43 | + echo "$LISTENER_PID" > "${BATS_TEST_TMPDIR}/exporter.pid" |
| 44 | + |
| 45 | + local retries=30 |
| 46 | + if [ "$readiness" = "port" ]; then |
| 47 | + # TCP-only check: doesn't drain the LogStream queue, so hook output |
| 48 | + # remains buffered for the test command to consume. |
| 49 | + while ! nc -z 127.0.0.1 "$LISTENER_PORT" 2>/dev/null; do |
| 50 | + retries=$((retries - 1)) |
| 51 | + if [ "$retries" -le 0 ]; then |
| 52 | + echo "Port $LISTENER_PORT did not become available" >&2 |
| 53 | + return 1 |
| 54 | + fi |
| 55 | + sleep 0.5 |
| 56 | + done |
| 57 | + else |
| 58 | + # Full gRPC check: ensures exporter is ready for commands. |
| 59 | + # Drains LogStream queue (unsuitable for hook output tests). |
| 60 | + local grpc_args=(--tls-grpc "127.0.0.1:${LISTENER_PORT}" --tls-grpc-insecure) |
| 61 | + if [ -n "$passphrase" ]; then |
| 62 | + grpc_args+=(--passphrase "$passphrase") |
| 63 | + fi |
| 64 | + while ! jmp shell "${grpc_args[@]}" -- j --help >/dev/null 2>&1; do |
| 65 | + retries=$((retries - 1)) |
| 66 | + if [ "$retries" -le 0 ]; then |
| 67 | + echo "Exporter did not become ready in time" >&2 |
| 68 | + return 1 |
| 69 | + fi |
| 70 | + sleep 0.5 |
| 71 | + done |
| 72 | + fi |
| 73 | +} |
| 74 | + |
| 75 | +start_exporter() { _start_exporter "$1" grpc; } |
| 76 | +start_exporter_with_logs() { _start_exporter "$1" grpc logs; } |
| 77 | +start_exporter_bg() { _start_exporter "$1" port; } |
| 78 | +start_exporter_bg_with_logs() { _start_exporter "$1" port logs; } |
| 79 | + |
| 80 | +start_exporter_with_passphrase() { _start_exporter "${2:-$EXPORTER_CONFIG}" grpc "" "$1"; } |
| 81 | + |
| 82 | +stop_exporter() { |
| 83 | + if [ -f "${BATS_TEST_TMPDIR}/exporter.pid" ]; then |
| 84 | + local pid |
| 85 | + pid=$(cat "${BATS_TEST_TMPDIR}/exporter.pid") |
| 86 | + if [ -n "$pid" ] && ps -p "$pid" > /dev/null 2>&1; then |
| 87 | + kill "$pid" 2>/dev/null || true |
| 88 | + wait "$pid" 2>/dev/null || true |
| 89 | + fi |
| 90 | + rm -f "${BATS_TEST_TMPDIR}/exporter.pid" |
| 91 | + fi |
| 92 | +} |
| 93 | + |
| 94 | +teardown() { |
| 95 | + stop_exporter |
| 96 | +} |
| 97 | + |
| 98 | +@test "direct listener: exporter starts and client can connect" { |
| 99 | + start_exporter |
| 100 | + |
| 101 | + run jmp shell --tls-grpc "127.0.0.1:${LISTENER_PORT}" --tls-grpc-insecure -- j power on |
| 102 | + assert_success |
| 103 | +} |
| 104 | + |
| 105 | +@test "direct listener: client can call multiple driver methods" { |
| 106 | + start_exporter |
| 107 | + |
| 108 | + run jmp shell --tls-grpc "127.0.0.1:${LISTENER_PORT}" --tls-grpc-insecure -- j power on |
| 109 | + assert_success |
| 110 | + |
| 111 | + run jmp shell --tls-grpc "127.0.0.1:${LISTENER_PORT}" --tls-grpc-insecure -- j power off |
| 112 | + assert_success |
| 113 | +} |
| 114 | + |
| 115 | +@test "direct listener: client without --tls-grpc-insecure fails against insecure server" { |
| 116 | + start_exporter |
| 117 | + |
| 118 | + run jmp shell --tls-grpc "127.0.0.1:${LISTENER_PORT}" -- j power on |
| 119 | + assert_failure |
| 120 | +} |
| 121 | + |
| 122 | +@test "direct listener hooks: beforeLease hook executes and j commands work" { |
| 123 | + # Use start_exporter_bg (TCP-only readiness check) to avoid draining |
| 124 | + # the LogStream queue before the test command connects. |
| 125 | + start_exporter_bg "${SCRIPT_DIR}/exporters/exporter-direct-hooks-before.yaml" |
| 126 | + |
| 127 | + run jmp shell --tls-grpc "127.0.0.1:${LISTENER_PORT}" --tls-grpc-insecure \ |
| 128 | + --exporter-logs -- j power off |
| 129 | + assert_success |
| 130 | + assert_output --partial "BEFORE_HOOK_DIRECT: executed" |
| 131 | + assert_output --partial "BEFORE_HOOK_DIRECT: complete" |
| 132 | +} |
| 133 | + |
| 134 | +@test "direct listener hooks: afterLease hook runs on exporter shutdown" { |
| 135 | + start_exporter_bg_with_logs "${SCRIPT_DIR}/exporters/exporter-direct-hooks-both.yaml" |
| 136 | + |
| 137 | + run jmp shell --tls-grpc "127.0.0.1:${LISTENER_PORT}" --tls-grpc-insecure \ |
| 138 | + --exporter-logs -- j power on |
| 139 | + assert_success |
| 140 | + assert_output --partial "BEFORE_HOOK_DIRECT: executed" |
| 141 | + |
| 142 | + # Stop the exporter (SIGTERM triggers _cleanup_after_lease). |
| 143 | + # stop_exporter waits for the process to exit, so the log is complete. |
| 144 | + stop_exporter |
| 145 | + |
| 146 | + # afterLease hook output should appear in the exporter's stderr log |
| 147 | + run cat "${BATS_TEST_TMPDIR}/exporter.log" |
| 148 | + assert_output --partial "AFTER_HOOK_DIRECT: executed" |
| 149 | +} |
| 150 | + |
| 151 | +@test "direct listener passphrase: correct passphrase connects" { |
| 152 | + start_exporter_with_passphrase "my-secret" |
| 153 | + |
| 154 | + run jmp shell --tls-grpc "127.0.0.1:${LISTENER_PORT}" --tls-grpc-insecure \ |
| 155 | + --passphrase "my-secret" -- j power on |
| 156 | + assert_success |
| 157 | +} |
| 158 | + |
| 159 | +@test "direct listener passphrase: wrong passphrase is rejected" { |
| 160 | + start_exporter_with_passphrase "my-secret" |
| 161 | + |
| 162 | + run jmp shell --tls-grpc "127.0.0.1:${LISTENER_PORT}" --tls-grpc-insecure \ |
| 163 | + --passphrase "wrong" -- j power on |
| 164 | + assert_failure |
| 165 | +} |
| 166 | + |
| 167 | +@test "direct listener passphrase: missing passphrase is rejected" { |
| 168 | + start_exporter_with_passphrase "my-secret" |
| 169 | + |
| 170 | + run jmp shell --tls-grpc "127.0.0.1:${LISTENER_PORT}" --tls-grpc-insecure \ |
| 171 | + -- j power on |
| 172 | + assert_failure |
| 173 | +} |
0 commit comments