(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
(N.b., not terribly pressing but definitely wrong/should be fixed. Opus's summary follows.)
Summary
NewApertureHarnessbuilds a per-test temp directory for aperture but then configures the sqlite backend withaperture.DefaultSqliteConfig(), whoseDatabaseFileNamepoints 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:BaseDiris correctly sandboxed, but the sqlite path is not. In aperture v0.4.0 (go.mod),DefaultSqliteConfigresolves to:which is
~/Library/Application Support/Aperture/aperture.dbon macOSand
~/.aperture/aperture.dbon Linux.Observed failure
On a machine where that file was previously created by a newer aperture, all five
*_hashmail_couriertests fail during harness startup, before any tapd logic runs:The stale DB is stamped
schema_migrations = 7and contains tables (l402_transactions,mpp_sessions,services) that do not exist in aperture v0.4.0, which ships only three migrations.applyMigrationscallssqlMigrate.Up(), the source has no version 7, and startup fails.Tests affected (one per tranche, in an 8-way
make itest-parallelrun):basic_send_unidirectional_hashmail_courierresume_pending_package_send_hashmail_courierreattempt_failed_send_hashmail_couriersending_multi_asset_groups_hashmail_courieroffline_receiver_eventually_receives_hashmail_courierThe 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.
make itest-parallelruns 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.clean-itest-logs.Suggested fix
Point the sqlite file at the temp dir the harness already creates:
DefaultSqliteConfigreturns a pointer, so this needs no new import and leavesSkipMigrationsat its default. Each harness instance then gets a fresh database undert.TempDir(), cleaned up automatically, and the migration state always matches the pinned aperture version.Environment
v0.8.1(also reproduces onmain; the harness code is unchanged there)v0.4.0darwin), sqlite backend