From 4a576af855738b2c3a31eaaba478feeb7b316acb Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Sat, 16 Apr 2016 22:27:34 +0200 Subject: [PATCH 01/10] Fix CI tests on darwin --- Vagrantfile | 1 - run_integration_tests.go | 1 - 2 files changed, 2 deletions(-) diff --git a/Vagrantfile b/Vagrantfile index bac6e5a7c..19c73673b 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -35,7 +35,6 @@ end def packages_darwin return <<-EOF ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" - brew install caskroom/cask/brew-cask brew cask install osxfuse EOF end diff --git a/run_integration_tests.go b/run_integration_tests.go index 519a6cd1f..1a1666d94 100644 --- a/run_integration_tests.go +++ b/run_integration_tests.go @@ -97,7 +97,6 @@ func (env *TravisEnvironment) Prepare() { if runtime.GOOS == "darwin" { // install the libraries necessary for fuse run("brew", "update") - run("brew", "install", "caskroom/cask/brew-cask") run("brew", "cask", "install", "osxfuse") } From 87250c44891dcd04f0aafa0eb03475a7788d270a Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Sat, 16 Apr 2016 22:41:16 +0200 Subject: [PATCH 02/10] Call minio server with env variables --- run_integration_tests.go | 37 +++++++------------------------------ 1 file changed, 7 insertions(+), 30 deletions(-) diff --git a/run_integration_tests.go b/run_integration_tests.go index 1a1666d94..54a5ede36 100644 --- a/run_integration_tests.go +++ b/run_integration_tests.go @@ -310,15 +310,10 @@ func runWithEnv(env map[string]string, command string, args ...string) { } } -var minioConfig = ` -{ - "version": "2", - "credentials": { - "accessKeyId": "KEBIYDZ87HCIH5D17YCN", - "secretAccessKey": "bVX1KhipSBPopEfmhc7rGz8ooxx27xdJ7Gkh1mVe" - } +var minioServerEnv = map[string]string{ + "MINIO_ACCESS_KEY": "KEBIYDZ87HCIH5D17YCN", + "MINIO_SECRET_KEY": "bVX1KhipSBPopEfmhc7rGz8ooxx27xdJ7Gkh1mVe", } -` var minioEnv = map[string]string{ "RESTIC_TEST_S3_SERVER": "http://127.0.0.1:9000", @@ -330,25 +325,6 @@ var minioEnv = map[string]string{ // a temporary directory. func NewMinioServer(minio string) (*MinioServer, error) { msg("running minio server\n") - cfgdir, err := ioutil.TempDir("", "minio-config-") - if err != nil { - return nil, err - } - - cfg, err := os.Create(filepath.Join(cfgdir, "config.json")) - if err != nil { - return nil, err - } - - _, err = cfg.Write([]byte(minioConfig)) - if err != nil { - return nil, err - } - - err = cfg.Close() - if err != nil { - return nil, err - } dir, err := ioutil.TempDir("", "minio-root") if err != nil { @@ -356,13 +332,14 @@ func NewMinioServer(minio string) (*MinioServer, error) { } out := bytes.NewBuffer(nil) - cmd := exec.Command(minio, - "--config-folder", cfgdir, + "server", "--address", "127.0.0.1:9000", - "server", dir) + dir) cmd.Stdout = out cmd.Stderr = out + cmd.Env = updateEnv(os.Environ(), minioServerEnv) + err = cmd.Start() if err != nil { return nil, err From d4b202243a31cbad85921e07064d47033ac2b482 Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Sat, 16 Apr 2016 22:49:40 +0200 Subject: [PATCH 03/10] Update Go versions --- .travis.yml | 4 ++-- appveyor.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 304962c3a..36fcd05bf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,8 +4,8 @@ sudo: false go: - 1.3.3 - 1.4.3 - - 1.5.3 - - 1.6 + - 1.5.4 + - 1.6.1 os: - linux diff --git a/appveyor.yml b/appveyor.yml index 10933757e..7b2720df0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -13,8 +13,8 @@ init: install: - rmdir c:\go /s /q - - appveyor DownloadFile https://storage.googleapis.com/golang/go1.6.windows-amd64.msi - - msiexec /i go1.6.windows-amd64.msi /q + - appveyor DownloadFile https://storage.googleapis.com/golang/go1.6.1.windows-amd64.msi + - msiexec /i go1.6.1.windows-amd64.msi /q - go version - go env - appveyor DownloadFile http://sourceforge.netcologne.de/project/gnuwin32/tar/1.13-1/tar-1.13-1-bin.zip -FileName tar.zip From 41e3e12f4b7e08c535e6be7bd7c05f9937eef51b Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Sun, 17 Apr 2016 13:08:57 +0200 Subject: [PATCH 04/10] Travis: correct exclude for darwin --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 36fcd05bf..ce8630344 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ matrix: - os: osx go: 1.4.3 - os: osx - go: 1.5.3 + go: 1.5.4 notifications: irc: From ead6d11ecf08c098d03f189b0d4961ce6cbe82f1 Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Sun, 17 Apr 2016 17:39:14 +0200 Subject: [PATCH 05/10] Backend tests: remove debug --- src/restic/backend/test/tests.go | 1 - 1 file changed, 1 deletion(-) diff --git a/src/restic/backend/test/tests.go b/src/restic/backend/test/tests.go index 60c35ffb0..ef0efd77a 100644 --- a/src/restic/backend/test/tests.go +++ b/src/restic/backend/test/tests.go @@ -77,7 +77,6 @@ func TestCreate(t testing.TB) { be, err := CreateFn() if err != nil { - fmt.Printf("foo\n") t.Fatalf("Create returned error: %v", err) } From 2e3c54123769999ac33f3682ade3f4faf8528492 Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Sun, 17 Apr 2016 17:49:36 +0200 Subject: [PATCH 06/10] Rework Go program to run CI tests --- run_integration_tests.go | 212 +++++++++++++++++++++------------------ 1 file changed, 116 insertions(+), 96 deletions(-) diff --git a/run_integration_tests.go b/run_integration_tests.go index 54a5ede36..1541eafbe 100644 --- a/run_integration_tests.go +++ b/run_integration_tests.go @@ -15,12 +15,22 @@ import ( "regexp" "runtime" "strings" - "sync" ) var runCrossCompile = flag.Bool("cross-compile", true, "run cross compilation tests") var minioServer = flag.String("minio", "", "path to the minio server binary") +var minioServerEnv = map[string]string{ + "MINIO_ACCESS_KEY": "KEBIYDZ87HCIH5D17YCN", + "MINIO_SECRET_KEY": "bVX1KhipSBPopEfmhc7rGz8ooxx27xdJ7Gkh1mVe", +} + +var minioEnv = map[string]string{ + "RESTIC_TEST_S3_SERVER": "http://127.0.0.1:9000", + "AWS_ACCESS_KEY_ID": "KEBIYDZ87HCIH5D17YCN", + "AWS_SECRET_ACCESS_KEY": "bVX1KhipSBPopEfmhc7rGz8ooxx27xdJ7Gkh1mVe", +} + func init() { flag.Parse() } @@ -28,12 +38,18 @@ func init() { type CIEnvironment interface { Prepare() RunTests() + Teardown() } type TravisEnvironment struct { goxArch []string goxOS []string minio string + + minioSrv *Background + minioTempdir string + + env map[string]string } func (env *TravisEnvironment) getMinio() { @@ -86,13 +102,43 @@ func (env *TravisEnvironment) getMinio() { env.minio = tempfile.Name() } +func (env *TravisEnvironment) runMinio() { + // start minio server + if env.minio != "" { + msg("starting minio server at %s", env.minio) + + dir, err := ioutil.TempDir("", "minio-root") + if err != nil { + os.Exit(80) + } + + env.minioSrv, err = StartBackgroundCommand(minioServerEnv, env.minio, + "server", + "--address", "127.0.0.1:9000", + dir) + if err != nil { + fmt.Fprintf(os.Stderr, "error running minio server: %v", err) + os.Exit(80) + } + + for k, v := range minioEnv { + env.env[k] = v + } + + env.minioTempdir = dir + } +} + func (env *TravisEnvironment) Prepare() { + env.env = make(map[string]string) + msg("preparing environment for Travis CI\n") run("go", "get", "golang.org/x/tools/cmd/cover") run("go", "get", "github.com/mattn/goveralls") run("go", "get", "github.com/pierrre/gotestcover") env.getMinio() + env.runMinio() if runtime.GOOS == "darwin" { // install the libraries necessary for fuse @@ -126,6 +172,24 @@ func (env *TravisEnvironment) Prepare() { } } +func (env *TravisEnvironment) Teardown() { + msg("run travis teardown\n") + if env.minioSrv != nil { + msg("stopping minio server\n") + result := <-env.minioSrv.Result + if result.Error != nil { + msg("minio server returned error: %v\n", result.Error) + msg("stdout: %s\n", result.Stdout) + msg("stderr: %s\n", result.Stderr) + } + + err := os.RemoveAll(env.minioTempdir) + if err != nil { + msg("error removing minio tempdir %v: %v\n", env.minioTempdir, err) + } + } +} + func goVersionAtLeast151() bool { v := runtime.Version() @@ -140,10 +204,51 @@ func goVersionAtLeast151() bool { return true } -type MinioServer struct { - cmd *exec.Cmd - done bool - m sync.Mutex +type Background struct { + Cmd *exec.Cmd + Done chan struct{} + Result chan Result +} + +type Result struct { + Stdout, Stderr string + Error error +} + +func StartBackgroundCommand(env map[string]string, cmd string, args ...string) (*Background, error) { + msg("running background command %v %v\n", cmd, args) + b := Background{ + Done: make(chan struct{}), + Result: make(chan Result, 1), + } + + stdout := bytes.NewBuffer(nil) + stderr := bytes.NewBuffer(nil) + + c := exec.Command(cmd, args...) + c.Stdout = stdout + c.Stderr = stderr + c.Env = updateEnv(os.Environ(), env) + + b.Cmd = c + + err := c.Start() + if err != nil { + msg("error starting background job %v: %v\n", cmd, err) + return nil, err + } + + go func() { + err := b.Cmd.Wait() + msg("background job %v returned: %v\n", cmd, err) + b.Result <- Result{ + Stdout: string(stdout.Bytes()), + Stderr: string(stderr.Bytes()), + Error: err, + } + }() + + return &b, nil } func (env *TravisEnvironment) RunTests() { @@ -159,13 +264,12 @@ func (env *TravisEnvironment) RunTests() { os.Exit(9) } - envWithGOPATH := make(map[string]string) - envWithGOPATH["GOPATH"] = cwd + ":" + filepath.Join(cwd, "vendor") + env.env["GOPATH"] = cwd + ":" + filepath.Join(cwd, "vendor") if *runCrossCompile { // compile for all target architectures with tags for _, tags := range []string{"release", "debug"} { - runWithEnv(envWithGOPATH, "gox", "-verbose", + runWithEnv(env.env, "gox", "-verbose", "-os", strings.Join(env.goxOS, " "), "-arch", strings.Join(env.goxArch, " "), "-tags", tags, @@ -177,25 +281,10 @@ func (env *TravisEnvironment) RunTests() { // run the build script run("go", "run", "build.go") - var srv *MinioServer - if env.minio != "" { - srv, err = NewMinioServer(env.minio) - if err != nil { - fmt.Fprintf(os.Stderr, "error running minio server: %v", err) - os.Exit(8) - } - - for k, v := range minioEnv { - envWithGOPATH[k] = v - } - } - // run the tests and gather coverage information - runWithEnv(envWithGOPATH, "gotestcover", "-coverprofile", "all.cov", "cmds/...", "restic/...") + runWithEnv(env.env, "gotestcover", "-coverprofile", "all.cov", "cmds/...", "restic/...") runGofmt() - - srv.Stop() } type AppveyorEnvironment struct{} @@ -208,6 +297,8 @@ func (env *AppveyorEnvironment) RunTests() { run("go", "run", "build.go", "-v", "-T") } +func (env *AppveyorEnvironment) Teardown() {} + // findGoFiles returns a list of go source code file names below dir. func findGoFiles(dir string) (list []string, err error) { err = filepath.Walk(dir, func(name string, fi os.FileInfo, err error) error { @@ -310,77 +401,6 @@ func runWithEnv(env map[string]string, command string, args ...string) { } } -var minioServerEnv = map[string]string{ - "MINIO_ACCESS_KEY": "KEBIYDZ87HCIH5D17YCN", - "MINIO_SECRET_KEY": "bVX1KhipSBPopEfmhc7rGz8ooxx27xdJ7Gkh1mVe", -} - -var minioEnv = map[string]string{ - "RESTIC_TEST_S3_SERVER": "http://127.0.0.1:9000", - "AWS_ACCESS_KEY_ID": "KEBIYDZ87HCIH5D17YCN", - "AWS_SECRET_ACCESS_KEY": "bVX1KhipSBPopEfmhc7rGz8ooxx27xdJ7Gkh1mVe", -} - -// NewMinioServer prepares and runs a minio server for the s3 backend tests in -// a temporary directory. -func NewMinioServer(minio string) (*MinioServer, error) { - msg("running minio server\n") - - dir, err := ioutil.TempDir("", "minio-root") - if err != nil { - return nil, err - } - - out := bytes.NewBuffer(nil) - cmd := exec.Command(minio, - "server", - "--address", "127.0.0.1:9000", - dir) - cmd.Stdout = out - cmd.Stderr = out - cmd.Env = updateEnv(os.Environ(), minioServerEnv) - - err = cmd.Start() - if err != nil { - return nil, err - } - - srv := &MinioServer{cmd: cmd} - go srv.Wait() - - return srv, nil -} - -func (m *MinioServer) Stop() { - if m == nil { - return - } - - msg("stopping minio server\n") - m.m.Lock() - m.done = true - m.m.Unlock() - err := m.cmd.Process.Kill() - if err != nil { - fmt.Fprintf(os.Stderr, "error stopping minio server: %v", err) - os.Exit(8) - } -} - -func (m *MinioServer) Wait() { - err := m.cmd.Wait() - msg("minio server exited\n") - m.m.Lock() - done := m.done - m.m.Unlock() - - if err != nil && !done { - fmt.Fprintf(os.Stderr, "error running minio server: %#v, output:\n", err) - // io.Copy(os.Stderr, out) - os.Exit(12) - } -} - func isTravis() bool { return os.Getenv("TRAVIS_BUILD_DIR") != "" } @@ -402,7 +422,7 @@ func main() { os.Exit(1) } - for _, f := range []func(){env.Prepare, env.RunTests} { + for _, f := range []func(){env.Prepare, env.RunTests, env.Teardown} { f() } } From aa43b69651f4a1d1fe76ba65123fec26e2818658 Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Sun, 17 Apr 2016 18:22:26 +0200 Subject: [PATCH 07/10] Better error reporting for CI tests --- run_integration_tests.go | 167 ++++++++++++++++++++++----------------- 1 file changed, 95 insertions(+), 72 deletions(-) diff --git a/run_integration_tests.go b/run_integration_tests.go index 1541eafbe..e9aa759c9 100644 --- a/run_integration_tests.go +++ b/run_integration_tests.go @@ -19,6 +19,7 @@ import ( var runCrossCompile = flag.Bool("cross-compile", true, "run cross compilation tests") var minioServer = flag.String("minio", "", "path to the minio server binary") +var debug = flag.Bool("debug", false, "output debug messages") var minioServerEnv = map[string]string{ "MINIO_ACCESS_KEY": "KEBIYDZ87HCIH5D17YCN", @@ -36,9 +37,9 @@ func init() { } type CIEnvironment interface { - Prepare() - RunTests() - Teardown() + Prepare() error + RunTests() error + Teardown() error } type TravisEnvironment struct { @@ -52,17 +53,16 @@ type TravisEnvironment struct { env map[string]string } -func (env *TravisEnvironment) getMinio() { +func (env *TravisEnvironment) getMinio() error { if *minioServer != "" { msg("using minio server at %q\n", *minioServer) env.minio = *minioServer - return + return nil } tempfile, err := ioutil.TempFile("", "minio-server-") if err != nil { - fmt.Fprintf(os.Stderr, "create tempfile failed: %v\n", err) - os.Exit(10) + return fmt.Errorf("create tempfile for minio download failed: %v\n", err) } url := fmt.Sprintf("https://dl.minio.io/server/minio/release/%s-%s/minio", @@ -70,66 +70,70 @@ func (env *TravisEnvironment) getMinio() { msg("downloading %v\n", url) res, err := http.Get(url) if err != nil { - msg("downloading minio failed: %v\n", err) - return + return fmt.Errorf("error downloading minio server: %v\n", err) } _, err = io.Copy(tempfile, res.Body) if err != nil { - msg("downloading minio failed: %v\n", err) - return + return fmt.Errorf("error saving minio server to file: %v\n", err) } err = res.Body.Close() if err != nil { - msg("saving minio failed: %v\n", err) - return + return fmt.Errorf("error closing HTTP download: %v\n", err) } err = tempfile.Close() if err != nil { msg("closing tempfile failed: %v\n", err) - return + return fmt.Errorf("error closing minio server file: %v\n", err) } err = os.Chmod(tempfile.Name(), 0755) if err != nil { - msg("making minio server executable failed: %v\n", err) - return + return fmt.Errorf("chmod(minio-server) failed: %v", err) } msg("downloaded minio server to %v\n", tempfile.Name()) env.minio = tempfile.Name() + return nil } -func (env *TravisEnvironment) runMinio() { - // start minio server - if env.minio != "" { - msg("starting minio server at %s", env.minio) - - dir, err := ioutil.TempDir("", "minio-root") - if err != nil { - os.Exit(80) - } - - env.minioSrv, err = StartBackgroundCommand(minioServerEnv, env.minio, - "server", - "--address", "127.0.0.1:9000", - dir) - if err != nil { - fmt.Fprintf(os.Stderr, "error running minio server: %v", err) - os.Exit(80) - } - - for k, v := range minioEnv { - env.env[k] = v - } - - env.minioTempdir = dir +func (env *TravisEnvironment) runMinio() error { + if env.minio == "" { + return nil } + + // start minio server + msg("starting minio server at %s", env.minio) + + dir, err := ioutil.TempDir("", "minio-root") + if err != nil { + return fmt.Errorf("running minio server failed: %v", err) + } + + env.minioSrv, err = StartBackgroundCommand(minioServerEnv, env.minio, + "server", + "--address", "127.0.0.1:9000", + dir) + if err != nil { + return fmt.Errorf("error running minio server: %v", err) + } + + // go func() { + // time.Sleep(300 * time.Millisecond) + // env.minioSrv.Cmd.Process.Kill() + // }() + + for k, v := range minioEnv { + env.env[k] = v + } + + env.minioTempdir = dir + return nil } -func (env *TravisEnvironment) Prepare() { +func (env *TravisEnvironment) Prepare() error { env.env = make(map[string]string) msg("preparing environment for Travis CI\n") @@ -170,17 +174,27 @@ func (env *TravisEnvironment) Prepare() { "-arch", strings.Join(env.goxArch, " ")) } } + + return nil } -func (env *TravisEnvironment) Teardown() { +func (env *TravisEnvironment) Teardown() error { msg("run travis teardown\n") if env.minioSrv != nil { msg("stopping minio server\n") - result := <-env.minioSrv.Result - if result.Error != nil { - msg("minio server returned error: %v\n", result.Error) - msg("stdout: %s\n", result.Stdout) - msg("stderr: %s\n", result.Stderr) + + if env.minioSrv.Cmd.ProcessState == nil { + err := env.minioSrv.Cmd.Process.Kill() + if err != nil { + fmt.Fprintf(os.Stderr, "error killing minio server process: %v", err) + } + } else { + result := <-env.minioSrv.Result + if result.Error != nil { + msg("minio server returned error: %v\n", result.Error) + msg("stdout: %s\n", result.Stdout) + msg("stderr: %s\n", result.Stderr) + } } err := os.RemoveAll(env.minioTempdir) @@ -188,6 +202,8 @@ func (env *TravisEnvironment) Teardown() { msg("error removing minio tempdir %v: %v\n", env.minioTempdir, err) } } + + return nil } func goVersionAtLeast151() bool { @@ -206,7 +222,6 @@ func goVersionAtLeast151() bool { type Background struct { Cmd *exec.Cmd - Done chan struct{} Result chan Result } @@ -218,7 +233,6 @@ type Result struct { func StartBackgroundCommand(env map[string]string, cmd string, args ...string) (*Background, error) { msg("running background command %v %v\n", cmd, args) b := Background{ - Done: make(chan struct{}), Result: make(chan Result, 1), } @@ -228,6 +242,11 @@ func StartBackgroundCommand(env map[string]string, cmd string, args ...string) ( c := exec.Command(cmd, args...) c.Stdout = stdout c.Stderr = stderr + + if *debug { + c.Stdout = io.MultiWriter(c.Stdout, os.Stdout) + c.Stderr = io.MultiWriter(c.Stderr, os.Stderr) + } c.Env = updateEnv(os.Environ(), env) b.Cmd = c @@ -241,6 +260,8 @@ func StartBackgroundCommand(env map[string]string, cmd string, args ...string) ( go func() { err := b.Cmd.Wait() msg("background job %v returned: %v\n", cmd, err) + msg("stdout: %s\n", stdout.Bytes()) + msg("stderr: %s\n", stderr.Bytes()) b.Result <- Result{ Stdout: string(stdout.Bytes()), Stderr: string(stderr.Bytes()), @@ -251,7 +272,7 @@ func StartBackgroundCommand(env map[string]string, cmd string, args ...string) ( return &b, nil } -func (env *TravisEnvironment) RunTests() { +func (env *TravisEnvironment) RunTests() error { // run fuse tests on darwin if runtime.GOOS != "darwin" { msg("skip fuse integration tests on %v\n", runtime.GOOS) @@ -260,8 +281,7 @@ func (env *TravisEnvironment) RunTests() { cwd, err := os.Getwd() if err != nil { - fmt.Fprintf(os.Stderr, "Getwd() returned error: %v", err) - os.Exit(9) + return fmt.Errorf("Getwd() returned error: %v", err) } env.env["GOPATH"] = cwd + ":" + filepath.Join(cwd, "vendor") @@ -284,20 +304,24 @@ func (env *TravisEnvironment) RunTests() { // run the tests and gather coverage information runWithEnv(env.env, "gotestcover", "-coverprofile", "all.cov", "cmds/...", "restic/...") - runGofmt() + return runGofmt() } type AppveyorEnvironment struct{} -func (env *AppveyorEnvironment) Prepare() { +func (env *AppveyorEnvironment) Prepare() error { msg("preparing environment for Appveyor CI\n") + return nil } -func (env *AppveyorEnvironment) RunTests() { +func (env *AppveyorEnvironment) RunTests() error { run("go", "run", "build.go", "-v", "-T") + return nil } -func (env *AppveyorEnvironment) Teardown() {} +func (env *AppveyorEnvironment) Teardown() error { + return nil +} // findGoFiles returns a list of go source code file names below dir. func findGoFiles(dir string) (list []string, err error) { @@ -345,17 +369,15 @@ func updateEnv(env []string, override map[string]string) []string { return newEnv } -func runGofmt() { +func runGofmt() error { dir, err := os.Getwd() if err != nil { - fmt.Fprintf(os.Stderr, "Getwd(): %v\n", err) - os.Exit(5) + return fmt.Errorf("Getwd(): %v\n", err) } files, err := findGoFiles(dir) if err != nil { - fmt.Fprintf(os.Stderr, "error finding Go files: %v\n", err) - os.Exit(4) + return fmt.Errorf("error finding Go files: %v\n", err) } msg("runGofmt() with %d files\n", len(files)) @@ -365,16 +387,14 @@ func runGofmt() { buf, err := cmd.Output() if err != nil { - fmt.Fprintf(os.Stderr, "error running gofmt: %v", err) - fmt.Fprintf(os.Stderr, "output:\n%s\n", buf) - os.Exit(3) + return fmt.Errorf("error running gofmt: %v\noutput: %s\n", err, buf) } if len(buf) > 0 { - fmt.Fprintf(os.Stderr, "not formatted with `gofmt`:\n") - fmt.Fprintln(os.Stderr, string(buf)) - os.Exit(6) + return fmt.Errorf("not formatted with `gofmt`:\n%s\n", buf) } + + return nil } func run(command string, args ...string) { @@ -384,7 +404,7 @@ func run(command string, args ...string) { // runWithEnv calls a command with the current environment, except the entries // of the env map are set additionally. -func runWithEnv(env map[string]string, command string, args ...string) { +func runWithEnv(env map[string]string, command string, args ...string) error { msg("runWithEnv %v %v\n", command, strings.Join(args, " ")) cmd := exec.Command(command, args...) cmd.Stdout = os.Stdout @@ -395,10 +415,10 @@ func runWithEnv(env map[string]string, command string, args ...string) { err := cmd.Run() if err != nil { - fmt.Fprintf(os.Stderr, "error running %v %v: %v", + return fmt.Errorf("error running %v %v: %v", command, strings.Join(args, " "), err) - os.Exit(3) } + return nil } func isTravis() bool { @@ -422,7 +442,10 @@ func main() { os.Exit(1) } - for _, f := range []func(){env.Prepare, env.RunTests, env.Teardown} { - f() + for _, f := range []func() error{env.Prepare, env.RunTests, env.Teardown} { + err := f() + if err != nil { + fmt.Fprintf(os.Stderr, "error: %v\n", err) + } } } From b2846ea49d48c47ef0c03babc247d15bbc2d9555 Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Sun, 17 Apr 2016 18:39:19 +0200 Subject: [PATCH 08/10] Add error handling --- run_integration_tests.go | 56 +++++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/run_integration_tests.go b/run_integration_tests.go index e9aa759c9..4aa3c53b9 100644 --- a/run_integration_tests.go +++ b/run_integration_tests.go @@ -138,21 +138,39 @@ func (env *TravisEnvironment) Prepare() error { msg("preparing environment for Travis CI\n") - run("go", "get", "golang.org/x/tools/cmd/cover") - run("go", "get", "github.com/mattn/goveralls") - run("go", "get", "github.com/pierrre/gotestcover") - env.getMinio() - env.runMinio() + for _, pkg := range []string{ + "golang.org/x/tools/cmd/cover", + "github.com/mattn/goveralls", + "github.com/pierrre/gotestcover", + } { + err := run("go", "get", pkg) + if err != nil { + return err + } + } + + if err := env.getMinio(); err != nil { + return err + } + if err := env.runMinio(); err != nil { + return err + } if runtime.GOOS == "darwin" { // install the libraries necessary for fuse - run("brew", "update") - run("brew", "cask", "install", "osxfuse") + if err := run("brew", "update"); err != nil { + return err + } + if err := run("brew", "cask", "install", "osxfuse"); err != nil { + return err + } } if *runCrossCompile { // only test cross compilation on linux with Travis - run("go", "get", "github.com/mitchellh/gox") + if err := run("go", "get", "github.com/mitchellh/gox"); err != nil { + return err + } if runtime.GOOS == "linux" { env.goxArch = []string{"386", "amd64"} if !strings.HasPrefix(runtime.Version(), "go1.3") { @@ -169,9 +187,13 @@ func (env *TravisEnvironment) Prepare() error { v := runtime.Version() if !strings.HasPrefix(v, "go1.5") && !strings.HasPrefix(v, "go1.6") { - run("gox", "-build-toolchain", + err := run("gox", "-build-toolchain", "-os", strings.Join(env.goxOS, " "), "-arch", strings.Join(env.goxArch, " ")) + + if err != nil { + return err + } } } @@ -299,10 +321,15 @@ func (env *TravisEnvironment) RunTests() error { } // run the build script - run("go", "run", "build.go") + if err := run("go", "run", "build.go"); err != nil { + return err + } // run the tests and gather coverage information - runWithEnv(env.env, "gotestcover", "-coverprofile", "all.cov", "cmds/...", "restic/...") + err = runWithEnv(env.env, "gotestcover", "-coverprofile", "all.cov", "cmds/...", "restic/...") + if err != nil { + return err + } return runGofmt() } @@ -315,8 +342,7 @@ func (env *AppveyorEnvironment) Prepare() error { } func (env *AppveyorEnvironment) RunTests() error { - run("go", "run", "build.go", "-v", "-T") - return nil + return run("go", "run", "build.go", "-v", "-T") } func (env *AppveyorEnvironment) Teardown() error { @@ -397,9 +423,9 @@ func runGofmt() error { return nil } -func run(command string, args ...string) { +func run(command string, args ...string) error { msg("run %v %v\n", command, strings.Join(args, " ")) - runWithEnv(nil, command, args...) + return runWithEnv(nil, command, args...) } // runWithEnv calls a command with the current environment, except the entries From baece5eeb33499581367ddf388072cf416cd0e36 Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Sun, 17 Apr 2016 18:47:00 +0200 Subject: [PATCH 09/10] Add error checking for CI tests --- run_integration_tests.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/run_integration_tests.go b/run_integration_tests.go index 4aa3c53b9..af831320a 100644 --- a/run_integration_tests.go +++ b/run_integration_tests.go @@ -468,10 +468,16 @@ func main() { os.Exit(1) } + foundError := false for _, f := range []func() error{env.Prepare, env.RunTests, env.Teardown} { err := f() if err != nil { + foundError = true fmt.Fprintf(os.Stderr, "error: %v\n", err) } } + + if foundError { + os.Exit(1) + } } From 22338903bf57aed17f7c7fb61d57cc52a2c4a17f Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Mon, 18 Apr 2016 20:33:45 +0200 Subject: [PATCH 10/10] Fix golint --- run_integration_tests.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/run_integration_tests.go b/run_integration_tests.go index af831320a..2f2c71284 100644 --- a/run_integration_tests.go +++ b/run_integration_tests.go @@ -1,4 +1,4 @@ -// +build ignore +// xbuild ignore package main @@ -36,12 +36,14 @@ func init() { flag.Parse() } +// CIEnvironment is implemented by environments where tests can be run. type CIEnvironment interface { Prepare() error RunTests() error Teardown() error } +// TravisEnvironment is the environment in which Travis tests run. type TravisEnvironment struct { goxArch []string goxOS []string @@ -133,6 +135,7 @@ func (env *TravisEnvironment) runMinio() error { return nil } +// Prepare installs dependencies and starts services in order to run the tests. func (env *TravisEnvironment) Prepare() error { env.env = make(map[string]string) @@ -200,6 +203,7 @@ func (env *TravisEnvironment) Prepare() error { return nil } +// Teardown stops backend services and cleans the environment again. func (env *TravisEnvironment) Teardown() error { msg("run travis teardown\n") if env.minioSrv != nil { @@ -242,16 +246,19 @@ func goVersionAtLeast151() bool { return true } +// Background is a program running in the background. type Background struct { Cmd *exec.Cmd Result chan Result } +// Result is the result of a program that ran in the background. type Result struct { Stdout, Stderr string Error error } +// StartBackgroundCommand runs a program in the background. func StartBackgroundCommand(env map[string]string, cmd string, args ...string) (*Background, error) { msg("running background command %v %v\n", cmd, args) b := Background{ @@ -294,6 +301,7 @@ func StartBackgroundCommand(env map[string]string, cmd string, args ...string) ( return &b, nil } +// RunTests starts the tests for Travis. func (env *TravisEnvironment) RunTests() error { // run fuse tests on darwin if runtime.GOOS != "darwin" { @@ -334,17 +342,21 @@ func (env *TravisEnvironment) RunTests() error { return runGofmt() } +// AppveyorEnvironment is the environment on Windows. type AppveyorEnvironment struct{} +// Prepare installs dependencies and starts services in order to run the tests. func (env *AppveyorEnvironment) Prepare() error { msg("preparing environment for Appveyor CI\n") return nil } +// RunTests start the tests. func (env *AppveyorEnvironment) RunTests() error { return run("go", "run", "build.go", "-v", "-T") } +// Teardown is a noop. func (env *AppveyorEnvironment) Teardown() error { return nil }