Skip to content

refactor(test): migrate messages repo tests to createTestDb (section B2, part 2)#3500

Merged
Yeraze merged 2 commits into
mainfrom
refactor/b2-bulk-test-db
Jun 16, 2026
Merged

refactor(test): migrate messages repo tests to createTestDb (section B2, part 2)#3500
Yeraze merged 2 commits into
mainfrom
refactor/b2-bulk-test-db

Conversation

@Yeraze

@Yeraze Yeraze commented Jun 16, 2026

Copy link
Copy Markdown
Owner

Continues the section-B2 bulk migration: convert hand-rolled test DDL to the shared createTestDb() helper (landed in #3498).

Change

The five messages repository tests previously hand-rolled CREATE TABLE nodes + CREATE TABLE messages (duplicating src/db/schema/). They now use createTestDb() — the full production schema from the migration registry:

  • messages.insert, messages.timestamp, messages.purge, messages.createdAt-ordering, messages.exclude-portnums

Note on the node seeding

Each test seeded its referenced nodes with a minimal (nodeNum, nodeId) insert. The real nodes schema requires sourceId (composite PK (nodeNum, sourceId) from migration 029) and createdAt/updatedAt NOT NULL — so the node seeds now include those. This is the per-file friction of the migration: the full schema has stricter constraints than the simplified hand-rolled tables.

Validation

  • tsc --noEmit: clean
  • Full Vitest suite: 6527 pass, 0 fail, 0 suite failures (same count — no tests lost)

Remaining B2 scope

~32 hand-rolled-DDL test files remain (nodes, auth, channels, meshcore, services, database facade, etc.). They have heterogeneous setups (different reference-data seeding, some multi-backend) so each batch needs individual verification — these will follow as further small, verified PRs. Intentionally left: telemetry.multidb.test.ts (multi-backend by design) and schemaIntegrity.test.ts (asserts DDL alignment on purpose).

🤖 Generated with Claude Code

…B2, part 2)

Convert the messages repository tests from hand-rolled `CREATE TABLE nodes` +
`CREATE TABLE messages` DDL to the shared createTestDb() helper (the full
production schema from the migration registry):
- messages.insert, messages.timestamp, messages.purge,
  messages.createdAt-ordering, messages.exclude-portnums

Each seeded its referenced nodes with a minimal (nodeNum, nodeId) insert; the
real nodes schema requires sourceId (composite PK from migration 029) and
createdAt/updatedAt, so the node seeds now include those. No behavior change —
full suite green (6527).

Part of the incremental B2 migration of ~40 hand-rolled-DDL test files.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown

Claude finished @Yeraze's task —— View job


PR Review: refactor(test): migrate messages repo tests to createTestDb (section B2, part 2)

Tasks

  • Gather context and understand the request
  • Read changed test files
  • Read createTestDb helper
  • Analyze code quality, bugs, performance, security, test coverage
  • Post review feedback

Summary

This is a clean, well-executed refactor. The migration from hand-rolled DDL to createTestDb() is the right approach, and the net -194 lines is a meaningful reduction in maintenance surface. All five files follow the same consistent pattern. A few observations:

Bug: Incomplete node seed in messages.purge.test.ts:131

The broadcast-node insert at line 131 is missing the three NOT NULL columns that the rest of this file correctly supplies:

// Current (line 131) — missing sourceId, createdAt, updatedAt
db.exec(`INSERT OR IGNORE INTO nodes (nodeNum, nodeId) VALUES (${0xffffffff}, '!ffffffff')`);

// Should match the pattern used everywhere else in this file
const now = Date.now();
db.prepare(
  "INSERT OR IGNORE INTO nodes (nodeNum, nodeId, sourceId, createdAt, updatedAt) VALUES (?, ?, 'default', ?, ?)"
).run(0xffffffff, '!ffffffff', now, now);

SQLite's INSERT OR IGNORE will silently swallow the NOT NULL constraint violation (it treats it as a conflict), so the node row never gets inserted. The test then passes only because the FK enforcement may also be absent in this in-memory setup — meaning the test passes for the wrong reason. This is the exact class of drift the B2 migration is designed to prevent.

Minor: db.exec() vs db.prepare() inconsistency

Relatedly, the same line uses db.exec() with string interpolation (${0xffffffff}) while every other seed in all five files uses db.prepare() with parameterized runs. The interpolation is safe here (it's a numeric literal, not user input), but the inconsistency is worth flagging for style uniformity.

Positive observations

  • Pattern consistency across all five files is excellent. Every file follows the same createTestDb() → seed nodes → construct repo structure.
  • Comment quality is high. The notes about "full schema NOT NULL/PK columns: sourceId, timestamps" directly explain the friction encountered.
  • afterEach(() => db.close()) is correctly present in all five files — no resource leak risk.
  • messages.createdAt-ordering.test.ts covers the cursor-based pagination case (getMessagesBeforeInChannel) which is the subtlest ordering edge case; good to see it explicitly tested.
  • messages.exclude-portnums.test.ts correctly uses rxTime as createdAt in the insert helper (with the inline comment explaining why), showing awareness of the [BUG] Large Meshtastic TCP node repeatedly disconnects during/after full config sync; passive per-source mode improves stability #3122 ordering change.
  • The createTestDb() helper itself (testDb.ts) is well-designed: the getSetting/setSetting shims that bridge the pre-settings-table window are a nice defensive touch.

Suggestion: Use close() from TestDb

createTestDb() returns a close() method on the TestDb interface for exactly this purpose. All five tests call db.close() directly on the raw sqlite handle instead of t.close(). Both are equivalent today, but using the interface method is more future-proof if close() ever needs to do cleanup beyond closing the connection:

// Current
afterEach(() => { db.close(); });

// More idiomatic given the TestDb interface
afterEach(() => { close(); }); // destructure close from createTestDb()
// or:
afterEach(() => { testDb.close(); });

This is stylistic, not a correctness issue.


The broadcast-node seed bug is the only substantive issue. The rest is a clean, well-reasoned migration. The B2 approach of small, verified batches is the right strategy for this kind of refactor.


claude-pr review on #3500 caught a real bug: the broadcast-node seed in the
'excludes broadcast messages' test still used a minimal INSERT OR IGNORE
without sourceId/createdAt/updatedAt. OR IGNORE silently swallowed the NOT NULL
violation, so the row never inserted (test passed only because FKs aren't
enforced). Use the full parameterized insert like the rest of the file.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown

Claude finished @Yeraze's task —— View job


PR Review: refactor(test): migrate messages repo tests to createTestDb (section B2, part 2)

Tasks

  • Gather context and understand the request
  • Read changed test files
  • Analyze code quality, bugs, performance, security, test coverage
  • Post review feedback

Summary

This is a clean, well-executed refactor. The migration from hand-rolled DDL to createTestDb() is the right approach, and the net −194 lines is a meaningful reduction in maintenance surface. All five files follow the same consistent pattern.

Previously identified bug: Fixed ✅

The broadcast-node seed in messages.purge.test.ts:131 that was flagged in the earlier review has been corrected. The fix is correct and complete — the node insert at lines 134–136 now supplies all required columns (sourceId, createdAt, updatedAt):

// Fixed — all NOT NULL/PK columns present
db.prepare(
  "INSERT OR IGNORE INTO nodes (nodeNum, nodeId, sourceId, createdAt, updatedAt) VALUES (?, ?, 'default', ?, ?)",
).run(0xffffffff, '!ffffffff', now, now);

The inline comment at line 131–132 also documents exactly why the full column set is needed, which is a good addition for future readers.

Remaining observations (minor/stylistic)

db.close() vs testDb.close() — All five files call db.close() on the raw sqlite handle in afterEach rather than t.close() (the TestDb interface method). Both are equivalent today, but using the interface method is marginally more future-proof if cleanup ever needs to expand. This is stylistic, not a correctness issue.

Test coverage quality — All five files cover the right edge cases:

No gaps found. The regression comments linking issue numbers (#2631, #2741, #3122) are particularly helpful.

Positive observations

  • Pattern consistency across all five files is excellent — same createTestDb() → seed nodes → construct repo → afterEach close structure throughout.
  • Comment quality is high. The "full schema NOT NULL/PK columns" notes in every file directly explain the migration friction.
  • afterEach(() => db.close()) is correctly present in all five files with no resource leaks.
  • The incremental B2 strategy (small, verified batches with confirmed test counts) is the right approach for this kind of large refactor.

Verdict

Clean PR. The one substantive bug from the previous review has been addressed. No new issues found.


@Yeraze Yeraze merged commit a6bd408 into main Jun 16, 2026
20 checks passed
@Yeraze Yeraze deleted the refactor/b2-bulk-test-db branch June 16, 2026 21:19
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