177 lines
5.4 KiB
Go
177 lines
5.4 KiB
Go
package migration
|
|
|
|
import (
|
|
"context"
|
|
_ "embed"
|
|
"os"
|
|
"testing"
|
|
fs "testing/fstest"
|
|
|
|
"github.com/jackc/pgerrcode"
|
|
"github.com/jackc/pgx/v4"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/supabase/cli/pkg/pgtest"
|
|
)
|
|
|
|
//go:embed testdata/seed.sql
|
|
var testSeed string
|
|
|
|
func TestPendingSeeds(t *testing.T) {
|
|
pending := []string{"testdata/seed.sql"}
|
|
|
|
t.Run("finds new seeds", func(t *testing.T) {
|
|
// Setup mock postgres
|
|
conn := pgtest.NewConn()
|
|
defer conn.Close(t)
|
|
conn.Query(SELECT_SEED_TABLE).
|
|
Reply("SELECT 0")
|
|
// Run test
|
|
seeds, err := GetPendingSeeds(context.Background(), pending, conn.MockClient(t), testMigrations)
|
|
// Check error
|
|
assert.NoError(t, err)
|
|
require.Len(t, seeds, 1)
|
|
assert.Equal(t, seeds[0].Path, pending[0])
|
|
assert.Equal(t, seeds[0].Hash, "61868484fc0ddca2a2022217629a9fd9a4cf1ca479432046290797d6d40ffcc3")
|
|
assert.False(t, seeds[0].Dirty)
|
|
})
|
|
|
|
t.Run("finds dirty seeds", func(t *testing.T) {
|
|
// Setup mock postgres
|
|
conn := pgtest.NewConn()
|
|
defer conn.Close(t)
|
|
conn.Query(SELECT_SEED_TABLE).
|
|
Reply("SELECT 1", SeedFile{Path: pending[0], Hash: "outdated"})
|
|
// Run test
|
|
seeds, err := GetPendingSeeds(context.Background(), pending, conn.MockClient(t), testMigrations)
|
|
// Check error
|
|
assert.NoError(t, err)
|
|
require.Len(t, seeds, 1)
|
|
assert.Equal(t, seeds[0].Path, pending[0])
|
|
assert.Equal(t, seeds[0].Hash, "61868484fc0ddca2a2022217629a9fd9a4cf1ca479432046290797d6d40ffcc3")
|
|
assert.True(t, seeds[0].Dirty)
|
|
})
|
|
|
|
t.Run("skips applied seed", func(t *testing.T) {
|
|
// Setup mock postgres
|
|
conn := pgtest.NewConn()
|
|
defer conn.Close(t)
|
|
conn.Query(SELECT_SEED_TABLE).
|
|
Reply("SELECT 1", SeedFile{Path: pending[0], Hash: "61868484fc0ddca2a2022217629a9fd9a4cf1ca479432046290797d6d40ffcc3"})
|
|
// Run test
|
|
seeds, err := GetPendingSeeds(context.Background(), pending, conn.MockClient(t), testMigrations)
|
|
// Check error
|
|
assert.NoError(t, err)
|
|
require.Empty(t, seeds)
|
|
})
|
|
|
|
t.Run("ignores missing seed table", func(t *testing.T) {
|
|
// Setup mock postgres
|
|
conn := pgtest.NewConn()
|
|
defer conn.Close(t)
|
|
conn.Query(SELECT_SEED_TABLE).
|
|
ReplyError(pgerrcode.UndefinedTable, `relation "seed_files" does not exist`)
|
|
// Run test
|
|
_, err := GetPendingSeeds(context.Background(), pending, conn.MockClient(t), testMigrations)
|
|
// Check error
|
|
assert.NoError(t, err)
|
|
})
|
|
|
|
t.Run("ignores missing seed file", func(t *testing.T) {
|
|
// Setup in-memory fs
|
|
fsys := fs.MapFS{}
|
|
// Run test
|
|
_, err := GetPendingSeeds(context.Background(), pending, nil, fsys)
|
|
// Check error
|
|
assert.NoError(t, err)
|
|
})
|
|
}
|
|
|
|
func TestSeedData(t *testing.T) {
|
|
t.Run("seeds from file", func(t *testing.T) {
|
|
seed := SeedFile{
|
|
Path: "testdata/seed.sql",
|
|
Hash: "61868484fc0ddca2a2022217629a9fd9a4cf1ca479432046290797d6d40ffcc3",
|
|
Dirty: true,
|
|
}
|
|
// Setup mock postgres
|
|
conn := pgtest.NewConn()
|
|
defer conn.Close(t)
|
|
mockSeedHistory(conn).
|
|
Query(UPSERT_SEED_FILE, seed.Path, seed.Hash).
|
|
Reply("INSERT 0 1")
|
|
// Run test
|
|
err := SeedData(context.Background(), []SeedFile{seed}, conn.MockClient(t), testMigrations)
|
|
// Check error
|
|
assert.NoError(t, err)
|
|
})
|
|
|
|
t.Run("throws error on upsert failure", func(t *testing.T) {
|
|
seed := SeedFile{
|
|
Path: "testdata/seed.sql",
|
|
Hash: "61868484fc0ddca2a2022217629a9fd9a4cf1ca479432046290797d6d40ffcc3",
|
|
}
|
|
// Setup mock postgres
|
|
conn := pgtest.NewConn()
|
|
defer conn.Close(t)
|
|
mockSeedHistory(conn).
|
|
Query(testSeed+`;INSERT INTO supabase_migrations.seed_files(path, hash) VALUES( 'testdata/seed.sql' , '61868484fc0ddca2a2022217629a9fd9a4cf1ca479432046290797d6d40ffcc3' ) ON CONFLICT (path) DO UPDATE SET hash = EXCLUDED.hash`).
|
|
ReplyError(pgerrcode.NotNullViolation, `null value in column "age" of relation "employees"`)
|
|
// Run test
|
|
err := SeedData(context.Background(), []SeedFile{seed}, conn.MockClient(t, func(cc *pgx.ConnConfig) {
|
|
cc.PreferSimpleProtocol = true
|
|
}), testMigrations)
|
|
// Check error
|
|
assert.ErrorContains(t, err, `ERROR: null value in column "age" of relation "employees" (SQLSTATE 23502)`)
|
|
})
|
|
}
|
|
|
|
func mockSeedHistory(conn *pgtest.MockConn) *pgtest.MockConn {
|
|
conn.Query(SET_LOCK_TIMEOUT).
|
|
Query(CREATE_VERSION_SCHEMA).
|
|
Reply("CREATE SCHEMA").
|
|
Query(CREATE_SEED_TABLE).
|
|
Reply("CREATE TABLE")
|
|
return conn
|
|
}
|
|
|
|
//go:embed testdata/1_globals.sql
|
|
var testGlobals string
|
|
|
|
func TestSeedGlobals(t *testing.T) {
|
|
pending := []string{"testdata/1_globals.sql"}
|
|
|
|
t.Run("seeds from file", func(t *testing.T) {
|
|
// Setup mock postgres
|
|
conn := pgtest.NewConn()
|
|
defer conn.Close(t)
|
|
conn.Query(testGlobals).
|
|
Reply("CREATE ROLE")
|
|
// Run test
|
|
err := SeedGlobals(context.Background(), pending, conn.MockClient(t), testMigrations)
|
|
// Check error
|
|
assert.NoError(t, err)
|
|
})
|
|
|
|
t.Run("throws error on missing file", func(t *testing.T) {
|
|
// Setup in-memory fs
|
|
fsys := fs.MapFS{}
|
|
// Run test
|
|
err := SeedGlobals(context.Background(), pending, nil, fsys)
|
|
// Check error
|
|
assert.ErrorIs(t, err, os.ErrNotExist)
|
|
})
|
|
|
|
t.Run("throws error on create failure", func(t *testing.T) {
|
|
// Setup mock postgres
|
|
conn := pgtest.NewConn()
|
|
defer conn.Close(t)
|
|
conn.Query(testGlobals).
|
|
ReplyError(pgerrcode.InvalidCatalogName, `database "postgres" does not exist`)
|
|
// Run test
|
|
err := SeedGlobals(context.Background(), pending, conn.MockClient(t), testMigrations)
|
|
// Check error
|
|
assert.ErrorContains(t, err, `ERROR: database "postgres" does not exist (SQLSTATE 3D000)`)
|
|
})
|
|
}
|