Skip to content

test: add API integration tests#34

Merged
pthmas merged 3 commits intomainfrom
pthmas/integration-tests
Mar 19, 2026
Merged

test: add API integration tests#34
pthmas merged 3 commits intomainfrom
pthmas/integration-tests

Conversation

@pthmas
Copy link
Collaborator

@pthmas pthmas commented Mar 19, 2026

Summary

  • 21 integration tests across 7 files covering blocks, transactions, search, status, addresses, ERC-20 tokens, and NFT collections
  • Uses testcontainers-rs to spin up a real PostgreSQL instance with migrations applied — no mocking, no external setup required (Docker must be running)
  • Tests hit the actual Axum router via tower::ServiceExt::oneshot and assert on real HTTP responses + JSON bodies
  • All tests run in parallel by default, sharing a single persistent runtime and connection pool

What's NOT tested (and why)

  • SSE/events — already unit-tested with HeadTracker
  • Faucet — already has router-level tests with mock backend
  • Etherscan API — pass-through to RPC, needs mock RPC server
  • NFT/collection get_* endpoints — trigger on-demand RPC calls for metadata
  • Proxy/ABI endpoints — deferred to a follow-up

Running

# Docker must be running — testcontainers handles Postgres automatically
cargo test --package atlas-server --test integration

Other changes

  • src/lib.rs added to expose api, faucet, head modules to the integration test binary
  • head.rs: pub(crate)pub on HeadTracker and its methods (required for external test access)

Summary by CodeRabbit

  • Tests

    • Added comprehensive integration tests for core API endpoints including addresses, blocks, NFTs, search, status, tokens, and transactions using containerized PostgreSQL support and shared test utilities.
  • Chores

    • Added testing framework dependencies (testcontainers and testcontainers-modules).

@coderabbitai
Copy link

coderabbitai bot commented Mar 19, 2026

📝 Walkthrough

Walkthrough

This PR adds comprehensive integration tests for the Atlas server's HTTP API endpoints, introduces testcontainers-based PostgreSQL test fixtures, exports internal modules (head, api, faucet) as public, and establishes a shared test environment infrastructure with dev-dependencies.

Changes

Cohort / File(s) Summary
Dependency Management
backend/Cargo.toml, backend/crates/atlas-server/Cargo.toml
Added testcontainers, testcontainers-modules, and related dev-only dependencies for integration testing.
Public API Exports
backend/crates/atlas-server/src/lib.rs, backend/crates/atlas-server/src/head.rs
Exported api, faucet, and head modules publicly; changed HeadTracker and ReplaySnapshot types and their methods from pub(crate) to pub.
Test Infrastructure
backend/crates/atlas-server/tests/integration/common.rs
Added shared test utilities: TestEnv with lazy-initialized Postgres container, sqlx::PgPool, migration runner, and helper functions (pool(), test_router(), json_body(), run()).
Integration Test Suite
backend/crates/atlas-server/tests/integration/main.rs, backend/crates/atlas-server/tests/integration/addresses.rs, backend/crates/atlas-server/tests/integration/blocks.rs, backend/crates/atlas-server/tests/integration/nfts.rs, backend/crates/atlas-server/tests/integration/search.rs, backend/crates/atlas-server/tests/integration/status.rs, backend/crates/atlas-server/tests/integration/tokens.rs, backend/crates/atlas-server/tests/integration/transactions.rs
Added comprehensive endpoint tests for addresses, blocks, NFTs, search, status, tokens, and transactions APIs with deterministic database seeding and HTTP assertion validation.

Sequence Diagram(s)

sequenceDiagram
    actor Test
    participant LazyLock as LazyLock<TestEnv>
    participant Testcontainers as Testcontainers
    participant Container as Postgres Container
    participant SQLx as SQLx
    participant Pool as PgPool

    Test->>LazyLock: Initialize TestEnv (once)
    LazyLock->>Testcontainers: Start container
    Testcontainers->>Container: Spawn Postgres instance
    Container-->>Testcontainers: Host/Port info
    Testcontainers-->>LazyLock: Container handle
    LazyLock->>SQLx: Create connection pool
    SQLx->>Container: Connect to Postgres
    Container-->>SQLx: Connection established
    LazyLock->>SQLx: Run migrations
    SQLx->>Container: Execute migration scripts
    Container-->>SQLx: Migrations complete
    SQLx-->>LazyLock: Pool ready
    LazyLock-->>Test: Return shared TestEnv
    Test->>Pool: pool() - access PgPool
    Pool-->>Test: PgPool reference
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • add faucet page #31: Implements and wires the faucet module that is now being exported publicly in this PR's lib.rs changes.

Suggested reviewers

  • tac0turtle

Poem

🐰 Hopping through code with testcontainers in tow,
Public APIs bloom, let the endpoints all glow,
PostgreSQL gardens, seeded with care,
Integration tests everywhere, everywhere!
A robust framework, now ready to play,
Atlas stands stronger—hip-hip-hooray! 🌟

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'test: add API integration tests' accurately summarizes the main change: adding comprehensive integration tests for the API endpoints.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pthmas/integration-tests
📝 Coding Plan
  • Generate coding plan for human review comments

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

pthmas added 3 commits March 19, 2026 13:20
21 integration tests covering blocks, transactions, search, status,
addresses, ERC-20 tokens, and NFT collections. Tests use testcontainers
to spin up a real PostgreSQL instance with migrations applied, and hit
the actual Axum router via tower::ServiceExt::oneshot — no mocking.

All tests share a single persistent runtime and connection pool to avoid
the tokio-per-test-runtime problem, and are isolated by block number
ranges to prevent data collisions when running in parallel.
@pthmas pthmas force-pushed the pthmas/integration-tests branch from e1e5b53 to 85a1ee8 Compare March 19, 2026 12:20
@pthmas pthmas marked this pull request as ready for review March 19, 2026 12:31
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
backend/crates/atlas-server/tests/integration/nfts.rs (1)

130-138: Consider extending the ordering assertion to all three tokens.

The ordering check only verifies id0 < id1 but not id1 < id2. For consistency with transactions.rs (which checks all three indices), consider:

♻️ Extend ordering verification
         let id0 = parse_token_id(&data[0]["token_id"]);
         let id1 = parse_token_id(&data[1]["token_id"]);
-        assert!(id0 < id1);
+        let id2 = parse_token_id(&data[2]["token_id"]);
+        assert!(id0 < id1 && id1 < id2);
     });
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/crates/atlas-server/tests/integration/nfts.rs` around lines 130 -
138, The test currently parses token_id for the first two items using the
closure parse_token_id and asserts id0 < id1 but never checks the third token;
parse the third token into id2 (e.g., let id2 =
parse_token_id(&data[2]["token_id"])) and add an assertion to verify ordering
across all three tokens (e.g., assert!(id1 < id2) or combine into assert!(id0 <
id1 && id1 < id2)) so the test enforces full ascending order for the data array.
backend/crates/atlas-server/tests/integration/common.rs (1)

59-81: Consider documenting the empty HeadTracker limitation.

HeadTracker::empty(10) initializes with latest=None. This is fine for the current tests since they avoid endpoints that depend on real-time head state (SSE, /api/height). Adding a brief comment would help future contributors understand why certain endpoints are excluded from integration testing.

📝 Optional documentation improvement
 pub fn test_router() -> Router {
     let pool = pool().clone();
+    // HeadTracker::empty means latest() returns None. This is fine for DB-backed
+    // endpoints but SSE/height endpoints won't work correctly in integration tests.
     let head_tracker = Arc::new(HeadTracker::empty(10));
     let (tx, _) = broadcast::channel(1);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/crates/atlas-server/tests/integration/common.rs` around lines 59 -
81, Add a short inline comment in the test setup (inside test_router)
documenting that HeadTracker::empty(10) initializes with latest=None and
therefore the test router deliberately excludes endpoints depending on real-time
head state (SSE, /api/height), so future contributors understand why those
endpoints are not covered by these integration tests; place the comment near the
HeadTracker::empty(10) line and mention HeadTracker, test_router, and
build_router for context.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@backend/crates/atlas-server/tests/integration/common.rs`:
- Around line 59-81: Add a short inline comment in the test setup (inside
test_router) documenting that HeadTracker::empty(10) initializes with
latest=None and therefore the test router deliberately excludes endpoints
depending on real-time head state (SSE, /api/height), so future contributors
understand why those endpoints are not covered by these integration tests; place
the comment near the HeadTracker::empty(10) line and mention HeadTracker,
test_router, and build_router for context.

In `@backend/crates/atlas-server/tests/integration/nfts.rs`:
- Around line 130-138: The test currently parses token_id for the first two
items using the closure parse_token_id and asserts id0 < id1 but never checks
the third token; parse the third token into id2 (e.g., let id2 =
parse_token_id(&data[2]["token_id"])) and add an assertion to verify ordering
across all three tokens (e.g., assert!(id1 < id2) or combine into assert!(id0 <
id1 && id1 < id2)) so the test enforces full ascending order for the data array.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 73da0d79-0059-4b64-9e16-87dd1a509dd5

📥 Commits

Reviewing files that changed from the base of the PR and between 1c00648 and 85a1ee8.

📒 Files selected for processing (13)
  • backend/Cargo.toml
  • backend/crates/atlas-server/Cargo.toml
  • backend/crates/atlas-server/src/head.rs
  • backend/crates/atlas-server/src/lib.rs
  • backend/crates/atlas-server/tests/integration/addresses.rs
  • backend/crates/atlas-server/tests/integration/blocks.rs
  • backend/crates/atlas-server/tests/integration/common.rs
  • backend/crates/atlas-server/tests/integration/main.rs
  • backend/crates/atlas-server/tests/integration/nfts.rs
  • backend/crates/atlas-server/tests/integration/search.rs
  • backend/crates/atlas-server/tests/integration/status.rs
  • backend/crates/atlas-server/tests/integration/tokens.rs
  • backend/crates/atlas-server/tests/integration/transactions.rs

@pthmas pthmas merged commit 1cf750a into main Mar 19, 2026
8 checks passed
@pthmas pthmas deleted the pthmas/integration-tests branch March 19, 2026 13:00
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