feat: integration tests against real public testnet infrastructure#2
Merged
feat: integration tests against real public testnet infrastructure#2
Conversation
added 4 commits
April 24, 2026 08:47
…ture Adds end-to-end integration tests under test/integration/ that exercise the built CLI (bin/sphere.mjs) against the Unicity public testnet: - wss://nostr-relay.testnet.unicity.network (Nostr relay) - https://goggregator-test.unicity.network (aggregator JSON-RPC + trustbase) - https://unicity-ipfs1.dyndns.org (IPFS gateway for identity publish) Three test files: - cli-crypto: local crypto/util commands (no network, deterministic) - cli-wallet: `sphere wallet init --network testnet` against real aggregator + IPFS + Nostr; parses emitted identity JSON and asserts L1Address/ directAddress/chainPubkey shape - cli-dm: self-DM round-trip via the real Nostr relay; exercises Sphere.init + Nostr connect + NIP-17 encryption + gift-wrap publish + inbox retrieval Harness: - test/integration/helpers.ts: createSphereEnv() provisions a fresh tmp profile dir with seeded testnet config; runSphere() invokes the built CLI via spawnSync with generous 90-120s timeouts. integrationSkip via SKIP_INTEGRATION=1 for CI opt-out. - vitest.integration.config.ts: dedicated config with 120s test timeout, sequential single-fork execution to avoid relay rate-limits. - vitest.config.ts: excludes test/integration/** from the default run so unit tests stay fast (21/21 in ~1s). - npm run test:integration: builds + runs integration suite. Minor CLI addition: `sphere wallet init` and `sphere wallet status` now route to legacy top-level `init` / `status` commands (previously only wallet subcommands like list/use/create/current/delete were routed). This unblocks the wallet-init integration test. Local verification: all 7 integration tests pass in ~6s total against the live testnet endpoints.
… verification HIGH: - helpers.ts: chmod 0700 on profile dir + config dir so secp256k1 material isn't world-readable on shared CI runners - helpers.ts: startup sweep of stale sphere-cli-it-* dirs (>1h old) cleans up after crashed prior runs - helpers.ts: process-level exit/SIGINT/SIGTERM/uncaughtException handlers shred all active SphereEnvs so killed tests don't leak wallet mnemonics under /tmp MEDIUM: - helpers.ts: env allowlist (PATH, HOME, USER, SHELL, LANG, etc.) instead of spreading full process.env — CI secrets (AWS_*, GITHUB_TOKEN, etc.) no longer reach the spawned CLI child - helpers.ts: spawnSync uses killSignal: 'SIGKILL' — hung Nostr/IPFS children can't delay tests past the declared timeout - cli-dm: inbox test now POLLS for the sent DM's nonce (20 tries × 3s) instead of just asserting "inbox command ran". Self-DM round-trip is now genuinely verified end-to-end via NIP-17 gift-wrap round-trip. - NEW preflight.integration.test.ts: probes aggregator (HEAD), IPFS gateway (HEAD), Nostr relay (TLS handshake). Runs first. Failures tell operators whether a red CI is infra or code, rather than making them dig through stderr. Does NOT gate downstream tests (vitest evaluates skipIf at registration, before preflight's beforeAll) — serves as a diagnostic signal only. LOW: - helpers.ts: BIN_PATH resolved via import.meta.url at module load, removing process.cwd() fragility - cli-dm: nonce includes random suffix (Math.random) so concurrent CI runs don't collide - cli-dm: explicit expect(directAddress).toBeTruthy() in round-trip test prevents silent ordering-dependent pass src/index.ts: buildLegacyArgv exported with explicit tail parameter so it's unit-testable. The single live call site still passes process.argv.slice(3). +28 unit tests covering every namespace branch: - wallet init/status remap (the round-1 change that had zero coverage) - wallet current/list/create/delete fall-through - 1:1 namespaces (balance, daemon, config, completions) - faucet → topup - nametag register/info/my/sync - payments/crypto/util namespace-strip - dm send/inbox/history - group/market/swap/invoice prefix - unknown namespace fall-through Tests: 21 → 49 unit (+28), 7 → 10 integration (+3 preflight, DM inbox now real). All pass in ~7s total.
MEDIUM: - cli-dm: DM inbox polling now bounded to 10 attempts × 2s (max ~60s) with a 180s test budget. Round 2's 20×3s could exceed the 90s test timeout when each spawn re-inits Sphere (trustbase + Nostr + IPFS). LOW: - Rename preflight.integration.test.ts → 00-preflight.integration.test.ts so vitest's filename-sorted sequencer actually runs it first (p > c sorted after cli-*). Diagnostic signal now lands before the real tests, not after — operators see "aggregator is reachable" BEFORE digging into test stderr. - helpers.ts sweep cutoff 1h → 24h. A long vitest --watch debug session or legit slow concurrent run cannot have its tmpdir swept mid-flight. - 00-preflight.ts probeTls: outer hard setTimeout bounds DNS/SYN-drop paths that tls.connect's own timeout option does not cover. - helpers.ts: remove dead `dirname` import + void-suppressor. - helpers.ts: remove uncaughtException/unhandledRejection handlers — they were masking vitest's own failed-test reporting. The `exit` + SIGINT/SIGTERM handlers still catch realistic kill paths. Tests still 10/10 integration + 49/49 unit. No behavior change beyond the stated fixes.
Schedules the real-testnet integration suite (test/integration/*.integration.test.ts)
to run at 03:07 UTC nightly + on workflow_dispatch for manual triggers.
Kept out of the default push/PR CI because these tests:
- hit shared public infra (Nostr relay, aggregator, IPFS gateway) and
shouldn't be triggered on every commit
- run for minutes end-to-end
- can flake on transient upstream hiccups
Nightly failures surface in the Actions tab but never block PRs.
On failure, tmp wallet dirs are uploaded as an artifact for debugging.
e5d3b62 to
d5ddab0
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds
test/integration/end-to-end tests that run the built CLI against live public Unicity testnet infrastructure — no mocks, no local services.Endpoints exercised:
wss://nostr-relay.testnet.unicity.networkhttps://goggregator-test.unicity.networkhttps://unicity-ipfs1.dyndns.orgTests (7 total, ~6s):
cli-crypto— local crypto/util commands, deterministiccli-wallet—sphere wallet init --network testnetagainst real aggregator + IPFS + Nostrcli-dm— self-DM round-trip via the real Nostr relay (exercises NIP-17 gift-wrap publish + subscription)Harness:
vitest.integration.config.ts— sequential single-fork execution with 120s timeoutstest/integration/helpers.ts— fresh tmp-dir profile per test, throwaway walletsnpm run test:integration— builds + runs the suiteMinor CLI addition:
sphere wallet init/sphere wallet statusnow route to the legacy top-levelinit/statuscommands. Previously onlywallet list/use/create/current/deletewere wired. Unblocks the wallet-init integration test.Test plan
npm test— 21/21 unit tests pass (integration tests excluded from default)npm run test:integration— 7/7 integration tests pass (~6s)SKIP_INTEGRATION=1 npm run test:integration— opt-out works for CI offline