github.com/supabase/cli@v1.168.1/internal/migration/up/up_test.go (about) 1 package up 2 3 import ( 4 "context" 5 "os" 6 "path/filepath" 7 "testing" 8 9 "github.com/jackc/pgconn" 10 "github.com/spf13/afero" 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/require" 13 "github.com/supabase/cli/internal/migration/list" 14 "github.com/supabase/cli/internal/testing/fstest" 15 "github.com/supabase/cli/internal/testing/pgtest" 16 "github.com/supabase/cli/internal/utils" 17 ) 18 19 func TestPendingMigrations(t *testing.T) { 20 t.Run("finds pending migrations", func(t *testing.T) { 21 // Setup in-memory fs 22 fsys := afero.NewMemMapFs() 23 files := []string{ 24 "20221201000000_test.sql", 25 "20221201000001_test.sql", 26 "20221201000002_test.sql", 27 "20221201000003_test.sql", 28 } 29 for _, name := range files { 30 path := filepath.Join(utils.MigrationsDir, name) 31 require.NoError(t, afero.WriteFile(fsys, path, []byte(""), 0644)) 32 } 33 // Setup mock postgres 34 conn := pgtest.NewConn() 35 defer conn.Close(t) 36 conn.Query(list.LIST_MIGRATION_VERSION). 37 Reply("SELECT 2", []interface{}{"20221201000000"}, []interface{}{"20221201000001"}) 38 // Connect to mock 39 ctx := context.Background() 40 mock, err := utils.ConnectLocalPostgres(ctx, pgconn.Config{Port: 5432}, conn.Intercept) 41 require.NoError(t, err) 42 defer mock.Close(ctx) 43 // Run test 44 pending, err := GetPendingMigrations(ctx, false, mock, fsys) 45 // Check error 46 assert.NoError(t, err) 47 assert.ElementsMatch(t, files[2:], pending) 48 }) 49 50 t.Run("throws error on local load failure", func(t *testing.T) { 51 // Setup in-memory fs 52 fsys := &fstest.OpenErrorFs{DenyPath: utils.MigrationsDir} 53 // Setup mock postgres 54 conn := pgtest.NewConn() 55 defer conn.Close(t) 56 conn.Query(list.LIST_MIGRATION_VERSION). 57 Reply("SELECT 0") 58 // Connect to mock 59 ctx := context.Background() 60 mock, err := utils.ConnectLocalPostgres(ctx, pgconn.Config{Port: 5432}, conn.Intercept) 61 require.NoError(t, err) 62 defer mock.Close(ctx) 63 // Run test 64 _, err = GetPendingMigrations(ctx, false, mock, fsys) 65 // Check error 66 assert.ErrorIs(t, err, os.ErrPermission) 67 }) 68 69 t.Run("throws error on missing local migration", func(t *testing.T) { 70 // Setup in-memory fs 71 fsys := afero.NewMemMapFs() 72 // Setup mock postgres 73 conn := pgtest.NewConn() 74 defer conn.Close(t) 75 conn.Query(list.LIST_MIGRATION_VERSION). 76 Reply("SELECT 1", []interface{}{"0"}) 77 // Connect to mock 78 ctx := context.Background() 79 mock, err := utils.ConnectLocalPostgres(ctx, pgconn.Config{Port: 5432}, conn.Intercept) 80 require.NoError(t, err) 81 defer mock.Close(ctx) 82 // Run test 83 _, err = GetPendingMigrations(ctx, false, mock, fsys) 84 // Check error 85 assert.ErrorIs(t, err, errMissingLocal) 86 assert.Contains(t, utils.CmdSuggestion, "supabase migration repair --status reverted 0") 87 }) 88 89 t.Run("throws error on missing remote version", func(t *testing.T) { 90 // Setup in-memory fs 91 fsys := afero.NewMemMapFs() 92 files := []string{"0_test.sql", "1_test.sql"} 93 for _, name := range files { 94 path := filepath.Join(utils.MigrationsDir, name) 95 require.NoError(t, afero.WriteFile(fsys, path, []byte(""), 0644)) 96 } 97 // Setup mock postgres 98 conn := pgtest.NewConn() 99 defer conn.Close(t) 100 conn.Query(list.LIST_MIGRATION_VERSION). 101 Reply("SELECT 1", []interface{}{"1"}) 102 // Connect to mock 103 ctx := context.Background() 104 mock, err := utils.ConnectLocalPostgres(ctx, pgconn.Config{Port: 5432}, conn.Intercept) 105 require.NoError(t, err) 106 defer mock.Close(ctx) 107 // Run test 108 _, err = GetPendingMigrations(ctx, false, mock, fsys) 109 // Check error 110 assert.ErrorIs(t, err, errMissingRemote) 111 }) 112 } 113 114 func TestIgnoreVersionMismatch(t *testing.T) { 115 t.Run("applies out-of-order local migrations", func(t *testing.T) { 116 // Setup in-memory fs 117 fsys := afero.NewMemMapFs() 118 files := []string{ 119 "20221201000000_test.sql", 120 "20221201000001_test.sql", 121 "20221201000002_test.sql", 122 "20221201000003_test.sql", 123 } 124 for _, name := range files { 125 path := filepath.Join(utils.MigrationsDir, name) 126 require.NoError(t, afero.WriteFile(fsys, path, []byte(""), 0644)) 127 } 128 // Setup mock postgres 129 conn := pgtest.NewConn() 130 defer conn.Close(t) 131 conn.Query(list.LIST_MIGRATION_VERSION). 132 Reply("SELECT 2", []interface{}{"20221201000000"}, []interface{}{"20221201000002"}) 133 // Connect to mock 134 ctx := context.Background() 135 mock, err := utils.ConnectLocalPostgres(ctx, pgconn.Config{Port: 5432}, conn.Intercept) 136 require.NoError(t, err) 137 defer mock.Close(ctx) 138 // Run test 139 pending, err := GetPendingMigrations(ctx, true, mock, fsys) 140 // Check error 141 assert.NoError(t, err) 142 assert.ElementsMatch(t, []string{files[1], files[3]}, pending) 143 }) 144 145 t.Run("throws error on missing local and remote migration", func(t *testing.T) { 146 // Setup in-memory fs 147 fsys := afero.NewMemMapFs() 148 files := []string{ 149 "20221201000000_test.sql", 150 "20221201000001_test.sql", 151 "20221201000002_test.sql", 152 "20221201000003_test.sql", 153 } 154 for _, name := range files { 155 path := filepath.Join(utils.MigrationsDir, name) 156 require.NoError(t, afero.WriteFile(fsys, path, []byte(""), 0644)) 157 } 158 // Setup mock postgres 159 conn := pgtest.NewConn() 160 defer conn.Close(t) 161 conn.Query(list.LIST_MIGRATION_VERSION). 162 Reply("SELECT 2", []interface{}{"20221201000002"}, []interface{}{"20221201000004"}) 163 // Connect to mock 164 ctx := context.Background() 165 mock, err := utils.ConnectLocalPostgres(ctx, pgconn.Config{Port: 5432}, conn.Intercept) 166 require.NoError(t, err) 167 defer mock.Close(ctx) 168 // Run test 169 _, err = GetPendingMigrations(ctx, true, mock, fsys) 170 // Check error 171 assert.ErrorIs(t, err, errMissingLocal) 172 assert.Contains(t, utils.CmdSuggestion, "supabase migration repair --status reverted 20221201000004") 173 }) 174 175 t.Run("throws error on missing local migration", func(t *testing.T) { 176 // Setup in-memory fs 177 fsys := afero.NewMemMapFs() 178 files := []string{ 179 "20221201000000_test.sql", 180 "20221201000002_test.sql", 181 } 182 for _, name := range files { 183 path := filepath.Join(utils.MigrationsDir, name) 184 require.NoError(t, afero.WriteFile(fsys, path, []byte(""), 0644)) 185 } 186 // Setup mock postgres 187 conn := pgtest.NewConn() 188 defer conn.Close(t) 189 conn.Query(list.LIST_MIGRATION_VERSION). 190 Reply("SELECT 5", 191 []interface{}{"20221201000000"}, 192 []interface{}{"20221201000001"}, 193 []interface{}{"20221201000002"}, 194 []interface{}{"20221201000003"}, 195 []interface{}{"20221201000004"}, 196 ) 197 // Connect to mock 198 ctx := context.Background() 199 mock, err := utils.ConnectLocalPostgres(ctx, pgconn.Config{Port: 5432}, conn.Intercept) 200 require.NoError(t, err) 201 defer mock.Close(ctx) 202 // Run test 203 _, err = GetPendingMigrations(ctx, true, mock, fsys) 204 // Check error 205 assert.ErrorIs(t, err, errMissingLocal) 206 assert.Contains(t, utils.CmdSuggestion, "supabase migration repair --status reverted 20221201000001 20221201000003 20221201000004") 207 }) 208 }