Skip to content

Commit 94da23c

Browse files
Accelerate tests (#219)
1 parent 988bdb9 commit 94da23c

27 files changed

+233
-135
lines changed

build/Dockerfile.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,5 @@ RUN adduser --disabled-password --gecos '' testrunner
2424
USER testrunner
2525

2626
# Run tests serially so logs can be streamed. Set overall timeout to 30m (the default is 10m, which is not enough)
27-
CMD ["-v", "-race", "-p", "1", "./...", "-timeout", "30m"]
27+
CMD ["-v", "-race", "./...", "-timeout", "30m"]
2828
ENTRYPOINT ["go", "test"]

internal/migration_acceptance_tests/acceptance_test.go

Lines changed: 76 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@ import (
44
"context"
55
"database/sql"
66
"fmt"
7+
stdlog "log"
8+
"os"
79
"testing"
810

911
"github.com/google/uuid"
1012
_ "github.com/jackc/pgx/v4/stdlib"
1113
"github.com/kr/pretty"
12-
"github.com/stretchr/testify/suite"
14+
"github.com/stretchr/testify/assert"
15+
"github.com/stretchr/testify/require"
1316
"github.com/stripe/pg-schema-diff/internal/pgdump"
1417
"github.com/stripe/pg-schema-diff/internal/pgengine"
1518
"github.com/stripe/pg-schema-diff/pkg/diff"
@@ -60,37 +63,45 @@ type (
6063
// If no expectedDBSchemaDDL is specified, the newSchemaDDL will be used
6164
expectedDBSchemaDDL []string
6265
}
63-
64-
acceptanceTestSuite struct {
65-
suite.Suite
66-
pgEngine *pgengine.Engine
67-
}
6866
)
6967

70-
func (suite *acceptanceTestSuite) SetupSuite() {
71-
engine, err := pgengine.StartEngine()
72-
suite.Require().NoError(err)
73-
suite.pgEngine = engine
74-
}
68+
var pgEngine *pgengine.Engine
7569

76-
func (suite *acceptanceTestSuite) TearDownSuite() {
77-
suite.pgEngine.Close()
70+
func TestMain(m *testing.M) {
71+
engine, err := pgengine.StartEngine()
72+
if err != nil {
73+
stdlog.Fatalf("Failed to start engine: %v", err)
74+
}
75+
pgEngine = engine
76+
exitCode := m.Run()
77+
if err := pgEngine.Close(); err != nil {
78+
stdlog.Fatalf("Failed to close engine: %v", err)
79+
}
80+
os.Exit(exitCode)
7881
}
7982

8083
// Simulates migrating a database and uses pgdump to compare the actual state to the expected state
81-
func (suite *acceptanceTestSuite) runTestCases(acceptanceTestCases []acceptanceTestCase) {
82-
for _, tc := range acceptanceTestCases {
83-
suite.Run(tc.name, func() {
84-
suite.runTest(tc)
84+
func runTestCases(t *testing.T, acceptanceTestCases []acceptanceTestCase) {
85+
t.Parallel()
86+
for _, _tc := range acceptanceTestCases {
87+
// Copy the test case since we are using t.Parallel (effectively spinning out a go routine).
88+
tc := _tc
89+
t.Run(tc.name, func(t *testing.T) {
90+
t.Parallel()
91+
runTest(t, tc)
8592
})
8693
}
8794
}
8895

89-
func (suite *acceptanceTestSuite) runTest(tc acceptanceTestCase) {
90-
uuid.SetRand(&deterministicRandReader{})
91-
92-
// Normalize the subtest
93-
tc.planOpts = append(tc.planOpts, diff.WithLogger(log.SimpleLogger()))
96+
func runTest(t *testing.T, tc acceptanceTestCase) {
97+
deterministicRandReader := &deterministicRandReader{}
98+
// We moved a call to the random when we made tests run in parallel. This caused assertions on exact statements to fail.
99+
// To keep the assertions passing, we will generate a UUID and throw it out. In the future, we should just create
100+
// a more advanced system for asserting random statements that captures variables and allows them to be referenced
101+
// in future assertions.
102+
_, err := uuid.NewRandomFromReader(deterministicRandReader)
103+
require.NoError(t, err)
104+
tc.planOpts = append([]diff.PlanOpt{diff.WithLogger(log.SimpleLogger()), diff.WithRandReader(deterministicRandReader)}, tc.planOpts...)
94105
if tc.expectedDBSchemaDDL == nil {
95106
tc.expectedDBSchemaDDL = tc.newSchemaDDL
96107
}
@@ -106,70 +117,77 @@ func (suite *acceptanceTestSuite) runTest(tc acceptanceTestCase) {
106117
}
107118
}
108119

120+
engine := pgEngine
121+
if len(tc.roles) > 0 {
122+
// If the test needs roles (server-wide), provide isolation by spinning out a dedicated pgengine.
123+
dedicatedEngine, err := pgengine.StartEngine()
124+
require.NoError(t, err)
125+
defer dedicatedEngine.Close()
126+
engine = dedicatedEngine
127+
}
128+
109129
// Create roles since they are global
110-
rootDb, err := sql.Open("pgx", suite.pgEngine.GetPostgresDatabaseDSN())
111-
suite.Require().NoError(err)
130+
rootDb, err := sql.Open("pgx", engine.GetPostgresDatabaseDSN())
131+
require.NoError(t, err)
112132
defer rootDb.Close()
113133
for _, r := range tc.roles {
114134
_, err := rootDb.Exec(fmt.Sprintf("CREATE ROLE %s", r))
115-
suite.Require().NoError(err)
135+
require.NoError(t, err)
116136
}
117-
defer func() {
118-
// This will drop the roles (and attempt to reset other cluster-level state)
119-
suite.Require().NoError(pgengine.ResetInstance(context.Background(), rootDb))
120-
}()
121137

122138
// Apply old schema DDL to old DB
123-
oldDb, err := suite.pgEngine.CreateDatabase()
124-
suite.Require().NoError(err)
139+
require.NoError(t, err)
140+
oldDb, err := engine.CreateDatabaseWithName(fmt.Sprintf("pgtemp_%s", uuid.NewString()))
141+
require.NoError(t, err)
125142
defer oldDb.DropDB()
126143
// Apply the old schema
127-
suite.Require().NoError(applyDDL(oldDb, tc.oldSchemaDDL))
144+
require.NoError(t, applyDDL(oldDb, tc.oldSchemaDDL))
128145

129146
// Migrate the old DB
130147
oldDBConnPool, err := sql.Open("pgx", oldDb.GetDSN())
131-
suite.Require().NoError(err)
148+
require.NoError(t, err)
132149
defer oldDBConnPool.Close()
150+
oldDBConnPool.SetMaxOpenConns(1)
133151

134152
tempDbFactory, err := tempdb.NewOnInstanceFactory(context.Background(), func(ctx context.Context, dbName string) (*sql.DB, error) {
135-
return sql.Open("pgx", suite.pgEngine.GetPostgresDatabaseConnOpts().With("dbname", dbName).ToDSN())
136-
})
137-
suite.Require().NoError(err)
153+
return sql.Open("pgx", engine.GetPostgresDatabaseConnOpts().With("dbname", dbName).ToDSN())
154+
}, tempdb.WithRandReader(deterministicRandReader))
155+
require.NoError(t, err)
138156
defer func(tempDbFactory tempdb.Factory) {
139157
// It's important that this closes properly (the temp database is dropped),
140158
// so assert it has no error for acceptance tests
141-
suite.Require().NoError(tempDbFactory.Close())
159+
require.NoError(t, tempDbFactory.Close())
142160
}(tempDbFactory)
143161

144162
plan, err := tc.planFactory(context.Background(), oldDBConnPool, tempDbFactory, tc.newSchemaDDL, tc.planOpts...)
145163
if tc.expectedPlanErrorIs != nil || len(tc.expectedPlanErrorContains) > 0 {
146164
if tc.expectedPlanErrorIs != nil {
147-
suite.ErrorIs(err, tc.expectedPlanErrorIs)
165+
assert.ErrorIs(t, err, tc.expectedPlanErrorIs)
148166
}
149167
if len(tc.expectedPlanErrorContains) > 0 {
150-
suite.ErrorContains(err, tc.expectedPlanErrorContains)
168+
assert.ErrorContains(t, err, tc.expectedPlanErrorContains)
151169
}
152170
return
153171
}
154-
suite.Require().NoError(err)
172+
require.NoError(t, err)
155173

156-
suite.assertValidPlan(plan)
174+
assertValidPlan(t, plan)
157175
if tc.expectEmptyPlan {
158176
// It shouldn't be necessary, but we'll run all checks below this point just in case rather than exiting early
159-
suite.Empty(plan.Statements)
177+
assert.Empty(t, plan.Statements)
160178
}
161-
suite.ElementsMatch(tc.expectedHazardTypes, getUniqueHazardTypesFromStatements(plan.Statements), prettySprintPlan(plan))
179+
assert.ElementsMatch(t, tc.expectedHazardTypes, getUniqueHazardTypesFromStatements(plan.Statements), prettySprintPlan(plan))
162180

163181
// Apply the plan
164-
suite.Require().NoError(applyPlan(oldDb, plan), prettySprintPlan(plan))
182+
require.NoError(t, applyPlan(oldDb, plan), prettySprintPlan(plan))
165183

166184
// Make sure the pgdump after running the migration is the same as the
167185
// pgdump from a database where we directly run the newSchemaDDL
168186
oldDbDump, err := pgdump.GetDump(oldDb, pgdump.WithSchemaOnly())
169-
suite.Require().NoError(err)
187+
require.NoError(t, err)
170188

171-
newDbDump := suite.directlyRunDDLAndGetDump(tc.expectedDBSchemaDDL)
172-
suite.Equal(newDbDump, oldDbDump, prettySprintPlan(plan))
189+
newDbDump := directlyRunDDLAndGetDump(t, engine, tc.expectedDBSchemaDDL)
190+
assert.Equal(t, newDbDump, oldDbDump, prettySprintPlan(plan))
173191

174192
if tc.expectedPlanDDL != nil {
175193
var generatedDDL []string
@@ -181,30 +199,30 @@ func (suite *acceptanceTestSuite) runTest(tc acceptanceTestCase) {
181199
// We can also make the system more advanced by using tokens in place of the "randomly" generated UUIDs, such
182200
// the test case doesn't need to be updated if the UUID generation changes. If we built this functionality, we
183201
// should also integrate it with the schema_migration_plan_test.go tests.
184-
suite.Equal(tc.expectedPlanDDL, generatedDDL, "data packing can change the the generated UUID and DDL")
202+
assert.Equal(t, tc.expectedPlanDDL, generatedDDL, "data packing can change the the generated UUID and DDL")
185203
}
186204

187205
// Make sure no diff is found if we try to regenerate a plan
188206
plan, err = tc.planFactory(context.Background(), oldDBConnPool, tempDbFactory, tc.newSchemaDDL, tc.planOpts...)
189-
suite.Require().NoError(err)
190-
suite.Empty(plan.Statements, prettySprintPlan(plan))
207+
require.NoError(t, err)
208+
assert.Empty(t, plan.Statements, prettySprintPlan(plan))
191209
}
192210

193-
func (suite *acceptanceTestSuite) assertValidPlan(plan diff.Plan) {
211+
func assertValidPlan(t *testing.T, plan diff.Plan) {
194212
for _, stmt := range plan.Statements {
195-
suite.Greater(stmt.Timeout.Nanoseconds(), int64(0), "timeout should be greater than 0. stmt=%+v", stmt)
196-
suite.Greater(stmt.LockTimeout.Nanoseconds(), int64(0), "lock timeout should be greater than 0. stmt=%+v", stmt)
213+
assert.Greater(t, stmt.Timeout.Nanoseconds(), int64(0), "timeout should be greater than 0. stmt=%+v", stmt)
214+
assert.Greater(t, stmt.LockTimeout.Nanoseconds(), int64(0), "lock timeout should be greater than 0. stmt=%+v", stmt)
197215
}
198216
}
199217

200-
func (suite *acceptanceTestSuite) directlyRunDDLAndGetDump(ddl []string) string {
201-
newDb, err := suite.pgEngine.CreateDatabase()
202-
suite.Require().NoError(err)
218+
func directlyRunDDLAndGetDump(t *testing.T, engine *pgengine.Engine, ddl []string) string {
219+
newDb, err := engine.CreateDatabase()
220+
require.NoError(t, err)
203221
defer newDb.DropDB()
204-
suite.Require().NoError(applyDDL(newDb, ddl))
222+
require.NoError(t, applyDDL(newDb, ddl))
205223

206224
newDbDump, err := pgdump.GetDump(newDb, pgdump.WithSchemaOnly())
207-
suite.Require().NoError(err)
225+
require.NoError(t, err)
208226
return newDbDump
209227
}
210228

@@ -261,7 +279,3 @@ func (r *deterministicRandReader) Read(p []byte) (int, error) {
261279
}
262280
return len(p), nil
263281
}
264-
265-
func TestAcceptanceSuite(t *testing.T) {
266-
suite.Run(t, new(acceptanceTestSuite))
267-
}

internal/migration_acceptance_tests/backwards_compat_cases_test.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package migration_acceptance_tests
22

3-
import "github.com/stripe/pg-schema-diff/pkg/diff"
3+
import (
4+
"testing"
5+
6+
"github.com/stripe/pg-schema-diff/pkg/diff"
7+
)
48

59
var backCompatAcceptanceTestCases = []acceptanceTestCase{
610
{
@@ -132,6 +136,6 @@ var backCompatAcceptanceTestCases = []acceptanceTestCase{
132136
},
133137
}
134138

135-
func (suite *acceptanceTestSuite) TestBackCompatTestCases() {
136-
suite.runTestCases(backCompatAcceptanceTestCases)
139+
func TestBackCompatTestCases(t *testing.T) {
140+
runTestCases(t, backCompatAcceptanceTestCases)
137141
}

internal/migration_acceptance_tests/check_constraint_cases_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package migration_acceptance_tests
22

33
import (
4+
"testing"
5+
46
"github.com/stripe/pg-schema-diff/pkg/diff"
57
)
68

@@ -551,6 +553,6 @@ var checkConstraintCases = []acceptanceTestCase{
551553
},
552554
}
553555

554-
func (suite *acceptanceTestSuite) TestCheckConstraintTestCases() {
555-
suite.runTestCases(checkConstraintCases)
556+
func TestCheckConstraintTestCases(t *testing.T) {
557+
runTestCases(t, checkConstraintCases)
556558
}

internal/migration_acceptance_tests/column_cases_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package migration_acceptance_tests
22

33
import (
4+
"testing"
5+
46
"github.com/stripe/pg-schema-diff/pkg/diff"
57
)
68

@@ -1184,6 +1186,6 @@ var columnAcceptanceTestCases = []acceptanceTestCase{
11841186
},
11851187
}
11861188

1187-
func (suite *acceptanceTestSuite) TestColumnTestCases() {
1188-
suite.runTestCases(columnAcceptanceTestCases)
1189+
func TestColumnTestCases(t *testing.T) {
1190+
runTestCases(t, columnAcceptanceTestCases)
11891191
}

internal/migration_acceptance_tests/data_packing_cases_test.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package migration_acceptance_tests
22

3-
import "github.com/stripe/pg-schema-diff/pkg/diff"
3+
import (
4+
"testing"
5+
6+
"github.com/stripe/pg-schema-diff/pkg/diff"
7+
)
48

59
var dataPackingCases = []acceptanceTestCase{
610
{
@@ -133,11 +137,11 @@ var dataPackingCases = []acceptanceTestCase{
133137
},
134138
}
135139

136-
func (suite *acceptanceTestSuite) TestDataPackingTestCases() {
140+
func TestDataPackingTestCases(t *testing.T) {
137141
var tcs []acceptanceTestCase
138142
for _, tc := range dataPackingCases {
139143
tc.planOpts = append(tc.planOpts, diff.WithDataPackNewTables())
140144
tcs = append(tcs, tc)
141145
}
142-
suite.runTestCases(tcs)
146+
runTestCases(t, tcs)
143147
}

internal/migration_acceptance_tests/database_schema_source_cases_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package migration_acceptance_tests
33
import (
44
"context"
55
"fmt"
6+
"testing"
67

78
"github.com/stripe/pg-schema-diff/pkg/diff"
89
"github.com/stripe/pg-schema-diff/pkg/sqldb"
@@ -187,6 +188,6 @@ var databaseSchemaSourceTestCases = []acceptanceTestCase{
187188
},
188189
}
189190

190-
func (suite *acceptanceTestSuite) TestDatabaseSchemaSourceTestCases() {
191-
suite.runTestCases(databaseSchemaSourceTestCases)
191+
func TestDatabaseSchemaSourceTestCases(t *testing.T) {
192+
runTestCases(t, databaseSchemaSourceTestCases)
192193
}

internal/migration_acceptance_tests/enum_cases_test.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package migration_acceptance_tests
22

3-
import "github.com/stripe/pg-schema-diff/pkg/diff"
3+
import (
4+
"testing"
5+
6+
"github.com/stripe/pg-schema-diff/pkg/diff"
7+
)
48

59
var enumAcceptanceTestCases = []acceptanceTestCase{
610
{
@@ -116,6 +120,6 @@ var enumAcceptanceTestCases = []acceptanceTestCase{
116120
},
117121
}
118122

119-
func (suite *acceptanceTestSuite) TestEnumTestCases() {
120-
suite.runTestCases(enumAcceptanceTestCases)
123+
func TestEnumTestCases(t *testing.T) {
124+
runTestCases(t, enumAcceptanceTestCases)
121125
}

internal/migration_acceptance_tests/extensions_cases_test.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package migration_acceptance_tests
22

3-
import "github.com/stripe/pg-schema-diff/pkg/diff"
3+
import (
4+
"testing"
5+
6+
"github.com/stripe/pg-schema-diff/pkg/diff"
7+
)
48

59
var extensionAcceptanceTestCases = []acceptanceTestCase{
610
{
@@ -67,6 +71,6 @@ var extensionAcceptanceTestCases = []acceptanceTestCase{
6771
},
6872
}
6973

70-
func (suite *acceptanceTestSuite) TestExtensionTestCases() {
71-
suite.runTestCases(extensionAcceptanceTestCases)
74+
func TestExtensionTestCases(t *testing.T) {
75+
runTestCases(t, extensionAcceptanceTestCases)
7276
}

0 commit comments

Comments
 (0)