Skip to content

Commit 365c1f3

Browse files
Add tests for Latest/Previous State methods
Ensure that the: * `LatestMigration` and `PreviousMigration` methods * `LatestVersion` and `PreviousVersion` methods work correctly in various scenarios.
1 parent ad1c223 commit 365c1f3

File tree

1 file changed

+366
-0
lines changed

1 file changed

+366
-0
lines changed

pkg/state/latest_test.go

Lines changed: 366 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,366 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package state_test
4+
5+
import (
6+
"context"
7+
"database/sql"
8+
"testing"
9+
10+
"github.com/stretchr/testify/require"
11+
"github.com/xataio/pgroll/internal/testutils"
12+
"github.com/xataio/pgroll/pkg/backfill"
13+
"github.com/xataio/pgroll/pkg/migrations"
14+
"github.com/xataio/pgroll/pkg/roll"
15+
)
16+
17+
func TestLatestAndPreviousMigrationMethods(t *testing.T) {
18+
t.Parallel()
19+
20+
t.Run("no migrations applied", func(t *testing.T) {
21+
testutils.WithMigratorAndConnectionToContainer(t, func(m *roll.Roll, db *sql.DB) {
22+
ctx := context.Background()
23+
24+
// Get the latest migration name
25+
latest, err := m.State().LatestMigration(ctx, "public")
26+
require.NoError(t, err)
27+
28+
// Get the previous migration name
29+
previous, err := m.State().PreviousMigration(ctx, "public")
30+
require.NoError(t, err)
31+
32+
// Assert that both latest and previous are nil as no migrations have
33+
// been applied
34+
require.Nil(t, latest)
35+
require.Nil(t, previous)
36+
})
37+
})
38+
39+
t.Run("one pgroll migration applied", func(t *testing.T) {
40+
testutils.WithMigratorAndConnectionToContainer(t, func(m *roll.Roll, db *sql.DB) {
41+
ctx := context.Background()
42+
43+
// Apply a pgroll migration
44+
err := m.Start(ctx, &migrations.Migration{
45+
Name: "01_initial_migration",
46+
Operations: migrations.Operations{&migrations.OpRawSQL{Up: "SELECT 1"}},
47+
}, backfill.NewConfig())
48+
require.NoError(t, err)
49+
err = m.Complete(ctx)
50+
require.NoError(t, err)
51+
52+
// Get the latest migration name
53+
latest, err := m.State().LatestMigration(ctx, "public")
54+
require.NoError(t, err)
55+
56+
// Get the previous migration name
57+
previous, err := m.State().PreviousMigration(ctx, "public")
58+
require.NoError(t, err)
59+
60+
// We have a latest migration name but no previous migration name
61+
require.NotNil(t, latest)
62+
require.Equal(t, "01_initial_migration", *latest)
63+
require.Nil(t, previous)
64+
})
65+
})
66+
67+
t.Run("two pgroll migrations applied", func(t *testing.T) {
68+
testutils.WithMigratorAndConnectionToContainer(t, func(m *roll.Roll, db *sql.DB) {
69+
ctx := context.Background()
70+
71+
// Apply a pgroll migration
72+
err := m.Start(ctx, &migrations.Migration{
73+
Name: "01_initial_migration",
74+
Operations: migrations.Operations{&migrations.OpRawSQL{Up: "SELECT 1"}},
75+
}, backfill.NewConfig())
76+
require.NoError(t, err)
77+
err = m.Complete(ctx)
78+
require.NoError(t, err)
79+
80+
// Apply another pgroll migration
81+
err = m.Start(ctx, &migrations.Migration{
82+
Name: "02_another_migration",
83+
Operations: migrations.Operations{&migrations.OpRawSQL{Up: "SELECT 1"}},
84+
}, backfill.NewConfig())
85+
require.NoError(t, err)
86+
err = m.Complete(ctx)
87+
require.NoError(t, err)
88+
89+
// Get the latest migration name
90+
latest, err := m.State().LatestMigration(ctx, "public")
91+
require.NoError(t, err)
92+
93+
// Get the previous migration name
94+
previous, err := m.State().PreviousMigration(ctx, "public")
95+
require.NoError(t, err)
96+
97+
// We have latest and previous migration names
98+
require.NotNil(t, latest)
99+
require.Equal(t, "02_another_migration", *latest)
100+
require.NotNil(t, previous)
101+
require.Equal(t, "01_initial_migration", *previous)
102+
})
103+
})
104+
105+
t.Run("one pgroll then one inferred migration", func(t *testing.T) {
106+
testutils.WithMigratorAndConnectionToContainer(t, func(m *roll.Roll, db *sql.DB) {
107+
ctx := context.Background()
108+
109+
// Apply a pgroll migration
110+
err := m.Start(ctx, &migrations.Migration{
111+
Name: "01_initial_migration",
112+
Operations: migrations.Operations{&migrations.OpRawSQL{Up: "SELECT 1"}},
113+
}, backfill.NewConfig())
114+
require.NoError(t, err)
115+
err = m.Complete(ctx)
116+
require.NoError(t, err)
117+
118+
// Execute a SQL DDL statement to generate an inferred migration
119+
_, err = db.ExecContext(ctx, "CREATE TABLE table1(id int)")
120+
require.NoError(t, err)
121+
122+
// Get the latest migration name
123+
latest, err := m.State().LatestMigration(ctx, "public")
124+
require.NoError(t, err)
125+
126+
// Get the previous migration name
127+
previous, err := m.State().PreviousMigration(ctx, "public")
128+
require.NoError(t, err)
129+
130+
// We have latest and previous migration names
131+
require.NotNil(t, latest)
132+
require.Regexp(t, `01_initial_migration_\d{20}$`, *latest)
133+
require.NotNil(t, previous)
134+
require.Equal(t, "01_initial_migration", *previous)
135+
})
136+
})
137+
}
138+
139+
func TestLatestAndPreviousVersionMethods(t *testing.T) {
140+
t.Parallel()
141+
142+
t.Run("no migrations applied", func(t *testing.T) {
143+
testutils.WithMigratorAndConnectionToContainer(t, func(m *roll.Roll, db *sql.DB) {
144+
ctx := context.Background()
145+
146+
// Get the latest version schema name
147+
latest, err := m.State().LatestVersion(ctx, "public")
148+
require.NoError(t, err)
149+
150+
// Get the previous version schema name
151+
previous, err := m.State().PreviousVersion(ctx, "public")
152+
require.NoError(t, err)
153+
154+
// Assert that both latest and previous are nil as no migrations have
155+
// been applied
156+
require.Nil(t, latest)
157+
require.Nil(t, previous)
158+
})
159+
})
160+
161+
t.Run("one inferred migration applied", func(t *testing.T) {
162+
testutils.WithMigratorAndConnectionToContainer(t, func(m *roll.Roll, db *sql.DB) {
163+
ctx := context.Background()
164+
165+
// Apply an inferred migration
166+
_, err := db.ExecContext(ctx, "CREATE TABLE apples(id int)")
167+
require.NoError(t, err)
168+
169+
// Get the latest version schema name
170+
latest, err := m.State().LatestVersion(ctx, "public")
171+
require.NoError(t, err)
172+
173+
// Get the previous version schema name
174+
previous, err := m.State().PreviousVersion(ctx, "public")
175+
require.NoError(t, err)
176+
177+
// Assert that both latest and previous are nil as the inferred migration
178+
// did not create a version schema
179+
require.Nil(t, latest)
180+
require.Nil(t, previous)
181+
})
182+
})
183+
184+
t.Run("one pgroll migration applied", func(t *testing.T) {
185+
testutils.WithMigratorAndConnectionToContainer(t, func(m *roll.Roll, db *sql.DB) {
186+
ctx := context.Background()
187+
188+
// Apply a pgroll migration
189+
err := m.Start(ctx, &migrations.Migration{
190+
Name: "01_initial_migration",
191+
VersionSchema: "initial_migration",
192+
Operations: migrations.Operations{&migrations.OpRawSQL{Up: "SELECT 1"}},
193+
}, backfill.NewConfig())
194+
require.NoError(t, err)
195+
err = m.Complete(ctx)
196+
require.NoError(t, err)
197+
198+
// Get the latest version schema name
199+
latest, err := m.State().LatestVersion(ctx, "public")
200+
require.NoError(t, err)
201+
202+
// Get the previous version schema name
203+
previous, err := m.State().PreviousVersion(ctx, "public")
204+
require.NoError(t, err)
205+
206+
// We have a latest version schema name but no previous one
207+
require.NotNil(t, latest)
208+
require.Equal(t, "initial_migration", *latest)
209+
require.Nil(t, previous)
210+
})
211+
})
212+
213+
t.Run("one pgroll migration applied, another active", func(t *testing.T) {
214+
testutils.WithMigratorAndConnectionToContainer(t, func(m *roll.Roll, db *sql.DB) {
215+
ctx := context.Background()
216+
217+
// Apply a pgroll migration
218+
err := m.Start(ctx, &migrations.Migration{
219+
Name: "01_initial_migration",
220+
VersionSchema: "initial_migration",
221+
Operations: migrations.Operations{&migrations.OpRawSQL{Up: "SELECT 1"}},
222+
}, backfill.NewConfig())
223+
require.NoError(t, err)
224+
err = m.Complete(ctx)
225+
require.NoError(t, err)
226+
227+
// Start but don't complete another pgroll migration.
228+
err = m.Start(ctx, &migrations.Migration{
229+
Name: "02_another_migration",
230+
VersionSchema: "another_migration",
231+
Operations: migrations.Operations{&migrations.OpRawSQL{Up: "SELECT 1"}},
232+
}, backfill.NewConfig())
233+
require.NoError(t, err)
234+
235+
// Get the latest version schema name
236+
latest, err := m.State().LatestVersion(ctx, "public")
237+
require.NoError(t, err)
238+
239+
// Get the previous version schema name
240+
previous, err := m.State().PreviousVersion(ctx, "public")
241+
require.NoError(t, err)
242+
243+
// We have latest and previous version schema names
244+
require.NotNil(t, latest)
245+
require.Equal(t, "another_migration", *latest)
246+
require.NotNil(t, previous)
247+
require.Equal(t, "initial_migration", *previous)
248+
})
249+
})
250+
251+
t.Run("two pgroll migrations applied", func(t *testing.T) {
252+
testutils.WithMigratorAndConnectionToContainer(t, func(m *roll.Roll, db *sql.DB) {
253+
ctx := context.Background()
254+
255+
// Apply a pgroll migration
256+
err := m.Start(ctx, &migrations.Migration{
257+
Name: "01_initial_migration",
258+
VersionSchema: "initial_migration",
259+
Operations: migrations.Operations{&migrations.OpRawSQL{Up: "SELECT 1"}},
260+
}, backfill.NewConfig())
261+
require.NoError(t, err)
262+
err = m.Complete(ctx)
263+
require.NoError(t, err)
264+
265+
// Apply another pgroll migration
266+
err = m.Start(ctx, &migrations.Migration{
267+
Name: "02_another_migration",
268+
VersionSchema: "another_migration",
269+
Operations: migrations.Operations{&migrations.OpRawSQL{Up: "SELECT 1"}},
270+
}, backfill.NewConfig())
271+
require.NoError(t, err)
272+
err = m.Complete(ctx)
273+
require.NoError(t, err)
274+
275+
// Get the latest version schema name
276+
latest, err := m.State().LatestVersion(ctx, "public")
277+
require.NoError(t, err)
278+
279+
// Get the previous version schema name
280+
previous, err := m.State().PreviousVersion(ctx, "public")
281+
require.NoError(t, err)
282+
283+
// We have only a latest version schema name because the previous version
284+
// schema was removed when the second migration was completed
285+
require.NotNil(t, latest)
286+
require.Equal(t, "another_migration", *latest)
287+
require.Nil(t, previous)
288+
})
289+
})
290+
291+
t.Run("one pgroll then one inferred migration", func(t *testing.T) {
292+
testutils.WithMigratorAndConnectionToContainer(t, func(m *roll.Roll, db *sql.DB) {
293+
ctx := context.Background()
294+
295+
// Apply a pgroll migration
296+
err := m.Start(ctx, &migrations.Migration{
297+
Name: "01_initial_migration",
298+
VersionSchema: "initial_migration",
299+
Operations: migrations.Operations{&migrations.OpRawSQL{Up: "SELECT 1"}},
300+
}, backfill.NewConfig())
301+
require.NoError(t, err)
302+
err = m.Complete(ctx)
303+
require.NoError(t, err)
304+
305+
// Execute a SQL DDL statement to generate an inferred migration
306+
_, err = db.ExecContext(ctx, "CREATE TABLE table1(id int)")
307+
require.NoError(t, err)
308+
309+
// Get the latest version schema name
310+
latest, err := m.State().LatestVersion(ctx, "public")
311+
require.NoError(t, err)
312+
313+
// Get the previous version schema name
314+
previous, err := m.State().PreviousVersion(ctx, "public")
315+
require.NoError(t, err)
316+
317+
// We have a latest version schema name that corresponds to the most
318+
// recent `pgroll` migration. There is no previous version schema name.
319+
require.NotNil(t, latest)
320+
require.Equal(t, "initial_migration", *latest)
321+
require.Nil(t, previous)
322+
})
323+
})
324+
325+
t.Run("one pgroll, one inferred migration, then another pgroll migration", func(t *testing.T) {
326+
testutils.WithMigratorAndConnectionToContainer(t, func(m *roll.Roll, db *sql.DB) {
327+
ctx := context.Background()
328+
329+
// Apply a pgroll migration
330+
err := m.Start(ctx, &migrations.Migration{
331+
Name: "01_initial_migration",
332+
VersionSchema: "initial_migration",
333+
Operations: migrations.Operations{&migrations.OpRawSQL{Up: "SELECT 1"}},
334+
}, backfill.NewConfig())
335+
require.NoError(t, err)
336+
err = m.Complete(ctx)
337+
require.NoError(t, err)
338+
339+
// Execute a SQL DDL statement to generate an inferred migration
340+
_, err = db.ExecContext(ctx, "CREATE TABLE table1(id int)")
341+
require.NoError(t, err)
342+
343+
// Start but do not complete a pgroll migration
344+
err = m.Start(ctx, &migrations.Migration{
345+
Name: "02_another_migration",
346+
Operations: migrations.Operations{&migrations.OpRawSQL{Up: "SELECT 1"}},
347+
}, backfill.NewConfig())
348+
require.NoError(t, err)
349+
350+
// Get the latest version schema name
351+
latest, err := m.State().LatestVersion(ctx, "public")
352+
require.NoError(t, err)
353+
354+
// Get the previous version schema name
355+
previous, err := m.State().PreviousVersion(ctx, "public")
356+
require.NoError(t, err)
357+
358+
// We have a latest and a previous version schema name. The inferred
359+
// migation that was created after the first pgroll migration is ignored.
360+
require.NotNil(t, latest)
361+
require.Equal(t, "02_another_migration", *latest)
362+
require.NotNil(t, previous)
363+
require.Equal(t, "initial_migration", *previous)
364+
})
365+
})
366+
}

0 commit comments

Comments
 (0)