Skip to content

fix(etl): clear out 6 failing entity_manager tests (4 code bugs + 2 test bugs) - #307

Closed
raymondjacobson wants to merge 1 commit into
mainfrom
etl/fix-failing-tests
Closed

fix(etl): clear out 6 failing entity_manager tests (4 code bugs + 2 test bugs)#307
raymondjacobson wants to merge 1 commit into
mainfrom
etl/fix-failing-tests

Conversation

@raymondjacobson

Copy link
Copy Markdown
Contributor

Summary

The entity_manager package had six db-backed tests failing on a working ETL_TEST_DB_URL setup — long called out as out-of-scope in prior PRs. Walked each one and split into real code bugs vs. test bugs. Four of the six were genuine handler bugs that would have produced wrong/missing rows in production; two were test sloppiness.

Per-test triage

Test Verdict What was wrong
TestAssociatedWalletCreate_SOL_Success Code bug strings.ToLower on the wallet destroys Solana base58 (capital L → invalid l). Now: lowercase only ETH, preserve SOL case.
TestAssociatedWalletDelete_Success Code bug Delete UPDATE filtered by chain = $4, but delete tx has no chain field in metadata, so the WHERE never matched. Bring the UPDATE in line with the validation's (user_id, wallet) key.
TestDashboardWalletCreate_Success Test bug Handler canonicalizes ETH addr to lowercase (correct); test query used the cased address. Fix the query.
TestDashboardWalletDelete_Success Test bug Same.
TestSave_Album_Success Code bug Save/Repost/Unsave/Unrepost preferred chain entity_type ("Playlist") over metadata type ("album"). But chain entity_type can't distinguish playlist from album (albums are playlists with is_album=true), so album saves were silently coerced to playlist saves. New resolveSaveType/resolveRepostType: metadata type wins; if entity_type is the ambiguous "playlist", defer to DB inference (is_album).
TestTrackUpdate_NotFound Test bug Test seeded user wallet 0xo but signed with 0xOwner, so ValidateSigner rejected before the existence check the test means to exercise. Seed with matching wallet.

Test plan

  • go build ./... and go vet ./... clean
  • Targeted tests pass individually
  • Full go test ./pkg/etl/... clean against fresh Postgres
  • Ran 5 times sequentially: all entity_manager suite passes (one run timed out on a slow box — not a logic failure)

Known intermittent

TestTrackCreate_AppliesAccessNormalization flakes ~10-20% of full-suite runs with column "access_authorities" of relation "tracks" does not exist, even though migrate.Up() returned without error and the migration's ALTER TABLE ... ADD COLUMN IF NOT EXISTS is in place at 0024_tracks_access_authorities.up.sql. Passes deterministically in isolation. Predates this PR — looks like a golang-migrate down/up cycle anomaly. Tracked separately; not blocking here.

🤖 Generated with Claude Code

The entity_manager package had six db-backed tests failing on a working
ETL_TEST_DB_URL setup. Per-test triage (patch-code / patch-test):

1. TestAssociatedWalletCreate_SOL_Success — code bug. The create handler
   unconditionally lowercased the wallet address. Lowercasing destroys
   Solana base58 addresses (capital L → lowercase l, which is not in the
   bitcoin base58 alphabet), so the signature verifier rejected with
   "invalid base58 character: l". Introduce canonicalizeWallet that
   lowercases ETH (hex, case-insensitive) and preserves SOL case.

2. TestAssociatedWalletDelete_Success — code bug. The delete UPDATE
   filtered by `chain = $4`, but the delete tx doesn't include `chain`
   in metadata, so chain was empty and the row was never updated.
   validateAssociatedWalletDelete's own existence check already uses
   `(user_id, wallet)` as the lookup key with no chain; bring the
   UPDATE's WHERE in line with it.

3. & 4. TestDashboardWalletCreate_Success / TestDashboardWalletDelete_Success
   — test bug. The handler canonicalizes ETH wallet addresses to
   lowercase for storage (correct); the assertion query used the
   original cased address and missed the row. Lowercase the address
   in the test query to match the canonical form.

5. TestSave_Album_Success — code bug. Save/Repost/Unsave/Unrepost
   handlers preferred the chain-level entity_type ("Playlist") over the
   metadata `type` ("album") when deriving save_type. The chain
   entity_type can't distinguish playlist vs album (albums are stored
   as playlists with is_album=true), so a Playlist entity_type was
   silently coercing album saves to playlist saves. New resolve helpers:
   metadata `type` wins; if entity_type is the ambiguous "playlist",
   defer to DB inference (which reads is_album).

6. TestTrackUpdate_NotFound — test bug. The test seeded a user with
   wallet "0xo" but signed with "0xOwner", so ValidateSigner fired
   before the existence check the test means to exercise. Seed the
   user with a wallet matching the signer.

All six tests now pass. Same suite (`go test ./...`) verified clean
end-to-end across multiple runs against a fresh Postgres.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@raymondjacobson

Copy link
Copy Markdown
Contributor Author

Closing in favor of #308

raymondjacobson added a commit that referenced this pull request May 22, 2026
Findings from running the indexer against a production database clone
for ~3h and diffing the result against a live production read replica.
This PR includes the corrected versions of #307's test fixes (one had a
regression we caught in the diff) plus four new prod-only bugs.

1. save_type/repost_type mistyped on entity-id collisions (REGRESSION
   from PR #307). When chain entity_type was "Playlist", #307 fell
   through to inferSaveType, which ranks tracks first. Whenever a track
   existed with the same numeric id as the playlist being saved
   (track_id and playlist_id are independent namespaces — collisions are
   real), the save was written with save_type='track' instead of
   'playlist'. Observed against prod: ~1% of saves mistyped. Fix:
   resolveSaveType / resolveRepostType only disambiguate "Playlist" via
   playlists.is_album; never cross over to "track". New
   TestSave_Playlist_WhenTrackIdCollides locks this in.

2. mergeNullStr treats "" as "clear field" instead of "no change". Chain
   User Update txs commonly include "handle":"" when the client doesn't
   want to change handle; our handler was wiping users.handle to NULL
   while leaving handle_lc populated. Real data corruption observed
   against prod (e.g. user_id=169901003 'richard627'). Fix: empty string
   now preserves the existing value, matching the prod indexer.

3. PRIMARY KEY violations on re-delivered txs (shares_pkey,
   reposts_pkey, saves_pkey, follows_pkey, subscriptions_pkey). Bare
   INSERTs into row-versioned (entity_keys..., txhash) PKs hit 23505
   when the prefetcher re-delivers a chain tx (root cause deferred). All
   five domain inserts now have ON CONFLICT (...) DO NOTHING — txhash
   is content-addressable, so re-delivered data is identical.

4. blockhash NOT NULL on prod schema. Our migrations declare
   `blockhash ... NOT NULL DEFAULT ''` (so omitting the column locally
   silently writes ''), but prod schemas have no default — every
   INSERT must include it. Observed events.blockhash 23502 violation in
   prod-clone run. Added blockhash to INSERTs into events,
   associated_wallets, muted_users.

Also folded in from #307 (the five non-regression fixes):

5. AssociatedWalletCreate: SOL base58 case preservation. ETH addresses
   lowercase; SOL preserve case (uppercase `L` → invalid base58 `l`).
   New `canonicalizeWallet` helper handles both based on chain or
   `0x` prefix.

6. AssociatedWalletDelete: drop bogus `chain = $4` filter from the
   UPDATE — delete tx doesn't include chain, so the filter was always
   matching empty string and updating nothing. Validation already keys
   on (user_id, wallet); UPDATE now matches.

7. dashboard_wallet_test.go: lowercase wallet address in test queries to
   match handler's canonical storage form.

8. track_update_test.go: seed user wallet matching the signer so the
   test reaches the existence check it means to exercise.

Closes #307 (superseded). Deferred: "no rows in result set" raw error
(needs context attribution), TCP "can't assign requested address"
(environmental).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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