Short and single-letter names in application code become full words (tests keep theirs). Wrapped calls, signatures and composite literals put one item per line, and one-line function bodies are expanded. Exported names and groups of constants get doc comments, and comments refer to the renamed identifiers.
106 lines
3.0 KiB
Go
106 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)
|
|
}
|
|
}
|