2017-02-10 03:42:48 +00:00
|
|
|
// Package testing has the database tests.
|
|
|
|
// All database drivers must pass the Test function.
|
|
|
|
// This lives in it's own package so it stays a test dependency.
|
2017-02-08 06:01:29 +00:00
|
|
|
package testing
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2019-04-26 22:47:16 +00:00
|
|
|
"errors"
|
2017-02-12 03:15:54 +00:00
|
|
|
"fmt"
|
2017-02-08 06:01:29 +00:00
|
|
|
"io"
|
|
|
|
"testing"
|
2017-02-12 03:15:54 +00:00
|
|
|
"time"
|
2017-02-08 06:01:29 +00:00
|
|
|
|
2018-10-10 22:11:48 +00:00
|
|
|
"github.com/golang-migrate/migrate/v4/database"
|
2017-02-08 06:01:29 +00:00
|
|
|
)
|
|
|
|
|
2017-02-10 03:42:48 +00:00
|
|
|
// Test runs tests against database implementations.
|
2017-02-08 06:01:29 +00:00
|
|
|
func Test(t *testing.T, d database.Driver, migration []byte) {
|
|
|
|
if migration == nil {
|
2019-02-19 09:59:04 +00:00
|
|
|
t.Fatal("test must provide migration reader")
|
2017-02-08 06:01:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TestNilVersion(t, d) // test first
|
|
|
|
TestLockAndUnlock(t, d)
|
2017-02-19 23:15:00 +00:00
|
|
|
TestRun(t, d, bytes.NewReader(migration))
|
|
|
|
TestSetVersion(t, d) // also tests Version()
|
2019-02-26 23:56:57 +00:00
|
|
|
// Drop breaks the driver, so test it last.
|
|
|
|
TestDrop(t, d)
|
2017-02-08 06:01:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestNilVersion(t *testing.T, d database.Driver) {
|
2017-02-19 23:15:00 +00:00
|
|
|
v, _, err := d.Version()
|
2017-02-08 06:01:29 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if v != database.NilVersion {
|
|
|
|
t.Fatalf("Version: expected version to be NilVersion (-1), got %v", v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestLockAndUnlock(t *testing.T, d database.Driver) {
|
2017-02-12 03:15:54 +00:00
|
|
|
// add a timeout, in case there is a deadlock
|
2019-04-26 22:47:16 +00:00
|
|
|
done := make(chan struct{})
|
|
|
|
errs := make(chan error)
|
|
|
|
|
2017-02-12 03:15:54 +00:00
|
|
|
go func() {
|
|
|
|
timeout := time.After(15 * time.Second)
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-done:
|
|
|
|
return
|
|
|
|
case <-timeout:
|
2019-04-26 22:47:16 +00:00
|
|
|
errs <- fmt.Errorf("Timeout after 15 seconds. Looks like a deadlock in Lock/UnLock.\n%#v", d)
|
|
|
|
return
|
2017-02-12 03:15:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
// run the locking test ...
|
2019-04-26 22:47:16 +00:00
|
|
|
go func() {
|
|
|
|
if err := d.Lock(); err != nil {
|
|
|
|
errs <- err
|
|
|
|
return
|
|
|
|
}
|
2017-02-12 03:15:54 +00:00
|
|
|
|
2019-04-26 22:47:16 +00:00
|
|
|
// try to acquire lock again
|
|
|
|
if err := d.Lock(); err == nil {
|
|
|
|
errs <- errors.New("lock: expected err not to be nil")
|
|
|
|
return
|
|
|
|
}
|
2017-02-08 06:01:29 +00:00
|
|
|
|
2019-04-26 22:47:16 +00:00
|
|
|
// unlock
|
|
|
|
if err := d.Unlock(); err != nil {
|
|
|
|
errs <- err
|
|
|
|
return
|
|
|
|
}
|
2017-02-08 06:01:29 +00:00
|
|
|
|
2019-04-26 22:47:16 +00:00
|
|
|
// try to lock
|
|
|
|
if err := d.Lock(); err != nil {
|
|
|
|
errs <- err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if err := d.Unlock(); err != nil {
|
|
|
|
errs <- err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// notify everyone
|
|
|
|
close(done)
|
|
|
|
}()
|
2017-02-08 06:01:29 +00:00
|
|
|
|
2019-04-26 22:47:16 +00:00
|
|
|
// wait for done or any error
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-done:
|
|
|
|
return
|
|
|
|
case err := <-errs:
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2017-02-08 06:01:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestRun(t *testing.T, d database.Driver, migration io.Reader) {
|
2017-02-19 23:15:00 +00:00
|
|
|
if migration == nil {
|
2019-02-19 09:59:04 +00:00
|
|
|
t.Fatal("migration can't be nil")
|
2017-02-08 06:01:29 +00:00
|
|
|
}
|
|
|
|
|
2017-02-19 23:15:00 +00:00
|
|
|
if err := d.Run(migration); err != nil {
|
2017-02-08 06:01:29 +00:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2017-02-19 23:15:00 +00:00
|
|
|
}
|
2017-02-08 06:01:29 +00:00
|
|
|
|
2017-02-19 23:15:00 +00:00
|
|
|
func TestDrop(t *testing.T, d database.Driver) {
|
2017-02-08 06:01:29 +00:00
|
|
|
if err := d.Drop(); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2017-02-19 23:15:00 +00:00
|
|
|
}
|
2017-02-08 06:01:29 +00:00
|
|
|
|
2017-02-19 23:15:00 +00:00
|
|
|
func TestSetVersion(t *testing.T, d database.Driver) {
|
|
|
|
if err := d.SetVersion(1, true); err != nil {
|
2017-02-08 06:01:29 +00:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2017-02-19 23:15:00 +00:00
|
|
|
// call again
|
|
|
|
if err := d.SetVersion(1, true); err != nil {
|
2017-02-08 06:01:29 +00:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2017-02-19 23:15:00 +00:00
|
|
|
v, dirty, err := d.Version()
|
2017-02-08 06:01:29 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2017-02-19 23:15:00 +00:00
|
|
|
if !dirty {
|
|
|
|
t.Fatal("expected dirty")
|
|
|
|
}
|
|
|
|
if v != 1 {
|
|
|
|
t.Fatal("expected version to be 1")
|
2017-02-08 06:01:29 +00:00
|
|
|
}
|
|
|
|
|
2017-02-19 23:15:00 +00:00
|
|
|
if err := d.SetVersion(2, false); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2017-02-08 06:01:29 +00:00
|
|
|
|
2017-02-19 23:15:00 +00:00
|
|
|
// call again
|
|
|
|
if err := d.SetVersion(2, false); err != nil {
|
2017-02-08 06:01:29 +00:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2017-02-19 23:15:00 +00:00
|
|
|
v, dirty, err = d.Version()
|
2017-02-08 06:01:29 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2017-02-19 23:15:00 +00:00
|
|
|
if dirty {
|
|
|
|
t.Fatal("expected not dirty")
|
|
|
|
}
|
|
|
|
if v != 2 {
|
|
|
|
t.Fatal("expected version to be 2")
|
2017-02-08 06:01:29 +00:00
|
|
|
}
|
|
|
|
}
|