Skip to content

fix(ci): unbreak the Go test suite on develop - #1459

Merged
tieubao merged 2 commits into
developfrom
fix/ci-test-green
Jul 19, 2026
Merged

fix(ci): unbreak the Go test suite on develop#1459
tieubao merged 2 commits into
developfrom
fix/ci-test-green

Conversation

@tieubao

@tieubao tieubao commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

What's this PR does ?

Fixes the CI test suite (ci-test.yml / make test), red on develop since the Alchemy pricing revamp. Test-only, zero production code changed.

Which UI commands affect by this change ?

None (test-only change).

DoD

  • Is it public API in documentation? Any docs update required ?, No, test-only.
  • Does it change the response data shape ?, No.
  • Is it require to update the mock data in preview ?, No.
  • Include the sample call / example in this PR, N/A, see Reproduce section below.

Summary

ci-test (make test) has been red on develop since the Alchemy pricing revamp (mochi-pricing-revamp sub-goal 05) retired Etherscan/SolScan/CoinGecko pricing for a tiered resolver (Alchemy by-symbol/by-contract -> DexScreener by-contract). The tests below never got their mocks/fixtures updated for the new call paths. This PR is test-only, zero production code changed.

  • Test_dexscreener_Get (pkg/service/dexscreener): fixture pair address (0x5201...be4d) was never a real dexscreener pair (confirmed live: the API returns pairs:null for it), pre-existing bad fixture, unrelated to the revamp. Swapped for the Uniswap V3 WETH/USDC pool, a deep-liquidity, long-lived pair, matching this file's existing convention of live unmocked calls.
  • TestEntity_SearchCoins / TestEntity_UpsertCustomToken (pkg/entities): repo.CoingeckoSupportedTokens.GetOne() never returns a nil token in production (pg.go always returns a non-nil pointer, even on gorm.ErrRecordNotFound); the CoinGecko-era mocks returned literal nil, nil-deref'ing at SearchCoins' token.ID check now that this path is actually reached. The new price_resolver.go tier also does a second GetOne call per priced token (to resolve its Alchemy ticker symbol), needed a new mock. Added an Alchemy service mock, and found + fixed a nil e.log in one test's Entity fixture that the new logTierCounts call nil-panics on.
  • TestHandler_SearchCoins (pkg/handler/defi): same root cause at the handler/DB-integration level. Mocked svc.Alchemy the same way, and updated the testdata/search_coin/200-ok-multiple.json golden fixture: two coingecko ids sharing symbol "doge" (binance-peg-dogecoin / dogecoin) used to get different hardcoded prices under old CoinGecko per-id batch pricing (0.1 / 0.2); the new Alchemy-by-symbol tier can't distinguish them, so both now expect the same price. New expected values were captured from a real run against the seeded test DB, not guessed.
  • TestHandler_GetCoin was already fixed (skip-with-comment, "re-sourced off CoinGecko in sub-goal 05; see TestBuildCoinResponseByID") by a prior commit already on develop; no change needed.

Scope note: the task brief named TestHandler_GetCoin as the 4th failing test, but it was already green (SKIP) on develop. CL-015's own backlog description names TestHandler_SearchCoins instead, which was genuinely still red, fixed here too so the branch actually earns its name.

Before / after

go test ./... (full suite, mise-pinned Go 1.24.2 to match go.mod's go 1.19 toolchain requirement, matching ci-test.yml's pinned toolchain approach):

Before (develop @ 8eb11ba) After (this branch)
pkg/entities FAIL (panic: nil deref in TestEntity_UpsertCustomToken, aborts the whole package before TestEntity_SearchCoins even completes) ok
pkg/service/dexscreener FAIL (Test_dexscreener_Get: dead fixture, real API returns no pairs) ok
pkg/handler/defi FAIL (TestHandler_SearchCoins: price mismatch) ok
Full suite 3 FAIL packages 0 FAIL packages (244 package results, all ok / no-test-files)

Confirmed via git stash before/after comparison on the same checkout (not just the 4 named tests in isolation).

Coverage (touched packages/functions; zero production lines changed)

Function Before After
pkg/entities (whole package, all tests) build/panic, no coverage obtainable 10.0%
SearchCoins (defi.go) n/a (panic) 56.3%
CreateCustomToken (tokens.go) n/a (panic) 48.6%
enrichPriceQuery (price_resolver.go) n/a (panic) 50.0%
symbolForCoingeckoID n/a (panic) 80.0%
tierAlchemy n/a (panic) 66.7%
GetTokenPricesByID n/a (panic) 92.3%
resolvePriceOne n/a (panic) 69.2%
pkg/service/dexscreener (package) 38.2% 41.2%
GetByChainAndPairAddress (only via a failing test) 61.5%

Per-function coverage on SearchCoins/CreateCustomToken/enrichPriceQuery/tierAlchemy sits in the 48-67% range, below an 80% bar. These are large, multi-branch functions (skull-symbol override, default-ticker/native/is_popular tie-break branches, DexScreener-fallback path) where the uncovered branches are pre-existing and unrelated to what broke CI. Reviewer 1 (test-coverage lens) assessed this as acceptable for a CI-red bugfix ("scope here is explicitly making CI green, not raising coverage") and flagged the tierAlchemy DexScreener-fallback branch as a cheap follow-up, not a blocker for this PR.

Review

Three review passes ran against this diff before opening:

  • kit:code-reviewer (test-coverage lens): PASS-WITH-NITS, no blocking findings. Confirmed mocks are correctly scoped (the gomock.Any() matchers are compensated by exact-match dispatch inside their DoAndReturn closures), the same-price fixture change is a legitimate reflection of the new architecture, and coverage levels are acceptable for this task's scope.
  • kit:security-reviewer: PASS. No secrets, no PII, no weakened security assertions. The one live unmocked network call (dexscreener) targets a public well-known Uniswap pool, matching this file's pre-existing convention.
  • kit:advisor (fable, critique mode): 4 findings, all addressed in the second commit:
    1. Branch didn't actually make CI green (TestHandler_SearchCoins still red), fixed, now 0 FAIL packages.
    2. "Architecturally indistinguishable" comment overclaimed; it's the current resolver's tier-ordering choice (by-symbol before by-contract), not an inherent limit, softened the comment and flagged it as worth an explicit accept-or-fix decision from whoever owns the pricing revamp (see below).
    3. Dead coinIds/coinPrices fixture fields left over from the pre-revamp mocks, deleted.
    4. A tests[0]-vs-loop-scoped-tt coupling in tokens_test.go's Alchemy mock, commented for the next person adding a test case.

Worth a follow-up decision (not blocking this PR)

Two coingecko ids that share one ticker symbol (ethereum/ethereum-wormhole, binance-peg-dogecoin/dogecoin) now resolve to the same Alchemy-sourced price, where the old CoinGecko-based pricing could tell them apart by id. This PR's tests document that as today's actual behavior rather than trying to fake differentiation. Whoever owns the pricing revamp should confirm whether that's an accepted tradeoff or worth a DexScreener-by-contract fallback for same-symbol tokens.

Not in scope

  • Deleting the 3 dead Etherscan/BscScan/Infura config fields (CL-014/CL-010 residual cleanup).
  • Raising SearchCoins/tierAlchemy/etc. coverage beyond what's needed to get CI green (see coverage table above).

Reproduce

export PATH="$HOME/.local/share/mise/installs/go/1.24.2/bin:$PATH"   # pin to go.mod's toolchain, avoid brew-go GOROOT mismatch
docker-compose up -d postgres_test redis chrome
sql-migrate up -env=test
PROJECT_PATH=$(pwd) go test ./...

This is a production service repo; this PR is not being merged by me. Waiting on human review.

tieubao added 2 commits July 18, 2026 16:18
…evelop

The mochi-pricing-revamp sub-goal 05 (Alchemy pricing) landed new call
paths these tests never wired mocks for:

- Test_dexscreener_Get: fixture pair address was never a real dexscreener
  pair (unrelated to the revamp, pre-existing bad fixture); swapped for
  the Uniswap V3 WETH/USDC pool.
- TestEntity_SearchCoins / TestEntity_UpsertCustomToken:
  repo.CoingeckoSupportedTokens.GetOne() never returns a nil token
  (pg.go always returns a non-nil pointer even on ErrRecordNotFound);
  the CoinGecko-era mocks returned nil, nil-deref'ing at SearchCoins'
  `token.ID` check now that this path is actually reached. The new
  price_resolver.go tier (Alchemy by-symbol/by-contract) also needed
  mocking: a symbol-resolution GetOne() call per priced token, an
  Alchemy mock, and a wired-up logger (logTierCounts nil-panics
  without one).

TestHandler_GetCoin was already fixed (skip-with-comment) by a prior
commit on develop; no change needed here.

TestHandler_SearchCoins remains red (same pricing-revamp root cause,
real-DB/testdata-JSON fixtures with hardcoded prices) but was not in
scope for this fix and was already failing before this change.
Three independent review passes (kit:code-reviewer test-coverage lens,
kit:security-reviewer, kit:advisor critique) ran against the first
commit. Security came back clean. The advisor caught a real scope gap
this commit closes, plus three nits addressed below.

- TestHandler_SearchCoins was still red after the first commit (it was
  never in this task's original 4-test list, which named
  TestHandler_GetCoin instead, already fixed via a prior skip on
  develop). CL-015's own backlog text names TestHandler_SearchCoins,
  not TestHandler_GetCoin, as the actual 4th target, and a branch named
  fix/ci-test-green that leaves a known test red doesn't earn its name.
  Fixed the same way as the pkg/entities tests: mock svc.Alchemy, and
  update the "get multiple coins" golden JSON fixture, two coingecko
  ids sharing symbol "doge" ("binance-peg-dogecoin" / "dogecoin") can
  no longer get different Alchemy-sourced prices, so both now expect
  0.2 with most_popular on the first (scan-order) entry, verified
  against the real DB-seeded test run, not guessed.
- Softened the "no longer price-distinguishable" comments (defi_test.go,
  handler/defi/defi_test.go): this is the CURRENT resolver's tier
  ordering (by-symbol before by-contract), not an inherent limitation,
  a populated contract could still differentiate via the DexScreener
  tier. Worth an explicit accept-or-fix call from whoever owns the
  pricing revamp; the test fixture documents today's behavior, it
  doesn't endorse it.
- Deleted now-dead coinIds/coinPrices fixture fields left over from the
  CoinGecko-mocked version of these tests (defi_test.go, tokens_test.go,
  handler/defi/defi_test.go) that nothing reads post-fix.
- Commented the tests[0]-vs-tt coupling in tokens_test.go's Alchemy mock
  (set up outside the test-case loop, matching this file's existing
  GetOne/List/GetTokenMetadata mocks): a second test case would need
  this hoisted into the loop.

Full suite verified: `go test ./...` is now 0 FAIL packages (244
package results, all ok/no-test-files).
@tieubao
tieubao merged commit b0b57d6 into develop Jul 19, 2026
5 checks passed
@tieubao
tieubao deleted the fix/ci-test-green branch July 19, 2026 01:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant