Skip to content

Commit b7fe8fa

Browse files
committed
test: add db migration tests for postgres and sqlite
1 parent 3822811 commit b7fe8fa

File tree

11 files changed

+275
-1
lines changed

11 files changed

+275
-1
lines changed

cmd_migrate_db_postgres_test.go

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
//go:build kvdb_postgres
2+
3+
package main
4+
5+
import (
6+
"context"
7+
"crypto/rand"
8+
"database/sql"
9+
"encoding/hex"
10+
"fmt"
11+
"testing"
12+
13+
embeddedpostgres "github.com/fergusstrange/embedded-postgres"
14+
"github.com/lightningnetwork/lnd/kvdb"
15+
"github.com/lightningnetwork/lnd/kvdb/postgres"
16+
"github.com/lightningnetwork/lnd/kvdb/sqlbase"
17+
"github.com/lightningnetwork/lnd/lncfg"
18+
"github.com/stretchr/testify/require"
19+
)
20+
21+
const (
22+
testMaxConnections = 100
23+
testDsnTemplate = "postgres://postgres:[email protected]:9877/%s?sslmode=disable"
24+
)
25+
26+
// PostgresTestSetup holds the test configuration for Postgres.
27+
type PostgresTestSetup struct {
28+
tempDir string
29+
dbName string
30+
postgres *embeddedpostgres.EmbeddedPostgres
31+
stopFunc func() error
32+
}
33+
34+
// setupEmbeddedPostgres initializes and starts the embedded postgres instance.
35+
func setupEmbeddedPostgres(t *testing.T) *PostgresTestSetup {
36+
sqlbase.Init(testMaxConnections)
37+
38+
setup := &PostgresTestSetup{}
39+
40+
// Initialize embedded postgres
41+
setup.postgres = embeddedpostgres.NewDatabase(
42+
embeddedpostgres.DefaultConfig().
43+
Port(9877).
44+
StartParameters(map[string]string{
45+
"max_connections": fmt.Sprintf("%d", testMaxConnections),
46+
}),
47+
)
48+
49+
// Start postgres
50+
err := setup.postgres.Start()
51+
require.NoError(t, err, "failed to start postgres")
52+
53+
setup.stopFunc = setup.postgres.Stop
54+
55+
return setup
56+
}
57+
58+
// createTestDatabase creates a new random test database.
59+
func (p *PostgresTestSetup) createTestDatabase(t *testing.T) {
60+
// Generate random database name
61+
randBytes := make([]byte, 8)
62+
_, err := rand.Read(randBytes)
63+
require.NoError(t, err)
64+
p.dbName = "test_" + hex.EncodeToString(randBytes)
65+
66+
// Create the database
67+
dbConn, err := sql.Open("pgx", p.getDsn("postgres"))
68+
require.NoError(t, err)
69+
defer dbConn.Close()
70+
71+
_, err = dbConn.ExecContext(
72+
context.Background(),
73+
"CREATE DATABASE "+p.dbName,
74+
)
75+
require.NoError(t, err)
76+
}
77+
78+
// setupTestDir creates and sets up the temporary test directory.
79+
func (p *PostgresTestSetup) setupTestDir(t *testing.T) {
80+
p.tempDir = setupTestData(t)
81+
}
82+
83+
// getDsn returns the DSN for the specified database.
84+
func (p *PostgresTestSetup) getDsn(dbName string) string {
85+
return fmt.Sprintf(testDsnTemplate, dbName)
86+
}
87+
88+
// cleanup performs necessary cleanup.
89+
func (p *PostgresTestSetup) cleanup() error {
90+
if p.stopFunc != nil {
91+
return p.stopFunc()
92+
}
93+
return nil
94+
}
95+
96+
// getDBConfigs returns the source and destination DB configs.
97+
func (p *PostgresTestSetup) getDBConfigs() (*SourceDB, *DestDB) {
98+
sourceDB := &SourceDB{
99+
Backend: lncfg.BoltBackend,
100+
Bolt: &Bolt{
101+
DBTimeout: kvdb.DefaultDBTimeout,
102+
DataDir: p.tempDir,
103+
TowerDir: p.tempDir,
104+
},
105+
}
106+
107+
destDB := &DestDB{
108+
Backend: lncfg.PostgresBackend,
109+
Postgres: &postgres.Config{
110+
Dsn: p.getDsn(p.dbName),
111+
},
112+
}
113+
114+
return sourceDB, destDB
115+
}
116+
117+
// TestMigrateDBPostgres tests the migration of a database from Bolt to
118+
// Postgres.
119+
func TestMigrateDBPostgres(t *testing.T) {
120+
t.Parallel()
121+
122+
// Setup postgres.
123+
setup := setupEmbeddedPostgres(t)
124+
defer func() {
125+
require.NoError(t, setup.cleanup())
126+
}()
127+
128+
// Setup test environment.
129+
setup.setupTestDir(t)
130+
setup.createTestDatabase(t)
131+
132+
sourceDB, destDB := setup.getDBConfigs()
133+
134+
// Create and run migration command.
135+
cmd := &migrateDBCommand{
136+
Source: sourceDB,
137+
Dest: destDB,
138+
Network: "regtest",
139+
ChunkSize: 1024,
140+
}
141+
142+
err := cmd.Execute(nil)
143+
require.NoError(t, err, "failed to execute migration")
144+
}

cmd_migrate_db_sqlite_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//go:build kvdb_sqlite
2+
3+
package main
4+
5+
import (
6+
"fmt"
7+
"testing"
8+
9+
"github.com/lightningnetwork/lnd/kvdb"
10+
"github.com/lightningnetwork/lnd/kvdb/sqlite"
11+
"github.com/lightningnetwork/lnd/lncfg"
12+
"github.com/stretchr/testify/require"
13+
)
14+
15+
// TestMigrateDBSqlite tests the migration of a database from Bolt to SQLite.
16+
func TestMigrateDBSqlite(t *testing.T) {
17+
t.Parallel()
18+
19+
// Create temp dir for test databases.
20+
tempDir := setupTestData(t)
21+
22+
fmt.Println("tempDir", tempDir)
23+
24+
// Copy entire test directory structure.
25+
err := copyTestDataDir("testdata/data", tempDir)
26+
require.NoError(t, err, "failed to copy test data")
27+
28+
// Set up source DB config (bolt).
29+
sourceDB := &SourceDB{
30+
Backend: lncfg.BoltBackend,
31+
Bolt: &Bolt{
32+
DBTimeout: kvdb.DefaultDBTimeout,
33+
DataDir: tempDir,
34+
TowerDir: tempDir,
35+
},
36+
}
37+
38+
// Set up destination DB config (sqlite).
39+
destDB := &DestDB{
40+
Backend: lncfg.SqliteBackend,
41+
Sqlite: &Sqlite{
42+
DataDir: tempDir,
43+
TowerDir: tempDir,
44+
Config: &sqlite.Config{},
45+
},
46+
}
47+
48+
// Create and run migration command.
49+
cmd := &migrateDBCommand{
50+
Source: sourceDB,
51+
Dest: destDB,
52+
Network: "regtest",
53+
// Select a small chunk size to test the chunking.
54+
ChunkSize: 1024,
55+
}
56+
57+
err = cmd.Execute(nil)
58+
59+
require.NoError(t, err, "migration failed")
60+
}

cmd_migrate_db_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package main
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
)
8+
9+
// testDataPath is the source directory containing test data.
10+
const testDataPath = "testdata/data"
11+
12+
// setupTestData creates a new temp directory and copies test data into it.
13+
// It returns the path to the new temp directory.
14+
func setupTestData(t *testing.T) string {
15+
// Create unique temp dir for this test.
16+
tempDir := t.TempDir()
17+
err := copyTestDataDir(testDataPath, tempDir)
18+
19+
require.NoError(t, err, "failed to copy test data")
20+
21+
return tempDir
22+
}

migratekvdb/migration_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ func createTestDatabase(dbPath string) (kvdb.Backend, error) {
105105
// Create test data structure.
106106
err = db.Update(func(tx kvdb.RwTx) error {
107107
fmt.Println("Creating test data structure...")
108-
// Create root bucket "accounts"
108+
// Create root bucket "accounts".
109109
accounts, err := tx.CreateTopLevelBucket([]byte("accounts"))
110110
if err != nil {
111111
fmt.Print("bucket creation failed.")
Binary file not shown.
Binary file not shown.
1 MB
Binary file not shown.
128 KB
Binary file not shown.
128 KB
Binary file not shown.
Binary file not shown.

utils.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package main
2+
3+
import (
4+
"io"
5+
"os"
6+
"path/filepath"
7+
)
8+
9+
// copyTestDataDir copies the entire test directory structure so that we do not
10+
// alter any original files.
11+
func copyTestDataDir(src, dst string) error {
12+
return filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
13+
if err != nil {
14+
return err
15+
}
16+
17+
relPath, err := filepath.Rel(src, path)
18+
if err != nil {
19+
return err
20+
}
21+
22+
dstPath := filepath.Join(dst, relPath)
23+
24+
if info.IsDir() {
25+
return os.MkdirAll(dstPath, info.Mode())
26+
}
27+
28+
return copyFile(path, dstPath)
29+
})
30+
}
31+
32+
// copyFile copies a file from src to dst.
33+
func copyFile(src, dst string) error {
34+
srcFile, err := os.Open(src)
35+
if err != nil {
36+
return err
37+
}
38+
defer srcFile.Close()
39+
40+
dstFile, err := os.Create(dst)
41+
if err != nil {
42+
return err
43+
}
44+
defer dstFile.Close()
45+
46+
_, err = io.Copy(dstFile, srcFile)
47+
return err
48+
}

0 commit comments

Comments
 (0)