Files
buzz/scripts/run-tests.sh
Brad Seiler 64d12e2975 BUZZ-511: Honor relay mode for community NIP-FI enforcement (#8988)
## Summary

Apply relay mode consistently across protected HTTP, root/audio
WebSocket, Git, media and V1 admission. Off requires no NIP-FI,
including for stored required communities. Shadow enforces only stored
community requirements and observes other communities. Enforce requires
NIP-FI for every community. Durable requirements survive all mode
changes.

Off retains ordinary tenant routing and authentication. It skips FI
policy/dependency reads for admission, uses cached WebSocket tenant
routing, and loads no FI binding snapshot at startup. Discovery reports
`requires_nip_fi=false` and no FI capability in Off. Evaluating modes
retain same-row WebSocket binding and immutable HTTP policy tenants,
including host remaps, pending deletion and unarchive races. Global
Enforce discovery retains its existing compatibility behavior.

Host-specific root NIP-11 and `/info` expose the additive
`requires_nip_fi` field with no-store. In evaluating modes, an
unavailable policy returns 503 and an unknown or non-serving host
returns 404. Off uses ordinary routing; a discovery lookup failure
returns 404. Stored requirements in Shadow require usable FI
dependencies.

Admission does not establish activation. BUZZ-512 owns existing-session
application, drain and mode-aware readback; its separate revision must
report stored requirements as suspended in Off. Production baseline
verification and human acceptance remain open.

Community status now shares the bounded host cache: 10,000 entries,
one-second leases measured before checkout, coalesced fills, and no
cached misses or errors. Git reuses one request policy. Root/audio
retain the final primary binding check: two reads on a cold successful
upgrade, one on a cache hit. Off creates no verifier or JWKS source and
reads no FI policy. Proof metrics count stored-required Shadow
enforcement.

Acceptance locks and validates the community row, takes the matching
host advisory lock, and drains optional leases for 1.1 seconds before
commit. Reads begun after commit see required across participating relay
instances, even without Redis invalidation. The row lock closes single
and double remap races. Admissions already in flight remain subject to
BUZZ-512 activation fencing.

### Related issue


[BUZZ-511](https://linear.app/squareup/issue/BUZZ-511/relay-enforce-per-community-nip-fi-policy-and-publish-compatible).
[BUZZ-510 / #8985](https://github.com/block/buzz/pull/8985) is merged;
this PR now targets main.

The restack retains main’s #8974 denial telemetry and artifact
capabilities. Related work includes #8526 tenant lookup errors and #8444
media authorization.

### Rollout and containment

Keep `BUZZ_NIP_FI_UPGRADES_ENABLED=false`. [The rollout
plan](docs/community-auth-upgrades.md#staging-and-containment) starts in
staging with zero required rows and a 30-minute before/after traffic
comparison. Initial abort limits include any policy timeout/503,
policy-read p99 above 50 ms, writer acquisition p99 above 20 ms or twice
baseline, and a five-minute 503 increase above 0.1 percentage point.
These are initial limits to validate against measured staging results,
not production capacity claims.

Verify signed/unsigned free controls, real required root/audio upgrades,
dependency failures, restart behavior and discovery before expansion.
Also watch binding timeouts/errors and their current generic 404
responses on known serving hosts alongside writer-pool pressure;
evaluating root/audio binding has a 500 ms budget; Off uses ordinary
cached routing. In Shadow, a pre-511 rollback loses enforcement of
accepted community requirements. Stop new upgrade calls, retain accepted
policy and receipts, and repair with an enforcing binary or
operator-approved containment. Never clear durable policy to restore
access. Off deliberately suspends FI enforcement and must be an explicit
operator mode choice. No production activation is claimed.

All acceptance paths must implement the lease protocol before upgrades
are enabled. Keep upgrades disabled through a mixed-version rollout. For
rollback, disable new acceptance before removing the protocol while
caching pods remain. A cold policy fill uses a six-statement transaction
and a 400 ms server timeout within the 500 ms lookup budget. A contended
policy fill returns 503. During the drain, archive, deletion, ownership,
issuer-binding and competing acceptance writers for that community may
wait; ordinary serving reads and writes retain their existing behavior.
Host-binding changes retain the existing one-second routing bound. Local
and Redis invalidation accelerate refresh; safety does not depend on
delivery. Deploy the verified Shadow revocation behavior from #8991
before accepting required communities in Shadow.

### Testing

Published review-fix head: `39dfe79b1fc04f10ee3eb94d6ea42cf686bafe1e`,
tree `1e2e8d3abd39ee1d6821defe8c8d34de73726e08`. McKeon cleared this
cache delta. Full affected auth (291), DB (192), pubsub (31) and relay
(1,682) package tests passed, including integration binaries. Two
previously documented hardcoded-Redis audit tests remained excluded.
All-target clippy, all 1,297 native PostgreSQL tests and the full pubsub
Redis suite passed. The full ACP package and `just ci` passed after
rebuilding cached test executables that embedded a removed checkout
path. No ACP source changed. Tauri's generated lockfile delta was
archived and restored; it is excluded from this candidate.

Both positive lease regressions passed. Four deliberately broken
variants failed at the intended assertions: removing the drain left an
optional lease alive after 202.935667 ms; skipping the fill lock failed
contention refusal; moving the timestamp after the read failed the
anchor check; taking the host lock before the row failed the
remap-blocking check. Exact source was restored after each mutation.
These are local validation results, not a deployed-fleet acceptance
claim. All applicable normal push hooks passed. GitHub reports the exact
tested head and tree; the published code has no delta from the reviewed
candidate.

Earlier mode-correction evidence follows for context.

Current mode-correction head:
`aa9abf07284b56a88eb78a2014e590f39d705288`, on main
`af54258f19ac32667c027f889652bdeb479c8e13`. Its code equals reviewed
`f1e7da5fc5`, plus the independently reviewed operator documentation
follow-up; all 19 earlier remote patches are preserved. McKeon verified
the correction and its mapping to the tested candidate.

The mode-correction candidate passed full auth (291) and relay (1,679)
package tests, clippy, and four explicit native PostgreSQL policy
workflows. There were 623 ignored relay tests and two excluded Redis
tests. Real PostgreSQL checks cover an ordinary unsigned caller on a
stored-required host in Off with no FI token or dependencies, discovery
false, durable policy retained, root/audio upgrades, host remaps and the
unarchive race in evaluating modes. The `STORED_OFF` mutation fails the
enum truth table only; `OFF_PRIMARY` fails cached upgrade routing.
Restored source hashes match. Earlier failed compile/fixture attempts
remain recorded.

The first normal push hook attempt passed Tauri checks but failed the
gateway startup verifier test (82/83 gateway tests passed). The remote
remained unchanged. The retry rebuilt gateway artifacts with separate
root and Tauri caches, then passed every normal push hook and published
this head. No gateway source changes or hook bypasses were needed.
Current-head hosted CI is tracked separately. Human acceptance and the
staging binding-timeout/404 workflow remain open. The following retained
validation and controls are historical and describe behavior before the
mode correction; their Off-enforcement statements are superseded by the
Summary above.


Published head: `9a717fa89725f9430ff4a8bb78cd600affb8836d`, on main
`1055f79d048ef22c878d02a7afb04f49c753564f`. CI, three schema checks,
2,136 ordinary tests, all 291 auth tests, 12 Redis tests, all 1,300
native PostgreSQL tests and discovery passed. The required wrapper
passed units, then exited 1 at unavailable Docker bootstrap. BUZZ-510 is
complete at `95c8d31c835d6f7ff6e432fb1ed248771d4f06dd`: CI, three schema
checks, 2,127 ordinary tests, 12 Redis tests, all 1,295 native Postgres
tests and discovery passed; its wrapper passed units and failed at
unavailable Docker bootstrap.

The first native run at historical BUZZ-510 `5380cb72` passed 1,291
tests and failed two event-follow-up queue assertions and the scale-sync
case. All three passed serially, then the full 1,294-test run passed
with normal concurrency. The original cause remains unresolved; failed
runs and resource samples are retained.

Standalone BUZZ-511 checks exposed access-slot callers, a Clippy warning
and early HTTP 503 attribution that had remained in the child. All are
now corrected in the parent. The unchanged real-router refusal
regression passed before the latest commit. BUZZ-512's final tree is
unchanged by moving these parent prerequisites. The remaining 46-file
child delta was audited; no additional parent prerequisite was found.
Earlier compile and native failures remain archived.

The following earlier-head results and controls are historical; the
current-head validation is reported above.

At `48388834f99b8d045e243b619904cb3e27b47146`, based on BUZZ-510
`130f14a675edd7cbe6a69d1c9d7818bd1a51f46c` and reconciled main
`152441ae0a56b204b42b6faa56a36ad2b98218b1`:

- `just ci`: passed.
- Four-package ordinary suite: 2,069 passed; full `buzz-auth` package:
291 passed.
- Native Redis: 12 passed. Native PostgreSQL: 1,261 passed. PostgreSQL
discovery checks passed.
- Required `just test`: units passed, then exited 1 because Docker
service bootstrap was unavailable. Native service results above are
separate.
- Real-router remap checks reject an A-only member under B policy, avoid
A data after B admission, and advertise B in discovery despite a stale A
cache. Removing each tenant pin separately fails its intended witness;
restored source passes. An unmapped host cannot reuse a cached tenant.
- Deadline witnesses advance their clock during real HTTP signature
verification and retain socket primary-lookup barriers. Removing either
final enforced or shadow HTTP deadline check separately fails its
intended witness; restored source passes both deadlines and the
single-resolution control.
- Telemetry regression: unsigned dev proofs now expect the earlier
NIP-98 `missing` denial; signed mismatched-key proofs retain pairing
denial and signer attribution. Removing unsigned-proof rejection fails
the exact two-counter assertion. Restored full relay package: 1,654
passed.
- Preserved failed runs: two prior bottom-layer desktop gates failed an
immediate inventory assertion, repaired with a bounded wait for the same
observable arrays and verified with delayed-notification and
frozen-provider controls. An earlier BUZZ-511 native run passed 1,242
tests and failed two deadline fixtures that relied on the tenant lookup
removed by the policy pin; the test-only adaptation above replaces that
seam. These failures remain archived. The first native run on
bottom-layer `130f14a6` passed 1,255 tests and failed partition
contention; its focused original test and fresh full 1,256-test run
passed without source changes. The cause remains unresolved. The first
CI run at `d8d88433` failed the old telemetry expectation; the test-only
correction above preserves exact denial counts and attribution.

Earlier evidence at `dddf05d8be8195d567db0f989f70825b1246a6c1`
(historical head):

- `cargo nextest run -p buzz-auth -p buzz-db -p buzz-relay --lib
--tests`: 2,139/2,139 passed.
- `scripts/postgres-test-run.sh -p buzz-db -p buzz-relay --lib --tests
--success-output final`: 1,236/1,236 passed with native PostgreSQL 16
and Redis. Docker's legacy `just test` wrapper was unavailable.
- `just ci`: passed, including repository checks, tests and client
builds.
- **Pre-correction behavior (superseded):** Real ES256 assertions
through TCP root/audio upgrades: valid evidence upgrades; missing
evidence denies in Off/Shadow, including submitted/inventoried/approved
deletion stages. Restoring the old query makes the regression fail on an
assertion-less Off/submitted/root HTTP 101.
- **Pre-correction behavior (superseded):** Deterministic unarchive
race: Notify barriers pause an actual archived-host policy miss; the
same required row becomes serving before binding. Both root/audio deny
missing assertions and admit valid ES256 assertions in Off/Shadow.
Ignoring bound-row policy makes this test fail on an assertion-less HTTP
101.
- The full rerun exposed an existing cancellation fixture whose
synthetic five-second replica fence expired between probes. Refreshing
that test fence per operation preserves its timeout assertions; the full
suite now passes.
- Local probe: 100 serial uncached primary policy reads took 12.33 ms.
Production latency is unmeasured.

No packaged-app, human or deployed-fleet acceptance run. Live activation
awaits BUZZ-512 and the staging verification tickets.

Published with the three-layer stack in one atomic push through normal
hooks. The published stack includes main
`1055f79d048ef22c878d02a7afb04f49c753564f`, including access logging,
storage reporting and mobile read-state changes. Access-slot integration
and early HTTP refusal attribution belong to BUZZ-511; activation
callback refusal close owners belong to BUZZ-512. Every changed layer
requires review at its published head and new-head CI. Fresh trunk,
remote membership, queue and immutable-lease guards passed before
publication. All nine normal pre-push hook lanes passed; no hooks were
bypassed. Remote heads, chained bases, membership, ready/draft states
and native tracking were verified after publication.

Trunk’s merged 0081 is unchanged. The parent upgrade expansion is 0082
and activation is 0083, with contiguous migrator versions, updated
documentation and a populated-upgrade fixture starting at 81. Trunk’s
storage-test repair supersedes our earlier local repair.

Before publication, main advanced three commits from
`1055f79d048ef22c878d02a7afb04f49c753564f` to `ba7d7825ea` (desktop
deep-link settling and mobile pairing/sign-in). The normal branch-skew
guard passed. Those later trunk commits are outside this validated
published head; current-trunk CI and delta review remain required before
merge.

Generated with Codex

---------

Signed-off-by: Brad Seiler <seiler@squareup.com>
Co-authored-by: Honor <e0bf479eeebe47dde1e35705212a4df70616a7bc834d907ddfb18cf0405f8b1b@seiler-test.communities.public.builderlabstaging.xyz>
2026-11-05 03:17:19 +00:00

582 lines
28 KiB
Bash
Executable File

#!/usr/bin/env bash
# =============================================================================
# run-tests.sh — Run Buzz test suite
# =============================================================================
# Usage:
# ./scripts/run-tests.sh # run all tests (default)
# ./scripts/run-tests.sh unit # unit tests only (no infra needed)
# ./scripts/run-tests.sh integration # integration tests only
# ./scripts/run-tests.sh all # explicit all
# =============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
MODE="${1:-all}"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
log() { echo -e "${BLUE}[run-tests]${NC} $*"; }
success(){ echo -e "${GREEN}[run-tests]${NC} $*"; }
warn() { echo -e "${YELLOW}[run-tests]${NC} $*"; }
error() { echo -e "${RED}[run-tests]${NC} $*" >&2; }
section(){ echo -e "\n${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"; echo -e "${CYAN} $*${NC}"; echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"; }
cd "${REPO_ROOT}"
# ---- Load .env if present ---------------------------------------------------
if [[ -f ".env" ]]; then
log "Loading .env..."
set -o allexport
# shellcheck disable=SC1091
source .env
set +o allexport
else
# Use defaults matching docker-compose.yml
export DATABASE_URL="postgres://buzz:buzz_dev@localhost:5432/buzz" # sadscan:disable np.postgres.1
export PGHOST=localhost
export PGPORT=5432
export PGUSER=buzz
export PGPASSWORD=buzz_dev
export PGDATABASE=buzz
export REDIS_URL="redis://localhost:6379"
fi
# ---- Track results ----------------------------------------------------------
declare -a PASSED=()
declare -a FAILED=()
run_test_step() {
local name="$1"
shift
log "Running: ${name}"
if "$@"; then
success "${name} passed"
PASSED+=("${name}")
else
error "${name} FAILED"
FAILED+=("${name}")
fi
}
# ---- Check / start infra (for integration tests) ----------------------------
ensure_infra() {
"${REPO_ROOT}/bin/just" _ensure-migrations
}
# ---- Unit tests (no infra needed) -------------------------------------------
run_unit_tests() {
section "Unit Tests (no infra required)"
run_test_step "buzz-core tests" \
cargo test -p buzz-core --lib -- --nocapture
run_test_step "buzz-audit tests" \
cargo test -p buzz-audit --lib -- --nocapture
run_test_step "buzz-auth unit tests" \
cargo test -p buzz-auth --lib -- --nocapture
# Mesh JWKS proxy-bypass regression: infra-free loopback I/O with
# child-process environment isolation. --lib does not select its binary.
# Keep this fallback in step with `just test-unit`.
run_test_step "buzz-auth mesh JWKS proxy regression" \
cargo test -p buzz-auth --test mesh_jwks_proxy -- --nocapture
# Cross-pod disconnect payload tests (NIP-FI and community archive fence;
# infra-free). Mirrors `just test-unit`.
run_test_step "buzz-pubsub conn_control tests" \
cargo test -p buzz-pubsub --lib conn_control::tests:: -- --nocapture
run_test_step "buzz-voice tests" \
cargo test -p buzz-voice --lib -- --nocapture
# Inter-relay mesh crate (infra-free). Mirrors `just test-unit`.
run_test_step "buzz-relay-mesh tests" \
cargo test -p buzz-relay-mesh -- --nocapture
run_test_step "buzz-cli tests" \
cargo test -p buzz-cli -- --nocapture
# buzz-sdk builder/validation unit tests: pure event-builder and input
# validation, no infra. Mirrors the nextest path in `just test-unit` — the
# two lists must stay in step. `--lib` matches the nextest invocation and
# avoids the full-package rustdoc dependency-resolution flake.
run_test_step "buzz-sdk unit tests" \
cargo test -p buzz-sdk --lib -- --nocapture
# buzz-workflow unit tests (infra-free). Mirrors `just test-unit`.
run_test_step "buzz-workflow unit tests" \
cargo test -p buzz-workflow --lib -- --nocapture
# Keep the relay-to-agent trust-boundary regressions in the fallback path
# when cargo-nextest is unavailable.
run_test_step "buzz-acp tests" \
cargo test -p buzz-acp -- --nocapture
# Keep MCP lifecycle coverage in step with the nextest path.
run_test_step "buzz-dev-mcp tests" \
cargo test -p buzz-dev-mcp -- --nocapture
# buzz-db migrator/lint unit tests (no infra): guard the embedded-migrator
# invariant (exactly the consolidated 0001; cutover/backfill stays an operator
# script, not startup state) and the tenant-scoping lints. The Postgres-backed
# buzz-db tests are #[ignore]d; nothing here (or in integration mode below,
# which runs `cargo test -p buzz-db` without --ignored) runs them — they need a
# separate isolated-DB gate, so --lib keeps this step infra-free.
run_test_step "buzz-db unit tests" \
cargo test -p buzz-db --lib -- --nocapture
run_test_step "buzz-db source-policy tests" \
cargo test -p buzz-db --test observability_source -- --nocapture
# buzz-search unit tests (no infra); its Postgres suite runs in the
# PostgreSQL lane.
run_test_step "buzz-search unit tests" \
cargo test -p buzz-search --lib -- --nocapture
run_test_step "buzz-media storage snapshot serialization test" \
cargo test -p buzz-media --lib bucket_index::tests::bucket_snapshot_json_round_trip_preserves_community_keys -- --exact --nocapture
run_test_step "buzz-admin storage snapshot tests" \
cargo test -p buzz-admin storage_snapshot -- --nocapture
run_test_step "buzz-admin community archive command tests" \
cargo test -p buzz-admin communities -- --nocapture
run_test_step "buzz-admin partition audit outcome contract test" \
cargo test -p buzz-admin tests::partition_audit_outcomes_keep_their_json_names_and_exit_codes -- --exact --nocapture
run_test_step "buzz-admin NIP-FI binding command tests" \
cargo test -p buzz-admin nip_fi::tests -- --nocapture
run_test_step "buzz-admin user-deletion intake command tests" \
cargo test -p buzz-admin user_deletions::tests -- --nocapture
# Multi-tenant conformance gate: independent replay checker + golden
# fixtures (buzz-conformance). Pure in-process trace replay, no infra.
run_test_step "buzz-conformance tests" \
cargo test -p buzz-conformance -- --nocapture
run_test_step "buzz-push-gateway tests" \
cargo test -p buzz-push-gateway -- --nocapture
run_test_step "buzz-push-gateway personal development tests" \
cargo test -p buzz-push-gateway --features personal-dev-app-attest -- --nocapture
# Kubernetes backend provider: pure decision layers driven by a fake
# substrate, no cluster. Mirrors the nextest path in `just test-unit` —
# the two lists must stay in step or the fallback silently covers less.
run_test_step "buzz-backend-kubernetes tests" \
cargo test -p buzz-backend-kubernetes -- --nocapture
# Keep fallback parity with `just test-unit`: one LaunchDarkly-feature run
# exercises both default and feature-gated buzz-feature-flags tests.
run_test_step "buzz-feature-flags tests (launchdarkly)" \
cargo test -p buzz-feature-flags --features launchdarkly -- --nocapture
# buzz-agent model-capabilities corpus: the Rust half of the cross-language
# drift guard. model_capabilities.rs embeds scripts/model-capabilities.json +
# scripts/normative-corpus.json via include_str! and replays the full locked
# corpus as pure in-process tests (no infra). Mirrors the nextest path in
# `just test-unit` — the two lists must stay in step.
run_test_step "buzz-agent unit tests" \
cargo test -p buzz-agent --lib -- --nocapture
# ACP author-gate and queue tests are pure unit tests. Keep this fallback in
# step with `just test-unit`; ignored lifecycle tests run elsewhere.
run_test_step "buzz-acp unit tests" \
cargo test -p buzz-acp --lib -- --nocapture
# Mirror the relay filters from `just test-unit`: the three handler modules,
# storage-snapshot helpers, readiness and router unit suites, and the single
# scoped admission regression in state::tests, plus the REQ lifecycle tests.
run_test_step "buzz-relay push runtime tests" \
cargo test -p buzz-relay --lib push_runtime:: -- --nocapture
run_test_step "buzz-relay operator listener tests" \
cargo test -p buzz-relay --lib operator_listener::tests:: -- --nocapture
run_test_step "buzz-relay channel authorization tests" \
cargo test -p buzz-relay --lib handlers::channel_authz:: -- --nocapture
run_test_step "buzz-relay moderation authorization tests" \
cargo test -p buzz-relay --lib handlers::moderation_authz:: -- --nocapture
run_test_step "buzz-relay side-effects helper tests" \
cargo test -p buzz-relay --lib handlers::side_effects::tests:: -- --nocapture
run_test_step "buzz-relay coalesced refresh tests" \
cargo test -p buzz-relay --lib handlers::coalesced_refresh::tests:: -- --nocapture
run_test_step "buzz-relay system channel scope tests" \
cargo test -p buzz-relay --lib handlers::system_channels::tests:: -- --nocapture
run_test_step "buzz-relay NIP-11 document tests" \
cargo test -p buzz-relay --lib nip11::tests:: -- --nocapture
run_test_step "buzz-relay storage snapshot tests" \
cargo test -p buzz-relay --lib storage_sweep::tests:: -- --nocapture
# Mirror the four audio/FI suites from `just test-unit`'s nextest expression.
# These are infra-free (no DB, no Redis); the `#[ignore]`-gated DB witnesses
# are excluded by cargo test's default filter. Keep in step with the Justfile
# `test-unit` relay expression.
run_test_step "buzz-relay audio join tests" \
cargo test -p buzz-relay --lib audio::join::tests:: -- --nocapture
run_test_step "buzz-relay audio handler tests" \
cargo test -p buzz-relay --lib audio::handler::tests:: -- --nocapture
run_test_step "buzz-relay NIP-FI gate tests" \
cargo test -p buzz-relay --lib nip_fi_gate::tests:: -- --nocapture
run_test_step "buzz-relay NIP-FI session tests" \
cargo test -p buzz-relay --lib nip_fi_session::tests:: -- --nocapture
run_test_step "buzz-relay NIP-FI shadow recorder tests" \
cargo test -p buzz-relay --lib nip_fi_shadow::tests:: -- --nocapture
run_test_step "buzz-relay NIP-FI shadow session tests" \
cargo test -p buzz-relay --lib nip_fi_shadow_session::tests:: -- --nocapture
run_test_step "buzz-relay startup step tests" \
cargo test -p buzz-relay --lib startup_steps::tests:: -- --nocapture
run_test_step "buzz-relay mesh boot tests" \
cargo test -p buzz-relay --lib mesh_boot::tests:: -- --nocapture
run_test_step "buzz-relay subscription registry tests" \
cargo test -p buzz-relay --lib subscription::tests:: -- --nocapture
# telemetry and config tests mutate process env. libtest runs one process
# with many threads (nextest, used by `just test-unit`, isolates each test),
# so run them single-threaded here. `--skip` keeps the substring filter
# `config::tests::` from also selecting nip_fi_config, which runs above.
run_test_step "buzz-relay telemetry tests" \
cargo test -p buzz-relay --lib telemetry::tests:: -- --test-threads=1 --nocapture
run_test_step "buzz-relay config tests" \
cargo test -p buzz-relay --lib config::tests:: -- --skip nip_fi_config:: --test-threads=1 --nocapture
# Mirror the NIP-FI (S3) stanza from `just test-unit`: module filters, then
# each exact name. Keep this list in step with that stanza's `test(=...)`s.
run_test_step "buzz-relay NIP-FI config tests" \
cargo test -p buzz-relay --lib nip_fi_config:: -- --nocapture
run_test_step "buzz-relay NIP-FI resolver tests" \
cargo test -p buzz-relay --lib nip_fi_resolver:: -- --nocapture
# Infra-free REQ subscription-lifecycle tests, by exact name: the rest of
# handlers::req needs a database.
run_test_step "buzz-relay REQ subscription lifecycle tests" \
cargo test -p buzz-relay --lib -- --exact --nocapture \
handlers::req::tests::timed_out_historical_read_deregisters_before_closed \
handlers::req::tests::superseded_timeout_leaves_replacement_intact \
handlers::req::tests::search_claim_retires_live_and_yields_to_replacement \
handlers::req::tests::failed_search_closes_without_eose_or_trying_later_filters \
handlers::req::tests::concurrent_claims_and_stale_teardowns_keep_the_last_owner \
handlers::req::tests::timeout_closed_is_emitted_before_a_replacement_can_claim \
handlers::req::tests::revoke_then_replacement_keeps_replacement_whole \
handlers::req::tests::claims_after_connection_cleanup_are_refused \
handlers::req::tests::dropped_terminal_frame_cancels_connection \
handlers::req::tests::revoke_dropped_terminal_frame_cancels_connection \
handlers::req::tests::count_fallback_covers_filters_that_can_match_private_deletions \
handlers::req::tests::group_state_t_and_creator_tags_reach_sql_only_for_group_state_kinds
# Access log line tests, mirroring `just test-unit`'s module filters.
run_test_step "buzz-relay access log tests" \
cargo test -p buzz-relay --lib access::tests:: -- --nocapture
run_test_step "buzz-relay git access log tests" \
cargo test -p buzz-relay --lib api::git::transport::access_log_tests:: -- --nocapture
# Infra-free tests the access-logging change added or edited, by exact
# name: their modules otherwise need a database.
run_test_step "buzz-relay access logging infra-free tests" \
cargo test -p buzz-relay --lib -- --exact --nocapture \
handlers::req::tests::unqueued_eose_logs_aborted_not_served \
api::bridge::postgres_tests::reject_code_keeps_only_a_known_prefix \
api::bridge::postgres_tests::nip98_replay_check_fails_closed_when_guard_errors \
api::bridge::postgres_tests::verify_bridge_auth_rejects_nip98_event_signed_for_wrong_communitys_host \
api::bridge::postgres_tests::verify_bridge_auth_can_require_payload_tag_for_json_body_endpoints \
api::bridge::postgres_tests::verify_bridge_auth_accepts_nip98_event_signed_for_matching_host \
api::bridge::postgres_tests::moderation_read_query_bearing_nip98_event_verifies_with_matching_query \
api::bridge::postgres_tests::moderation_read_query_bearing_nip98_event_rejected_against_bare_path \
api::bridge::postgres_tests::moderation_read_audit_query_bearing_nip98_event_verifies \
api::bridge::postgres_tests::moderation_read_restricted_no_query_still_verifies \
connection::tests::aborting_lifecycle_owner_is_drop_safe \
connection::tests::shutdown_terminalizes_auth_stalled_on_database_before_late_success \
connection::terminal_close_delivery_tests::upgrade_would_deny_line_without_auth_logs_absent_at_close \
handlers::event::tests::observer_owner_cache_is_scoped_to_community \
state::tests::shared_counter_between_direct_and_fanout \
api::bridge::postgres_tests::nip98_replay_check_logs_only_its_refusal \
api::bridge::postgres_tests::warn_only_artifact_read_lines_keep_the_filter_summary \
connection::tests::close_totals_count_a_batch_flushed_by_the_drain_after_cancellation \
connection::tests::close_totals_count_frames_the_writer_flushed \
connection::tests::close_totals_skip_a_frame_the_socket_rejects \
connection::tests::close_totals_skip_frames_stranded_by_a_failed_flush \
connection::tests::dispatcher_counts_each_req_and_count_frame_once \
connection::tests::read_before_login_logs_one_denial_from_the_handler \
connection::tests::read_refused_by_a_full_handler_semaphore_logs_one_denial \
connection::tests::read_refused_by_unavailable_admission_logs_one_denial \
handlers::auth::tests::repeat_auth_after_a_terminal_logs_one_denial \
nip_fi_upgrade::tests::deny_protected_logs_one_denied_auth_line \
api::bridge::moderation_refusal_tests::moderation_lookup_failure_is_unavailable \
api::admin::auth::tests::admin_role_refusal_logs_denied \
api::admin::auth::tests::admin_duplicate_authorization_logs_duplicate
# Infra-free bridge search extension parser tests, by exact name: the rest of
# api::bridge::postgres_tests needs a database.
run_test_step "buzz-relay bridge search extension tests" \
cargo test -p buzz-relay --lib -- --exact --nocapture \
api::bridge::postgres_tests::bridge_search_mode_extension_accepts_prefix_snake_or_camel_case \
api::bridge::postgres_tests::bridge_search_sort_extension_selects_newest_only_when_named
# Infra-free guard for the destructive invite fixture's database ownership
# check, by exact name: the rest of api::invites::postgres_tests needs a database.
run_test_step "buzz-relay invite fixture guard test" \
cargo test -p buzz-relay --lib -- --exact --nocapture \
api::invites::postgres_tests::restriction_tests::postgres_tests::destructive_fixture_rejects_shared_database_urls
run_test_step "buzz-relay readiness tests" \
cargo test -p buzz-relay --lib readiness::tests:: -- --nocapture
run_test_step "buzz-relay accessible-channel cache tests" \
cargo test -p buzz-relay --lib -- --exact --nocapture \
state::tests::accessible_channel_invalidation_is_scoped_to_community \
state::tests::accessible_channels_join_member_and_open_halves \
state::tests::channel_deleted_invalidation_is_scoped_to_community
run_test_step "buzz-relay admission regression test" \
cargo test -p buzz-relay --lib state::tests::neither_a_confirmed_inactive_community_nor_a_failed_lookup_admits_the_socket -- --nocapture
run_test_step "buzz-relay archive revalidation fence test" \
cargo test -p buzz-relay --lib state::tests::periodic_revalidation_disconnects_inside_the_fenced_callback -- --exact --nocapture
run_test_step "buzz-relay bare disconnect fail-closed test" \
cargo test -p buzz-relay --lib state::tests::bare_community_disconnect_fails_closed_when_the_fence_is_unavailable -- --exact --nocapture
run_test_step "buzz-relay archived close-reason test" \
cargo test -p buzz-relay --lib connection::tests::send_loop_sends_policy_close_when_community_is_archived -- --exact --nocapture
run_test_step "buzz-relay community close first-writer tests" \
cargo test -p buzz-relay --lib state::tests::community_disconnect_then_nip_fi_keeps_community_deleted_reason -- --exact --nocapture
run_test_step "buzz-relay community close suppresses losing denial frame test" \
cargo test -p buzz-relay --lib state::tests::disconnect_community_wins_reason_losing_nip_fi_does_not_enqueue_frame -- --exact --nocapture
run_test_step "buzz-relay read cache tests" \
cargo test -p buzz-relay --lib -- --exact --nocapture \
state::tests::admitted_index_follows_every_key_change \
shared_reads::tests::one_caller_reads_while_the_rest_wait_for_it \
shared_reads::tests::a_waiter_stops_waiting_for_a_hung_read \
state::tests::concurrent_open_channel_misses_share_the_in_flight_read \
state::tests::concurrent_restriction_and_host_misses_share_the_in_flight_read \
tenant::tests::app_state_resolver_serves_fresh_cached_hosts_only \
tenant::tests::an_overlong_host_fails_closed_before_the_resolver \
state::tests::disconnect_drops_the_cached_restriction_row
run_test_step "buzz-relay router tests" \
cargo test -p buzz-relay --lib router::tests:: -- --nocapture
run_test_step "buzz-relay NIP-FI shared core tests" \
cargo test -p buzz-relay --lib nip_fi_core::tests:: -- --nocapture
run_test_step "buzz-relay NIP-FI HTTP ingress tests" \
cargo test -p buzz-relay --lib nip_fi_http::tests:: -- --nocapture
run_test_step "buzz-relay API query parsing tests" \
cargo test -p buzz-relay --lib api::parse_query_tests:: -- --nocapture
run_test_step "buzz-relay profile search request tests" \
cargo test -p buzz-relay --lib api::profiles:: -- --nocapture
run_test_step "buzz-relay per-user search cap tests" \
cargo test -p buzz-relay --lib api::bridge::search_slots::tests:: -- --nocapture
run_test_step "buzz-relay Git transport Off-mode precedence tests" \
cargo test -p buzz-relay --lib api::git::transport::off_mode_precedence_tests:: -- --nocapture
run_test_step "buzz-relay community FI policy tests" \
cargo test -p buzz-relay --lib nip_fi_policy::tests:: -- --nocapture
run_test_step "buzz-relay NIP-FI upgrade tests" \
cargo test -p buzz-relay --lib nip_fi_upgrade:: -- --nocapture
run_test_step "buzz-relay NIP-FI admin API tests" \
cargo test -p buzz-relay --lib api::nip_fi:: -- --nocapture
run_test_step "buzz-relay auth metrics contract tests" \
cargo test -p buzz-relay --lib metrics::contract_tests:: -- --nocapture
run_test_step "buzz-relay partition alert series tests" \
cargo test -p buzz-relay --lib metrics::partition_alert_tests:: -- --nocapture
local nip_fi_exact_tests=(
audio::room::tests::roster_revisions_are_ordered_and_snapshot_is_authoritative
connection::tests::auth_lifecycle_reconciles_every_terminal_and_never_leaks_gauge
connection::tests::startup_cancellation_writes_one_close_line
connection::tests::connection_limit_refusal_writes_one_close_line
connection::tests::dropped_authenticated_handler_writes_one_close_line
audio::room::tests::b1_pending_peer_removed_before_commit_emits_no_delta
audio::room::tests::b2_commit_peer_emits_exactly_one_joined_delta_and_marks_visible
audio::room::tests::b3_commit_peer_revision_is_monotone_between_concurrent_events
audio::room::tests::f7a_pending_peer_excluded_from_snapshot_until_committed
connection::tests::b2_cancelled_connection_event_frame_not_dispatched
connection::tests::b3_expiry_denial_precedes_close_through_send_loop
connection::tests::b3_root_pairing_denial_precedes_close_through_send_loop
connection::tests::cancellation_during_select_with_fi_denial_routes_through_bounded_path
connection::tests::cancelled_never_ready_sink_with_queued_fi_denial_exits_within_timeout
connection::tests::deadline_exp_is_earliest_selects_exp
connection::tests::deadline_max_connection_lifetime_is_earliest_selects_partition
connection::tests::deadline_no_lifetime_returns_upstream_only
connection::tests::expiry_notice_queued_on_ctrl_before_cancel
connection::tests::f3_root_outer_wrapper_delivers_denial_on_bootstrap_cancellation
connection::tests::f3_root_pre_built_expired_gate_terminates_connection
connection::terminal_close_delivery_tests::key_pairing_mismatch_closes_with_1008_on_real_socket
connection::terminal_close_delivery_tests::session_expiry_denial_closes_with_1008_on_real_socket
connection::terminal_close_delivery_tests::server_holds_socket_for_client_close_reply
connection::terminal_close_delivery_tests::server_finishes_promptly_when_client_answers_close
connection::terminal_close_delivery_tests::stalled_cleanup_does_not_hold_socket_open
connection::terminal_close_delivery_tests::bootstrap_drain_holds_socket_for_client_close_reply
connection::terminal_close_delivery_tests::stalled_expiry_barrier_does_not_hold_socket_open
connection::terminal_close_delivery_tests::blocked_frame_handler_does_not_hold_socket_open
connection::terminal_close_delivery_tests::refused_bootstrap_holds_connection_slot_until_socket_ends
connection::terminal_close_delivery_tests::stalled_bootstrap_holds_connection_slot
connection::terminal_close_delivery_tests::peer_wait_replies_to_client_initiated_close
handlers::auth::tests::b2_pre_cancelled_connection_never_becomes_authenticated
handlers::auth::tests::fi_ban_check_error_emits_terminal_authorization_unavailable
handlers::auth::tests::fi_root_authorization_denied_rows_emit_identical_frames
handlers::auth::tests::fi_invalid_nip42_proof_emits_terminal_evidence_rejected
handlers::auth::tests::handle_auth_pairing_mismatch_runs_full_root_denial_path
handlers::auth::tests::shadow_root_auth_records_pairing_denial
handlers::auth::tests::shadow_root_auth_records_unavailable_owner_read
handlers::ingest::postgres_tests::relay_admin_ban_maps_to_blocked_auth_failure
handlers::ingest::postgres_tests::relay_admin_internal_maps_to_error_not_client_fault
handlers::auth::tests::shadow_root_invalid_nip42_retires_without_record
handlers::auth::tests::nip42_denial_class_separates_internal_failure_from_bad_evidence
handlers::event::tests::fanout_access::owner_only_kinds_keep_only_the_owner
handlers::event::tests::pubsub_fanout::pubsub_owner_only_kinds_reach_only_the_owner
handlers::event::tests::pubsub_fanout::dispatch_owner_only_kinds_reach_only_the_owner
handlers::req::tests::p1a_huddle_liveness_req_barrier_expiry_blocks_query_and_emission
state::tests::f3_cancellation_during_check_terminates_socket_without_waiting_for_check
state::tests::on_not_run_runs_once_on_each_deny_arm_and_never_on_admit
state::tests::conn_manager_disconnect_nip_fi_ignores_unproven_connection
state::tests::conn_manager_disconnect_nip_fi_is_issuer_scoped
state::tests::conn_manager_disconnect_nip_fi_sets_authorization_denied_reason
state::tests::nip_fi_disconnect_audio_is_issuer_scoped
state::tests::nip_fi_owner_disconnect_closes_owned_agent_sockets_on_root_and_audio
state::tests::nip_fi_disconnect_closes_proven_audio_socket_and_sends_policy_close_reason
state::tests::nip_fi_disconnect_closes_target_audio_only_and_preserves_collocated_peer
state::tests::nip_fi_disconnect_does_not_close_different_pubkey_audio_socket
state::tests::nip_fi_disconnect_does_not_close_unproven_audio_socket
state::tests::community_disconnect_then_nip_fi_keeps_community_deleted_reason
state::tests::enforce_end_is_recorded_only_by_the_winning_terminal
state::tests::disconnect_community_wins_reason_losing_nip_fi_does_not_enqueue_frame
state::tests::manager_disconnect_sets_reason_enqueues_frame_then_cancels
)
local name
for name in "${nip_fi_exact_tests[@]}"; do
run_test_step "buzz-relay ${name}" \
cargo test -p buzz-relay --lib "$name" -- --exact --nocapture
done
run_test_step "buzz-relay binary tests" \
cargo test -p buzz-relay --bin buzz-relay -- --nocapture
run_test_step "buzz-relay invitation token and cutoff contracts" \
cargo test -p buzz-relay --lib invite_token:: -- --nocapture
run_test_step "buzz-relay invitation cutoff configuration" \
cargo test -p buzz-relay --lib config::invite_cutoff_tests:: -- --nocapture
run_test_step "buzz-relay mesh receive lifetime regression" \
cargo test -p buzz-relay --lib mesh_boot::tests::demo_echo_retains_pending_receive_across_housekeeping_ticks -- --exact --nocapture
run_test_step "buzz-relay boot lifecycle tests" \
cargo test -p buzz-relay --test boot_lifecycle -- --nocapture
# Load generator unit tests are infra-free. Keep in step with `just test-unit`.
run_test_step "buzz-test-client loadgen unit tests" \
cargo test -p buzz-test-client --lib loadgen:: -- --nocapture
}
# ---- DB / integration tests (infra required) --------------------------------
run_integration_tests() {
section "Integration Tests (requires running services)"
ensure_infra
run_test_step "buzz-db tests" \
cargo test -p buzz-db -- --nocapture
if find crates/buzz-auth/tests -maxdepth 1 -name '*.rs' -print -quit 2>/dev/null | grep -q .; then
run_test_step "buzz-auth integration tests" \
cargo test -p buzz-auth --test '*' -- --nocapture
else
run_test_step "buzz-auth (no integration tests found)" true
fi
run_test_step "workspace integration tests" \
cargo test --test '*' -- --nocapture 2>/dev/null || \
run_test_step "workspace integration tests (none found)" true
}
# ---- Main -------------------------------------------------------------------
START_TIME=$(date +%s)
case "${MODE}" in
unit)
run_unit_tests
;;
integration)
run_integration_tests
;;
all|*)
run_unit_tests
run_integration_tests
;;
esac
END_TIME=$(date +%s)
ELAPSED=$((END_TIME - START_TIME))
# ---- Summary ----------------------------------------------------------------
section "Test Summary"
echo ""
echo -e " Duration: ${ELAPSED}s"
echo ""
if [[ ${#PASSED[@]} -gt 0 ]]; then
echo -e " ${GREEN}Passed (${#PASSED[@]}):${NC}"
for t in "${PASSED[@]}"; do
echo -e " ${GREEN}pass${NC} ${t}"
done
fi
if [[ ${#FAILED[@]} -gt 0 ]]; then
echo ""
echo -e " ${RED}Failed (${#FAILED[@]}):${NC}"
for t in "${FAILED[@]}"; do
echo -e " ${RED}fail${NC} ${t}"
done
echo ""
exit 1
fi
echo ""
success "All tests passed!"
exit 0