From 809c7f0ac8b991f7c6e185e2fdead9745168ee61 Mon Sep 17 00:00:00 2001 From: Dale Hui Date: Tue, 8 Jan 2019 02:20:34 -0800 Subject: [PATCH] Use dktest to run docker tests - Leaving migrate/testing in case there are unknown consumers - Add migrate/dktesting package - Update tests to use migrate/dktesting instead of migrate/testing --- Gopkg.lock | 57 +++- Gopkg.toml | 4 + database/cassandra/cassandra_test.go | 71 ++-- database/cockroachdb/cockroachdb_test.go | 164 +++++---- database/mongodb/mongodb_test.go | 363 ++++++++++---------- database/mysql/mysql_test.go | 132 ++++--- database/postgres/postgres_test.go | 416 +++++++++++++---------- database/redshift/redshift_test.go | 332 ++++++++++-------- dktesting/dktesting.go | 35 ++ dktesting/example_test.go | 29 ++ go.mod | 38 +-- go.sum | 87 +++-- 12 files changed, 1025 insertions(+), 703 deletions(-) create mode 100644 dktesting/dktesting.go create mode 100644 dktesting/example_test.go diff --git a/Gopkg.lock b/Gopkg.lock index f31055e..661c712 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -25,6 +25,17 @@ revision = "c728a003b238b26cef9ab6753a5dc424b331c3ad" version = "v0.27.0" +[[projects]] + branch = "master" + digest = "1:6da51e5ec493ad2b44cb04129e2d0a068c8fb9bd6cb5739d199573558696bb94" + name = "github.com/Azure/go-ansiterm" + packages = [ + ".", + "winterm", + ] + pruneopts = "UT" + revision = "d6e3b3328b783f23731bc4d058875b0371ff8109" + [[projects]] digest = "1:f9ae348e1f793dcf9ed930ed47136a67343dbd6809c5c91391322267f4476892" name = "github.com/Microsoft/go-winio" @@ -33,6 +44,14 @@ revision = "97e4973ce50b2ff5f09635a57e2b88a037aae829" version = "v0.4.11" +[[projects]] + branch = "master" + digest = "1:3721a10686511b80c052323423f0de17a8c06d417dbdd3b392b1578432a33aae" + name = "github.com/Nvveen/Gotty" + packages = ["."] + pruneopts = "UT" + revision = "cd527374f1e5bff4938207604a14f2e38a9cf512" + [[projects]] digest = "1:1d58a675bc7df5691f81b4a28a39d2d218f020b23644a6c7771f7ebaab272ac8" name = "github.com/aws/aws-sdk-go" @@ -171,6 +190,14 @@ pruneopts = "UT" revision = "2533cb5b45cc6c07421468ce262899ddc9d53fb7" +[[projects]] + digest = "1:68e57cbbbd288587542234a360b8e85203d5c401e17af111700b64c4e6fc18a0" + name = "github.com/dhui/dktest" + packages = ["."] + pruneopts = "UT" + revision = "000a05f875a42eae6ea121e1aa763d8b35944c19" + version = "v0.2.2" + [[projects]] branch = "master" digest = "1:4ddc17aeaa82cb18c5f0a25d7c253a10682f518f4b2558a82869506eec223d76" @@ -183,7 +210,7 @@ revision = "1cb4180b1a5b9c029b2f2beaeb38f0b5cf64e12e" [[projects]] - digest = "1:47eae8fd493e859163b3cace5b72c83a7f42f7e9aad758b2c747a58331ec24ab" + digest = "1:8a2c57c577e78f40e2b3cd34ba1d050d9afd1060f91552ea03704324d1f50024" name = "github.com/docker/docker" packages = [ "api", @@ -203,6 +230,9 @@ "api/types/versions", "api/types/volume", "client", + "pkg/jsonmessage", + "pkg/term", + "pkg/term/windows", ] pruneopts = "UT" revision = "453f2b8b40b923862ce1c08c11531ff5042770f1" @@ -386,6 +416,14 @@ pruneopts = "UT" revision = "0b12d6b5" +[[projects]] + digest = "1:0a69a1c0db3591fcefb47f115b224592c8dfa4368b7ba9fae509d5e16cdc95c8" + name = "github.com/konsorten/go-windows-terminal-sequences" + packages = ["."] + pruneopts = "UT" + revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242" + version = "v1.0.1" + [[projects]] digest = "1:f02dbf2124e5dfb5305a6c3c8957a41d54a89d2a3ef60f030769f86e7851d5f5" name = "github.com/kshvakov/clickhouse" @@ -487,6 +525,14 @@ revision = "645ef00459ed84a119197bfb8d8205042c6df63d" version = "v0.8.0" +[[projects]] + digest = "1:87c2e02fb01c27060ccc5ba7c5a407cc91147726f8f40b70cceeedbc52b1f3a8" + name = "github.com/sirupsen/logrus" + packages = ["."] + pruneopts = "UT" + revision = "e1e72e9de974bd926e5c56f83753fba2df402ce5" + version = "v1.3.0" + [[projects]] branch = "master" digest = "1:40fdfd6ab85ca32b6935853bbba35935dcb1d796c8135efd85947566c76e662e" @@ -528,9 +574,12 @@ [[projects]] branch = "master" - digest = "1:f92f6956e4059f6a3efc14924d2dd58ba90da25cc57fe07ae3779ef2f5e0c5f2" + digest = "1:9ff2b9f8d4e47013a213b9ea0d850ed787c51f5eab2038842d82397ad85a19c1" name = "golang.org/x/crypto" - packages = ["pbkdf2"] + packages = [ + "pbkdf2", + "ssh/terminal", + ] pruneopts = "UT" revision = "8d7daa0c54b357f3071e11eaef7efc4e19a417e2" @@ -737,6 +786,7 @@ "github.com/aws/aws-sdk-go/service/s3/s3iface", "github.com/cockroachdb/cockroach-go/crdb", "github.com/cznic/ql/driver", + "github.com/dhui/dktest", "github.com/docker/docker/api/types", "github.com/docker/docker/api/types/container", "github.com/docker/docker/api/types/network", @@ -750,7 +800,6 @@ "github.com/mattn/go-sqlite3", "github.com/mongodb/mongo-go-driver/bson", "github.com/mongodb/mongo-go-driver/mongo", - "github.com/mongodb/mongo-go-driver/x/bsonx", "github.com/mongodb/mongo-go-driver/x/network/connstring", "golang.org/x/net/context", "golang.org/x/tools/godoc/vfs", diff --git a/Gopkg.toml b/Gopkg.toml index 2f89115..601712b 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -100,3 +100,7 @@ [prune] go-tests = true unused-packages = true + +[[constraint]] + name = "github.com/dhui/dktest" + version = "0.2.2" diff --git a/database/cassandra/cassandra_test.go b/database/cassandra/cassandra_test.go index 30107fa..9bc4a0f 100644 --- a/database/cassandra/cassandra_test.go +++ b/database/cassandra/cassandra_test.go @@ -4,27 +4,39 @@ import ( "fmt" "strconv" "testing" - - "github.com/gocql/gocql" - - dt "github.com/golang-migrate/migrate/v4/database/testing" - mt "github.com/golang-migrate/migrate/v4/testing" ) -var versions = []mt.Version{ - {Image: "cassandra:3.0.10"}, - {Image: "cassandra:3.0"}, -} +import ( + "github.com/dhui/dktest" + "github.com/gocql/gocql" +) -func isReady(i mt.Instance) bool { +import ( + dt "github.com/golang-migrate/migrate/v4/database/testing" + "github.com/golang-migrate/migrate/v4/dktesting" +) + +var ( + opts = dktest.Options{PortRequired: true, ReadyFunc: isReady} + specs = []dktesting.ContainerSpec{ + {ImageName: "cassandra:3.0.10", Options: opts}, + {ImageName: "cassandra:3.0", Options: opts}, + } +) + +func isReady(c dktest.ContainerInfo) bool { // Cassandra exposes 5 ports (7000, 7001, 7199, 9042 & 9160) - // We only need the port bound to 9042, but we can only access to the first one - // through 'i.Port()' (which calls DockerContainer.firstPortMapping()) - // So we need to get port mapping to retrieve correct port number bound to 9042 - portMap := i.NetworkSettings().Ports - port, _ := strconv.Atoi(portMap["9042/tcp"][0].HostPort) + // We only need the port bound to 9042 + ip, portStr, err := c.Port(9042) + if err != nil { + return false + } + port, err := strconv.Atoi(portStr) + if err != nil { + return false + } - cluster := gocql.NewCluster(i.Host()) + cluster := gocql.NewCluster(ip) cluster.Port = port cluster.Consistency = gocql.All p, err := cluster.CreateSession() @@ -40,17 +52,18 @@ func isReady(i mt.Instance) bool { } func Test(t *testing.T) { - mt.ParallelTest(t, versions, isReady, - func(t *testing.T, i mt.Instance) { - p := &Cassandra{} - portMap := i.NetworkSettings().Ports - port, _ := strconv.Atoi(portMap["9042/tcp"][0].HostPort) - addr := fmt.Sprintf("cassandra://%v:%v/testks", i.Host(), port) - d, err := p.Open(addr) - if err != nil { - t.Fatalf("%v", err) - } - defer d.Close() - dt.Test(t, d, []byte("SELECT table_name from system_schema.tables")) - }) + dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { + ip, port, err := c.Port(9042) + if err != nil { + t.Fatal("Unable to get mapped port:", err) + } + addr := fmt.Sprintf("cassandra://%v:%v/testks", ip, port) + p := &Cassandra{} + d, err := p.Open(addr) + if err != nil { + t.Fatalf("%v", err) + } + defer d.Close() + dt.Test(t, d, []byte("SELECT table_name from system_schema.tables")) + }) } diff --git a/database/cockroachdb/cockroachdb_test.go b/database/cockroachdb/cockroachdb_test.go index de345e5..0643f02 100644 --- a/database/cockroachdb/cockroachdb_test.go +++ b/database/cockroachdb/cockroachdb_test.go @@ -5,88 +5,130 @@ package cockroachdb import ( "database/sql" "fmt" - "io" "strings" "testing" ) import ( - dt "github.com/golang-migrate/migrate/v4/database/testing" - mt "github.com/golang-migrate/migrate/v4/testing" - "github.com/lib/pq" + "github.com/dhui/dktest" + _ "github.com/lib/pq" ) -var versions = []mt.Version{ - {Image: "cockroachdb/cockroach:v1.0.2", Cmd: []string{"start", "--insecure"}}, -} +import ( + dt "github.com/golang-migrate/migrate/v4/database/testing" + "github.com/golang-migrate/migrate/v4/dktesting" +) -func isReady(i mt.Instance) bool { - db, err := sql.Open("postgres", fmt.Sprintf("postgres://root@%v:%v?sslmode=disable", i.Host(), i.PortFor(26257))) +const defaultPort = 26257 + +var ( + opts = dktest.Options{Cmd: []string{"start", "--insecure"}, PortRequired: true, ReadyFunc: isReady} + specs = []dktesting.ContainerSpec{{ImageName: "cockroachdb/cockroach:v1.0.2", Options: opts}} +) + +func isReady(c dktest.ContainerInfo) bool { + ip, port, err := c.Port(defaultPort) if err != nil { + fmt.Println("port error:", err) return false } - defer db.Close() - err = db.Ping() - if err == io.EOF { - _, err = db.Exec("CREATE DATABASE migrate") - return err == nil - } else if e, ok := err.(*pq.Error); ok { - if e.Code.Name() == "cannot_connect_now" { - return false - } + + db, err := sql.Open("postgres", fmt.Sprintf("postgres://root@%v:%v?sslmode=disable", ip, port)) + if err != nil { + fmt.Println("open error:", err) + return false } - - _, err = db.Exec("CREATE DATABASE migrate") - return err == nil - + if err := db.Ping(); err != nil { + fmt.Println("ping error:", err) + return false + } + db.Close() return true } +func createDB(t *testing.T, c dktest.ContainerInfo) { + ip, port, err := c.Port(defaultPort) + if err != nil { + t.Fatal(err) + } + + db, err := sql.Open("postgres", fmt.Sprintf("postgres://root@%v:%v?sslmode=disable", ip, port)) + if err != nil { + t.Fatal(err) + } + if err = db.Ping(); err != nil { + t.Fatal(err) + } + defer db.Close() + + if _, err = db.Exec("CREATE DATABASE migrate"); err != nil { + t.Fatal(err) + } +} + func Test(t *testing.T) { - mt.ParallelTest(t, versions, isReady, - func(t *testing.T, i mt.Instance) { - c := &CockroachDb{} - addr := fmt.Sprintf("cockroach://root@%v:%v/migrate?sslmode=disable", i.Host(), i.PortFor(26257)) - d, err := c.Open(addr) - if err != nil { - t.Fatalf("%v", err) - } - dt.Test(t, d, []byte("SELECT 1")) - }) + dktesting.ParallelTest(t, specs, func(t *testing.T, ci dktest.ContainerInfo) { + createDB(t, ci) + + ip, port, err := ci.Port(26257) + if err != nil { + t.Fatal(err) + } + + addr := fmt.Sprintf("cockroach://root@%v:%v/migrate?sslmode=disable", ip, port) + c := &CockroachDb{} + d, err := c.Open(addr) + if err != nil { + t.Fatalf("%v", err) + } + dt.Test(t, d, []byte("SELECT 1")) + }) } func TestMultiStatement(t *testing.T) { - mt.ParallelTest(t, versions, isReady, - func(t *testing.T, i mt.Instance) { - c := &CockroachDb{} - addr := fmt.Sprintf("cockroach://root@%v:%v/migrate?sslmode=disable", i.Host(), i.Port()) - d, err := c.Open(addr) - if err != nil { - t.Fatalf("%v", err) - } - if err := d.Run(strings.NewReader("CREATE TABLE foo (foo text); CREATE TABLE bar (bar text);")); err != nil { - t.Fatalf("expected err to be nil, got %v", err) - } + dktesting.ParallelTest(t, specs, func(t *testing.T, ci dktest.ContainerInfo) { + createDB(t, ci) - // make sure second table exists - var exists bool - if err := d.(*CockroachDb).db.QueryRow("SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'bar' AND table_schema = (SELECT current_schema()))").Scan(&exists); err != nil { - t.Fatal(err) - } - if !exists { - t.Fatalf("expected table bar to exist") - } - }) + ip, port, err := ci.Port(26257) + if err != nil { + t.Fatal(err) + } + + addr := fmt.Sprintf("cockroach://root@%v:%v/migrate?sslmode=disable", ip, port) + c := &CockroachDb{} + d, err := c.Open(addr) + if err != nil { + t.Fatalf("%v", err) + } + if err := d.Run(strings.NewReader("CREATE TABLE foo (foo text); CREATE TABLE bar (bar text);")); err != nil { + t.Fatalf("expected err to be nil, got %v", err) + } + + // make sure second table exists + var exists bool + if err := d.(*CockroachDb).db.QueryRow("SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'bar' AND table_schema = (SELECT current_schema()))").Scan(&exists); err != nil { + t.Fatal(err) + } + if !exists { + t.Fatalf("expected table bar to exist") + } + }) } func TestFilterCustomQuery(t *testing.T) { - mt.ParallelTest(t, versions, isReady, - func(t *testing.T, i mt.Instance) { - c := &CockroachDb{} - addr := fmt.Sprintf("cockroach://root@%v:%v/migrate?sslmode=disable&x-custom=foobar", i.Host(), i.PortFor(26257)) - _, err := c.Open(addr) - if err != nil { - t.Fatalf("%v", err) - } - }) + dktesting.ParallelTest(t, specs, func(t *testing.T, ci dktest.ContainerInfo) { + createDB(t, ci) + + ip, port, err := ci.Port(26257) + if err != nil { + t.Fatal(err) + } + + addr := fmt.Sprintf("cockroach://root@%v:%v/migrate?sslmode=disable&x-custom=foobar", ip, port) + c := &CockroachDb{} + _, err = c.Open(addr) + if err != nil { + t.Fatalf("%v", err) + } + }) } diff --git a/database/mongodb/mongodb_test.go b/database/mongodb/mongodb_test.go index 3fb02d9..9e09711 100644 --- a/database/mongodb/mongodb_test.go +++ b/database/mongodb/mongodb_test.go @@ -9,26 +9,40 @@ import ( "strconv" "testing" "time" +) - dt "github.com/golang-migrate/migrate/v4/database/testing" - mt "github.com/golang-migrate/migrate/v4/testing" +import ( + "github.com/dhui/dktest" "github.com/mongodb/mongo-go-driver/bson" "github.com/mongodb/mongo-go-driver/mongo" ) -var versions = []mt.Version{ - {Image: "mongo:4"}, - {Image: "mongo:3"}, +import ( + dt "github.com/golang-migrate/migrate/v4/database/testing" + "github.com/golang-migrate/migrate/v4/dktesting" +) + +var ( + opts = dktest.Options{PortRequired: true, ReadyFunc: isReady} + specs = []dktesting.ContainerSpec{ + {ImageName: "mongo:4", Options: opts}, + {ImageName: "mongo:3", Options: opts}, + } +) + +func mongoConnectionString(host, port string) string { + // there is connect option for excluding serverConnection algorithm + // it's let avoid errors with mongo replica set connection in docker container + return fmt.Sprintf("mongodb://%s:%s/testMigration?connect=single", host, port) } -func mongoConnectionString(host string, port uint) string { - //there is connect option for excluding serverConnection algorithm - //it's let avoid errors with mongo replica set connection in docker container - return fmt.Sprintf("mongodb://%s:%v/testMigration?connect=single", host, port) -} +func isReady(c dktest.ContainerInfo) bool { + ip, port, err := c.FirstPort() + if err != nil { + return false + } -func isReady(i mt.Instance) bool { - client, err := mongo.Connect(context.TODO(), mongoConnectionString(i.Host(), i.Port())) + client, err := mongo.Connect(context.TODO(), mongoConnectionString(ip, port)) if err != nil { return false } @@ -46,188 +60,195 @@ func isReady(i mt.Instance) bool { } func Test(t *testing.T) { - mt.ParallelTest(t, versions, isReady, - func(t *testing.T, i mt.Instance) { - p := &Mongo{} - addr := mongoConnectionString(i.Host(), i.Port()) - d, err := p.Open(addr) - if err != nil { - t.Fatalf("%v", err) - } - defer d.Close() - dt.TestNilVersion(t, d) - //TestLockAndUnlock(t, d) driver doesn't support lock on database level - dt.TestRun(t, d, bytes.NewReader([]byte(`[{"insert":"hello","documents":[{"wild":"world"}]}]`))) - dt.TestSetVersion(t, d) - dt.TestDrop(t, d) - }) + dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { + ip, port, err := c.FirstPort() + if err != nil { + t.Fatal(err) + } + + addr := mongoConnectionString(ip, port) + p := &Mongo{} + d, err := p.Open(addr) + if err != nil { + t.Fatalf("%v", err) + } + defer d.Close() + dt.TestNilVersion(t, d) + //TestLockAndUnlock(t, d) driver doesn't support lock on database level + dt.TestRun(t, d, bytes.NewReader([]byte(`[{"insert":"hello","documents":[{"wild":"world"}]}]`))) + dt.TestSetVersion(t, d) + dt.TestDrop(t, d) + }) } func TestWithAuth(t *testing.T) { - mt.ParallelTest(t, versions, isReady, - func(t *testing.T, i mt.Instance) { - p := &Mongo{} - addr := mongoConnectionString(i.Host(), i.Port()) - d, err := p.Open(addr) - if err != nil { - t.Fatalf("%v", err) - } - defer d.Close() - createUserCMD := []byte(`[{"createUser":"deminem","pwd":"gogo","roles":[{"role":"readWrite","db":"testMigration"}]}]`) - err = d.Run(bytes.NewReader(createUserCMD)) - if err != nil { - t.Fatalf("%v", err) - } - testcases := []struct { - name string - connectUri string - isErrorExpected bool - }{ - {"right auth data", "mongodb://deminem:gogo@%s:%v/testMigration", false}, - {"wrong auth data", "mongodb://wrong:auth@%s:%v/testMigration", true}, - } - insertCMD := []byte(`[{"insert":"hello","documents":[{"wild":"world"}]}]`) + dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { + ip, port, err := c.FirstPort() + if err != nil { + t.Fatal(err) + } - for _, tcase := range testcases { - //With wrong authenticate `Open` func doesn't return auth error - //Because at the moment golang mongo driver doesn't support auth during connection - //For getting auth error we should execute database command - t.Run(tcase.name, func(t *testing.T) { - mc := &Mongo{} - d, err := mc.Open(fmt.Sprintf(tcase.connectUri, i.Host(), i.Port())) - if err != nil { - t.Fatalf("%v", err) - } - defer d.Close() - err = d.Run(bytes.NewReader(insertCMD)) - switch { - case tcase.isErrorExpected && err == nil: - t.Fatalf("no error when expected") - case !tcase.isErrorExpected && err != nil: - t.Fatalf("unexpected error: %v", err) - } - }) - } - }) + addr := mongoConnectionString(ip, port) + p := &Mongo{} + d, err := p.Open(addr) + if err != nil { + t.Fatalf("%v", err) + } + defer d.Close() + createUserCMD := []byte(`[{"createUser":"deminem","pwd":"gogo","roles":[{"role":"readWrite","db":"testMigration"}]}]`) + err = d.Run(bytes.NewReader(createUserCMD)) + if err != nil { + t.Fatalf("%v", err) + } + testcases := []struct { + name string + connectUri string + isErrorExpected bool + }{ + {"right auth data", "mongodb://deminem:gogo@%s:%v/testMigration", false}, + {"wrong auth data", "mongodb://wrong:auth@%s:%v/testMigration", true}, + } + insertCMD := []byte(`[{"insert":"hello","documents":[{"wild":"world"}]}]`) + + for _, tcase := range testcases { + //With wrong authenticate `Open` func doesn't return auth error + //Because at the moment golang mongo driver doesn't support auth during connection + //For getting auth error we should execute database command + t.Run(tcase.name, func(t *testing.T) { + mc := &Mongo{} + d, err := mc.Open(fmt.Sprintf(tcase.connectUri, ip, port)) + if err != nil { + t.Fatalf("%v", err) + } + defer d.Close() + err = d.Run(bytes.NewReader(insertCMD)) + switch { + case tcase.isErrorExpected && err == nil: + t.Fatalf("no error when expected") + case !tcase.isErrorExpected && err != nil: + t.Fatalf("unexpected error: %v", err) + } + }) + } + }) } func TestTransaction(t *testing.T) { - versionsSupportedTransactions := []mt.Version{ - { - Image: "mongo:4", - Cmd: []string{ - "mongod", - "--bind_ip_all", - "--replSet", "rs0", - }}, + transactionSpecs := []dktesting.ContainerSpec{ + {ImageName: "mongo:4", Options: dktest.Options{PortRequired: true, ReadyFunc: isReady, + Cmd: []string{"mongod", "--bind_ip_all", "--replSet", "rs0"}}}, } - mt.ParallelTest(t, versionsSupportedTransactions, isReady, - func(t *testing.T, i mt.Instance) { - client, err := mongo.Connect(context.TODO(), mongoConnectionString(i.Host(), i.Port())) - if err != nil { - t.Fatalf("%v", err) - } - err = client.Ping(context.TODO(), nil) - if err != nil { - t.Fatalf("%v", err) - } - //rs.initiate() - err = client.Database("admin").RunCommand(context.TODO(), bson.D{{"replSetInitiate", bson.D{}}}).Err() - if err != nil { - t.Fatalf("%v", err) - } - err = waitForReplicaInit(client) - if err != nil { - t.Fatalf("%v", err) - } - d, err := WithInstance(client, &Config{ - DatabaseName: "testMigration", - }) - defer d.Close() - //We have to create collection - //transactions don't support operations with creating new dbs, collections - //Unique index need for checking transaction aborting - insertCMD := []byte(`[ + dktesting.ParallelTest(t, transactionSpecs, func(t *testing.T, c dktest.ContainerInfo) { + ip, port, err := c.FirstPort() + if err != nil { + t.Fatal(err) + } + + client, err := mongo.Connect(context.TODO(), mongoConnectionString(ip, port)) + if err != nil { + t.Fatalf("%v", err) + } + err = client.Ping(context.TODO(), nil) + if err != nil { + t.Fatalf("%v", err) + } + //rs.initiate() + err = client.Database("admin").RunCommand(context.TODO(), bson.D{{"replSetInitiate", bson.D{}}}).Err() + if err != nil { + t.Fatalf("%v", err) + } + err = waitForReplicaInit(client) + if err != nil { + t.Fatalf("%v", err) + } + d, err := WithInstance(client, &Config{ + DatabaseName: "testMigration", + }) + defer d.Close() + //We have to create collection + //transactions don't support operations with creating new dbs, collections + //Unique index need for checking transaction aborting + insertCMD := []byte(`[ {"create":"hello"}, {"createIndexes": "hello", "indexes": [{ - "key": { - "wild": 1 - }, - "name": "unique_wild", - "unique": true, - "background": true - }] + "key": { + "wild": 1 + }, + "name": "unique_wild", + "unique": true, + "background": true + }] }]`) - err = d.Run(bytes.NewReader(insertCMD)) - if err != nil { - t.Fatalf("%v", err) - } - testcases := []struct { - name string - cmds []byte - documentsCount int64 - isErrorExpected bool - }{ - { - name: "success transaction", - cmds: []byte(`[{"insert":"hello","documents":[ + err = d.Run(bytes.NewReader(insertCMD)) + if err != nil { + t.Fatalf("%v", err) + } + testcases := []struct { + name string + cmds []byte + documentsCount int64 + isErrorExpected bool + }{ + { + name: "success transaction", + cmds: []byte(`[{"insert":"hello","documents":[ {"wild":"world"}, {"wild":"west"}, {"wild":"natural"} ] }]`), - documentsCount: 3, - isErrorExpected: false, - }, - { - name: "failure transaction", - //transaction have to be failure - duplicate unique key wild:west - //none of the documents should be added - cmds: []byte(`[{"insert":"hello","documents":[{"wild":"flower"}]}, + documentsCount: 3, + isErrorExpected: false, + }, + { + name: "failure transaction", + //transaction have to be failure - duplicate unique key wild:west + //none of the documents should be added + cmds: []byte(`[{"insert":"hello","documents":[{"wild":"flower"}]}, {"insert":"hello","documents":[ {"wild":"cat"}, {"wild":"west"} ] }]`), - documentsCount: 3, - isErrorExpected: true, - }, - } - for _, tcase := range testcases { - t.Run(tcase.name, func(t *testing.T) { - client, err := mongo.Connect(context.TODO(), mongoConnectionString(i.Host(), i.Port())) - if err != nil { - t.Fatalf("%v", err) - } - err = client.Ping(context.TODO(), nil) - if err != nil { - t.Fatalf("%v", err) - } - d, err := WithInstance(client, &Config{ - DatabaseName: "testMigration", - TransactionMode: true, - }) - if err != nil { - t.Fatalf("%v", err) - } - defer d.Close() - runErr := d.Run(bytes.NewReader(tcase.cmds)) - if runErr != nil { - if !tcase.isErrorExpected { - t.Fatalf("%v", runErr) - } - } - documentsCount, err := client.Database("testMigration").Collection("hello").Count(context.TODO(), nil) - if err != nil { - t.Fatalf("%v", err) - } - if tcase.documentsCount != documentsCount { - t.Fatalf("expected %d and actual %d documents count not equal. run migration error:%s", tcase.documentsCount, documentsCount, runErr) - } + documentsCount: 3, + isErrorExpected: true, + }, + } + for _, tcase := range testcases { + t.Run(tcase.name, func(t *testing.T) { + client, err := mongo.Connect(context.TODO(), mongoConnectionString(ip, port)) + if err != nil { + t.Fatalf("%v", err) + } + err = client.Ping(context.TODO(), nil) + if err != nil { + t.Fatalf("%v", err) + } + d, err := WithInstance(client, &Config{ + DatabaseName: "testMigration", + TransactionMode: true, }) - } - }) + if err != nil { + t.Fatalf("%v", err) + } + defer d.Close() + runErr := d.Run(bytes.NewReader(tcase.cmds)) + if runErr != nil { + if !tcase.isErrorExpected { + t.Fatalf("%v", runErr) + } + } + documentsCount, err := client.Database("testMigration").Collection("hello").Count(context.TODO(), nil) + if err != nil { + t.Fatalf("%v", err) + } + if tcase.documentsCount != documentsCount { + t.Fatalf("expected %d and actual %d documents count not equal. run migration error:%s", tcase.documentsCount, documentsCount, runErr) + } + }) + } + }) } type isMaster struct { diff --git a/database/mysql/mysql_test.go b/database/mysql/mysql_test.go index 13a462c..02a985e 100644 --- a/database/mysql/mysql_test.go +++ b/database/mysql/mysql_test.go @@ -9,23 +9,35 @@ import ( ) import ( + "github.com/dhui/dktest" "github.com/go-sql-driver/mysql" ) import ( dt "github.com/golang-migrate/migrate/v4/database/testing" - mt "github.com/golang-migrate/migrate/v4/testing" + "github.com/golang-migrate/migrate/v4/dktesting" ) -var versions = []mt.Version{ - {Image: "mysql:8", ENV: []string{"MYSQL_ROOT_PASSWORD=root", "MYSQL_DATABASE=public"}}, - {Image: "mysql:5.7", ENV: []string{"MYSQL_ROOT_PASSWORD=root", "MYSQL_DATABASE=public"}}, - {Image: "mysql:5.6", ENV: []string{"MYSQL_ROOT_PASSWORD=root", "MYSQL_DATABASE=public"}}, - {Image: "mysql:5.5", ENV: []string{"MYSQL_ROOT_PASSWORD=root", "MYSQL_DATABASE=public"}}, -} +var ( + opts = dktest.Options{ + Env: map[string]string{"MYSQL_ROOT_PASSWORD": "root", "MYSQL_DATABASE": "public"}, + PortRequired: true, ReadyFunc: isReady, + } + specs = []dktesting.ContainerSpec{ + {ImageName: "mysql:8", Options: opts}, + {ImageName: "mysql:5.7", Options: opts}, + {ImageName: "mysql:5.6", Options: opts}, + {ImageName: "mysql:5.5", Options: opts}, + } +) -func isReady(i mt.Instance) bool { - db, err := sql.Open("mysql", fmt.Sprintf("root:root@tcp(%v:%v)/public", i.Host(), i.Port())) +func isReady(c dktest.ContainerInfo) bool { + ip, port, err := c.FirstPort() + if err != nil { + return false + } + + db, err := sql.Open("mysql", fmt.Sprintf("root:root@tcp(%v:%v)/public", ip, port)) if err != nil { return false } @@ -46,60 +58,68 @@ func isReady(i mt.Instance) bool { func Test(t *testing.T) { // mysql.SetLogger(mysql.Logger(log.New(ioutil.Discard, "", log.Ltime))) - mt.ParallelTest(t, versions, isReady, - func(t *testing.T, i mt.Instance) { - p := &Mysql{} - addr := fmt.Sprintf("mysql://root:root@tcp(%v:%v)/public", i.Host(), i.Port()) - d, err := p.Open(addr) - if err != nil { - t.Fatalf("%v", err) - } - defer d.Close() - dt.Test(t, d, []byte("SELECT 1")) + dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { + ip, port, err := c.FirstPort() + if err != nil { + t.Fatal(err) + } - // check ensureVersionTable - if err := d.(*Mysql).ensureVersionTable(); err != nil { - t.Fatal(err) - } - // check again - if err := d.(*Mysql).ensureVersionTable(); err != nil { - t.Fatal(err) - } - }) + addr := fmt.Sprintf("mysql://root:root@tcp(%v:%v)/public", ip, port) + p := &Mysql{} + d, err := p.Open(addr) + if err != nil { + t.Fatalf("%v", err) + } + defer d.Close() + dt.Test(t, d, []byte("SELECT 1")) + + // check ensureVersionTable + if err := d.(*Mysql).ensureVersionTable(); err != nil { + t.Fatal(err) + } + // check again + if err := d.(*Mysql).ensureVersionTable(); err != nil { + t.Fatal(err) + } + }) } func TestLockWorks(t *testing.T) { - mt.ParallelTest(t, versions, isReady, - func(t *testing.T, i mt.Instance) { - p := &Mysql{} - addr := fmt.Sprintf("mysql://root:root@tcp(%v:%v)/public", i.Host(), i.Port()) - d, err := p.Open(addr) - if err != nil { - t.Fatalf("%v", err) - } - dt.Test(t, d, []byte("SELECT 1")) + dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { + ip, port, err := c.FirstPort() + if err != nil { + t.Fatal(err) + } - ms := d.(*Mysql) + addr := fmt.Sprintf("mysql://root:root@tcp(%v:%v)/public", ip, port) + p := &Mysql{} + d, err := p.Open(addr) + if err != nil { + t.Fatalf("%v", err) + } + dt.Test(t, d, []byte("SELECT 1")) - err = ms.Lock() - if err != nil { - t.Fatal(err) - } - err = ms.Unlock() - if err != nil { - t.Fatal(err) - } + ms := d.(*Mysql) - // make sure the 2nd lock works (RELEASE_LOCK is very finicky) - err = ms.Lock() - if err != nil { - t.Fatal(err) - } - err = ms.Unlock() - if err != nil { - t.Fatal(err) - } - }) + err = ms.Lock() + if err != nil { + t.Fatal(err) + } + err = ms.Unlock() + if err != nil { + t.Fatal(err) + } + + // make sure the 2nd lock works (RELEASE_LOCK is very finicky) + err = ms.Lock() + if err != nil { + t.Fatal(err) + } + err = ms.Unlock() + if err != nil { + t.Fatal(err) + } + }) } func TestURLToMySQLConfig(t *testing.T) { diff --git a/database/postgres/postgres_test.go b/database/postgres/postgres_test.go index 70425a4..efe816e 100644 --- a/database/postgres/postgres_test.go +++ b/database/postgres/postgres_test.go @@ -14,24 +14,36 @@ import ( ) import ( - dt "github.com/golang-migrate/migrate/v4/database/testing" - mt "github.com/golang-migrate/migrate/v4/testing" + "github.com/dhui/dktest" ) -var versions = []mt.Version{ - {Image: "postgres:10"}, - {Image: "postgres:9.6"}, - {Image: "postgres:9.5"}, - {Image: "postgres:9.4"}, - {Image: "postgres:9.3"}, +import ( + dt "github.com/golang-migrate/migrate/v4/database/testing" + "github.com/golang-migrate/migrate/v4/dktesting" +) + +var ( + opts = dktest.Options{PortRequired: true, ReadyFunc: isReady} + specs = []dktesting.ContainerSpec{ + {ImageName: "postgres:10", Options: opts}, + {ImageName: "postgres:9.6", Options: opts}, + {ImageName: "postgres:9.5", Options: opts}, + {ImageName: "postgres:9.4", Options: opts}, + {ImageName: "postgres:9.3", Options: opts}, + } +) + +func pgConnectionString(host, port string) string { + return fmt.Sprintf("postgres://postgres@%s:%s/postgres?sslmode=disable", host, port) } -func pgConnectionString(host string, port uint) string { - return fmt.Sprintf("postgres://postgres@%s:%v/postgres?sslmode=disable", host, port) -} +func isReady(c dktest.ContainerInfo) bool { + ip, port, err := c.FirstPort() + if err != nil { + return false + } -func isReady(i mt.Instance) bool { - db, err := sql.Open("postgres", pgConnectionString(i.Host(), i.Port())) + db, err := sql.Open("postgres", pgConnectionString(ip, port)) if err != nil { return false } @@ -50,183 +62,207 @@ func isReady(i mt.Instance) bool { } func Test(t *testing.T) { - mt.ParallelTest(t, versions, isReady, - func(t *testing.T, i mt.Instance) { - p := &Postgres{} - addr := pgConnectionString(i.Host(), i.Port()) - d, err := p.Open(addr) - if err != nil { - t.Fatalf("%v", err) - } - defer d.Close() - dt.Test(t, d, []byte("SELECT 1")) - }) + dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { + ip, port, err := c.FirstPort() + if err != nil { + t.Fatal(err) + } + + addr := pgConnectionString(ip, port) + p := &Postgres{} + d, err := p.Open(addr) + if err != nil { + t.Fatalf("%v", err) + } + defer d.Close() + dt.Test(t, d, []byte("SELECT 1")) + }) } func TestMultiStatement(t *testing.T) { - mt.ParallelTest(t, versions, isReady, - func(t *testing.T, i mt.Instance) { - p := &Postgres{} - addr := pgConnectionString(i.Host(), i.Port()) - d, err := p.Open(addr) - if err != nil { - t.Fatalf("%v", err) - } - defer d.Close() - if err := d.Run(strings.NewReader("CREATE TABLE foo (foo text); CREATE TABLE bar (bar text);")); err != nil { - t.Fatalf("expected err to be nil, got %v", err) - } + dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { + ip, port, err := c.FirstPort() + if err != nil { + t.Fatal(err) + } - // make sure second table exists - var exists bool - if err := d.(*Postgres).conn.QueryRowContext(context.Background(), "SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'bar' AND table_schema = (SELECT current_schema()))").Scan(&exists); err != nil { - t.Fatal(err) - } - if !exists { - t.Fatalf("expected table bar to exist") - } - }) + addr := pgConnectionString(ip, port) + p := &Postgres{} + d, err := p.Open(addr) + if err != nil { + t.Fatalf("%v", err) + } + defer d.Close() + if err := d.Run(strings.NewReader("CREATE TABLE foo (foo text); CREATE TABLE bar (bar text);")); err != nil { + t.Fatalf("expected err to be nil, got %v", err) + } + + // make sure second table exists + var exists bool + if err := d.(*Postgres).conn.QueryRowContext(context.Background(), "SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'bar' AND table_schema = (SELECT current_schema()))").Scan(&exists); err != nil { + t.Fatal(err) + } + if !exists { + t.Fatalf("expected table bar to exist") + } + }) } func TestErrorParsing(t *testing.T) { - mt.ParallelTest(t, versions, isReady, - func(t *testing.T, i mt.Instance) { - p := &Postgres{} - addr := pgConnectionString(i.Host(), i.Port()) - d, err := p.Open(addr) - if err != nil { - t.Fatalf("%v", err) - } - defer d.Close() + dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { + ip, port, err := c.FirstPort() + if err != nil { + t.Fatal(err) + } - wantErr := `migration failed: syntax error at or near "TABLEE" (column 37) in line 1: CREATE TABLE foo ` + - `(foo text); CREATE TABLEE bar (bar text); (details: pq: syntax error at or near "TABLEE")` - if err := d.Run(strings.NewReader("CREATE TABLE foo (foo text); CREATE TABLEE bar (bar text);")); err == nil { - t.Fatal("expected err but got nil") - } else if err.Error() != wantErr { - t.Fatalf("expected '%s' but got '%s'", wantErr, err.Error()) - } - }) + addr := pgConnectionString(ip, port) + p := &Postgres{} + d, err := p.Open(addr) + if err != nil { + t.Fatalf("%v", err) + } + defer d.Close() + + wantErr := `migration failed: syntax error at or near "TABLEE" (column 37) in line 1: CREATE TABLE foo ` + + `(foo text); CREATE TABLEE bar (bar text); (details: pq: syntax error at or near "TABLEE")` + if err := d.Run(strings.NewReader("CREATE TABLE foo (foo text); CREATE TABLEE bar (bar text);")); err == nil { + t.Fatal("expected err but got nil") + } else if err.Error() != wantErr { + t.Fatalf("expected '%s' but got '%s'", wantErr, err.Error()) + } + }) } func TestFilterCustomQuery(t *testing.T) { - mt.ParallelTest(t, versions, isReady, - func(t *testing.T, i mt.Instance) { - p := &Postgres{} - addr := fmt.Sprintf("postgres://postgres@%v:%v/postgres?sslmode=disable&x-custom=foobar", i.Host(), i.Port()) - d, err := p.Open(addr) - if err != nil { - t.Fatalf("%v", err) - } - defer d.Close() - }) + dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { + ip, port, err := c.FirstPort() + if err != nil { + t.Fatal(err) + } + + addr := fmt.Sprintf("postgres://postgres@%v:%v/postgres?sslmode=disable&x-custom=foobar", ip, port) + p := &Postgres{} + d, err := p.Open(addr) + if err != nil { + t.Fatalf("%v", err) + } + defer d.Close() + }) } func TestWithSchema(t *testing.T) { - mt.ParallelTest(t, versions, isReady, - func(t *testing.T, i mt.Instance) { - p := &Postgres{} - addr := pgConnectionString(i.Host(), i.Port()) - d, err := p.Open(addr) - if err != nil { - t.Fatalf("%v", err) - } - defer d.Close() + dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { + ip, port, err := c.FirstPort() + if err != nil { + t.Fatal(err) + } - // create foobar schema - if err := d.Run(strings.NewReader("CREATE SCHEMA foobar AUTHORIZATION postgres")); err != nil { - t.Fatal(err) - } - if err := d.SetVersion(1, false); err != nil { - t.Fatal(err) - } + addr := pgConnectionString(ip, port) + p := &Postgres{} + d, err := p.Open(addr) + if err != nil { + t.Fatalf("%v", err) + } + defer d.Close() - // re-connect using that schema - d2, err := p.Open(fmt.Sprintf("postgres://postgres@%v:%v/postgres?sslmode=disable&search_path=foobar", i.Host(), i.Port())) - if err != nil { - t.Fatalf("%v", err) - } - defer d2.Close() + // create foobar schema + if err := d.Run(strings.NewReader("CREATE SCHEMA foobar AUTHORIZATION postgres")); err != nil { + t.Fatal(err) + } + if err := d.SetVersion(1, false); err != nil { + t.Fatal(err) + } - version, _, err := d2.Version() - if err != nil { - t.Fatal(err) - } - if version != -1 { - t.Fatal("expected NilVersion") - } + // re-connect using that schema + d2, err := p.Open(fmt.Sprintf("postgres://postgres@%v:%v/postgres?sslmode=disable&search_path=foobar", ip, port)) + if err != nil { + t.Fatalf("%v", err) + } + defer d2.Close() - // now update version and compare - if err := d2.SetVersion(2, false); err != nil { - t.Fatal(err) - } - version, _, err = d2.Version() - if err != nil { - t.Fatal(err) - } - if version != 2 { - t.Fatal("expected version 2") - } + version, _, err := d2.Version() + if err != nil { + t.Fatal(err) + } + if version != -1 { + t.Fatal("expected NilVersion") + } - // meanwhile, the public schema still has the other version - version, _, err = d.Version() - if err != nil { - t.Fatal(err) - } - if version != 1 { - t.Fatal("expected version 2") - } - }) + // now update version and compare + if err := d2.SetVersion(2, false); err != nil { + t.Fatal(err) + } + version, _, err = d2.Version() + if err != nil { + t.Fatal(err) + } + if version != 2 { + t.Fatal("expected version 2") + } + + // meanwhile, the public schema still has the other version + version, _, err = d.Version() + if err != nil { + t.Fatal(err) + } + if version != 1 { + t.Fatal("expected version 2") + } + }) } func TestParallelSchema(t *testing.T) { - mt.ParallelTest(t, versions, isReady, - func(t *testing.T, i mt.Instance) { - p := &Postgres{} - addr := pgConnectionString(i.Host(), i.Port()) - d, err := p.Open(addr) - if err != nil { - t.Fatalf("%v", err) - } - defer d.Close() + dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { + ip, port, err := c.FirstPort() + if err != nil { + t.Fatal(err) + } - // create foo and bar schemas - if err := d.Run(strings.NewReader("CREATE SCHEMA foo AUTHORIZATION postgres")); err != nil { - t.Fatal(err) - } - if err := d.Run(strings.NewReader("CREATE SCHEMA bar AUTHORIZATION postgres")); err != nil { - t.Fatal(err) - } + addr := pgConnectionString(ip, port) + p := &Postgres{} + d, err := p.Open(addr) + if err != nil { + t.Fatalf("%v", err) + } + defer d.Close() - // re-connect using that schemas - dfoo, err := p.Open(fmt.Sprintf("postgres://postgres@%v:%v/postgres?sslmode=disable&search_path=foo", i.Host(), i.Port())) - if err != nil { - t.Fatalf("%v", err) - } - defer dfoo.Close() + // create foo and bar schemas + if err := d.Run(strings.NewReader("CREATE SCHEMA foo AUTHORIZATION postgres")); err != nil { + t.Fatal(err) + } + if err := d.Run(strings.NewReader("CREATE SCHEMA bar AUTHORIZATION postgres")); err != nil { + t.Fatal(err) + } - dbar, err := p.Open(fmt.Sprintf("postgres://postgres@%v:%v/postgres?sslmode=disable&search_path=bar", i.Host(), i.Port())) - if err != nil { - t.Fatalf("%v", err) - } - defer dbar.Close() + // re-connect using that schemas + dfoo, err := p.Open(fmt.Sprintf("postgres://postgres@%v:%v/postgres?sslmode=disable&search_path=foo", ip, port)) + if err != nil { + t.Fatalf("%v", err) + } + defer dfoo.Close() - if err := dfoo.Lock(); err != nil { - t.Fatal(err) - } + dbar, err := p.Open(fmt.Sprintf("postgres://postgres@%v:%v/postgres?sslmode=disable&search_path=bar", ip, port)) + if err != nil { + t.Fatalf("%v", err) + } + defer dbar.Close() - if err := dbar.Lock(); err != nil { - t.Fatal(err) - } + if err := dfoo.Lock(); err != nil { + t.Fatal(err) + } - if err := dbar.Unlock(); err != nil { - t.Fatal(err) - } + if err := dbar.Lock(); err != nil { + t.Fatal(err) + } - if err := dfoo.Unlock(); err != nil { - t.Fatal(err) - } - }) + if err := dbar.Unlock(); err != nil { + t.Fatal(err) + } + + if err := dfoo.Unlock(); err != nil { + t.Fatal(err) + } + }) } func TestWithInstance(t *testing.T) { @@ -234,39 +270,43 @@ func TestWithInstance(t *testing.T) { } func TestPostgres_Lock(t *testing.T) { - mt.ParallelTest(t, versions, isReady, - func(t *testing.T, i mt.Instance) { - p := &Postgres{} - addr := pgConnectionString(i.Host(), i.Port()) - d, err := p.Open(addr) - if err != nil { - t.Fatalf("%v", err) - } + dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { + ip, port, err := c.FirstPort() + if err != nil { + t.Fatal(err) + } - dt.Test(t, d, []byte("SELECT 1")) + addr := pgConnectionString(ip, port) + p := &Postgres{} + d, err := p.Open(addr) + if err != nil { + t.Fatalf("%v", err) + } - ps := d.(*Postgres) + dt.Test(t, d, []byte("SELECT 1")) - err = ps.Lock() - if err != nil { - t.Fatal(err) - } + ps := d.(*Postgres) - err = ps.Unlock() - if err != nil { - t.Fatal(err) - } + err = ps.Lock() + if err != nil { + t.Fatal(err) + } - err = ps.Lock() - if err != nil { - t.Fatal(err) - } + err = ps.Unlock() + if err != nil { + t.Fatal(err) + } - err = ps.Unlock() - if err != nil { - t.Fatal(err) - } - }) + err = ps.Lock() + if err != nil { + t.Fatal(err) + } + + err = ps.Unlock() + if err != nil { + t.Fatal(err) + } + }) } func Test_computeLineFromPos(t *testing.T) { diff --git a/database/redshift/redshift_test.go b/database/redshift/redshift_test.go index 87be74c..37f0995 100644 --- a/database/redshift/redshift_test.go +++ b/database/redshift/redshift_test.go @@ -12,29 +12,43 @@ import ( "strconv" "strings" "testing" - - dt "github.com/golang-migrate/migrate/v4/database/testing" - mt "github.com/golang-migrate/migrate/v4/testing" ) -var versions = []mt.Version{ - {Image: "postgres:8"}, -} +import ( + "github.com/dhui/dktest" +) -func redshiftConnectionString(host string, port uint) string { +import ( + dt "github.com/golang-migrate/migrate/v4/database/testing" + "github.com/golang-migrate/migrate/v4/dktesting" +) + +var ( + opts = dktest.Options{PortRequired: true, ReadyFunc: isReady} + specs = []dktesting.ContainerSpec{ + {ImageName: "postgres:8", Options: opts}, + } +) + +func redshiftConnectionString(host, port string) string { return connectionString("redshift", host, port) } -func pgConnectionString(host string, port uint) string { +func pgConnectionString(host, port string) string { return connectionString("postgres", host, port) } -func connectionString(schema, host string, port uint) string { - return fmt.Sprintf("%s://postgres@%s:%v/postgres?sslmode=disable", schema, host, port) +func connectionString(schema, host, port string) string { + return fmt.Sprintf("%s://postgres@%s:%s/postgres?sslmode=disable", schema, host, port) } -func isReady(i mt.Instance) bool { - db, err := sql.Open("postgres", pgConnectionString(i.Host(), i.Port())) +func isReady(c dktest.ContainerInfo) bool { + ip, port, err := c.FirstPort() + if err != nil { + return false + } + + db, err := sql.Open("postgres", pgConnectionString(ip, port)) if err != nil { return false } @@ -53,133 +67,153 @@ func isReady(i mt.Instance) bool { } func Test(t *testing.T) { - mt.ParallelTest(t, versions, isReady, - func(t *testing.T, i mt.Instance) { - p := &Redshift{} - addr := redshiftConnectionString(i.Host(), i.Port()) - d, err := p.Open(addr) - if err != nil { - t.Fatalf("%v", err) - } - defer d.Close() - dt.Test(t, d, []byte("SELECT 1")) - }) + dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { + ip, port, err := c.FirstPort() + if err != nil { + t.Fatal(err) + } + + addr := redshiftConnectionString(ip, port) + p := &Redshift{} + d, err := p.Open(addr) + if err != nil { + t.Fatalf("%v", err) + } + defer d.Close() + dt.Test(t, d, []byte("SELECT 1")) + }) } func TestMultiStatement(t *testing.T) { - mt.ParallelTest(t, versions, isReady, - func(t *testing.T, i mt.Instance) { - p := &Redshift{} - addr := redshiftConnectionString(i.Host(), i.Port()) - d, err := p.Open(addr) - if err != nil { - t.Fatalf("%v", err) - } - defer d.Close() - if err := d.Run(bytes.NewReader([]byte("CREATE TABLE foo (foo text); CREATE TABLE bar (bar text);"))); err != nil { - t.Fatalf("expected err to be nil, got %v", err) - } + dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { + ip, port, err := c.FirstPort() + if err != nil { + t.Fatal(err) + } - // make sure second table exists - var exists bool - if err := d.(*Redshift).conn.QueryRowContext(context.Background(), "SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'bar' AND table_schema = (SELECT current_schema()))").Scan(&exists); err != nil { - t.Fatal(err) - } - if !exists { - t.Fatalf("expected table bar to exist") - } - }) + addr := redshiftConnectionString(ip, port) + p := &Redshift{} + d, err := p.Open(addr) + if err != nil { + t.Fatalf("%v", err) + } + defer d.Close() + if err := d.Run(bytes.NewReader([]byte("CREATE TABLE foo (foo text); CREATE TABLE bar (bar text);"))); err != nil { + t.Fatalf("expected err to be nil, got %v", err) + } + + // make sure second table exists + var exists bool + if err := d.(*Redshift).conn.QueryRowContext(context.Background(), "SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'bar' AND table_schema = (SELECT current_schema()))").Scan(&exists); err != nil { + t.Fatal(err) + } + if !exists { + t.Fatalf("expected table bar to exist") + } + }) } func TestErrorParsing(t *testing.T) { - mt.ParallelTest(t, versions, isReady, - func(t *testing.T, i mt.Instance) { - p := &Redshift{} - addr := redshiftConnectionString(i.Host(), i.Port()) - d, err := p.Open(addr) - if err != nil { - t.Fatalf("%v", err) - } - defer d.Close() + dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { + ip, port, err := c.FirstPort() + if err != nil { + t.Fatal(err) + } - wantErr := `migration failed: syntax error at or near "TABLEE" (column 37) in line 1: CREATE TABLE foo ` + - `(foo text); CREATE TABLEE bar (bar text); (details: pq: syntax error at or near "TABLEE")` - if err := d.Run(bytes.NewReader([]byte("CREATE TABLE foo (foo text); CREATE TABLEE bar (bar text);"))); err == nil { - t.Fatal("expected err but got nil") - } else if err.Error() != wantErr { - t.Fatalf("expected '%s' but got '%s'", wantErr, err.Error()) - } - }) + addr := redshiftConnectionString(ip, port) + p := &Redshift{} + d, err := p.Open(addr) + if err != nil { + t.Fatalf("%v", err) + } + defer d.Close() + + wantErr := `migration failed: syntax error at or near "TABLEE" (column 37) in line 1: CREATE TABLE foo ` + + `(foo text); CREATE TABLEE bar (bar text); (details: pq: syntax error at or near "TABLEE")` + if err := d.Run(bytes.NewReader([]byte("CREATE TABLE foo (foo text); CREATE TABLEE bar (bar text);"))); err == nil { + t.Fatal("expected err but got nil") + } else if err.Error() != wantErr { + t.Fatalf("expected '%s' but got '%s'", wantErr, err.Error()) + } + }) } func TestFilterCustomQuery(t *testing.T) { - mt.ParallelTest(t, versions, isReady, - func(t *testing.T, i mt.Instance) { - p := &Redshift{} - addr := fmt.Sprintf("postgres://postgres@%v:%v/postgres?sslmode=disable&x-custom=foobar", i.Host(), i.Port()) - d, err := p.Open(addr) - if err != nil { - t.Fatalf("%v", err) - } - defer d.Close() - }) + dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { + ip, port, err := c.FirstPort() + if err != nil { + t.Fatal(err) + } + + addr := fmt.Sprintf("postgres://postgres@%v:%v/postgres?sslmode=disable&x-custom=foobar", ip, port) + p := &Redshift{} + d, err := p.Open(addr) + if err != nil { + t.Fatalf("%v", err) + } + defer d.Close() + }) } func TestWithSchema(t *testing.T) { - mt.ParallelTest(t, versions, isReady, - func(t *testing.T, i mt.Instance) { - p := &Redshift{} - addr := redshiftConnectionString(i.Host(), i.Port()) - d, err := p.Open(addr) - if err != nil { - t.Fatalf("%v", err) - } - defer d.Close() + dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { + ip, port, err := c.FirstPort() + if err != nil { + t.Fatal(err) + } - // create foobar schema - if err := d.Run(bytes.NewReader([]byte("CREATE SCHEMA foobar AUTHORIZATION postgres"))); err != nil { - t.Fatal(err) - } - if err := d.SetVersion(1, false); err != nil { - t.Fatal(err) - } + addr := redshiftConnectionString(ip, port) + p := &Redshift{} + d, err := p.Open(addr) + if err != nil { + t.Fatalf("%v", err) + } + defer d.Close() - // re-connect using that schema - d2, err := p.Open(fmt.Sprintf("postgres://postgres@%v:%v/postgres?sslmode=disable&search_path=foobar", i.Host(), i.Port())) - if err != nil { - t.Fatalf("%v", err) - } - defer d2.Close() + // create foobar schema + if err := d.Run(bytes.NewReader([]byte("CREATE SCHEMA foobar AUTHORIZATION postgres"))); err != nil { + t.Fatal(err) + } + if err := d.SetVersion(1, false); err != nil { + t.Fatal(err) + } - version, _, err := d2.Version() - if err != nil { - t.Fatal(err) - } - if version != -1 { - t.Fatal("expected NilVersion") - } + // re-connect using that schema + d2, err := p.Open(fmt.Sprintf("postgres://postgres@%v:%v/postgres?sslmode=disable&search_path=foobar", ip, port)) + if err != nil { + t.Fatalf("%v", err) + } + defer d2.Close() - // now update version and compare - if err := d2.SetVersion(2, false); err != nil { - t.Fatal(err) - } - version, _, err = d2.Version() - if err != nil { - t.Fatal(err) - } - if version != 2 { - t.Fatal("expected version 2") - } + version, _, err := d2.Version() + if err != nil { + t.Fatal(err) + } + if version != -1 { + t.Fatal("expected NilVersion") + } - // meanwhile, the public schema still has the other version - version, _, err = d.Version() - if err != nil { - t.Fatal(err) - } - if version != 1 { - t.Fatal("expected version 2") - } - }) + // now update version and compare + if err := d2.SetVersion(2, false); err != nil { + t.Fatal(err) + } + version, _, err = d2.Version() + if err != nil { + t.Fatal(err) + } + if version != 2 { + t.Fatal("expected version 2") + } + + // meanwhile, the public schema still has the other version + version, _, err = d.Version() + if err != nil { + t.Fatal(err) + } + if version != 1 { + t.Fatal("expected version 2") + } + }) } func TestWithInstance(t *testing.T) { @@ -187,39 +221,43 @@ func TestWithInstance(t *testing.T) { } func TestRedshift_Lock(t *testing.T) { - mt.ParallelTest(t, versions, isReady, - func(t *testing.T, i mt.Instance) { - p := &Redshift{} - addr := pgConnectionString(i.Host(), i.Port()) - d, err := p.Open(addr) - if err != nil { - t.Fatalf("%v", err) - } + dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { + ip, port, err := c.FirstPort() + if err != nil { + t.Fatal(err) + } - dt.Test(t, d, []byte("SELECT 1")) + addr := pgConnectionString(ip, port) + p := &Redshift{} + d, err := p.Open(addr) + if err != nil { + t.Fatalf("%v", err) + } - ps := d.(*Redshift) + dt.Test(t, d, []byte("SELECT 1")) - err = ps.Lock() - if err != nil { - t.Fatal(err) - } + ps := d.(*Redshift) - err = ps.Unlock() - if err != nil { - t.Fatal(err) - } + err = ps.Lock() + if err != nil { + t.Fatal(err) + } - err = ps.Lock() - if err != nil { - t.Fatal(err) - } + err = ps.Unlock() + if err != nil { + t.Fatal(err) + } - err = ps.Unlock() - if err != nil { - t.Fatal(err) - } - }) + err = ps.Lock() + if err != nil { + t.Fatal(err) + } + + err = ps.Unlock() + if err != nil { + t.Fatal(err) + } + }) } func Test_computeLineFromPos(t *testing.T) { diff --git a/dktesting/dktesting.go b/dktesting/dktesting.go new file mode 100644 index 0000000..342af2f --- /dev/null +++ b/dktesting/dktesting.go @@ -0,0 +1,35 @@ +package dktesting + +import ( + "testing" +) + +import ( + "github.com/dhui/dktest" +) + +// ContainerSpec holds Docker testing setup specifications +type ContainerSpec struct { + ImageName string + Options dktest.Options +} + +// ParallelTest runs Docker tests in parallel +func ParallelTest(t *testing.T, specs []ContainerSpec, + testFunc func(*testing.T, dktest.ContainerInfo)) { + + for i, spec := range specs { + spec := spec // capture range variable, see https://goo.gl/60w3p2 + + // Only test against one version in short mode + // TODO: order is random, maybe always pick first version instead? + if i > 0 && testing.Short() { + t.Logf("Skipping %v in short mode", spec.ImageName) + } else { + t.Run(spec.ImageName, func(t *testing.T) { + t.Parallel() + dktest.Run(t, spec.ImageName, spec.Options, testFunc) + }) + } + } +} diff --git a/dktesting/example_test.go b/dktesting/example_test.go new file mode 100644 index 0000000..4561692 --- /dev/null +++ b/dktesting/example_test.go @@ -0,0 +1,29 @@ +package dktesting_test + +import ( + "testing" +) + +import ( + "github.com/dhui/dktest" +) + +import ( + "github.com/golang-migrate/migrate/v4/dktesting" +) + +func ExampleParallelTest() { + t := &testing.T{} // Should actually be used in a Test + + var isReady = func(c dktest.ContainerInfo) bool { + // Return true if the container is ready to run tests. + // Don't block here though. + return true + } + + dktesting.ParallelTest(t, []dktesting.ContainerSpec{{ImageName: "docker_image:9.6", + Options: dktest.Options{ReadyFunc: isReady}}}, func(t *testing.T, c dktest.ContainerInfo) { + // Run your test/s ... + t.Fatal("...") + }) +} diff --git a/go.mod b/go.mod index bf695e3..c248f24 100644 --- a/go.mod +++ b/go.mod @@ -1,32 +1,24 @@ module github.com/golang-migrate/migrate/v4 require ( - cloud.google.com/go v0.30.0 - github.com/Microsoft/go-winio v0.4.11 // indirect + cloud.google.com/go v0.34.0 github.com/aws/aws-sdk-go v1.15.54 github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 // indirect github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect github.com/cockroachdb/apd v1.1.0 // indirect github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c github.com/cznic/ql v1.2.0 - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/docker/distribution v0.0.0-20180720172123-0dae0957e5fe // indirect - github.com/docker/docker v0.7.3-0.20180221142240-453f2b8b40b9 - github.com/docker/go-connections v0.4.0 // indirect - github.com/docker/go-units v0.3.3 // indirect + github.com/dhui/dktest v0.2.2 + github.com/docker/docker v0.7.3-0.20190108045446-77df18c24acf github.com/fsouza/fake-gcs-server v1.3.0 github.com/go-ini/ini v1.39.0 // indirect github.com/go-sql-driver/mysql v1.4.1 github.com/go-stack/stack v1.8.0 // indirect github.com/gocql/gocql v0.0.0-20181012100315-44e29ed5b8a4 - github.com/gogo/protobuf v1.1.1 // indirect - github.com/google/go-cmp v0.2.0 // indirect github.com/google/go-github v17.0.0+incompatible github.com/google/go-querystring v1.0.0 // indirect github.com/google/martian v2.1.0+incompatible // indirect github.com/gopherjs/gopherjs v0.0.0-20181004151105-1babbf986f6f // indirect - github.com/gorilla/context v1.1.1 // indirect - github.com/gotestyourself/gotestyourself v2.1.0+incompatible // indirect github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect github.com/jackc/pgx v3.2.0+incompatible // indirect github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect @@ -36,25 +28,25 @@ require ( github.com/lib/pq v1.0.0 github.com/mattn/go-sqlite3 v1.9.0 github.com/mongodb/mongo-go-driver v0.1.0 - github.com/opencontainers/go-digest v1.0.0-rc1 // indirect - github.com/opencontainers/image-spec v1.0.1 // indirect - github.com/pkg/errors v0.8.0 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pkg/errors v0.8.1 // indirect github.com/satori/go.uuid v1.2.0 // indirect github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 // indirect + github.com/sirupsen/logrus v1.3.0 // indirect github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a // indirect - github.com/stretchr/testify v1.2.2 // indirect + github.com/stretchr/testify v1.3.0 // indirect + github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51 // indirect github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c // indirect github.com/xdg/stringprep v1.0.0 // indirect - golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9 // indirect - golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1 - golang.org/x/oauth2 v0.0.0-20181003184128-c57b0facaced // indirect - golang.org/x/sys v0.0.0-20181011152604-fa43e7bc11ba // indirect - golang.org/x/tools v0.0.0-20181015201034-8919434dde1e + golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc // indirect + golang.org/x/net v0.0.0-20190107210223-45ffb0cd1ba0 + golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890 // indirect + golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 // indirect + golang.org/x/sys v0.0.0-20190108104531-7fbe1cd0fcc2 // indirect + golang.org/x/tools v0.0.0-20190107155254-e063def13b29 google.golang.org/api v0.0.0-20181015145326-625cd1887957 - google.golang.org/genproto v0.0.0-20181004005441-af9cb2a35e7f + google.golang.org/appengine v1.4.0 // indirect + google.golang.org/genproto v0.0.0-20181221175505-bd9b4fb69e2f gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect gopkg.in/ini.v1 v1.39.0 // indirect - gotest.tools v2.1.0+incompatible // indirect ) diff --git a/go.sum b/go.sum index 09fe59d..3df608c 100644 --- a/go.sum +++ b/go.sum @@ -1,12 +1,16 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.28.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.30.0 h1:xKvyLgk56d0nksWq49J0UyGEeUIicTl4+UBiX1NPX9g= -cloud.google.com/go v0.30.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= contrib.go.opencensus.io/exporter/stackdriver v0.6.0/go.mod h1:QeFzMJDAw8TXt5+aRaSuE8l5BwaMIOIlaVkBOPRuMuw= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= git.apache.org/thrift.git v0.0.0-20180924222215-a9235805469b/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Microsoft/go-winio v0.4.11 h1:zoIOcVf0xPN1tnMVbTtEdI+P8OofVk3NObnwOQ6nK2Q= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/aws/aws-sdk-go v1.15.54 h1:yNFryYgHYlEuNnMM74EZgAaOM2BsJvu77/ev9I9GHlU= github.com/aws/aws-sdk-go v1.15.54/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -39,12 +43,17 @@ github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186 h1:0rkFMAbn5KBKNpJyH github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc= github.com/cznic/zappy v0.0.0-20160723133515-2533cb5b45cc h1:YKKpTb2BrXN2GYyGaygIdis1vXbE7SSAG9axGWIMClg= github.com/cznic/zappy v0.0.0-20160723133515-2533cb5b45cc/go.mod h1:Y1SNZ4dRUOKXshKUbwUapqNncRrho4mkjQebgEHZLj8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/docker/distribution v0.0.0-20180720172123-0dae0957e5fe h1:ZRQNMB7Sw5jf9g/0imDbI+vTFNk4J7qBdtFI5/zf1kg= -github.com/docker/distribution v0.0.0-20180720172123-0dae0957e5fe/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v0.7.3-0.20180221142240-453f2b8b40b9 h1:T9/p6Tf8lgB+fBZRwUCn1/b0w8w2/xT2Lsi6SPVp7OU= -github.com/docker/docker v0.7.3-0.20180221142240-453f2b8b40b9/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/dhui/dktest v0.2.2 h1:MlsuwzLw0xo2oAryeUxo5BAlTd+xH3iTLBcfIOyCDdg= +github.com/dhui/dktest v0.2.2/go.mod h1:cyzIUfGsBEbZ6BT7tnXqAShHSXCZhSNmFl70sZ7c1yc= +github.com/docker/distribution v2.7.0+incompatible h1:neUDAlf3wX6Ml4HdqTrbcOHXtfRN0TFIwt6YFL7N9RU= +github.com/docker/distribution v2.7.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190103212154-2b7e084dc98b h1:Y0C03XhDDcak1Ow6em58mBJmUJjxaMfB5sFttITXE0Q= +github.com/docker/docker v0.7.3-0.20190103212154-2b7e084dc98b/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v0.7.3-0.20190108045446-77df18c24acf h1:2v/98rHzs3v6X0AHtoCH9u+e56SdnpogB1Z2fFe1KqQ= +github.com/docker/docker v0.7.3-0.20190108045446-77df18c24acf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk= @@ -62,8 +71,8 @@ github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gocql/gocql v0.0.0-20181012100315-44e29ed5b8a4 h1:Zqj6+hV7PwTdjwDMZ78rX9ZMi8VCX9HEJmMhsQhTrSY= github.com/gocql/gocql v0.0.0-20181012100315-44e29ed5b8a4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0= -github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= @@ -89,8 +98,6 @@ github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8 github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gotestyourself/gotestyourself v2.1.0+incompatible h1:JdX/5sh/7yF7jRW5Xpvh1wlkAlgZS+X3HVCMlYqlxmw= -github.com/gotestyourself/gotestyourself v2.1.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc= @@ -103,6 +110,8 @@ github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -124,6 +133,8 @@ github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zM github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -135,43 +146,66 @@ github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= +github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.3.0 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME= +github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a h1:JSvGDIbmil4Ui/dDdFBExb7/cmkNjyX5F97oglmvCDo= github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51 h1:BP2bjP495BBPaBcS5rmqviTfrOkN5rO5ceKAMRZCRFc= +github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v1.0.0 h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0= github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= go.opencensus.io v0.17.0 h1:2Cu88MYg+1LU+WVD+NWwYhyP0kKgRlN9QjWGaX0jKTE= go.opencensus.io v0.17.0/go.mod h1:mp1VrMQxhlqqDpKvH4UcQUa4YwlzNmymAjPrDdfxNpI= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9 h1:mKdxBk7AujPs8kU4m80U72y/zjbZ3UcXC7dClwKbUI0= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc h1:F5tKCVGp+MUAHhKp5MZtGqAlGX3+oCsiL1Q629FL90M= +golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180925072008-f04abc6bdfa7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1 h1:Y/KGZSOdz/2r0WJ9Mkmz6NJBusp0kiNx1Cn82lzJQ6w= -golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3 h1:eH6Eip3UpmR+yM/qI9Ijluzb1bNv/cAU/n+6l8tRSis= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190107210223-45ffb0cd1ba0 h1:1DW40AJQ7AP4nY6ORUGUdkpXyEC9W2GAXcOPaMZK0K8= +golang.org/x/net v0.0.0-20190107210223-45ffb0cd1ba0/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20181003184128-c57b0facaced h1:4oqSq7eft7MdPKBGQK11X9WYUxmj6ZLgGTqYIbY1kyw= -golang.org/x/oauth2 v0.0.0-20181003184128-c57b0facaced/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890 h1:uESlIz09WIHT2I+pasSXcpLYqYK8wHcdCetU3VuMBJE= +golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180925112736-b09afc3d579e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181011152604-fa43e7bc11ba h1:nZJIJPGow0Kf9bU9QTc1U6OXbs/7Hu4e+cNv+hxH+Zc= -golang.org/x/sys v0.0.0-20181011152604-fa43e7bc11ba/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190102155601-82a175fd1598 h1:S8GOgffXV1X3fpVG442QRfWOt0iFl79eHJ7OPt725bo= +golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190108104531-7fbe1cd0fcc2 h1:ku9Kvp2ZBWAz3GyvuUH3UV1bZCd7RxH0Qf1epWfIDKc= +golang.org/x/sys v0.0.0-20190108104531-7fbe1cd0fcc2/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180924175601-e93be7f42f9f/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181015201034-8919434dde1e h1:45Fcw0KPH5qHaA/7SI9sRN3UfCjYC6S59MmABMhMV0A= -golang.org/x/tools v0.0.0-20181015201034-8919434dde1e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190107155254-e063def13b29 h1:mtLB/BpwjjSIylF0++D6EG1ExPVEIcFKMMwK6HFmbtU= +golang.org/x/tools v0.0.0-20190107155254-e063def13b29/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20180921000521-920bb1beccf7/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181015145326-625cd1887957 h1:jwCmWUTrTFfjsobRuGurnCQeW4NZKijaIf6yAXwLR0E= @@ -179,21 +213,26 @@ google.golang.org/api v0.0.0-20181015145326-625cd1887957/go.mod h1:4mhQ8q/RsB7i+ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0 h1:S0iUepdCWODXRvtE+gcRDd15L+k+k1AiHlMiMjefH24= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180924164928-221a8d4f7494/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20181004005441-af9cb2a35e7f h1:FU37niK8AQ59mHcskRyQL7H0ErSeNh650vdcj8HqdSI= -google.golang.org/genproto v0.0.0-20181004005441-af9cb2a35e7f/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181221175505-bd9b4fb69e2f h1:eT3B0O2ghdSPzjAOznr3oOLyN1HFeYUncYl7FRwg4VI= +google.golang.org/genproto v0.0.0-20181221175505-bd9b4fb69e2f/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.15.0 h1:Az/KuahOM4NAidTEuJCv/RonAA7rYsTPkqXVjr+8OOw= google.golang.org/grpc v1.15.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.17.0 h1:TRJYBgMclJvGYn2rIMjj+h9KtMt5r1Ij7ODVRIZkwhk= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.39.0 h1:Jf2sFGT+sAd7i+4ftUN1Jz90uw8XNH8NXbbOY16taA8= gopkg.in/ini.v1 v1.39.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gotest.tools v2.1.0+incompatible h1:5USw7CrJBYKqjg9R7QlA6jzqZKEAtvW82aNmsxxGPxw= -gotest.tools v2.1.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=