Skip to content

itest: aperture harness uses machine-global sqlite DB #2233

Description

@jtobin

(N.b., not terribly pressing but definitely wrong/should be fixed. Opus's summary follows.)

Summary

NewApertureHarness builds a per-test temp directory for aperture but then configures the sqlite backend with aperture.DefaultSqliteConfig(), whose DatabaseFileName points at a fixed, machine-global path. Every hashmail-courier itest therefore reads and writes one shared database outside the test sandbox, persisting across runs and shared between concurrently running tranches.

Affected code

itest/aperture_harness.go:30-55:

// Create a temporary directory for the aperture service to use.
baseDir := filepath.Join(t.TempDir(), "aperture")
...
cfg := &aperture.Config{
        ...
        DatabaseBackend: "sqlite",
        Sqlite:          aperture.DefaultSqliteConfig(),
        ...
        BaseDir:    baseDir,
}

BaseDir is correctly sandboxed, but the sqlite path is not. In aperture v0.4.0 (go.mod), DefaultSqliteConfig resolves to:

apertureDataDir           = btcutil.AppDataDir("aperture", false)
defaultSqliteDatabasePath = filepath.Join(apertureDataDir, "aperture.db")

which is ~/Library/Application Support/Aperture/aperture.db on macOS
and ~/.aperture/aperture.db on Linux.

Observed failure

On a machine where that file was previously created by a newer aperture, all five *_hashmail_courier tests fail during harness startup, before any tapd logic runs:

Error:      Received unexpected error:
            unable to connect to sqlite: no migration found for version 7:
            read down for version 7 sqlc/migrations: file does not exist
Messages:   aperture proof courier harness

The stale DB is stamped schema_migrations = 7 and contains tables (l402_transactions, mpp_sessions, services) that do not exist in aperture v0.4.0, which ships only three migrations. applyMigrations calls sqlMigrate.Up(), the source has no version 7, and startup fails.

Tests affected (one per tranche, in an 8-way make itest-parallel run):

  • basic_send_unidirectional_hashmail_courier
  • resume_pending_package_send_hashmail_courier
  • reattempt_failed_send_hashmail_courier
  • sending_multi_asset_groups_hashmail_courier
  • offline_receiver_eventually_receives_hashmail_courier

The tell that the state is not test-owned: the file predates the code under test by weeks, and nothing in the repo creates or cleans it.

Why this matters beyond the migration error

The migration mismatch is the visible symptom; the underlying problem is that the itests depend on machine-wide mutable state.

  • Not hermetic. Results depend on whatever aperture last touched the developer's home directory. CI passes and local runs fail, or vice versa, for reasons invisible in the diff.
  • Shared across parallel tranches. make itest-parallel runs eight tranches concurrently and five of them exercise a hashmail test, so five processes open the same sqlite file at once. WAL mode plus the 5s busy timeout mostly hides this, but it is a latent source of flakes and lock contention rather than a guarantee.
  • Leaks between runs. Rows written by one test run are visible to the next, and the file is never cleaned by clean-itest-logs.
  • Pollutes a real install. If the developer also runs aperture locally, the itests write into that daemon's production database.

Suggested fix

Point the sqlite file at the temp dir the harness already creates:

sqliteCfg := aperture.DefaultSqliteConfig()
sqliteCfg.DatabaseFileName = filepath.Join(baseDir, "aperture.db")

cfg := &aperture.Config{
        ...
        Sqlite: sqliteCfg,
        ...
}

DefaultSqliteConfig returns a pointer, so this needs no new import and leaves SkipMigrations at its default. Each harness instance then gets a fresh database under t.TempDir(), cleaned up automatically, and the migration state always matches the pinned aperture version.

Environment

  • taproot-assets v0.8.1 (also reproduces on main; the harness code is unchanged there)
  • aperture v0.4.0
  • macOS (darwin), sqlite backend

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingitests

    Type

    No type

    Projects

    Status
    🆕 New

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions