Skip to content

Commit 8f52178

Browse files
committed
test(acceptance): move listen telemetry proxy test under telemetry tag
- Add telemetry_listen_test.go (//go:build telemetry) with TestTelemetryListenProxy - Remove test from listen_test.go so matrix slices with telemetry disabled never run it - CI/run_parallel: single go test -tags=telemetry (no separate listen invocation) - README: document telemetry-tagged proxy tests Made-with: Cursor
1 parent ec62347 commit 8f52178

5 files changed

Lines changed: 112 additions & 54 deletions

File tree

.github/workflows/test-acceptance.yml

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,15 @@ jobs:
1717
tags: "basic connection source destination gateway mcp listen project_use connection_list connection_upsert connection_error_hints connection_oauth_aws connection_update"
1818
- slice: "1"
1919
api_key_secret: HOOKDECK_CLI_TESTING_API_KEY_2
20-
tags: "request event telemetry"
20+
tags: "request event"
2121
- slice: "2"
2222
api_key_secret: HOOKDECK_CLI_TESTING_API_KEY_3
2323
tags: "attempt metrics issue transformation"
2424
runs-on: ubuntu-latest
2525
env:
2626
ACCEPTANCE_SLICE: ${{ matrix.slice }}
2727
HOOKDECK_CLI_TESTING_API_KEY: ${{ secrets[matrix.api_key_secret] }}
28+
HOOKDECK_CLI_TELEMETRY_DISABLED: "1"
2829
steps:
2930
- name: Check out code
3031
uses: actions/checkout@v3
@@ -36,3 +37,23 @@ jobs:
3637

3738
- name: Run Go Acceptance Tests (slice ${{ matrix.slice }})
3839
run: go test -tags="${{ matrix.tags }}" ./test/acceptance/... -v -timeout 12m
40+
41+
# Telemetry proxy tests require the real telemetry header; matrix jobs set
42+
# HOOKDECK_CLI_TELEMETRY_DISABLED=1. This job runs only -tags=telemetry without
43+
# disabling telemetry (same as local when HOOKDECK_CLI_TELEMETRY_DISABLED is unset).
44+
acceptance-telemetry:
45+
runs-on: ubuntu-latest
46+
env:
47+
ACCEPTANCE_SLICE: "0"
48+
HOOKDECK_CLI_TESTING_API_KEY: ${{ secrets.HOOKDECK_CLI_TESTING_API_KEY }}
49+
steps:
50+
- name: Check out code
51+
uses: actions/checkout@v3
52+
53+
- name: Set up Go
54+
uses: actions/setup-go@v3
55+
with:
56+
go-version: "1.24.9"
57+
58+
- name: Run telemetry acceptance tests
59+
run: go test -tags=telemetry ./test/acceptance/... -v -timeout 12m

test/acceptance/README.md

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ These tests require browser-based authentication via `hookdeck login` and must b
2020

2121
### Recording proxy (telemetry tests)
2222

23-
Some tests (e.g. `TestTelemetryGatewayConnectionListProxy` in `telemetry_test.go`) use a **recording proxy**: the CLI is run with `--api-base` pointing at a local HTTP server that forwards every request to the real Hookdeck API and records method, path, and the `X-Hookdeck-CLI-Telemetry` header. The same `CLIRunner` and `go run main.go` flow are used as in other acceptance tests; only the API base URL is overridden so traffic goes through the proxy. This verifies that a single CLI run sends consistent telemetry (same `invocation_id` and `command_path`) on all API calls. Helpers: `StartRecordingProxy`, `AssertTelemetryConsistent`.
23+
Some tests (e.g. `TestTelemetryGatewayConnectionListProxy` in `telemetry_test.go`, `TestTelemetryListenProxy` in `telemetry_listen_test.go`) use a **recording proxy**: the CLI is run with `--api-base` pointing at a local HTTP server that forwards every request to the real Hookdeck API and records method, path, and the `X-Hookdeck-CLI-Telemetry` header. The same `CLIRunner` and `go run main.go` flow are used as in other acceptance tests; only the API base URL is overridden so traffic goes through the proxy. This verifies that a single CLI run sends consistent telemetry (same `invocation_id` and `command_path`) on all API calls. Helpers: `StartRecordingProxy`, `AssertTelemetryConsistent`.
2424

2525
**Login telemetry test (TestTelemetryLoginProxy)** uses the same proxy approach: it runs `hookdeck login --api-key KEY` with `--api-base` set to the proxy, and asserts exactly one recorded request (GET `/2025-07-01/cli-auth/validate`) with consistent telemetry. It uses **HOOKDECK_CLI_TESTING_CLI_KEY** (not the API/CI key), because the validate endpoint accepts CLI keys from interactive login; if unset, the test is skipped. Other telemetry tests still use the normal API key via `NewCLIRunner`.
2626

@@ -48,7 +48,11 @@ HOOKDECK_CLI_TESTING_API_KEY_3=key_for_slice2
4848

4949
### CI/CD
5050

51-
CI runs acceptance tests in **three parallel jobs**, each with its own API key (`HOOKDECK_CLI_TESTING_API_KEY`, `HOOKDECK_CLI_TESTING_API_KEY_2`, `HOOKDECK_CLI_TESTING_API_KEY_3`). No test-name list in the workflow—tests are partitioned by **feature tags** (see [Parallelisation](#parallelisation)).
51+
CI runs **three parallel matrix jobs**, each with its own API key (`HOOKDECK_CLI_TESTING_API_KEY`, `HOOKDECK_CLI_TESTING_API_KEY_2`, `HOOKDECK_CLI_TESTING_API_KEY_3`). Those jobs set **`HOOKDECK_CLI_TELEMETRY_DISABLED=1`** so the CLI does not send telemetry during normal acceptance tests.
52+
53+
A **fourth job** (`acceptance-telemetry` in `.github/workflows/test-acceptance.yml`) does **not** disable telemetry. It runs `go test -tags=telemetry` only (all proxy tests that assert `X-Hookdeck-CLI-Telemetry`, including listen, live under the `telemetry` build tag). It uses `HOOKDECK_CLI_TESTING_API_KEY` and `ACCEPTANCE_SLICE=0` (same project as slice 0; tests use unique resource names).
54+
55+
No test-name list in the workflow—tests are partitioned by **feature tags** (see [Parallelisation](#parallelisation)).
5256

5357
## Running Tests
5458

@@ -62,25 +66,27 @@ go test -tags="basic connection source destination gateway mcp listen project_us
6266
Same commands as CI; use when debugging a subset or running in parallel:
6367
```bash
6468
# Slice 0 (same tags as CI job 0)
65-
ACCEPTANCE_SLICE=0 go test -tags="basic connection source destination gateway mcp listen project_use connection_list connection_upsert connection_error_hints connection_oauth_aws connection_update" ./test/acceptance/... -v -timeout 12m
69+
ACCEPTANCE_SLICE=0 HOOKDECK_CLI_TELEMETRY_DISABLED=1 go test -tags="basic connection source destination gateway mcp listen project_use connection_list connection_upsert connection_error_hints connection_oauth_aws connection_update" ./test/acceptance/... -v -timeout 12m
6670

67-
# Slice 1 (same tags as CI job 1: request, event, telemetry)
68-
ACCEPTANCE_SLICE=1 go test -tags="request event telemetry" ./test/acceptance/... -v -timeout 12m
71+
# Slice 1 (same tags as CI job 1)
72+
ACCEPTANCE_SLICE=1 HOOKDECK_CLI_TELEMETRY_DISABLED=1 go test -tags="request event" ./test/acceptance/... -v -timeout 12m
6973

7074
# Slice 2 (same tags as CI job 2)
71-
ACCEPTANCE_SLICE=2 go test -tags="attempt metrics issue transformation" ./test/acceptance/... -v -timeout 12m
75+
ACCEPTANCE_SLICE=2 HOOKDECK_CLI_TELEMETRY_DISABLED=1 go test -tags="attempt metrics issue transformation" ./test/acceptance/... -v -timeout 12m
7276

77+
# Telemetry (same as CI acceptance-telemetry: do not set HOOKDECK_CLI_TELEMETRY_DISABLED)
78+
ACCEPTANCE_SLICE=0 go test -tags=telemetry ./test/acceptance/... -v -timeout 12m
7379
```
74-
For slice 1 set `HOOKDECK_CLI_TESTING_API_KEY_2`; for slice 2 set `HOOKDECK_CLI_TESTING_API_KEY_3` (or set `HOOKDECK_CLI_TESTING_API_KEY` to that key).
80+
For slice 1 set `HOOKDECK_CLI_TESTING_API_KEY_2`; for slice 2 set `HOOKDECK_CLI_TESTING_API_KEY_3` (or set `HOOKDECK_CLI_TESTING_API_KEY` to that key). For telemetry, use the slice 0 key and leave `HOOKDECK_CLI_TELEMETRY_DISABLED` unset.
7581

7682
**Project list tests** (`TestProjectListShowsType`, `TestProjectListJSONOutput`) require a **CLI key**, not an API or CI key: only keys created via interactive login can list or switch projects. Set `HOOKDECK_CLI_TESTING_CLI_KEY` in your `.env` (or environment) to run these tests; if unset, they are skipped with a clear message.
7783

7884
### Run in parallel locally (three keys)
79-
From the **repository root**, run the script that runs all three slices in parallel (same as CI):
85+
From the **repository root**, run the script that runs three matrix slices plus telemetry in parallel (same as CI):
8086
```bash
8187
./test/acceptance/run_parallel.sh
8288
```
83-
Requires `HOOKDECK_CLI_TESTING_API_KEY`, `HOOKDECK_CLI_TESTING_API_KEY_2`, and `HOOKDECK_CLI_TESTING_API_KEY_3` in `.env` or the environment.
89+
Requires `HOOKDECK_CLI_TESTING_API_KEY`, `HOOKDECK_CLI_TESTING_API_KEY_2`, and `HOOKDECK_CLI_TESTING_API_KEY_3` in `.env` or the environment. The script sets `HOOKDECK_CLI_TELEMETRY_DISABLED=1` for matrix slices only; the telemetry run leaves it unset.
8490

8591
### Run manual tests (requires human authentication):
8692
```bash
@@ -100,13 +106,14 @@ Use the same `-tags` as "Run all" if you want to skip the full acceptance set. A
100106

101107
## Parallelisation
102108

103-
Tests are partitioned by **feature build tags** so CI and local runs can execute three slices in parallel (each slice uses its own Hookdeck project and config file).
109+
Tests are partitioned by **feature build tags** so CI and local runs can execute three matrix slices in parallel (each slice uses its own Hookdeck project and config file).
104110

105111
- **Slice 0 features:** `basic`, `connection`, `source`, `destination`, `gateway`, `mcp`, `listen`, `project_use`, `connection_list`, `connection_upsert`, `connection_error_hints`, `connection_oauth_aws`, `connection_update`
106-
- **Slice 1 features:** `request`, `event`, `telemetry`
112+
- **Slice 1 features:** `request`, `event`
107113
- **Slice 2 features:** `attempt`, `metrics`, `issue`, `transformation`
114+
- **Telemetry job:** `telemetry` only — separate CI job with telemetry **not** disabled (see [CI/CD](#cicd))
108115

109-
The CI workflow (`.github/workflows/test-acceptance.yml`) runs three jobs with the same `go test -tags="..."` commands and env (`ACCEPTANCE_SLICE`, API keys). No test names or regexes are listed in YAML.
116+
The CI workflow (`.github/workflows/test-acceptance.yml`) runs three matrix jobs plus `acceptance-telemetry`. Matrix jobs set `HOOKDECK_CLI_TELEMETRY_DISABLED=1`; the telemetry job does not. No test names or regexes are listed in YAML.
110117

111118
**Untagged files:** A test file with **no** build tag is included in every build and runs in **both** slices (duplicated). **Every new acceptance test file must have exactly one feature tag** so it runs in only one slice.
112119

test/acceptance/listen_test.go

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -163,36 +163,3 @@ func TestListenCommandWithContext(t *testing.T) {
163163

164164
t.Logf("Listen command terminated via context cancellation")
165165
}
166-
167-
// TestTelemetryListenProxy runs "listen" with the CLI pointed at a recording proxy
168-
// that forwards to the real API. It lets listen run for a few seconds (so it can
169-
// perform initial API calls: get sources, get connections, create session), then
170-
// stops it. Asserts that every API request in that run has the same invocation_id
171-
// and command_path "hookdeck listen".
172-
func TestTelemetryListenProxy(t *testing.T) {
173-
if testing.Short() {
174-
t.Skip("Skipping acceptance test in short mode")
175-
}
176-
177-
cli := NewCLIRunner(t)
178-
proxy := StartRecordingProxy(t, defaultAPIUpstream)
179-
defer proxy.Close()
180-
181-
timestamp := generateTimestamp()
182-
sourceName := "test-telemetry-" + timestamp
183-
184-
_, _, _ = cli.RunListenWithTimeout([]string{
185-
"--api-base", proxy.URL(),
186-
"listen", "9999", sourceName,
187-
"--output", "compact",
188-
}, 6*time.Second)
189-
// Process is killed after 6s; we don't assert on exit error
190-
191-
recorded := proxy.Recorded()
192-
require.GreaterOrEqual(t, len(recorded), 1,
193-
"expected at least one API request from listen (sources, connections, or cli-sessions)")
194-
for i, req := range recorded {
195-
t.Logf("listen API request %d: %s %s (telemetry: %s)", i+1, req.Method, req.Path, req.Telemetry)
196-
}
197-
AssertTelemetryConsistent(t, recorded, "hookdeck listen")
198-
}

test/acceptance/run_parallel.sh

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
#!/usr/bin/env bash
2-
# Run acceptance tests in three parallel slices (same as CI).
2+
# Run acceptance tests in four parallel jobs (same as CI): three matrix slices + telemetry.
33
# Requires HOOKDECK_CLI_TESTING_API_KEY, HOOKDECK_CLI_TESTING_API_KEY_2, and HOOKDECK_CLI_TESTING_API_KEY_3 in environment or test/acceptance/.env.
44
# Run from the repository root.
55
#
6+
# Matrix slices set HOOKDECK_CLI_TELEMETRY_DISABLED=1. The telemetry slice unsets it and runs
7+
# -tags=telemetry (telemetry_test.go and telemetry_listen_test.go).
8+
#
69
# Output: each slice writes to a log file so you can see which run produced what.
7-
# Logs are written to test/acceptance/logs/slice0.log, slice1.log, slice2.log (created on first run).
10+
# Logs are written to test/acceptance/logs/slice0.log, slice1.log, slice2.log, telemetry.log (created on first run).
811

912
set -e
1013

@@ -24,47 +27,61 @@ mkdir -p "$LOG_DIR"
2427
SLICE0_LOG="$LOG_DIR/slice0.log"
2528
SLICE1_LOG="$LOG_DIR/slice1.log"
2629
SLICE2_LOG="$LOG_DIR/slice2.log"
30+
TELEMETRY_LOG="$LOG_DIR/telemetry.log"
2731

2832
SLICE0_TAGS="basic connection source destination gateway mcp listen project_use connection_list connection_upsert connection_error_hints connection_oauth_aws connection_update"
29-
SLICE1_TAGS="request event telemetry"
33+
SLICE1_TAGS="request event"
3034
SLICE2_TAGS="attempt metrics issue transformation"
3135

3236
run_slice0() {
33-
ACCEPTANCE_SLICE=0 go test -tags="$SLICE0_TAGS" ./test/acceptance/... -v -timeout 12m > "$SLICE0_LOG" 2>&1
37+
ACCEPTANCE_SLICE=0 HOOKDECK_CLI_TELEMETRY_DISABLED=1 go test -tags="$SLICE0_TAGS" ./test/acceptance/... -v -timeout 12m > "$SLICE0_LOG" 2>&1
3438
}
3539

3640
run_slice1() {
37-
ACCEPTANCE_SLICE=1 go test -tags="$SLICE1_TAGS" ./test/acceptance/... -v -timeout 12m > "$SLICE1_LOG" 2>&1
41+
ACCEPTANCE_SLICE=1 HOOKDECK_CLI_TELEMETRY_DISABLED=1 go test -tags="$SLICE1_TAGS" ./test/acceptance/... -v -timeout 12m > "$SLICE1_LOG" 2>&1
3842
}
3943

4044
run_slice2() {
41-
ACCEPTANCE_SLICE=2 go test -tags="$SLICE2_TAGS" ./test/acceptance/... -v -timeout 12m > "$SLICE2_LOG" 2>&1
45+
ACCEPTANCE_SLICE=2 HOOKDECK_CLI_TELEMETRY_DISABLED=1 go test -tags="$SLICE2_TAGS" ./test/acceptance/... -v -timeout 12m > "$SLICE2_LOG" 2>&1
46+
}
47+
48+
run_telemetry() {
49+
(
50+
unset HOOKDECK_CLI_TELEMETRY_DISABLED
51+
export ACCEPTANCE_SLICE=0
52+
go test -tags=telemetry ./test/acceptance/... -v -timeout 12m
53+
) > "$TELEMETRY_LOG" 2>&1
4254
}
4355

44-
echo "Running acceptance tests in parallel (slice 0, 1, and 2)..."
56+
echo "Running acceptance tests in parallel (slice 0, 1, 2, and telemetry)..."
4557
echo " Slice 0 -> $SLICE0_LOG"
4658
echo " Slice 1 -> $SLICE1_LOG"
4759
echo " Slice 2 -> $SLICE2_LOG"
60+
echo " Telemetry -> $TELEMETRY_LOG"
4861
run_slice0 &
4962
PID0=$!
5063
run_slice1 &
5164
PID1=$!
5265
run_slice2 &
5366
PID2=$!
67+
run_telemetry &
68+
PIDT=$!
5469

5570
FAIL=0
5671
wait $PID0 || FAIL=1
5772
wait $PID1 || FAIL=1
5873
wait $PID2 || FAIL=1
74+
wait $PIDT || FAIL=1
5975

6076
if [ $FAIL -eq 1 ]; then
6177
echo ""
6278
echo "One or more slices failed. Tail of failed log(s):"
6379
[ ! -f "$SLICE0_LOG" ] || (echo "--- slice 0 ---" && tail -50 "$SLICE0_LOG")
6480
[ ! -f "$SLICE1_LOG" ] || (echo "--- slice 1 ---" && tail -50 "$SLICE1_LOG")
6581
[ ! -f "$SLICE2_LOG" ] || (echo "--- slice 2 ---" && tail -50 "$SLICE2_LOG")
82+
[ ! -f "$TELEMETRY_LOG" ] || (echo "--- telemetry ---" && tail -50 "$TELEMETRY_LOG")
6683
fi
6784

6885
echo ""
69-
echo "Logs: $SLICE0_LOG $SLICE1_LOG $SLICE2_LOG"
86+
echo "Logs: $SLICE0_LOG $SLICE1_LOG $SLICE2_LOG $TELEMETRY_LOG"
7087
exit $FAIL
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//go:build telemetry
2+
3+
package acceptance
4+
5+
import (
6+
"testing"
7+
"time"
8+
9+
"github.com/stretchr/testify/require"
10+
)
11+
12+
// TestTelemetryListenProxy runs "listen" with the CLI pointed at a recording proxy
13+
// that forwards to the real API. It lets listen run for a few seconds (so it can
14+
// perform initial API calls: get sources, get connections, create session), then
15+
// stops it. Asserts that every API request in that run has the same invocation_id
16+
// and command_path "hookdeck listen".
17+
//
18+
// Build tag telemetry: runs only in the acceptance-telemetry CI job (telemetry enabled),
19+
// not in matrix slices where HOOKDECK_CLI_TELEMETRY_DISABLED=1.
20+
func TestTelemetryListenProxy(t *testing.T) {
21+
if testing.Short() {
22+
t.Skip("Skipping acceptance test in short mode")
23+
}
24+
25+
cli := NewCLIRunner(t)
26+
proxy := StartRecordingProxy(t, defaultAPIUpstream)
27+
defer proxy.Close()
28+
29+
timestamp := generateTimestamp()
30+
sourceName := "test-telemetry-" + timestamp
31+
32+
_, _, _ = cli.RunListenWithTimeout([]string{
33+
"--api-base", proxy.URL(),
34+
"listen", "9999", sourceName,
35+
"--output", "compact",
36+
}, 6*time.Second)
37+
// Process is killed after 6s; we don't assert on exit error
38+
39+
recorded := proxy.Recorded()
40+
require.GreaterOrEqual(t, len(recorded), 1,
41+
"expected at least one API request from listen (sources, connections, or cli-sessions)")
42+
for i, req := range recorded {
43+
t.Logf("listen API request %d: %s %s (telemetry: %s)", i+1, req.Method, req.Path, req.Telemetry)
44+
}
45+
AssertTelemetryConsistent(t, recorded, "hookdeck listen")
46+
}

0 commit comments

Comments
 (0)