0003-relocate-testutil-to-factory

ADR 0003: Relocate adapter test helpers to internal/adapter/factory

Status: Proposed

Date: 2025-09-11

Author: (please fill: repo owner)

Context

The repository contains small test helper factories under internal/adapter/testutil that produce seeded adapters and RefreshFunc fixtures for unit and handler tests. During refactors these helpers initially returned any to avoid import cycles; later changes made them return adapter.Adapter successfully. However, placing these helpers under internal/adapter/testutil creates a package dependency graph that can be confusing and risks accidental import cycles when other packages want to reuse factories.

Decision

Move the test helper factories into a new package internal/adapter/factory and treat that package as the canonical location for programmatic adapter construction used by tests and examples. The factory package will:

  • Depend only on internal/adapter (the interface), internal/adapter/memory (provider), and internal/model as needed.
  • Export typed factory functions that return adapter.Adapter (no any), e.g. NewSeededAdapter() (adapter.Adapter, error) and NewAdapterFromData(...) (adapter.Adapter, error).
  • Avoid importing any packages that themselves import test-only helper packages to keep the dependency graph acyclic.

Rationale

  • Clearer package responsibility: factory is explicitly a construction helper and not a test package.
  • Eliminates historical any returns and the need for tests to type-assert.
  • Reduces risk of import cycles and makes package dependencies explicit.
  • Easier discovery: other packages and integration tests can import internal/adapter/factory when they need seeded adapters.

Consequences

  • Minor API change for tests: imports change from internal/adapter/testutil to internal/adapter/factory.
  • A small migration effort is required to update test imports and README/documentation.
  • The testutil package may be removed after migration or kept as a thin compatibility shim for a release cycle.

Alternatives considered

  1. Keep testutil but rename it factory in-place.

    • Pros: minimal filesystem churn.
    • Cons: still ambiguous — testutil name signals test-only code; a neutral factory name clarifies broader applicability.
  2. Keep helpers where they are and accept any return types.

    • Pros: least immediate work.
    • Cons: retains type-asserts and reduces API clarity; risks future import-cycle regressions.
  3. Move factories into a separate top-level internal/testhelpers package.

    • Pros: makes it clear they are test helpers.
    • Cons: increases surface area and may encourage non-adapters to depend on test helpers.

Migration plan

  1. Add new package internal/adapter/factory with equivalent functions implemented in the existing testutil code, returning adapter.Adapter.
  2. Update existing tests to import internal/adapter/factory instead of internal/adapter/testutil and remove type-assertions.
  3. Run go test ./... and fix any remaining import or build issues.
  4. Optionally leave a lightweight internal/adapter/testutil that re-exports factory functions (deprecated) for one release to ease migration, then delete it.

Rollback

If the migration introduces unexpected build or import-cycle issues, revert to the previous commit and implement a compatibility shim (step 4 above) to provide the old APIs while diagnosing cycles.

Open questions

  • Author/Approver: please fill in the ADR metadata (Author and Approver) and confirm the preferred migration window (immediate vs. staged compatibility shim).
  • Naming: confirm factory vs builder vs construct as the package name.