mirror of https://github.com/pressly/goose.git
216 lines
6.2 KiB
Go
216 lines
6.2 KiB
Go
package goose_test
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strconv"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
_ "modernc.org/sqlite"
|
|
)
|
|
|
|
const (
|
|
// gooseTestBinaryVersion is utilized in conjunction with a linker variable to set the version
|
|
// of a binary created solely for testing purposes. It is used to test the --version flag.
|
|
gooseTestBinaryVersion = "v0.0.0"
|
|
)
|
|
|
|
func TestFullBinary(t *testing.T) {
|
|
t.Parallel()
|
|
cli := buildGooseCLI(t, false)
|
|
out, err := cli.run("--version")
|
|
require.NoError(t, err)
|
|
require.Equal(t, "goose version: "+gooseTestBinaryVersion+"\n", out)
|
|
}
|
|
|
|
func TestLiteBinary(t *testing.T) {
|
|
t.Parallel()
|
|
cli := buildGooseCLI(t, true)
|
|
|
|
t.Run("binary_version", func(t *testing.T) {
|
|
t.Parallel()
|
|
out, err := cli.run("--version")
|
|
require.NoError(t, err)
|
|
require.Equal(t, "goose version: "+gooseTestBinaryVersion+"\n", out)
|
|
})
|
|
t.Run("default_binary", func(t *testing.T) {
|
|
t.Parallel()
|
|
dir := t.TempDir()
|
|
total := countSQLFiles(t, "testdata/migrations")
|
|
commands := []struct {
|
|
cmd string
|
|
out string
|
|
}{
|
|
{"up", "goose: successfully migrated database to version: " + strconv.Itoa(total)},
|
|
{"version", "goose: version " + strconv.Itoa(total)},
|
|
{"down", "OK"},
|
|
{"version", "goose: version " + strconv.Itoa(total-1)},
|
|
{"status", ""},
|
|
{"reset", "OK"},
|
|
{"version", "goose: version 0"},
|
|
}
|
|
for _, c := range commands {
|
|
out, err := cli.run("-dir=testdata/migrations", "sqlite3", filepath.Join(dir, "sql.db"), c.cmd)
|
|
require.NoError(t, err)
|
|
require.Contains(t, out, c.out)
|
|
}
|
|
})
|
|
t.Run("gh_issue_532", func(t *testing.T) {
|
|
// https://github.com/pressly/goose/issues/532
|
|
t.Parallel()
|
|
dir := t.TempDir()
|
|
total := countSQLFiles(t, "testdata/migrations")
|
|
_, err := cli.run("-dir=testdata/migrations", "sqlite3", filepath.Join(dir, "sql.db"), "up")
|
|
require.NoError(t, err)
|
|
out, err := cli.run("-dir=testdata/migrations", "sqlite3", filepath.Join(dir, "sql.db"), "up")
|
|
require.NoError(t, err)
|
|
require.Contains(t, out, "goose: no migrations to run. current version: "+strconv.Itoa(total))
|
|
out, err = cli.run("-dir=testdata/migrations", "sqlite3", filepath.Join(dir, "sql.db"), "version")
|
|
require.NoError(t, err)
|
|
require.Contains(t, out, "goose: version "+strconv.Itoa(total))
|
|
})
|
|
t.Run("gh_issue_293", func(t *testing.T) {
|
|
// https://github.com/pressly/goose/issues/293
|
|
t.Parallel()
|
|
dir := t.TempDir()
|
|
total := countSQLFiles(t, "testdata/migrations")
|
|
commands := []struct {
|
|
cmd string
|
|
out string
|
|
}{
|
|
{"up", "goose: successfully migrated database to version: " + strconv.Itoa(total)},
|
|
{"version", "goose: version " + strconv.Itoa(total)},
|
|
{"down", "OK"},
|
|
{"down", "OK"},
|
|
{"version", "goose: version " + strconv.Itoa(total-2)},
|
|
{"up", "goose: successfully migrated database to version: " + strconv.Itoa(total)},
|
|
{"status", ""},
|
|
}
|
|
for _, c := range commands {
|
|
out, err := cli.run("-dir=testdata/migrations", "sqlite3", filepath.Join(dir, "sql.db"), c.cmd)
|
|
require.NoError(t, err)
|
|
require.Contains(t, out, c.out)
|
|
}
|
|
})
|
|
t.Run("gh_issue_336", func(t *testing.T) {
|
|
// https://github.com/pressly/goose/issues/336
|
|
t.Parallel()
|
|
dir := t.TempDir()
|
|
_, err := cli.run("-dir="+dir, "sqlite3", filepath.Join(dir, "sql.db"), "up")
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "goose run: no migration files found")
|
|
})
|
|
t.Run("create_and_fix", func(t *testing.T) {
|
|
t.Parallel()
|
|
dir := t.TempDir()
|
|
createEmptyFile(t, dir, "00001_alpha.sql")
|
|
createEmptyFile(t, dir, "00003_bravo.sql")
|
|
createEmptyFile(t, dir, "20230826163141_charlie.sql")
|
|
createEmptyFile(t, dir, "20230826163151_delta.go")
|
|
total, err := os.ReadDir(dir)
|
|
require.NoError(t, err)
|
|
require.Len(t, total, 4)
|
|
migrationFiles := []struct {
|
|
name string
|
|
fileType string
|
|
}{
|
|
{"echo", "sql"},
|
|
{"foxtrot", "go"},
|
|
{"golf", ""},
|
|
}
|
|
for i, f := range migrationFiles {
|
|
args := []string{"-dir=" + dir, "create", f.name}
|
|
if f.fileType != "" {
|
|
args = append(args, f.fileType)
|
|
}
|
|
out, err := cli.run(args...)
|
|
require.NoError(t, err)
|
|
require.Contains(t, out, "Created new file")
|
|
// ensure different timestamps, granularity is 1 second
|
|
if i < len(migrationFiles)-1 {
|
|
time.Sleep(1100 * time.Millisecond)
|
|
}
|
|
}
|
|
total, err = os.ReadDir(dir)
|
|
require.NoError(t, err)
|
|
require.Len(t, total, 7)
|
|
out, err := cli.run("-dir="+dir, "fix")
|
|
require.NoError(t, err)
|
|
require.Contains(t, out, "RENAMED")
|
|
files, err := os.ReadDir(dir)
|
|
require.NoError(t, err)
|
|
require.Len(t, files, 7)
|
|
expected := []string{
|
|
"00001_alpha.sql",
|
|
"00003_bravo.sql",
|
|
"00004_charlie.sql",
|
|
"00005_delta.go",
|
|
"00006_echo.sql",
|
|
"00007_foxtrot.go",
|
|
"00008_golf.go",
|
|
}
|
|
for i, f := range files {
|
|
require.Equal(t, f.Name(), expected[i])
|
|
}
|
|
})
|
|
}
|
|
|
|
type gooseBinary struct {
|
|
binaryPath string
|
|
}
|
|
|
|
func (g gooseBinary) run(params ...string) (string, error) {
|
|
cmd := exec.Command(g.binaryPath, params...)
|
|
out, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to run goose command: %v\nout: %v", err, string(out))
|
|
}
|
|
return string(out), nil
|
|
}
|
|
|
|
// buildGooseCLI builds goose test binary, which is used for testing goose CLI. It is built with all
|
|
// drivers enabled, unless lite is true, in which case all drivers are disabled except sqlite3
|
|
func buildGooseCLI(t *testing.T, lite bool) gooseBinary {
|
|
t.Helper()
|
|
binName := "goose-test"
|
|
dir := t.TempDir()
|
|
output := filepath.Join(dir, binName)
|
|
// usage: go build [-o output] [build flags] [packages]
|
|
args := []string{
|
|
"build",
|
|
"-o", output,
|
|
"-ldflags=-s -w -X main.version=" + gooseTestBinaryVersion,
|
|
}
|
|
if lite {
|
|
args = append(args, "-tags=no_clickhouse no_mssql no_mysql no_vertica no_postgres")
|
|
}
|
|
args = append(args, "./cmd/goose")
|
|
build := exec.Command("go", args...)
|
|
out, err := build.CombinedOutput()
|
|
if err != nil {
|
|
t.Fatalf("failed to build %s binary: %v: %s", binName, err, string(out))
|
|
}
|
|
return gooseBinary{
|
|
binaryPath: output,
|
|
}
|
|
}
|
|
|
|
func countSQLFiles(t *testing.T, dir string) int {
|
|
t.Helper()
|
|
files, err := filepath.Glob(filepath.Join(dir, "*.sql"))
|
|
require.NoError(t, err)
|
|
return len(files)
|
|
}
|
|
|
|
func createEmptyFile(t *testing.T, dir, name string) {
|
|
t.Helper()
|
|
path := filepath.Join(dir, name)
|
|
f, err := os.Create(path)
|
|
require.NoError(t, err)
|
|
defer f.Close()
|
|
}
|