-
Notifications
You must be signed in to change notification settings - Fork 273
Expand file tree
/
Copy pathdb.go
More file actions
144 lines (123 loc) · 3.76 KB
/
db.go
File metadata and controls
144 lines (123 loc) · 3.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package testutils
import (
"context"
"os/exec"
"path/filepath"
"strings"
"sync"
"testing"
"time"
_ "github.com/jackc/pgx/v5/stdlib" // this allows goose to function
"github.com/pressly/goose/v3"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/modules/postgres"
"github.com/testcontainers/testcontainers-go/wait"
db "github.com/e2b-dev/infra/packages/db/client"
authdb "github.com/e2b-dev/infra/packages/db/pkg/auth"
"github.com/e2b-dev/infra/packages/db/pkg/pool"
"github.com/e2b-dev/infra/packages/db/pkg/testutils/queries"
)
const (
testPostgresImage = "postgres:16-alpine"
testDatabaseName = "test_db"
testUsername = "postgres"
testPassword = "test_password"
)
func init() {
goose.SetTableName("_migrations")
}
// Database encapsulates the test database container and clients
type Database struct {
SqlcClient *db.Client
AuthDb *authdb.Client
TestQueries *queries.Queries
}
// SetupDatabase creates a fresh PostgreSQL container with migrations applied
func SetupDatabase(t *testing.T) *Database {
t.Helper()
if testing.Short() {
t.Skip("Skipping integration test in short mode")
}
// Start PostgreSQL container
container, err := postgres.Run(
t.Context(),
testPostgresImage,
postgres.WithDatabase(testDatabaseName),
postgres.WithUsername(testUsername),
postgres.WithPassword(testPassword),
testcontainers.WithWaitStrategy(
wait.ForLog("database system is ready to accept connections").
WithOccurrence(2).
WithStartupTimeout(60*time.Second),
),
)
require.NoError(t, err, "Failed to start postgres container")
t.Cleanup(func() {
ctx := t.Context()
ctx = context.WithoutCancel(ctx)
err := container.Terminate(ctx)
assert.NoError(t, err)
})
connStr, err := container.ConnectionString(t.Context(), "sslmode=disable")
require.NoError(t, err, "Failed to get connection string")
// Setup environment and run migrations
runDatabaseMigrations(t, connStr)
// create test queries client
dbClient, connPool, err := pool.New(t.Context(), connStr, "tests")
require.NoError(t, err)
t.Cleanup(func() {
connPool.Close()
})
testQueries := queries.New(dbClient)
// Create app db client
sqlcClient, err := db.NewClient(t.Context(), connStr)
require.NoError(t, err, "Failed to create sqlc client")
t.Cleanup(func() {
err := sqlcClient.Close()
assert.NoError(t, err)
})
// Create the auth db client
authDb, err := authdb.NewClient(t.Context(), connStr, connStr)
require.NoError(t, err, "Failed to create auth db client")
t.Cleanup(func() {
err := authDb.Close()
assert.NoError(t, err)
})
return &Database{
SqlcClient: sqlcClient,
AuthDb: authDb,
TestQueries: testQueries,
}
}
// gooseMu serializes goose operations across parallel tests.
// goose.OpenDBWithDriver calls goose.SetDialect which writes to package-level
// globals (dialect, store) without synchronization. Concurrent test goroutines
// race on these globals, triggering the race detector on ARM64.
var gooseMu sync.Mutex
// runDatabaseMigrations executes all required database migrations
func runDatabaseMigrations(t *testing.T, connStr string) {
t.Helper()
cmd := exec.CommandContext(t.Context(), "git", "rev-parse", "--show-toplevel")
output, err := cmd.Output()
require.NoError(t, err, "Failed to find git root")
repoRoot := strings.TrimSpace(string(output))
gooseMu.Lock()
defer gooseMu.Unlock()
db, err := goose.OpenDBWithDriver("pgx", connStr)
require.NoError(t, err)
t.Cleanup(func() {
err := db.Close()
assert.NoError(t, err)
})
// run the db migration
err = goose.RunWithOptionsContext(
t.Context(),
"up",
db,
filepath.Join(repoRoot, "packages", "db", "migrations"),
nil,
)
require.NoError(t, err)
}