Files
buzz/test/otel-e2e
npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7andWill Pfleger fd59e6660f test(otel): add E2E harness for relay OTEL export surfaces
Adds a one-command local E2E that proves both observability export
surfaces introduced in PR #1398:

  (a) Prometheus /metrics: buzz_ws_connections_total,
      buzz_events_received_total, buzz_auth_attempts_total present with
      non-zero values; target_info absent (suppressed via PR #1398).

  (b) OTLP traces: ws.auth and ws.event spans arrive at the collector
      carrying conn_id attribute and service.name=buzz-relay resource.

  (c) OTLP metrics: collector receives data tagged service.name=buzz-relay.

  (d) OTLP-disabled control: with OTEL_EXPORTER_OTLP_ENDPOINT unset
      /metrics still serves correctly; collector receives nothing.

Architecture: relay runs on the host (matching the existing
host.docker.internal Prometheus pattern); an otel-collector container
added via compose overlay receives OTLP on :4317. The collector image is
distroless so the output dir is bind-mounted to the host rather than read
via docker exec. The Rust assertions in buzz-test-client read the host
path directly.

New files:
- test/otel-e2e/run.sh — main driver script
- test/otel-e2e/compose.otel-e2e.yml — compose overlay
- test/otel-e2e/otelcol-config.yml — collector config
- test/otel-e2e/README.md — prerequisites and usage
- crates/buzz-test-client/tests/e2e_otel.rs — Rust assertions (all #[ignore])
- Justfile: just otel-e2e target

No changes to crates/buzz-relay/src/**.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
2026-06-30 14:03:45 -04:00
..

OTEL E2E Harness

Local end-to-end validation for the Buzz relay's observability export surfaces (PR #1398 — crates/buzz-relay OTEL migration).

What it proves

Assertion What's checked
(a) Prometheus scrape GET :9102/metrics contains buzz_ws_connections_total, buzz_events_received_total, buzz_auth_attempts_total with non-zero values; does not contain target_info (suppressed via .without_target_info())
(b) OTLP traces The otel-collector received spans named ws.auth and ws.event carrying a conn_id attribute, tagged service.name=buzz-relay
(c) OTLP metrics The otel-collector received OTLP metric data tagged service.name=buzz-relay
(d) OTLP-disabled control With OTEL_EXPORTER_OTLP_ENDPOINT unset the relay still serves /metrics correctly; the collector receives nothing

Prerequisites

  • Docker (for compose services: postgres, redis, minio, otel-collector)
  • Rust toolchain (builds the relay + test binary)
  • psql on PATH, or it falls back to docker exec into the postgres container
  • Ports available: 3000 (relay WS), 4317 (OTLP gRPC), 5432, 6379, 9000, 9102

One-command run

just otel-e2e

Or directly:

./test/otel-e2e/run.sh

Pass --skip-build to reuse an existing target/ci/buzz-relay binary:

just otel-e2e --skip-build

To test against a relay built from the duncan/otel-migration branch (PR #1398):

# Build the OTEL relay binary first:
cd /path/to/buzz/.worktrees/duncan-otel-migration
cargo build --profile ci -p buzz-relay

# Run the harness pointing at that binary:
RELAY_BINARY=/path/to/buzz/.worktrees/duncan-otel-migration/target/ci/buzz-relay \
  just otel-e2e --skip-build

Architecture

┌─────────────────────── HOST ──────────────────────────────────┐
│                                                                │
│  buzz-relay (host process)                                     │
│    • WS :3000       ← test driver connects here               │
│    • health :8080                                              │
│    • Prometheus :9102  ← test scrapes here                    │
│    • OTLP gRPC → http://localhost:4317 (collector below)      │
│                                                                │
└───────────────────────────────────────────────────────────────┘
          │ OTLP gRPC                 │ psql/redis/s3
          ▼                           ▼
┌─────── DOCKER (buzz-net) ──────────────────────────────────────┐
│                                                                 │
│  otel-collector :4317  ←── relay pushes traces + metrics here  │
│    exports to: debug stdout + /tmp/otelcol-output/             │
│                                                                 │
│  postgres :5432  redis :6379  minio :9000                      │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

The relay runs on the host (matching the existing host.docker.internal Prometheus pattern in docker-compose.yml). Only the backing services and the collector run in Docker. This avoids a slow full-image rebuild on each test run.

Files

File Purpose
run.sh Main driver: boots stack, starts relay twice (OTLP on/off), runs assertions
compose.otel-e2e.yml Compose overlay — adds otel-collector to the existing dev stack
otelcol-config.yml Collector config: OTLP gRPC receiver on :4317, debug + file exporter
README.md This file

The Rust assertions live in:

crates/buzz-test-client/tests/e2e_otel.rs

All four tests are #[ignore] by default and selected by run.sh.

Running individual tests manually

# Start the stack first:
docker compose -f docker-compose.yml -f test/otel-e2e/compose.otel-e2e.yml \
  up -d postgres redis minio minio-init otel-collector

# Start relay with OTLP enabled:
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 \
OTEL_SERVICE_NAME=buzz-relay \
DATABASE_URL=postgres://buzz:buzz_dev@localhost:5432/buzz \
REDIS_URL=redis://localhost:6379 \
RELAY_URL=ws://localhost:3000 \
BUZZ_REQUIRE_AUTH_TOKEN=false \
  ./target/ci/buzz-relay &

# Run all four tests:
RELAY_URL=ws://localhost:3000 \
METRICS_URL=http://localhost:9102/metrics \
  cargo test -p buzz-test-client --test e2e_otel -- --ignored

# Teardown:
docker compose -f docker-compose.yml -f test/otel-e2e/compose.otel-e2e.yml down -v

Relationship to the relay source

This harness is read-only with respect to crates/buzz-relay/src/**. The relay binary is built from the duncan/otel-migration branch (PR #1398) which is gate-cleared and frozen. This harness lives on a separate branch (duncan/otel-e2e-harness) and adds only:

  • test/otel-e2e/ — this directory
  • crates/buzz-test-client/tests/e2e_otel.rs — the Rust assertions
  • Justfile — just otel-e2e target