Skip to content

Tests: Cover internal/repository (interfaces & helpers), repository/factory, and repository/postgresql #685

@vfusco

Description

@vfusco

Context / Problem

The repository layer is split into three parts:

Layer Purpose
internal/repository Declares repository interfaces (ApplicationRepository, EpochRepository, …) and small helpers.
internal/repository/factory Chooses a concrete backend (postgresql, future sqlite, etc.) based on configuration.
internal/repository/postgresql Current production implementation of the interfaces.

Today we have no dedicated test suite for these layers, so query errors or future back-end additions could break behaviour unnoticed.


Contract-Style Testing

Write one reusable test suite per interface (the contract) that asserts “this is how an ApplicationRepository must behave.”
Each concrete backend (PostgreSQL now, SQLite later) simply feeds its implementation into that same suite.
Result: you author the behavioural tests once, yet they run against every backend, guaranteeing consistent behaviour and making new back-ends inherit the tests automatically.


Suggested Solution

  1. Contract package

    • internal/repository/contract/ exports functions such as
      RunApplicationRepoContract(t *testing.T, repo repository.ApplicationRepository).
    • Each function is a table-driven suite covering happy path, edge cases, and error paths.
  2. PostgreSQL implementation

    • Test files like internal/repository/postgresql/app_test.go call the contract runner with a Postgres-backed repo.
    • Each test opens a transaction and rolls it back on cleanup to isolate state.
  3. Fixture seeding

  • Store deterministic seed data in internal/repository/testdata/*.sql.
  • Load these fixtures (via go:embed) inside the contract harness immediately after migrations.
  • Each test still runs in its own SQL transaction; the fixture rows are visible inside the txn and rolled back on cleanup.
  1. Helper & factory tests

    • internal/repository/helpers_test.go – filter builders, pagination tokens, nil-safety, etc.
    • internal/repository/factory/factory_test.go – correct backend selection, errors on unknown schemes.
  2. Concurrency & race checks

    • All tests run under go test -race; some use t.Parallel() to ensure thread safety.
  3. CI integration

    • GitHub Actions spins up Postgres, exports CARTESI_TEST_DATABASE_CONNECTION, then runs go test ./internal/repository/... -race.

Deliverables & File Layout

Path Purpose
internal/repository/contract/ Contract suites (application.go, epoch.go, …).
internal/repository/helpers_test.go Unit tests for shared helper funcs.
internal/repository/factory/factory_test.go Backend-selection tests.
internal/repository/postgresql/*_test.go Runs contract tests against Postgres impl.
internal/repository/testdata/*.sql Seed fixtures (embedded via go:embed).
internal/repository/testutil/db.go Connect, migrate, load fixtures, wrap each test in rollback TX.

Acceptance Criteria

# Scenario Expected outcome
1 go test -race ./internal/repository/... All tests pass; repository code coverage ≥ 80 %
2 Break a JOIN in PostgreSQL repo Contract test fails with clear assertion
3 Pass unknown DSN (foo://…) to factory Factory returns descriptive error
4 Parallel run (go test -parallel 8) No data races; state isolation via per-test TX

This contract-driven suite will give us a strong regression net for the current PostgreSQL backend and any future database implementations.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    📋 Backlog

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions