Skip to content

refactor: extract Migrator interface and un-skip migration handler tests - #374

Open
mrofreP wants to merge 1 commit into
UndernetIRC:masterfrom
mrofreP:refactor/migrator-interface-for-migration-handler
Open

mrofreP wants to merge 1 commit into
UndernetIRC:masterfrom
mrofreP:refactor/migrator-interface-for-migration-handler

Conversation

@mrofreP

@mrofreP mrofreP commented Jul 18, 2026

Copy link
Copy Markdown

db/migration_test.go had three tests disabled with skips explaining
they needed a mockable migrate.Migrate or a real database:

  • TestMigrationHandler_Step
  • TestMigrationHandler_RunMigrations
  • TestNewMigrationHandler (empty body, just a placeholder)

The blocker was that MigrationHandler embedded *migrate.Migrate
directly and MigrationStep / ForceVersion called globals.LogAndExit
on both success and failure — so callers could not observe outcomes
and tests could not run in-process.

Refactor:

  • db/migration.go

    • Introduce a Migrator interface (Steps, Version, Up, Force) that
      captures the subset of *migrate.Migrate MigrationHandler uses.
    • Replace the *migrate.Migrate embedding with a Migrator field.
    • Add NewMigrationHandlerWith(m Migrator) for test injection.
    • MigrationStep now returns (uint, error); ForceVersion returns
      error. Neither calls LogAndExit — that decision belongs to the
      CLI layer, not the library.
    • RunMigrations still returns error (unchanged shape); implementation
      routes through the new interface field.
  • cmd/cservice-api/main.go

    • runMigrations now handles the errors from MigrationStep and
      ForceVersion, calling globals.LogAndExit with the same messages
      that previously lived in the library.
  • db/migration_test.go

    • Add a hand-rolled mockMigrator (no mockery / no external mock
      library) that records last-call args and returns configurable
      errors.
    • Un-skip TestMigrationHandler_Step with a table covering up-one,
      down-one, Steps failure (asserts the wrapped error mentions the
      direction), and Version failure.
    • Un-skip TestMigrationHandler_RunMigrations with a table covering
      clean apply, the "no change" success convention, and other-error
      propagation.
    • Add TestMigrationHandler_ForceVersion covering happy path and
      error propagation.
    • Delete the placeholder TestNewMigrationHandler (empty body, only a
      t.Skip — was dead scaffolding, not a test).

Breaking API changes on the exported MigrationHandler:

  • MigrationStep(int) → MigrationStep(int) (uint, error)
  • ForceVersion(int) → ForceVersion(int) error
    Only main.go consumed these; caller updated in the same commit. The
    project is pre-1.0 (README: "WORK IN PROGRESS ... DO NOT USE IN
    PRODUCTION") so this is an acceptable break.

Net effect: three previously-unreachable code paths in MigrationHandler
now have real unit test coverage without needing a live Postgres.

db/migration_test.go had three tests disabled with skips explaining
they needed a mockable migrate.Migrate or a real database:
- TestMigrationHandler_Step
- TestMigrationHandler_RunMigrations
- TestNewMigrationHandler (empty body, just a placeholder)

The blocker was that MigrationHandler embedded *migrate.Migrate
directly and MigrationStep / ForceVersion called globals.LogAndExit
on both success and failure — so callers could not observe outcomes
and tests could not run in-process.

Refactor:

- db/migration.go
  - Introduce a Migrator interface (Steps, Version, Up, Force) that
    captures the subset of *migrate.Migrate MigrationHandler uses.
  - Replace the *migrate.Migrate embedding with a Migrator field.
  - Add NewMigrationHandlerWith(m Migrator) for test injection.
  - MigrationStep now returns (uint, error); ForceVersion returns
    error. Neither calls LogAndExit — that decision belongs to the
    CLI layer, not the library.
  - RunMigrations still returns error (unchanged shape); implementation
    routes through the new interface field.

- cmd/cservice-api/main.go
  - runMigrations now handles the errors from MigrationStep and
    ForceVersion, calling globals.LogAndExit with the same messages
    that previously lived in the library.

- db/migration_test.go
  - Add a hand-rolled mockMigrator (no mockery / no external mock
    library) that records last-call args and returns configurable
    errors.
  - Un-skip TestMigrationHandler_Step with a table covering up-one,
    down-one, Steps failure (asserts the wrapped error mentions the
    direction), and Version failure.
  - Un-skip TestMigrationHandler_RunMigrations with a table covering
    clean apply, the "no change" success convention, and other-error
    propagation.
  - Add TestMigrationHandler_ForceVersion covering happy path and
    error propagation.
  - Delete the placeholder TestNewMigrationHandler (empty body, only a
    t.Skip — was dead scaffolding, not a test).

Breaking API changes on the exported MigrationHandler:
- MigrationStep(int) → MigrationStep(int) (uint, error)
- ForceVersion(int) → ForceVersion(int) error
Only main.go consumed these; caller updated in the same commit. The
project is pre-1.0 (README: "WORK IN PROGRESS ... DO NOT USE IN
PRODUCTION") so this is an acceptable break.

Net effect: three previously-unreachable code paths in MigrationHandler
now have real unit test coverage without needing a live Postgres.
@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 0 complexity · 0 duplication

Metric Results
Complexity 0
Duplication 0

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

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