102 lines
3.0 KiB
Go
102 lines
3.0 KiB
Go
package migrate
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/pressly/goose/v3"
|
|
)
|
|
|
|
// The commands are tested through the real command tree in cmd/jobsearch.
|
|
// These tests cover reporting a failed migration, which a working set of
|
|
// migrations can't trigger.
|
|
|
|
func result(path, direction string) *goose.MigrationResult {
|
|
return &goose.MigrationResult{
|
|
Source: &goose.Source{Path: "migrations/" + path},
|
|
Direction: direction,
|
|
Duration: 1500 * time.Microsecond,
|
|
}
|
|
}
|
|
|
|
func TestFailurePartial(t *testing.T) {
|
|
cause := errors.New("no such table: missing")
|
|
var out bytes.Buffer
|
|
err := failure(&out, &goose.PartialError{
|
|
Applied: []*goose.MigrationResult{result("00001_first.sql", "up")},
|
|
Failed: result("00002_second.sql", "up"),
|
|
Err: cause,
|
|
})
|
|
|
|
if want := " applied 00001_first.sql (2ms)\n"; out.String() != want {
|
|
t.Errorf("output = %q, want %q", out.String(), want)
|
|
}
|
|
if !errors.Is(err, cause) {
|
|
t.Errorf("err = %v, want it to wrap the migration error", err)
|
|
}
|
|
for _, want := range []string{"00002_second.sql", "rolled back", "last version that succeeded"} {
|
|
if err == nil || !strings.Contains(err.Error(), want) {
|
|
t.Errorf("err = %v, want it to mention %q", err, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFailureWithoutFailedSource(t *testing.T) {
|
|
err := failure(&bytes.Buffer{}, &goose.PartialError{Err: errors.New("boom")})
|
|
if err == nil || !strings.Contains(err.Error(), "unknown migration") {
|
|
t.Errorf("err = %v, want unknown migration", err)
|
|
}
|
|
}
|
|
|
|
func TestFailureOtherError(t *testing.T) {
|
|
cause := errors.New("database is locked")
|
|
var out bytes.Buffer
|
|
if err := failure(&out, cause); err != cause {
|
|
t.Errorf("err = %v, want the error unchanged", err)
|
|
}
|
|
if out.Len() != 0 {
|
|
t.Errorf("printed %q for a non-migration error", out.String())
|
|
}
|
|
}
|
|
|
|
func TestPrintResults(t *testing.T) {
|
|
var out bytes.Buffer
|
|
err := printResults(&out, []*goose.MigrationResult{
|
|
result("00001_first.sql", "up"),
|
|
result("00002_second.sql", "down"),
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
want := " applied 00001_first.sql (2ms)\n reverted 00002_second.sql (2ms)\n"
|
|
if out.String() != want {
|
|
t.Errorf("output = %q, want %q", out.String(), want)
|
|
}
|
|
}
|
|
|
|
// failingWriter fails every write.
|
|
type failingWriter struct{}
|
|
|
|
var errWrite = errors.New("write failed")
|
|
|
|
func (failingWriter) Write([]byte) (int, error) { return 0, errWrite }
|
|
|
|
// A write error is returned, and the failed migration is still reported.
|
|
func TestWriteErrors(t *testing.T) {
|
|
results := []*goose.MigrationResult{result("00001_first.sql", "up")}
|
|
if err := printResults(failingWriter{}, results); !errors.Is(err, errWrite) {
|
|
t.Errorf("printResults: err = %v, want the write error", err)
|
|
}
|
|
|
|
cause := errors.New("boom")
|
|
err := failure(failingWriter{}, &goose.PartialError{
|
|
Applied: results, Failed: result("00002_second.sql", "up"), Err: cause,
|
|
})
|
|
if !errors.Is(err, cause) || !errors.Is(err, errWrite) {
|
|
t.Errorf("failure: err = %v, want both the migration and write errors", err)
|
|
}
|
|
}
|