test(wallet-service): isolate tests making real fullnode HTTP calls#394
Conversation
The test was implicitly making a real HTTP call to the public mainnet fullnode (DEFAULT_SERVER) from CI on every run. This happened because: - txProposalCreate() -> getFullnodeData() -> fullnode.version() - the mock on hathorLib.axios.createRequestInstance does NOT intercept that call (fullnode.ts imports axios directly) - so the request hits node1.mainnet.hathor.network for real It "worked" by accident, and broke when axios was bumped to 1.x (because axios 1.x stopped silently ignoring `data: null` on GETs, causing the fullnode to reject the request with the unwanted body). Fix: pre-populate the version_data table in beforeEach, matching the pattern used by tests/txProposal.test.ts. No more implicit network dependency, and the test is stable regardless of the fullnode's availability or axios internals. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 0 minutes and 36 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughTest infrastructure enhancements that prevent real HTTP/HTTPS calls during test execution by installing runtime guards and providing utilities to seed the database cache with fullnode version data, allowing tests to avoid external network dependencies. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Same anti-pattern as txProposalUtxoUnlock.test.ts: the CORS test for POST /tx/proposal calls txProposalCreate -> getFullnodeData -> fullnode.version() with no mock and no cached version_data, silently making a real HTTP call to the public mainnet fullnode on every CI run. This one didn't surface as a failure because _testCORSHeaders only asserts on response headers, not status or body — so a 500 from the fullnode call still passes the CORS assertion. But it is still a flaky network dependency that shouldn't exist. Fix: seed version_data in the test so getFullnodeData reads from the DB cache instead. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ta helper Two related improvements that generalize the network-isolation fixes: 1. Added \`seedFullnodeVersionData(mysql, overrides?)\` in tests/utils.ts so tests don't have to repeat the same ~20-line version_data literal every time. Replaces the inline seeding in txProposalUtxoUnlock.test.ts and the POST /tx/proposal CORS test. 2. Patched http.request / https.request in tests/jestSetup.ts to throw on any outbound request with a clear message pointing at the helper. This turns silent network escapes into loud test failures — the exact anti-pattern we just spent half a day chasing down would now fail fast on first run. If an integration test genuinely needs to reach a host, add it to ALLOWED_HOSTS in jestSetup.ts (intentionally empty for the unit suite). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Updates the wallet-service unit test suite to prevent accidental real HTTP calls to public fullnodes by seeding cached version_data where needed and adding a global outbound network blocker in Jest setup.
Changes:
- Added
DEFAULT_TEST_VERSION_DATAandseedFullnodeVersionData(mysql, overrides?)helper to consistently seedversion_datafor tests. - Updated specific tests (
txProposalUtxoUnlockand API CORS test forPOST /tx/proposal) to seed version data before invoking handlers that callgetFullnodeData(). - Patched Jest setup to throw on outbound
http.request/https.requestduring unit tests to catch network escapes early.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| packages/wallet-service/tests/utils.ts | Introduces reusable default fullnode version payload + seeding helper for version_data. |
| packages/wallet-service/tests/txProposalUtxoUnlock.test.ts | Seeds version_data in beforeEach to prevent real fullnode calls during tx proposal create. |
| packages/wallet-service/tests/api.test.ts | Seeds version_data before the POST /tx/proposal CORS header test. |
| packages/wallet-service/tests/jestSetup.ts | Adds a global outbound HTTP/HTTPS request blocker for the unit test suite. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Three fixes on top of the network-isolation setup: - Block `http.get` / `https.get` too. Node's `get()` keeps an internal reference to the original `request()`, so patching only `request` left `get` as a bypass. Delegate `get` through the patched `request` and call `.end()` ourselves so allow-listed hosts still behave. - Normalize `arg.host` by stripping port and IPv6 brackets before matching against `ALLOWED_HOSTS` (which is keyed by hostname only). URL parsing handles both forms cleanly. - Use `getUnixTimestamp()` instead of `Date.now()` in `seedFullnodeVersionData` to match the rest of the codebase. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Addressed Copilot's three comments in f01d1df:
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/wallet-service/tests/utils.ts (1)
857-902: Optional: consider upsert inaddToVersionDataTablefor helper safety.
seedFullnodeVersionDatais now the canonical seed path and will typically run inbeforeEachaftercleanDatabase. However,addToVersionDataTableuses a plainINSERTand theversion_datarow is keyed onid = 1, so calling the helper twice in a single test (e.g., seeding inbeforeEachplus an explicit override later) would fail with a duplicate key error. The productionupdateVersionDataatpackages/wallet-service/src/db/index.ts:1619already usesON DUPLICATE KEY UPDATE. Routing throughupdateVersionData(or switchingaddToVersionDataTableto upsert) would make the helper safer to call multiple times with overrides.export const seedFullnodeVersionData = async ( mysql: ServerlessMysql, overrides: Partial<FullNodeApiVersionResponse> = {}, ): Promise<void> => { - await addToVersionDataTable(mysql, getUnixTimestamp(), { ...DEFAULT_TEST_VERSION_DATA, ...overrides }); + await updateVersionData(mysql, getUnixTimestamp(), { ...DEFAULT_TEST_VERSION_DATA, ...overrides }); };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/wallet-service/tests/utils.ts` around lines 857 - 902, addToVersionDataTable currently does a straight INSERT for id=1 which causes duplicate-key failures when called multiple times; change it to perform an upsert or reuse the existing DB helper: either (A) modify addToVersionDataTable to use the same ON DUPLICATE KEY UPDATE semantics as updateVersionData (preserving id, timestamp and data fields) so repeated calls replace the row, or (B) have seedFullnodeVersionData call the existing updateVersionData function instead of addToVersionDataTable; update references to addToVersionDataTable/seedFullnodeVersionData accordingly so tests can safely call the helper multiple times.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/wallet-service/tests/utils.ts`:
- Around line 873-890: DEFAULT_TEST_VERSION_DATA currently captures
process.env.NETWORK at module load, causing stale values if tests mutate the env
later; update the code so the network is computed at access time (e.g., replace
the hard-coded network property in DEFAULT_TEST_VERSION_DATA with a getter or
remove it and inline computation into seedFullnodeVersionData) so that functions
like seedFullnodeVersionData use process.env.NETWORK ?? 'mainnet' at call time
rather than at import time.
---
Nitpick comments:
In `@packages/wallet-service/tests/utils.ts`:
- Around line 857-902: addToVersionDataTable currently does a straight INSERT
for id=1 which causes duplicate-key failures when called multiple times; change
it to perform an upsert or reuse the existing DB helper: either (A) modify
addToVersionDataTable to use the same ON DUPLICATE KEY UPDATE semantics as
updateVersionData (preserving id, timestamp and data fields) so repeated calls
replace the row, or (B) have seedFullnodeVersionData call the existing
updateVersionData function instead of addToVersionDataTable; update references
to addToVersionDataTable/seedFullnodeVersionData accordingly so tests can safely
call the helper multiple times.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: a464f1d0-912b-46cb-b62e-2ccd01739933
📒 Files selected for processing (4)
packages/wallet-service/tests/api.test.tspackages/wallet-service/tests/jestSetup.tspackages/wallet-service/tests/txProposalUtxoUnlock.test.tspackages/wallet-service/tests/utils.ts
…Data DEFAULT_TEST_VERSION_DATA captured process.env.NETWORK at module load, so tests that mutate the env after import (e.g. to parameterize network) would get a stale value. Turn it into a function so `network` is read when the test actually seeds the cache. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Motivation
While fixing CI on #370, we discovered the suite was silently making real HTTP requests to the public mainnet fullnode (`node1.mainnet.hathor.network`, our CI `DEFAULT_SERVER`). Two offenders:
Root cause is the same in both: handlers call `getFullnodeData()` → `fullnode.version()` at the top of the handler body before any input validation. `src/fullnode.ts` imports `axios` directly, so the in-test mock on `hathorLib.axios.createRequestInstance` does not intercept it. When `version_data` isn't seeded in the DB, the call goes out over the network for real.
Changes
Why the global block matters
The CORS test had been silently reaching out to the mainnet fullnode for an unknown amount of time. `_testCORSHeaders` only checks response headers, so a 500 from a dead fullnode still passes the assertion. Without a global block, this class of bug is invisible: tests pass locally, tests pass in CI, but the suite is doing real network I/O on every run. With the block in place, the same mistake fails immediately with a message pointing at the fix.
Audit scope
Swept `packages/wallet-service/tests/` and `packages/daemon/tests/` for the same anti-pattern:
Only the two wallet-service cases were actually making real outbound calls.
Acceptance Criteria
Checklist
🤖 Generated with Claude Code
Summary by CodeRabbit