1 package popx
2
3 import (
4 "bytes"
5 "context"
6 "embed"
7 "fmt"
8 "io/ioutil"
9 "os"
10 "strings"
11 "testing"
12
13 "github.com/gobuffalo/pop/v5"
14 "github.com/sirupsen/logrus"
15 "github.com/stretchr/testify/assert"
16 "github.com/stretchr/testify/require"
17
18 "github.com/ory/x/logrusx"
19 "github.com/ory/x/pkgerx"
20 "github.com/ory/x/sqlcon/dockertest"
21 )
22
23
24 var transactionalMigrations embed.FS
25
26 func TestMigratorUpgrading(t *testing.T) {
27 litedb, err := ioutil.TempFile(os.TempDir(), "sqlite-*")
28 require.NoError(t, err)
29 require.NoError(t, litedb.Close())
30
31 ctx := context.Background()
32
33 sqlite, err := pop.NewConnection(&pop.ConnectionDetails{
34 URL: "sqlite://file::memory:?_fk=true",
35 })
36 require.NoError(t, err)
37 require.NoError(t, sqlite.Open())
38
39 connections := map[string]*pop.Connection{
40 "sqlite": sqlite,
41 }
42
43 if !testing.Short() {
44 dockertest.Parallel([]func(){
45 func() {
46 connections["postgres"] = dockertest.ConnectToTestPostgreSQLPop(t)
47 },
48 func() {
49 connections["mysql"] = dockertest.ConnectToTestMySQLPop(t)
50 },
51 func() {
52 connections["cockroach"] = dockertest.ConnectToTestCockroachDBPop(t)
53 },
54 })
55 }
56
57 l := logrusx.New("", "", logrusx.ForceLevel(logrus.DebugLevel))
58
59 for name, c := range connections {
60 t.Run(fmt.Sprintf("database=%s", name), func(t *testing.T) {
61 legacy, err := pkgerx.NewMigrationBox("/popx/stub/migrations/legacy", c, l)
62 require.NoError(t, err)
63 require.NoError(t, legacy.Up())
64
65 var legacyStatusBuffer bytes.Buffer
66 require.NoError(t, legacy.Status(&legacyStatusBuffer))
67
68 legacyStatus := filterMySQL(t, name, legacyStatusBuffer.String())
69
70 require.NotContains(t, legacyStatus, Pending)
71
72 expected := legacy.DumpMigrationSchema()
73
74 transactional, err := NewMigrationBox(transactionalMigrations, NewMigrator(c, l, nil, 0))
75 require.NoError(t, err)
76
77 var transactionalStatusBuffer bytes.Buffer
78 statuses, err := transactional.Status(ctx)
79 require.NoError(t, err)
80
81 require.NoError(t, statuses.Write(&transactionalStatusBuffer))
82 transactionalStatus := filterMySQL(t, name, transactionalStatusBuffer.String())
83 require.NotContains(t, transactionalStatus, Pending)
84 require.False(t, statuses.HasPending())
85
86 require.NoError(t, transactional.Up(ctx))
87
88 actual := transactional.DumpMigrationSchema(ctx)
89 assert.EqualValues(t, expected, actual)
90
91
92
93 require.NoError(t, legacy.Down(-1))
94 require.NoError(t, transactional.Up(ctx))
95 actual = transactional.DumpMigrationSchema(ctx)
96 assert.EqualValues(t, expected, actual)
97 })
98 }
99 }
100
101 func filterMySQL(t *testing.T, name string, status string) string {
102 if name == "mysql" {
103 return status
104 }
105
106
107
108
109
110
111
112 pending := []string{"20191100000005", "20191100000009", "20200519101058", "20200601101001"}
113 var lines []string
114 for _, l := range strings.Split(status, "\n") {
115 var skip bool
116 for _, p := range pending {
117 if strings.Contains(l, p) {
118 t.Logf("Removing expected pending line: %s", l)
119 skip = true
120 break
121 }
122 }
123 if !skip {
124 lines = append(lines, l)
125 }
126 }
127
128 return strings.Join(lines, "\n")
129 }
130
131 func TestMigratorUpgradingFromStart(t *testing.T) {
132 litedb, err := ioutil.TempFile(os.TempDir(), "sqlite-*")
133 require.NoError(t, err)
134 require.NoError(t, litedb.Close())
135
136 ctx := context.Background()
137
138 c, err := pop.NewConnection(&pop.ConnectionDetails{
139 URL: "sqlite://file::memory:?_fk=true",
140 })
141 require.NoError(t, err)
142 require.NoError(t, c.Open())
143
144 l := logrusx.New("", "", logrusx.ForceLevel(logrus.DebugLevel))
145 transactional, err := NewMigrationBox(transactionalMigrations, NewMigrator(c, l, nil, 0))
146 require.NoError(t, err)
147 status, err := transactional.Status(ctx)
148 require.NoError(t, err)
149 require.True(t, status.HasPending())
150
151 require.NoError(t, transactional.Up(ctx))
152
153 status, err = transactional.Status(ctx)
154 require.NoError(t, err)
155 require.False(t, status.HasPending())
156
157
158 var rows []string
159 require.NoError(t, c.Store.Select(&rows, "SELECT name FROM sqlite_master WHERE type='table'"))
160
161 for _, expected := range []string{
162 "schema_migration",
163 "identities",
164 } {
165 require.Contains(t, rows, expected)
166 }
167
168 require.NoError(t, transactional.Down(ctx, -1))
169 }
170
View as plain text