Merge remote-tracking branch 'origin/master' into postgres-lock-fix

This commit is contained in:
Dale Hui 2018-02-20 15:32:34 -08:00
commit ab7dfb38ac
63 changed files with 401 additions and 269 deletions

1
.gitignore vendored
View File

@ -4,3 +4,4 @@ cli/cli
cli/migrate
.coverage
.godoc.pid
vendor/

View File

@ -2,46 +2,53 @@ language: go
sudo: required
go:
- 1.7
- 1.8
- 1.9
- 1.9.1
- 1.9.2
- "1.9.x"
- "1.10"
env:
- MIGRATE_TEST_CONTAINER_BOOT_DELAY=10
- MIGRATE_TEST_CONTAINER_BOOT_TIMEOUT=60
# TODO: https://docs.docker.com/engine/installation/linux/ubuntu/
# pre-provision with travis docker setup and pin down docker version in install step
services:
- docker
- docker
before_cache:
- mv $GOPATH/src/github.com/golang-migrate /tmp/golang-migrate
- rm -rf $GOPATH/pkg/**/github.com/golang-migrate
cache:
directories:
- $GOPATH/src
- $GOPATH/pkg
install:
- make deps
- (cd $GOPATH/src/github.com/docker/docker && git fetch --all --tags --prune && git checkout v17.05.0-ce)
- sudo apt-get update && sudo apt-get install docker-ce=17.05.0*
- sudo apt-get update && sudo apt-get --allow-downgrades install docker-ce=17.05.0*
- go get github.com/mattn/goveralls
script:
- make test
- make test COVERAGE_DIR=/tmp/coverage
after_success:
- goveralls -service=travis-ci -coverprofile .coverage/combined.txt
- mv /tmp/golang-migrate $GOPATH/src/github.com/golang-migrate
- goveralls -service=travis-ci -coverprofile /tmp/coverage/combined.txt
- make list-external-deps > dependency_tree.txt && cat dependency_tree.txt
before_deploy:
- make build-cli
- gem install --no-ri --no-rdoc fpm
- fpm -s dir -t deb -n migrate -v "$(git describe --tags 2>/dev/null | cut -c 2-)" --license MIT -m matthias.kadenbach@gmail.com --url https://github.com/mattes/migrate --description='Database migrations' -a amd64 -p migrate.$(git describe --tags 2>/dev/null | cut -c 2-).deb --deb-no-default-config-files -f -C cli/build migrate.linux-amd64=/usr/bin/migrate
- fpm -s dir -t deb -n migrate -v "$(git describe --tags 2>/dev/null | cut -c 2-)" --license MIT -m dhui@users.noreply.github.com --url https://github.com/golang-migrate/migrate --description='Database migrations' -a amd64 -p migrate.$(git describe --tags 2>/dev/null | cut -c 2-).deb --deb-no-default-config-files -f -C cli/build migrate.linux-amd64=/usr/bin/migrate
deploy:
- provider: releases
api_key:
secure: EFow50BI448HVb/uQ1Kk2Kq0xzmwIYq3V67YyymXIuqSCodvXEsMiBPUoLrxEknpPEIc67LEQTNdfHBgvyHk6oRINWAfie+7pr5tKrpOTF9ghyxoN1PlO8WKQCqwCvGMBCnc5ur5rvzp0bqfpV2rs5q9/nngy3kBuEvs12V7iho=
secure: hWH1HLPpzpfA8pXQ93T1qKQVFSpQp0as/JLQ7D91jHuJ8p+RxVeqblDrR6HQY/95R/nyiE9GJmvUolSuw5h449LSrGxPtVWhdh6EnkxlQHlen5XeMhVjRjFV0sE9qGe8v7uAkiTfRO61ktTWHrEAvw5qpyqnNISodmZS78XIasPODQbNlzwINhWhDTHIjXGb4FpizYaL3OGCanrxfR9fQyCaqKGGBjRq3Mfq8U6Yd4mApmsE+uJxgaZV8K5zBqpkSzQRWhcVGNL5DuLsU3gfSJOo7kZeA2G71SHffH577dBoqtCZ4VFv169CoUZehLWCb+7XKJZmHXVujCURATSySLGUOPc6EoLFAn3YtsCA04mS4bZVo5FZPWVwfhjmkhtDR4f6wscKp7r1HsFHSOgm59QfETQdrn4MnZ44H2Jd39axqndn5DvK9EcZVjPHynOPnueXP2u6mTuUgh2VyyWBCDO3CNo0fGlo7VJI69IkIWNSD87K9cHZWYMClyKZkUzS+PmRAhHRYbVd+9ZjKOmnU36kUHNDG/ft1D4ogsY+rhVtXB4lgWDM5adri+EIScYdYnB1/pQexLBigcJY9uE7nQTR0U6QgVNYvun7uRNs40E0c4voSfmPdFO0FlOD2y1oQhnaXfWLbu9nMcTcs4RFGrcC7NzkUN4/WjG8s285V6w=
skip_cleanup: true
on:
go: 1.9
repo: mattes/migrate
go: "1.10"
repo: golang-migrate/migrate
tags: true
file:
- cli/build/migrate.linux-amd64.tar.gz
@ -51,14 +58,13 @@ deploy:
- dependency_tree.txt
- provider: packagecloud
repository: migrate
username: mattes
username: golang-migrate
token:
secure: RiHJ/+J9DvXUah/APYdWySWZ5uOOISYJ0wS7xddc7/BNStRVjzFzvJ9zmb67RkyZZrvGuVjPiL4T8mtDyCJCj47RmU/56wPdEHbar/FjsiUCgwvR19RlulkgbV4okBCePbwzMw6HNHRp14TzfQCPtnN4kef0lOI4gZJkImN7rtQ=
secure: aICwu3gJ1sJ1QVCD3elpg+Jxzt4P+Zj1uoh5f0sOwnjDNIZ4FwUT1cMrWloP8P2KD0iyCOawuZER27o/kQ21oX2OxHvQbYPReA2znLm7lHzCmypAAOHPxpgnQ4rMGHHJXd+OsxtdclGs67c+EbdBfoRRbK400Qz/vjPJEDeH4mh02ZHC2nw4Nk/wV4jjBIkIt9dGEx6NgOA17FCMa3MaPHlHeFIzU7IfTlDHbS0mCCYbg/wafWBWcbGqtZLWAYtJDmfjrAStmDLdAX5J5PsB7taGSGPZHmPmpGoVgrKt/tb9Xz1rFBGslTpGROOiO4CiMAvkEKFn8mxrBGjfSBqp7Dp3eeSalKXB1DJAbEXx2sEbMcvmnoR9o43meaAn+ZRts8lRL8S/skBloe6Nk8bx3NlJCGB9WPK1G56b7c/fZnJxQbrCw6hxDfbZwm8S2YPviFTo/z1BfZDhRsL74reKsN2kgnGo2W/k38vvzIpsssQ9DHN1b0TLCxolCNPtQ7oHcQ1ohcjP2UgYXk0FhqDoL+9LQva/DU4N9sKH0UbAaqsMVSErLeG8A4aauuFcVrWRBaDYyTag4dQqzTulEy7iru2kDDIBgSQ1gMW/yoBOIPK4oi6MtbTf1X39fzXFLS1cDd3LW61yAu3YrbjAetpfx2frIvrRAiL9TxWA1gnrs5o=
dist: ubuntu/xenial
package_glob: '*.deb'
skip_cleanup: true
on:
go: 1.9
repo: mattes/migrate
go: "1.10"
repo: golang-migrate/migrate
tags: true

View File

@ -12,11 +12,12 @@
Some more helpful commands:
* You can specify which database/ source tests to run:
* You can specify which database/ source tests to run:
`make test-short SOURCE='file go-bindata' DATABASE='postgres cassandra'`
* After `make test`, run `make html-coverage` which opens a shiny test coverage overview.
* After `make test`, run `make html-coverage` which opens a shiny test coverage overview.
* Missing imports? `make deps`
* `make build-cli` builds the CLI in directory `cli/build/`.
* `make list-external-deps` lists all external dependencies for each package
* `make docs && make open-docs` opens godoc in your browser, `make kill-docs` kills the godoc server.
Repeatedly call `make docs` to refresh the server.
* `make docs && make open-docs` opens godoc in your browser, `make kill-docs` kills the godoc server.
Repeatedly call `make docs` to refresh the server.
* Set the `DOCKER_API_VERSION` environment variable to the latest supported version if you get errors regarding the docker client API version being too new.

View File

@ -1,15 +1,16 @@
SOURCE ?= file go-bindata github aws-s3 google-cloud-storage
DATABASE ?= postgres mysql redshift cassandra sqlite3 spanner cockroachdb clickhouse
DATABASE ?= postgres mysql redshift cassandra spanner cockroachdb clickhouse
VERSION ?= $(shell git describe --tags 2>/dev/null | cut -c 2-)
TEST_FLAGS ?=
REPO_OWNER ?= $(shell cd .. && basename "$$(pwd)")
COVERAGE_DIR ?= .coverage
build-cli: clean
-mkdir ./cli/build
cd ./cli && CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -a -o build/migrate.linux-amd64 -ldflags='-X main.Version=$(VERSION)' -tags '$(DATABASE) $(SOURCE)' .
cd ./cli && CGO_ENABLED=1 GOOS=darwin GOARCH=amd64 go build -a -o build/migrate.darwin-amd64 -ldflags='-X main.Version=$(VERSION)' -tags '$(DATABASE) $(SOURCE)' .
cd ./cli && CGO_ENABLED=1 GOOS=windows GOARCH=amd64 go build -a -o build/migrate.windows-amd64.exe -ldflags='-X main.Version=$(VERSION)' -tags '$(DATABASE) $(SOURCE)' .
cd ./cli && GOOS=linux GOARCH=amd64 go build -a -o build/migrate.linux-amd64 -ldflags='-X main.Version=$(VERSION)' -tags '$(DATABASE) $(SOURCE)' .
cd ./cli && GOOS=darwin GOARCH=amd64 go build -a -o build/migrate.darwin-amd64 -ldflags='-X main.Version=$(VERSION)' -tags '$(DATABASE) $(SOURCE)' .
cd ./cli && GOOS=windows GOARCH=amd64 go build -a -o build/migrate.windows-amd64.exe -ldflags='-X main.Version=$(VERSION)' -tags '$(DATABASE) $(SOURCE)' .
cd ./cli/build && find . -name 'migrate*' | xargs -I{} tar czf {}.tar.gz {}
cd ./cli/build && shasum -a 256 * > sha256sum.txt
cat ./cli/build/sha256sum.txt
@ -24,11 +25,11 @@ test-short:
test:
@-rm -r .coverage
@mkdir .coverage
make test-with-flags TEST_FLAGS='-v -race -covermode atomic -coverprofile .coverage/_$$(RAND).txt -bench=. -benchmem'
@echo 'mode: atomic' > .coverage/combined.txt
@cat .coverage/*.txt | grep -v 'mode: atomic' >> .coverage/combined.txt
@-rm -r $(COVERAGE_DIR)
@mkdir $(COVERAGE_DIR)
make test-with-flags TEST_FLAGS='-v -race -covermode atomic -coverprofile $$(COVERAGE_DIR)/_$$(RAND).txt -bench=. -benchmem -timeout 20m'
@echo 'mode: atomic' > $(COVERAGE_DIR)/combined.txt
@cat $(COVERAGE_DIR)/_*.txt | grep -v 'mode: atomic' >> $(COVERAGE_DIR)/combined.txt
test-with-flags:
@ -53,14 +54,15 @@ kill-orphaned-docker-containers:
html-coverage:
go tool cover -html=.coverage/combined.txt
go tool cover -html=$(COVERAGE_DIR)/combined.txt
deps:
-go get -v -u ./...
-go test -v -i ./...
# TODO: why is this not being fetched with the command above?
# TODO: why are these not being fetched by `go get`?
-go get -u github.com/fsouza/fake-gcs-server/fakestorage
-go get -u github.com/kshvakov/clickhouse
list-external-deps:

View File

@ -1,7 +1,9 @@
[![Build Status](https://travis-ci.org/mattes/migrate.svg?branch=master)](https://travis-ci.org/mattes/migrate)
[![GoDoc](https://godoc.org/github.com/mattes/migrate?status.svg)](https://godoc.org/github.com/mattes/migrate)
[![Coverage Status](https://coveralls.io/repos/github/mattes/migrate/badge.svg?branch=v3.0-prev)](https://coveralls.io/github/mattes/migrate?branch=v3.0-prev)
[![packagecloud.io](https://img.shields.io/badge/deb-packagecloud.io-844fec.svg)](https://packagecloud.io/mattes/migrate?filter=debs)
[![Build Status](https://img.shields.io/travis/golang-migrate/migrate/master.svg)](https://travis-ci.org/golang-migrate/migrate)
[![GoDoc](https://godoc.org/github.com/golang-migrate/migrate?status.svg)](https://godoc.org/github.com/golang-migrate/migrate)
[![Coverage Status](https://img.shields.io/coveralls/github/golang-migrate/migrate/master.svg)](https://coveralls.io/github/golang-migrate/migrate?branch=master)
[![packagecloud.io](https://img.shields.io/badge/deb-packagecloud.io-844fec.svg)](https://packagecloud.io/golang-migrate/migrate?filter=debs)
[![GitHub Release](https://img.shields.io/github/release/golang-migrate/migrate.svg)](https://github.com/golang-migrate/migrate/releases)
# migrate
@ -9,12 +11,12 @@ __Database migrations written in Go. Use as [CLI](#cli-usage) or import as [libr
* Migrate reads migrations from [sources](#migration-sources)
and applies them in correct order to a [database](#databases).
* Drivers are "dumb", migrate glues everything together and makes sure the logic is bulletproof.
* Drivers are "dumb", migrate glues everything together and makes sure the logic is bulletproof.
(Keeps the drivers lightweight, too.)
* Database drivers don't assume things or try to correct user input. When in doubt, fail.
Looking for [v1](https://github.com/mattes/migrate/tree/v1)?
Looking for [v1](https://github.com/golang-migrate/migrate/tree/v1)?
## Databases
@ -25,7 +27,7 @@ Database drivers run migrations. [Add a new database?](database/driver.go)
* [Redshift](database/redshift)
* [Ql](database/ql)
* [Cassandra](database/cassandra)
* [SQLite](database/sqlite3)
* [SQLite](database/sqlite3) ([todo #165](https://github.com/mattes/migrate/issues/165))
* [MySQL/ MariaDB](database/mysql)
* [Neo4j](database/neo4j) ([todo #167](https://github.com/mattes/migrate/issues/167))
* [MongoDB](database/mongodb) ([todo #169](https://github.com/mattes/migrate/issues/169))
@ -69,19 +71,19 @@ $ migrate -database postgres://localhost:5432/database up 2
* API is stable and frozen for this release (v3.x).
* Package migrate has no external dependencies.
* Only import the drivers you need.
(check [dependency_tree.txt](https://github.com/mattes/migrate/releases) for each driver)
(check [dependency_tree.txt](https://github.com/golang-migrate/migrate/releases) for each driver)
* To help prevent database corruptions, it supports graceful stops via `GracefulStop chan bool`.
* Bring your own logger.
* Uses `io.Reader` streams internally for low memory overhead.
* Thread-safe and no goroutine leaks.
__[Go Documentation](https://godoc.org/github.com/mattes/migrate)__
__[Go Documentation](https://godoc.org/github.com/golang-migrate/migrate)__
```go
import (
"github.com/mattes/migrate"
_ "github.com/mattes/migrate/database/postgres"
_ "github.com/mattes/migrate/source/github"
"github.com/golang-migrate/migrate"
_ "github.com/golang-migrate/migrate/database/postgres"
_ "github.com/golang-migrate/migrate/source/github"
)
func main() {
@ -98,9 +100,9 @@ Want to use an existing database client?
import (
"database/sql"
_ "github.com/lib/pq"
"github.com/mattes/migrate"
"github.com/mattes/migrate/database/postgres"
_ "github.com/mattes/migrate/source/file"
"github.com/golang-migrate/migrate"
"github.com/golang-migrate/migrate/database/postgres"
_ "github.com/golang-migrate/migrate/source/file"
)
func main() {

View File

@ -5,8 +5,8 @@
#### With Go toolchain
```
$ go get -u -d github.com/mattes/migrate/cli github.com/lib/pq
$ go build -tags 'postgres' -o /usr/local/bin/migrate github.com/mattes/migrate/cli
$ go get -u -d github.com/golang-migrate/migrate/cli github.com/lib/pq
$ go build -tags 'postgres' -o /usr/local/bin/migrate github.com/golang-migrate/migrate/cli
```
Note: This example builds the cli which will only work with postgres. In order
@ -26,18 +26,18 @@ $ brew install migrate --with-postgres
#### Linux (*.deb package)
```
$ curl -L https://packagecloud.io/mattes/migrate/gpgkey | apt-key add -
$ echo "deb https://packagecloud.io/mattes/migrate/ubuntu/ xenial main" > /etc/apt/sources.list.d/migrate.list
$ curl -L https://packagecloud.io/golang-migrate/migrate/gpgkey | apt-key add -
$ echo "deb https://packagecloud.io/golang-migrate/migrate/ubuntu/ xenial main" > /etc/apt/sources.list.d/migrate.list
$ apt-get update
$ apt-get install -y migrate
```
#### Download pre-build binary (Windows, MacOS, or Linux)
[Release Downloads](https://github.com/mattes/migrate/releases)
[Release Downloads](https://github.com/golang-migrate/migrate/releases)
```
$ curl -L https://github.com/mattes/migrate/releases/download/$version/migrate.$platform-amd64.tar.gz | tar xvz
$ curl -L https://github.com/golang-migrate/migrate/releases/download/$version/migrate.$platform-amd64.tar.gz | tar xvz
```

View File

@ -3,5 +3,5 @@
package main
import (
_ "github.com/mattes/migrate/source/aws-s3"
_ "github.com/golang-migrate/migrate/source/aws-s3"
)

View File

@ -3,5 +3,5 @@
package main
import (
_ "github.com/mattes/migrate/database/cassandra"
_ "github.com/golang-migrate/migrate/database/cassandra"
)

View File

@ -4,5 +4,5 @@ package main
import (
_ "github.com/kshvakov/clickhouse"
_ "github.com/mattes/migrate/database/clickhouse"
_ "github.com/golang-migrate/migrate/database/clickhouse"
)

View File

@ -3,5 +3,5 @@
package main
import (
_ "github.com/mattes/migrate/database/cockroachdb"
_ "github.com/golang-migrate/migrate/database/cockroachdb"
)

View File

@ -3,5 +3,5 @@
package main
import (
_ "github.com/mattes/migrate/source/github"
_ "github.com/golang-migrate/migrate/source/github"
)

View File

@ -3,5 +3,5 @@
package main
import (
_ "github.com/mattes/migrate/source/go-bindata"
_ "github.com/golang-migrate/migrate/source/go-bindata"
)

View File

@ -3,5 +3,5 @@
package main
import (
_ "github.com/mattes/migrate/source/google-cloud-storage"
_ "github.com/golang-migrate/migrate/source/google-cloud-storage"
)

View File

@ -3,5 +3,5 @@
package main
import (
_ "github.com/mattes/migrate/database/mysql"
_ "github.com/golang-migrate/migrate/database/mysql"
)

View File

@ -3,5 +3,5 @@
package main
import (
_ "github.com/mattes/migrate/database/postgres"
_ "github.com/golang-migrate/migrate/database/postgres"
)

View File

@ -3,5 +3,5 @@
package main
import (
_ "github.com/mattes/migrate/database/ql"
_ "github.com/golang-migrate/migrate/database/ql"
)

View File

@ -3,5 +3,5 @@
package main
import (
_ "github.com/mattes/migrate/database/redshift"
_ "github.com/golang-migrate/migrate/database/redshift"
)

View File

@ -3,5 +3,5 @@
package main
import (
_ "github.com/mattes/migrate/database/spanner"
_ "github.com/golang-migrate/migrate/database/spanner"
)

View File

@ -3,5 +3,5 @@
package main
import (
_ "github.com/mattes/migrate/database/sqlite3"
_ "github.com/golang-migrate/migrate/database/sqlite3"
)

View File

@ -1,24 +1,81 @@
package main
import (
"github.com/mattes/migrate"
_ "github.com/mattes/migrate/database/stub" // TODO remove again
_ "github.com/mattes/migrate/source/file"
"os"
"errors"
"fmt"
"github.com/golang-migrate/migrate"
_ "github.com/golang-migrate/migrate/database/stub" // TODO remove again
_ "github.com/golang-migrate/migrate/source/file"
"os"
"path/filepath"
"strconv"
"strings"
)
func createCmd(dir string, timestamp int64, name string, ext string) {
base := fmt.Sprintf("%v%v_%v.", dir, timestamp, name)
func nextSeq(matches []string, dir string, seqDigits int) (string, error) {
if seqDigits <= 0 {
return "", errors.New("Digits must be positive")
}
nextSeq := 1
if len(matches) > 0 {
filename := matches[len(matches)-1]
matchSeqStr := strings.TrimPrefix(filename, dir)
idx := strings.Index(matchSeqStr, "_")
if idx < 1 { // Using 1 instead of 0 since there should be at least 1 digit
return "", errors.New("Malformed migration filename: " + filename)
}
matchSeqStr = matchSeqStr[0:idx]
var err error
nextSeq, err = strconv.Atoi(matchSeqStr)
if err != nil {
return "", err
}
nextSeq++
}
if nextSeq <= 0 {
return "", errors.New("Next sequence number must be positive")
}
nextSeqStr := strconv.Itoa(nextSeq)
if len(nextSeqStr) > seqDigits {
return "", fmt.Errorf("Next sequence number %s too large. At most %d digits are allowed", nextSeqStr, seqDigits)
}
padding := seqDigits - len(nextSeqStr)
if padding > 0 {
nextSeqStr = strings.Repeat("0", padding) + nextSeqStr
}
return nextSeqStr, nil
}
func createCmd(dir string, timestamp int64, name string, ext string, seq bool, seqDigits int) {
var base string
if seq {
if seqDigits <= 0 {
log.fatalErr(errors.New("Digits must be positive"))
}
matches, err := filepath.Glob(dir + "*" + ext)
if err != nil {
log.fatalErr(err)
}
nextSeqStr, err := nextSeq(matches, dir, seqDigits)
if err != nil {
log.fatalErr(err)
}
base = fmt.Sprintf("%v%v_%v.", dir, nextSeqStr, name)
} else {
base = fmt.Sprintf("%v%v_%v.", dir, timestamp, name)
}
os.MkdirAll(dir, os.ModePerm)
createFile(base + "up" + ext)
createFile(base + "down" + ext)
}
func createFile(fname string) {
if _, err := os.Create(fname); err != nil {
log.fatalErr(err)
}
if _, err := os.Create(fname); err != nil {
log.fatalErr(err)
}
}
func gotoCmd(m *migrate.Migrate, v uint) {

45
cli/commands_test.go Normal file
View File

@ -0,0 +1,45 @@
package main
import (
"testing"
)
func TestNextSeq(t *testing.T) {
cases := []struct {
name string
matches []string
dir string
seqDigits int
expected string
expectedErrStr string
}{
{"Bad digits", []string{}, "migrationDir", 0, "", "Digits must be positive"},
{"Single digit initialize", []string{}, "migrationDir", 1, "1", ""},
{"Single digit malformed", []string{"bad"}, "migrationDir", 1, "", "Malformed migration filename: bad"},
{"Single digit no int", []string{"bad_bad"}, "migrationDir", 1, "", "strconv.Atoi: parsing \"bad\": invalid syntax"},
{"Single digit negative seq", []string{"-5_test"}, "migrationDir", 1, "", "Next sequence number must be positive"},
{"Single digit increment", []string{"3_test", "4_test"}, "migrationDir", 1, "5", ""},
{"Single digit overflow", []string{"9_test"}, "migrationDir", 1, "", "Next sequence number 10 too large. At most 1 digits are allowed"},
{"Zero-pad initialize", []string{}, "migrationDir", 6, "000001", ""},
{"Zero-pad malformed", []string{"bad"}, "migrationDir", 6, "", "Malformed migration filename: bad"},
{"Zero-pad no int", []string{"bad_bad"}, "migrationDir", 6, "", "strconv.Atoi: parsing \"bad\": invalid syntax"},
{"Zero-pad negative seq", []string{"-000005_test"}, "migrationDir", 6, "", "Next sequence number must be positive"},
{"Zero-pad increment", []string{"000003_test", "000004_test"}, "migrationDir", 6, "000005", ""},
{"Zero-pad overflow", []string{"999999_test"}, "migrationDir", 6, "", "Next sequence number 1000000 too large. At most 6 digits are allowed"},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
nextSeq, err := nextSeq(c.matches, c.dir, c.seqDigits)
if nextSeq != c.expected {
t.Error("Incorrect nextSeq: " + nextSeq + " != " + c.expected)
}
if err != nil {
if err.Error() != c.expectedErrStr {
t.Error("Incorrect error: " + err.Error() + " != " + c.expectedErrStr)
}
} else if c.expectedErrStr != "" {
t.Error("Expected error: " + c.expectedErrStr + " but got nil instead")
}
})
}
}

View File

@ -3,8 +3,8 @@ FROM ubuntu:xenial
RUN apt-get update && \
apt-get install -y curl apt-transport-https
RUN curl -L https://packagecloud.io/mattes/migrate/gpgkey | apt-key add - && \
echo "deb https://packagecloud.io/mattes/migrate/ubuntu/ xenial main" > /etc/apt/sources.list.d/migrate.list && \
RUN curl -L https://packagecloud.io/golang-migrate/migrate/gpgkey | apt-key add - && \
echo "deb https://packagecloud.io/golang-migrate/migrate/ubuntu/ xenial main" > /etc/apt/sources.list.d/migrate.list && \
apt-get update && \
apt-get install -y migrate

View File

@ -10,7 +10,7 @@ import (
"syscall"
"time"
"github.com/mattes/migrate"
"github.com/golang-migrate/migrate"
)
// set main log
@ -42,8 +42,9 @@ Options:
-help Print usage
Commands:
create [-ext E] [-dir D] NAME
Create a set of timestamped up/down migrations titled NAME, in directory D with extension E
create [-ext E] [-dir D] [-seq] [-digits N] NAME
Create a set of timestamped up/down migrations titled NAME, in directory D with extension E.
Use -seq option to generate sequential up/down migrations with N digits.
goto V Migrate to version V
up [N] Apply all or N up migrations
down [N] Apply all or N down migrations
@ -106,10 +107,14 @@ Commands:
switch flag.Arg(0) {
case "create":
args := flag.Args()[1:]
seq := false
seqDigits := 6
createFlagSet := flag.NewFlagSet("create", flag.ExitOnError)
extPtr := createFlagSet.String("ext", "", "File extension")
dirPtr := createFlagSet.String("dir", "", "Directory to place file in (default: current working directory)")
createFlagSet.BoolVar(&seq, "seq", seq, "Use sequential numbers instead of timestamps (default: false)")
createFlagSet.IntVar(&seqDigits, "digits", seqDigits, "The number of digits to use in sequences (default: 6)")
createFlagSet.Parse(args)
if createFlagSet.NArg() == 0 {
@ -126,7 +131,7 @@ Commands:
timestamp := startTime.Unix()
createCmd(*dirPtr, timestamp, name, *extPtr)
createCmd(*dirPtr, timestamp, name, *extPtr, seq, seqDigits)
case "goto":
if migraterErr != nil {

View File

@ -9,7 +9,7 @@ import (
"time"
"github.com/gocql/gocql"
"github.com/mattes/migrate/database"
"github.com/golang-migrate/migrate/database"
)
func init() {

View File

@ -3,8 +3,8 @@ package cassandra
import (
"fmt"
"testing"
dt "github.com/mattes/migrate/database/testing"
mt "github.com/mattes/migrate/testing"
dt "github.com/golang-migrate/migrate/database/testing"
mt "github.com/golang-migrate/migrate/testing"
"github.com/gocql/gocql"
"time"
"strconv"

View File

@ -8,8 +8,8 @@ import (
"net/url"
"time"
"github.com/mattes/migrate"
"github.com/mattes/migrate/database"
"github.com/golang-migrate/migrate"
"github.com/golang-migrate/migrate/database"
)
var DefaultMigrationsTable = "schema_migrations"

View File

@ -9,8 +9,8 @@ import (
"github.com/cockroachdb/cockroach-go/crdb"
"github.com/lib/pq"
"github.com/mattes/migrate"
"github.com/mattes/migrate/database"
"github.com/golang-migrate/migrate"
"github.com/golang-migrate/migrate/database"
"regexp"
"strconv"
"context"
@ -223,7 +223,7 @@ func (c *CockroachDb) Run(migration io.Reader) error {
func (c *CockroachDb) SetVersion(version int, dirty bool) error {
return crdb.ExecuteTx(context.Background(), c.db, nil, func(tx *sql.Tx) error {
if _, err := tx.Exec( `TRUNCATE "` + c.config.MigrationsTable + `"`); err != nil {
if _, err := tx.Exec(`DELETE FROM "` + c.config.MigrationsTable + `"`); err != nil {
return err
}

View File

@ -10,8 +10,8 @@ import (
"testing"
"github.com/lib/pq"
dt "github.com/mattes/migrate/database/testing"
mt "github.com/mattes/migrate/testing"
dt "github.com/golang-migrate/migrate/database/testing"
mt "github.com/golang-migrate/migrate/testing"
"bytes"
)

View File

@ -1,53 +1,53 @@
# MySQL
`mysql://user:password@tcp(host:port)/dbname?query`
| URL Query | WithInstance Config | Description |
|------------|---------------------|-------------|
| `x-migrations-table` | `MigrationsTable` | Name of the migrations table |
| `dbname` | `DatabaseName` | The name of the database to connect to |
| `user` | | The user to sign in as |
| `password` | | The user's password |
| `host` | | The host to connect to. |
| `port` | | The port to bind to. |
| `x-tls-ca` | | The location of the root certificate file. |
| `x-tls-cert` | | Cert file location. |
| `x-tls-key` | | Key file location. |
| `x-tls-insecure-skip-verify` | | Whether or not to use SSL (true\|false) |
## Use with existing client
If you use the MySQL driver with existing database client, you must create the client with parameter `multiStatements=true`:
```go
package main
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
"github.com/mattes/migrate"
"github.com/mattes/migrate/database/mysql"
_ "github.com/mattes/migrate/source/file"
)
func main() {
db, _ := sql.Open("mysql", "user:password@tcp(host:port)/dbname?multiStatements=true")
driver, _ := mysql.WithInstance(db, &mysql.Config{})
m, _ := migrate.NewWithDatabaseInstance(
"file:///migrations",
"mysql",
driver,
)
m.Steps(2)
}
```
## Upgrading from v1
1. Write down the current migration version from schema_migrations
1. `DROP TABLE schema_migrations`
2. Wrap your existing migrations in transactions ([BEGIN/COMMIT](https://dev.mysql.com/doc/refman/5.7/en/commit.html)) if you use multiple statements within one migration.
3. Download and install the latest migrate version.
4. Force the current migration version with `migrate force <current_version>`.
# MySQL
`mysql://user:password@tcp(host:port)/dbname?query`
| URL Query | WithInstance Config | Description |
|------------|---------------------|-------------|
| `x-migrations-table` | `MigrationsTable` | Name of the migrations table |
| `dbname` | `DatabaseName` | The name of the database to connect to |
| `user` | | The user to sign in as |
| `password` | | The user's password |
| `host` | | The host to connect to. |
| `port` | | The port to bind to. |
| `x-tls-ca` | | The location of the root certificate file. |
| `x-tls-cert` | | Cert file location. |
| `x-tls-key` | | Key file location. |
| `x-tls-insecure-skip-verify` | | Whether or not to use SSL (true\|false) |
## Use with existing client
If you use the MySQL driver with existing database client, you must create the client with parameter `multiStatements=true`:
```go
package main
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
"github.com/golang-migrate/migrate"
"github.com/golang-migrate/migrate/database/mysql"
_ "github.com/golang-migrate/migrate/source/file"
)
func main() {
db, _ := sql.Open("mysql", "user:password@tcp(host:port)/dbname?multiStatements=true")
driver, _ := mysql.WithInstance(db, &mysql.Config{})
m, _ := migrate.NewWithDatabaseInstance(
"file:///migrations",
"mysql",
driver,
)
m.Steps(2)
}
```
## Upgrading from v1
1. Write down the current migration version from schema_migrations
1. `DROP TABLE schema_migrations`
2. Wrap your existing migrations in transactions ([BEGIN/COMMIT](https://dev.mysql.com/doc/refman/5.7/en/commit.html)) if you use multiple statements within one migration.
3. Download and install the latest migrate version.
4. Force the current migration version with `migrate force <current_version>`.

View File

@ -12,8 +12,8 @@ import (
"strings"
"github.com/go-sql-driver/mysql"
"github.com/mattes/migrate"
"github.com/mattes/migrate/database"
"github.com/golang-migrate/migrate"
"github.com/golang-migrate/migrate/database"
)
func init() {

View File

@ -8,9 +8,9 @@ import (
// "log"
"testing"
// "github.com/go-sql-driver/mysql"
dt "github.com/mattes/migrate/database/testing"
mt "github.com/mattes/migrate/testing"
"github.com/go-sql-driver/mysql"
dt "github.com/golang-migrate/migrate/database/testing"
mt "github.com/golang-migrate/migrate/testing"
)
var versions = []mt.Version{
@ -26,9 +26,13 @@ func isReady(i mt.Instance) bool {
return false
}
defer db.Close()
err = db.Ping()
if err == sqldriver.ErrBadConn {
if err = db.Ping(); err != nil {
switch err {
case sqldriver.ErrBadConn, mysql.ErrInvalidConn:
return false
default:
fmt.Println(err)
}
return false
}
@ -46,6 +50,7 @@ func Test(t *testing.T) {
if err != nil {
t.Fatalf("%v", err)
}
defer d.Close()
dt.Test(t, d, []byte("SELECT 1"))
// check ensureVersionTable

View File

@ -1,4 +1,5 @@
// +build go1.9
package postgres
import (
@ -8,10 +9,10 @@ import (
"io/ioutil"
nurl "net/url"
"github.com/lib/pq"
"github.com/mattes/migrate"
"github.com/mattes/migrate/database"
"context"
"github.com/golang-migrate/migrate"
"github.com/golang-migrate/migrate/database"
"github.com/lib/pq"
)
func init() {
@ -207,7 +208,7 @@ func (p *Postgres) SetVersion(version int, dirty bool) error {
func (p *Postgres) Version() (version int, dirty bool, err error) {
query := `SELECT version, dirty FROM "` + p.config.MigrationsTable + `" LIMIT 1`
err = p.db.QueryRowContext(context.Background(),query).Scan(&version, &dirty)
err = p.db.QueryRowContext(context.Background(), query).Scan(&version, &dirty)
switch {
case err == sql.ErrNoRows:
return database.NilVersion, false, nil
@ -228,7 +229,7 @@ func (p *Postgres) Version() (version int, dirty bool, err error) {
func (p *Postgres) Drop() error {
// select all tables in current schema
query := `SELECT table_name FROM information_schema.tables WHERE table_schema=(SELECT current_schema())`
tables, err := p.db.QueryContext(context.Background(),query)
tables, err := p.db.QueryContext(context.Background(), query)
if err != nil {
return &database.Error{OrigErr: err, Query: []byte(query)}
}
@ -266,7 +267,7 @@ func (p *Postgres) ensureVersionTable() error {
// check if migration table exists
var count int
query := `SELECT COUNT(1) FROM information_schema.tables WHERE table_name = $1 AND table_schema = (SELECT current_schema()) LIMIT 1`
if err := p.db.QueryRowContext(context.Background(),query, p.config.MigrationsTable).Scan(&count); err != nil {
if err := p.db.QueryRowContext(context.Background(), query, p.config.MigrationsTable).Scan(&count); err != nil {
return &database.Error{OrigErr: err, Query: []byte(query)}
}
if count == 1 {
@ -275,7 +276,7 @@ func (p *Postgres) ensureVersionTable() error {
// if not, create the empty migration table
query = `CREATE TABLE "` + p.config.MigrationsTable + `" (version bigint not null primary key, dirty boolean not null)`
if _, err := p.db.ExecContext(context.Background(),query); err != nil {
if _, err := p.db.ExecContext(context.Background(), query); err != nil {
return &database.Error{OrigErr: err, Query: []byte(query)}
}
return nil

View File

@ -5,14 +5,15 @@ package postgres
import (
"bytes"
"database/sql"
sqldriver "database/sql/driver"
"fmt"
"io"
"testing"
"github.com/lib/pq"
dt "github.com/mattes/migrate/database/testing"
mt "github.com/mattes/migrate/testing"
"context"
dt "github.com/golang-migrate/migrate/database/testing"
mt "github.com/golang-migrate/migrate/testing"
// "github.com/lib/pq"
)
var versions = []mt.Version{
@ -29,14 +30,14 @@ func isReady(i mt.Instance) bool {
return false
}
defer db.Close()
err = db.Ping()
if err == io.EOF {
return false
} else if e, ok := err.(*pq.Error); ok {
if e.Code.Name() == "cannot_connect_now" {
if err = db.Ping(); err != nil {
switch err {
case sqldriver.ErrBadConn, io.EOF:
return false
default:
fmt.Println(err)
}
return false
}
return true
@ -51,6 +52,7 @@ func Test(t *testing.T) {
if err != nil {
t.Fatalf("%v", err)
}
defer d.Close()
dt.Test(t, d, []byte("SELECT 1"))
})
}
@ -64,6 +66,7 @@ func TestMultiStatement(t *testing.T) {
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)
}
@ -84,10 +87,11 @@ func TestFilterCustomQuery(t *testing.T) {
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())
_, err := p.Open(addr)
d, err := p.Open(addr)
if err != nil {
t.Fatalf("%v", err)
}
defer d.Close()
})
}
@ -100,6 +104,7 @@ func TestWithSchema(t *testing.T) {
if err != nil {
t.Fatalf("%v", err)
}
defer d.Close()
// create foobar schema
if err := d.Run(bytes.NewReader([]byte("CREATE SCHEMA foobar AUTHORIZATION postgres"))); err != nil {
@ -114,6 +119,7 @@ func TestWithSchema(t *testing.T) {
if err != nil {
t.Fatalf("%v", err)
}
defer d2.Close()
version, _, err := d2.Version()
if err != nil {
@ -184,4 +190,4 @@ func TestPostgres_Lock(t *testing.T) {
t.Fatal(err)
}
})
}
}

View File

@ -10,8 +10,8 @@ import (
nurl "net/url"
_ "github.com/cznic/ql/driver"
"github.com/mattes/migrate"
"github.com/mattes/migrate/database"
"github.com/golang-migrate/migrate"
"github.com/golang-migrate/migrate/database"
)
func init() {

View File

@ -9,9 +9,9 @@ import (
"testing"
_ "github.com/cznic/ql/driver"
"github.com/mattes/migrate"
dt "github.com/mattes/migrate/database/testing"
_ "github.com/mattes/migrate/source/file"
"github.com/golang-migrate/migrate"
dt "github.com/golang-migrate/migrate/database/testing"
_ "github.com/golang-migrate/migrate/source/file"
)
func Test(t *testing.T) {

View File

@ -3,8 +3,8 @@ package redshift
import (
"net/url"
"github.com/mattes/migrate/database"
"github.com/mattes/migrate/database/postgres"
"github.com/golang-migrate/migrate/database"
"github.com/golang-migrate/migrate/database/postgres"
)
// init registers the driver under the name 'redshift'

View File

@ -14,8 +14,8 @@ import (
"cloud.google.com/go/spanner"
sdb "cloud.google.com/go/spanner/admin/database/apiv1"
"github.com/mattes/migrate"
"github.com/mattes/migrate/database"
"github.com/golang-migrate/migrate"
"github.com/golang-migrate/migrate/database"
"google.golang.org/api/iterator"
adminpb "google.golang.org/genproto/googleapis/spanner/admin/database/v1"

View File

@ -5,7 +5,7 @@ import (
"os"
"testing"
dt "github.com/mattes/migrate/database/testing"
dt "github.com/golang-migrate/migrate/database/testing"
)
func Test(t *testing.T) {

View File

@ -3,8 +3,8 @@ package sqlite3
import (
"database/sql"
"fmt"
"github.com/mattes/migrate"
"github.com/mattes/migrate/database"
"github.com/golang-migrate/migrate"
"github.com/golang-migrate/migrate/database"
_ "github.com/mattn/go-sqlite3"
"io"
"io/ioutil"

View File

@ -3,9 +3,9 @@ package sqlite3
import (
"database/sql"
"fmt"
"github.com/mattes/migrate"
dt "github.com/mattes/migrate/database/testing"
_ "github.com/mattes/migrate/source/file"
"github.com/golang-migrate/migrate"
dt "github.com/golang-migrate/migrate/database/testing"
_ "github.com/golang-migrate/migrate/source/file"
_ "github.com/mattn/go-sqlite3"
"io/ioutil"
"os"

View File

@ -5,7 +5,7 @@ import (
"io/ioutil"
"reflect"
"github.com/mattes/migrate/database"
"github.com/golang-migrate/migrate/database"
)
func init() {

View File

@ -3,7 +3,7 @@ package stub
import (
"testing"
dt "github.com/mattes/migrate/database/testing"
dt "github.com/golang-migrate/migrate/database/testing"
)
func Test(t *testing.T) {

View File

@ -10,7 +10,7 @@ import (
"testing"
"time"
"github.com/mattes/migrate/database"
"github.com/golang-migrate/migrate/database"
)
// Test runs tests against database implementations.

View File

@ -10,8 +10,8 @@ import (
"sync"
"time"
"github.com/mattes/migrate/database"
"github.com/mattes/migrate/source"
"github.com/golang-migrate/migrate/database"
"github.com/golang-migrate/migrate/source"
)
// DefaultPrefetchMigrations sets the number of migrations to pre-read

View File

@ -8,9 +8,9 @@ import (
"os"
"testing"
dStub "github.com/mattes/migrate/database/stub"
"github.com/mattes/migrate/source"
sStub "github.com/mattes/migrate/source/stub"
dStub "github.com/golang-migrate/migrate/database/stub"
"github.com/golang-migrate/migrate/source"
sStub "github.com/golang-migrate/migrate/source/stub"
)
// sourceStubMigrations hold the following migrations:
@ -104,7 +104,7 @@ func ExampleNewWithDatabaseInstance() {
// Create driver instance from db.
// Check each driver if it supports the WithInstance function.
// `import "github.com/mattes/migrate/database/postgres"`
// `import "github.com/golang-migrate/migrate/database/postgres"`
instance, err := dStub.WithInstance(db, &dStub.Config{})
if err != nil {
log.Fatal(err)
@ -154,7 +154,7 @@ func ExampleNewWithSourceInstance() {
// Create driver instance from DummyInstance di.
// Check each driver if it support the WithInstance function.
// `import "github.com/mattes/migrate/source/stub"`
// `import "github.com/golang-migrate/migrate/source/stub"`
instance, err := sStub.WithInstance(di, &sStub.Config{})
if err != nil {
log.Fatal(err)

View File

@ -12,7 +12,7 @@ import (
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/service/s3/s3iface"
"github.com/mattes/migrate/source"
"github.com/golang-migrate/migrate/source"
)
func init() {

View File

@ -8,8 +8,8 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/mattes/migrate/source"
st "github.com/mattes/migrate/source/testing"
"github.com/golang-migrate/migrate/source"
st "github.com/golang-migrate/migrate/source/testing"
)
func Test(t *testing.T) {

View File

@ -9,7 +9,7 @@ import (
"path"
"path/filepath"
"github.com/mattes/migrate/source"
"github.com/golang-migrate/migrate/source"
)
func init() {

View File

@ -8,7 +8,7 @@ import (
"path/filepath"
"testing"
st "github.com/mattes/migrate/source/testing"
st "github.com/golang-migrate/migrate/source/testing"
)
func Test(t *testing.T) {

View File

@ -12,7 +12,7 @@ import (
"strings"
"github.com/google/go-github/github"
"github.com/mattes/migrate/source"
"github.com/golang-migrate/migrate/source"
)
func init() {

View File

@ -5,7 +5,7 @@ import (
"io/ioutil"
"testing"
st "github.com/mattes/migrate/source/testing"
st "github.com/golang-migrate/migrate/source/testing"
)
var GithubTestSecret = "" // username:token

View File

@ -13,9 +13,9 @@ cd examples/migrations && go-bindata -pkg migrations .
```go
import (
"github.com/mattes/migrate"
"github.com/mattes/migrate/source/go-bindata"
"github.com/mattes/migrate/source/go-bindata/examples/migrations"
"github.com/golang-migrate/migrate"
"github.com/golang-migrate/migrate/source/go-bindata"
"github.com/golang-migrate/migrate/source/go-bindata/examples/migrations"
)
func main() {

View File

@ -7,7 +7,7 @@ import (
"io/ioutil"
"os"
"github.com/mattes/migrate/source"
"github.com/golang-migrate/migrate/source"
)
type AssetFunc func(name string) ([]byte, error)

View File

@ -3,8 +3,8 @@ package bindata
import (
"testing"
"github.com/mattes/migrate/source/go-bindata/testdata"
st "github.com/mattes/migrate/source/testing"
"github.com/golang-migrate/migrate/source/go-bindata/testdata"
st "github.com/golang-migrate/migrate/source/testing"
)
func Test(t *testing.T) {

View File

@ -9,7 +9,7 @@ import (
"strings"
"cloud.google.com/go/storage"
"github.com/mattes/migrate/source"
"github.com/golang-migrate/migrate/source"
"golang.org/x/net/context"
"google.golang.org/api/iterator"
)

View File

@ -4,8 +4,8 @@ import (
"testing"
"github.com/fsouza/fake-gcs-server/fakestorage"
"github.com/mattes/migrate/source"
st "github.com/mattes/migrate/source/testing"
"github.com/golang-migrate/migrate/source"
st "github.com/golang-migrate/migrate/source/testing"
)
func Test(t *testing.T) {

View File

@ -9,7 +9,7 @@ type Direction string
const (
Down Direction = "down"
Up = "up"
Up Direction = "up"
)
// Migration is a helper struct for source drivers that need to

View File

@ -7,7 +7,7 @@ import (
"io/ioutil"
"os"
"github.com/mattes/migrate/source"
"github.com/golang-migrate/migrate/source"
)
func init() {

View File

@ -3,8 +3,8 @@ package stub
import (
"testing"
"github.com/mattes/migrate/source"
st "github.com/mattes/migrate/source/testing"
"github.com/golang-migrate/migrate/source"
st "github.com/golang-migrate/migrate/source/testing"
)
func Test(t *testing.T) {

View File

@ -7,7 +7,7 @@ import (
"os"
"testing"
"github.com/mattes/migrate/source"
"github.com/golang-migrate/migrate/source"
)
// Test runs tests against source implementations.

View File

@ -5,17 +5,18 @@ import (
"bufio"
"context"
"encoding/json"
"errors"
"fmt"
dockertypes "github.com/docker/docker/api/types"
dockercontainer "github.com/docker/docker/api/types/container"
dockernetwork "github.com/docker/docker/api/types/network"
dockerclient "github.com/docker/docker/client"
"io"
"math/rand"
"strconv"
"strings"
"testing"
"time"
dockertypes "github.com/docker/docker/api/types"
dockercontainer "github.com/docker/docker/api/types/container"
dockernetwork "github.com/docker/docker/api/types/network"
dockerclient "github.com/docker/docker/client"
)
func NewDockerContainer(t testing.TB, image string, env []string, cmd []string) (*DockerContainer, error) {
@ -33,7 +34,7 @@ func NewDockerContainer(t testing.TB, image string, env []string, cmd []string)
client: c,
ImageName: image,
ENV: env,
Cmd: cmd,
Cmd: cmd,
}
if err := contr.PullImage(); err != nil {
@ -62,6 +63,9 @@ type DockerContainer struct {
}
func (d *DockerContainer) PullImage() error {
if d == nil {
return errors.New("Cannot pull image on a nil *DockerContainer")
}
d.t.Logf("Docker: Pull image %v", d.ImageName)
r, err := d.client.ImagePull(context.Background(), d.ImageName, dockertypes.ImagePullOptions{})
if err != nil {
@ -84,7 +88,11 @@ func (d *DockerContainer) PullImage() error {
}
func (d *DockerContainer) Start() error {
containerName := fmt.Sprintf("migrate_test_%v", pseudoRandStr(10))
if d == nil {
return errors.New("Cannot start a nil *DockerContainer")
}
containerName := fmt.Sprintf("migrate_test_%s", pseudoRandStr(10))
// create container first
resp, err := d.client.ContainerCreate(context.Background(),
@ -119,16 +127,24 @@ func (d *DockerContainer) Start() error {
}
func (d *DockerContainer) KeepForDebugging() {
if d == nil {
return
}
d.keepForDebugging = true
}
func (d *DockerContainer) Remove() error {
if d == nil {
return errors.New("Cannot remove a nil *DockerContainer")
}
if d.keepForDebugging {
return nil
}
if len(d.ContainerId) == 0 {
return fmt.Errorf("missing containerId")
return errors.New("missing containerId")
}
if err := d.client.ContainerRemove(context.Background(), d.ContainerId,
dockertypes.ContainerRemoveOptions{
@ -142,8 +158,12 @@ func (d *DockerContainer) Remove() error {
}
func (d *DockerContainer) Inspect() error {
if d == nil {
return errors.New("Cannot inspect a nil *DockerContainer")
}
if len(d.ContainerId) == 0 {
return fmt.Errorf("missing containerId")
return errors.New("missing containerId")
}
resp, err := d.client.ContainerInspect(context.Background(), d.ContainerId)
if err != nil {
@ -156,8 +176,11 @@ func (d *DockerContainer) Inspect() error {
}
func (d *DockerContainer) Logs() (io.ReadCloser, error) {
if d == nil {
return nil, errors.New("Cannot view logs for a nil *DockerContainer")
}
if len(d.ContainerId) == 0 {
return nil, fmt.Errorf("missing containerId")
return nil, errors.New("missing containerId")
}
return d.client.ContainerLogs(context.Background(), d.ContainerId, dockertypes.ContainerLogsOptions{
@ -190,13 +213,16 @@ func (d *DockerContainer) portMapping(selectFirst bool, cPort int) (containerPor
}
if selectFirst {
return 0, "", 0, fmt.Errorf("no port binding")
return 0, "", 0, errors.New("no port binding")
} else {
return 0, "", 0, fmt.Errorf("specified port not bound")
return 0, "", 0, errors.New("specified port not bound")
}
}
func (d *DockerContainer) Host() string {
if d == nil {
panic("Cannot get host for a nil *DockerContainer")
}
_, hostIP, _, err := d.portMapping(true, -1)
if err != nil {
d.t.Fatal(err)
@ -210,6 +236,9 @@ func (d *DockerContainer) Host() string {
}
func (d *DockerContainer) Port() uint {
if d == nil {
panic("Cannot get port for a nil *DockerContainer")
}
_, _, port, err := d.portMapping(true, -1)
if err != nil {
d.t.Fatal(err)
@ -218,6 +247,9 @@ func (d *DockerContainer) Port() uint {
}
func (d *DockerContainer) PortFor(cPort int) uint {
if d == nil {
panic("Cannot get port for a nil *DockerContainer")
}
_, _, port, err := d.portMapping(false, cPort)
if err != nil {
d.t.Fatal(err)
@ -226,6 +258,9 @@ func (d *DockerContainer) PortFor(cPort int) uint {
}
func (d *DockerContainer) NetworkSettings() dockertypes.NetworkSettings {
if d == nil {
panic("Cannot get network settings for a nil *DockerContainer")
}
netSettings := d.ContainerJSON.NetworkSettings
return *netSettings
}

View File

@ -21,9 +21,9 @@ type Version struct {
}
func ParallelTest(t *testing.T, versions []Version, readyFn IsReadyFunc, testFn TestFunc) {
delay, err := strconv.Atoi(os.Getenv("MIGRATE_TEST_CONTAINER_BOOT_DELAY"))
timeout, err := strconv.Atoi(os.Getenv("MIGRATE_TEST_CONTAINER_BOOT_TIMEOUT"))
if err != nil {
delay = 0
timeout = 60 // Cassandra docker image can take ~30s to start
}
for i, version := range versions {
@ -49,8 +49,8 @@ func ParallelTest(t *testing.T, versions []Version, readyFn IsReadyFunc, testFn
// wait until database is ready
tick := time.Tick(1000 * time.Millisecond)
timeout := time.After(time.Duration(delay + 60) * time.Second)
outer:
timeout := time.After(time.Duration(timeout) * time.Second)
outer:
for {
select {
case <-tick:
@ -63,8 +63,6 @@ func ParallelTest(t *testing.T, versions []Version, readyFn IsReadyFunc, testFn
}
}
time.Sleep(time.Duration(int64(delay)) * time.Second)
// we can now run the tests
testFn(t, container)
})
@ -75,13 +73,13 @@ func ParallelTest(t *testing.T, versions []Version, readyFn IsReadyFunc, testFn
func containerLogs(t *testing.T, c *DockerContainer) []byte {
r, err := c.Logs()
if err != nil {
t.Error("%v", err)
t.Error(err)
return nil
}
defer r.Close()
b, err := ioutil.ReadAll(r)
if err != nil {
t.Error("%v", err)
t.Error(err)
return nil
}
return b

32
util.go
View File

@ -1,12 +1,9 @@
package migrate
import (
"bufio"
"fmt"
"io"
nurl "net/url"
"strings"
"time"
)
// MultiError holds multiple errors.
@ -46,35 +43,6 @@ func suint(n int) uint {
return uint(n)
}
// newSlowReader turns an io.ReadCloser into a slow io.ReadCloser.
// Use this to simulate a slow internet connection.
func newSlowReader(r io.ReadCloser) io.ReadCloser {
return &slowReader{
rx: r,
reader: bufio.NewReader(r),
}
}
type slowReader struct {
rx io.ReadCloser
reader *bufio.Reader
}
func (b *slowReader) Read(p []byte) (n int, err error) {
time.Sleep(10 * time.Millisecond)
c, err := b.reader.ReadByte()
if err != nil {
return 0, err
} else {
copy(p, []byte{c})
return 1, nil
}
}
func (b *slowReader) Close() error {
return b.rx.Close()
}
var errNoScheme = fmt.Errorf("no scheme")
// schemeFromUrl returns the scheme from a URL string