Skip to content

test: integration tier against real Postgres + Redis (Testcontainers): infra + auth/payments/isolation suites (#135) - #165

Merged
Levi-Ojukwu merged 3 commits into
OracleDesk:developfrom
choniszn1:test/135-integration-tier
Oct 17, 2026
Merged

Levi-Ojukwu merged 3 commits into
OracleDesk:developfrom
choniszn1:test/135-integration-tier

Conversation

@choniszn1

@choniszn1 choniszn1 commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds the integration test tier: real Postgres 16 and Redis 7, one migrated database per test file, and per-test truncation. It ports the auth and payments suites to it and adds an isolation check. npm test is unchanged and still runs only the unit tier, with no Docker needed.

What's included

Infrastructure (tests/helpers/, tests/integration/)

  • containers.ts › ensureContainers(): uses TEST_DATABASE_URL + TEST_REDIS_URL when set (CI). Otherwise it starts postgres:16-alpine and redis:7-alpine with Testcontainers, reusing them only when TESTCONTAINERS_REUSE_ENABLE=true. Without Docker and without the TEST_* URLs it returns null, and every integration test is skipped with one clear message instead of failing.
  • integration/global-setup.ts: loaded with --test-global-setup (Node ≥ 22.10, matching .nvmrc). It runs once, migrates an od_template database, and passes URLs to test files through env vars. Teardown stops the containers.
  • db.ts: createTestDatabase(label) clones the template (CREATE DATABASE … TEMPLATE od_template) with ?connection_limit=5 so parallel files don't exhaust Postgres connections. migrate(url) runs prisma migrate deploy. truncateAll(prisma) truncates every public table except _prisma_migrations with RESTART IDENTITY CASCADE.
  • integration/setup.ts › integrationEnv(label): sets DATABASE_URL / REDIS_URL before any src import, from an async before() hook. config and prisma read env when first imported, and the compiled output is CommonJS, so there's no top-level await.
  • redis.ts › withRedisPrefix(): a per-file key prefix, with a challenge store that issues the same real SET EX / GETDEL commands as redisChallengeStore. flushPrefix() deletes the file's keys with SCAN + UNLINK.
  • factories.ts: makeUser, makeMarket with counter-based values.
  • env.ts: setupTestEnv() now defaults REDIS_URL with ||, as it already did for DATABASE_URL.

Suites (tests/integration/*.int.test.ts)

File Tests
auth.int.test.ts login end to end (repeated logins → one users row via the real upsert) · replay → CHALLENGE_NOT_FOUND · 20 concurrent verifyChallenge of one signed challenge → exactly 1 success, 19 CHALLENGE_NOT_FOUND (real GETDEL atomicity)
payments.int.test.ts grants pass once (idempotent re-submit) · PAYMENT_ALREADY_USED for another user · concurrent double claim → one subscription and one payment event, via the real payment_events.txHash unique index. The loser's P2002 is marked // BUG: per the issue's non-goals · rollback on mid-transaction failure is test.todo, since it needs a fault-injection hook
isolation.int.test.ts two tests insert the same unique wallet address, which proves truncation isolates tests

Scripts, CI, docs

  • test:integration: node --test --test-concurrency=4 --test-global-setup=… dist-tests/tests/integration/*.int.test.js. test:all runs unit then integration. npm test still only globs dist-tests/tests/*.test.js, which excludes integration/.

  • ci.yml: after npm test, runs npm run test:integration with TEST_DATABASE_URL=…/postgres (the admin DB, for CREATE DATABASE) and TEST_REDIS_URL against the existing service containers.

  • CONTRIBUTING.md gets a Tests section (two tiers, local Docker, how to write an integration test). The README.md scripts table is updated.

  • New dev dependencies: testcontainers, @testcontainers/postgresql, @testcontainers/redis, pg, @types/pg.

  • indexer.int.test.ts: backfillEvents end to end, the atomic MarketResolved transaction, and trace linking by hash.

  • generation-status.int.test.ts: the JSON-path agentLog lookup.

  • The payments rollback test (currently test.todo).

  • A makeTrace / makePosition factory, which the indexer suite will need.

Verification, and what wasn't checked

  • Type-checked: npm run build:test reports no errors in any new file.
  • Not run against a database. There was no Docker in my environment, so I could not run the suites against real Postgres or Redis before opening this PR. The CI step will be their first real run, and fixes may be needed.
  • ci.yml still parses as valid YAML.
  • Problem already on develop: npm run build:test reports 16 TypeScript errors in existing files (e.g. src/services/trace-audit.service.ts, tests/resilience.test.ts, tests/copy-trade-verify.test.ts). tsconfig.test.json sets noEmitOnError, so these block npm test and this new tier alike until fixed.

Closes #132
Closes #133
Closes #134
Closes #135

…Redis prefix) (OracleDesk#135)

- ensureContainers(): TEST_DATABASE_URL/TEST_REDIS_URL or Testcontainers
  postgres:16-alpine + redis:7-alpine; skips cleanly without Docker
- global setup migrates od_template once; each file clones it
- truncateAll, typed factories, per-file Redis key prefix
- test:integration / test:all scripts; setupTestEnv defaults REDIS_URL
@drips-wave

drips-wave Bot commented Oct 17, 2026

Copy link
Copy Markdown

@choniszn1 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Levi-Ojukwu
Levi-Ojukwu merged commit 1d655fe into OracleDesk:develop Oct 17, 2026
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.

2 participants