diff --git a/sqldb/migrations_test.go b/sqldb/migrations_test.go new file mode 100644 index 000000000..cd55e92cb --- /dev/null +++ b/sqldb/migrations_test.go @@ -0,0 +1,154 @@ +package sqldb + +import ( + "context" + "testing" + + "github.com/lightningnetwork/lnd/sqldb/sqlc" + "github.com/stretchr/testify/require" +) + +// makeMigrationTestDB is a type alias for a function that creates a new test +// database and returns the base database and a function that executes selected +// migrations. +type makeMigrationTestDB = func(*testing.T, uint) (*BaseDB, + func(MigrationTarget) error) + +// TestMigrations is a meta test runner that runs all migration tests. +func TestMigrations(t *testing.T) { + sqliteTestDB := func(t *testing.T, version uint) (*BaseDB, + func(MigrationTarget) error) { + + db := NewTestSqliteDBWithVersion(t, version) + + return db.BaseDB, db.ExecuteMigrations + } + + postgresTestDB := func(t *testing.T, version uint) (*BaseDB, + func(MigrationTarget) error) { + + pgFixture := NewTestPgFixture(t, DefaultPostgresFixtureLifetime) + t.Cleanup(func() { + pgFixture.TearDown(t) + }) + + db := NewTestPostgresDBWithVersion( + t, pgFixture, version, + ) + + return db.BaseDB, db.ExecuteMigrations + } + + tests := []struct { + name string + test func(*testing.T, makeMigrationTestDB) + }{ + { + name: "TestInvoiceExpiryMigration", + test: testInvoiceExpiryMigration, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name+"_SQLite", func(t *testing.T) { + test.test(t, sqliteTestDB) + }) + + t.Run(test.name+"_Postgres", func(t *testing.T) { + test.test(t, postgresTestDB) + }) + + } +} + +// TestInvoiceExpiryMigration tests that the migration from version 3 to 4 +// correctly sets the expiry value of normal invoices to 86400 seconds and +// 2592000 seconds for AMP invoices. +func testInvoiceExpiryMigration(t *testing.T, makeDB makeMigrationTestDB) { + t.Parallel() + ctxb := context.Background() + + // Create a new database that already has the first version of the + // native invoice schema. + db, migrate := makeDB(t, 3) + + // Add a few invoices. For simplicity we reuse the payment hash as the + // payment address and payment request hash instead of setting them to + // NULL (to not run into uniqueness constraints). Note that SQLC + // currently doesn't support nullable blob fields porperly. A workaround + // is in progress: https://github.com/sqlc-dev/sqlc/issues/3149 + + // Add an invoice where is_amp will be set to false. + hash1 := []byte{1, 2, 3} + _, err := db.InsertInvoice(ctxb, sqlc.InsertInvoiceParams{ + Hash: hash1, + PaymentAddr: hash1, + PaymentRequestHash: hash1, + Expiry: -123, + IsAmp: false, + }) + require.NoError(t, err) + + // Add an invoice where is_amp will be set to false. + hash2 := []byte{4, 5, 6} + _, err = db.InsertInvoice(ctxb, sqlc.InsertInvoiceParams{ + Hash: hash2, + PaymentAddr: hash2, + PaymentRequestHash: hash2, + Expiry: -456, + IsAmp: true, + }) + require.NoError(t, err) + + // Now, we'll attempt to execute the migration that will fix the expiry + // values by inserting 86400 seconds for non AMP and 2592000 seconds for + // AMP invoices. + err = migrate(TargetVersion(4)) + + invoices, err := db.FilterInvoices(ctxb, sqlc.FilterInvoicesParams{ + AddIndexGet: SQLInt64(1), + NumLimit: 100, + }) + + const ( + // 1 day in seconds. + expiry = int32(86400) + // 30 days in seconds. + expiryAMP = int32(2592000) + ) + + expected := []sqlc.Invoice{ + { + ID: 1, + Hash: hash1, + PaymentAddr: hash1, + PaymentRequestHash: hash1, + Expiry: expiry, + }, + { + ID: 2, + Hash: hash2, + PaymentAddr: hash2, + PaymentRequestHash: hash2, + Expiry: expiryAMP, + IsAmp: true, + }, + } + + for i := range invoices { + // Override the timestamp location as the sql driver will scan + // the timestamp with no location and we can't create such + // timestamps in Golang using the standard time package. + invoices[i].CreatedAt = invoices[i].CreatedAt.UTC() + + // Override the preimage as depending on the driver it is either + // scanned as nil or an empty byte slice. + require.Len(t, invoices[i].Preimage, 0) + invoices[i].Preimage = nil + } + + require.NoError(t, err) + require.Equal(t, expected, invoices) +}