From 47c613f37fc33d9a64c02a40f52cad5fe3a2f974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20P=C3=89RONNET?= Date: Thu, 25 Feb 2021 19:35:47 +0100 Subject: [PATCH] feat(gexec) Add CompileTest functions. Close #410 (#411) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(gexec) Add CompileTest functions. Close #410 Adds following methods: - CompileTest(packagePath string, args ...string) (compiledPath string, err error) - CompileTestWithEnvironment(packagePath string, env []string, args ...string) (compiledPath string, err error) - CompileTestIn(gopath string, packagePath string, args ...string) (compiledPath string, err error) Signed-off-by: Pierre Péronnet * fix(gexec) Binaries for tests are built when needed This solve the issue in test where suite scoped firefly binary was removed by CleanupBuildArtifacts() in build_test.go Signed-off-by: Pierre Péronnet * feat(gexec) Add methods to get and compile tests Adds following methods: - GetAndCompileTest(packagePath string, args ...string) (compiledPath string, err error) - GetAndCompileTestWithEnvironment(packagePath string, env []string, args ...string) (compiledPath string, err error) - GetAndCompileTestIn(gopath string, packagePath string, args ...string) (compiledPath string, err error) Signed-off-by: Pierre Péronnet --- gexec/_fixture/firefly/main_test.go | 7 + gexec/build.go | 150 ++++++++- gexec/build_test.go | 177 +++++++++- gexec/exit_matcher_test.go | 4 +- gexec/gexec_suite_test.go | 8 - gexec/session_test.go | 499 ++++++++++++++++------------ 6 files changed, 604 insertions(+), 241 deletions(-) create mode 100644 gexec/_fixture/firefly/main_test.go diff --git a/gexec/_fixture/firefly/main_test.go b/gexec/_fixture/firefly/main_test.go new file mode 100644 index 000000000..9552fd2b0 --- /dev/null +++ b/gexec/_fixture/firefly/main_test.go @@ -0,0 +1,7 @@ +package main_test + +import "testing" + +func Test(t *testing.T) { + t.Log("Hum, it seems okay.") +} diff --git a/gexec/build.go b/gexec/build.go index 741d845f4..c7aba62b7 100644 --- a/gexec/build.go +++ b/gexec/build.go @@ -3,6 +3,8 @@ package gexec import ( + "crypto/md5" + "encoding/hex" "errors" "fmt" "go/build" @@ -46,6 +48,135 @@ func BuildIn(gopath string, packagePath string, args ...string) (compiledPath st return doBuild(gopath, packagePath, nil, args...) } +func doBuild(gopath, packagePath string, env []string, args ...string) (compiledPath string, err error) { + executable, err := newExecutablePath(gopath, packagePath) + if err != nil { + return "", err + } + + cmdArgs := append([]string{"build"}, args...) + cmdArgs = append(cmdArgs, "-o", executable, packagePath) + + build := exec.Command("go", cmdArgs...) + build.Env = replaceGoPath(os.Environ(), gopath) + build.Env = append(build.Env, env...) + + output, err := build.CombinedOutput() + if err != nil { + return "", fmt.Errorf("Failed to build %s:\n\nError:\n%s\n\nOutput:\n%s", packagePath, err, string(output)) + } + + return executable, nil +} + +/* +CompileTest uses go test to compile the test package at packagePath. The resulting binary is saved off in a temporary directory. +A path pointing to this binary is returned. + +CompileTest uses the $GOPATH set in your environment. If $GOPATH is not set and you are using Go 1.8+, +it will use the default GOPATH instead. It passes the variadic args on to `go test`. +*/ +func CompileTest(packagePath string, args ...string) (compiledPath string, err error) { + return doCompileTest(build.Default.GOPATH, packagePath, nil, args...) +} + +/* +GetAndCompileTest is identical to CompileTest but `go get` the package before compiling tests. +*/ +func GetAndCompileTest(packagePath string, args ...string) (compiledPath string, err error) { + if err := getForTest(build.Default.GOPATH, packagePath, nil); err != nil { + return "", err + } + + return doCompileTest(build.Default.GOPATH, packagePath, nil, args...) +} + +/* +CompileTestWithEnvironment is identical to CompileTest but allows you to specify env vars to be set at build time. +*/ +func CompileTestWithEnvironment(packagePath string, env []string, args ...string) (compiledPath string, err error) { + return doCompileTest(build.Default.GOPATH, packagePath, env, args...) +} + +/* +GetAndCompileTestWithEnvironment is identical to GetAndCompileTest but allows you to specify env vars to be set at build time. +*/ +func GetAndCompileTestWithEnvironment(packagePath string, env []string, args ...string) (compiledPath string, err error) { + if err := getForTest(build.Default.GOPATH, packagePath, env); err != nil { + return "", err + } + + return doCompileTest(build.Default.GOPATH, packagePath, env, args...) +} + +/* +CompileTestIn is identical to CompileTest but allows you to specify a custom $GOPATH (the first argument). +*/ +func CompileTestIn(gopath string, packagePath string, args ...string) (compiledPath string, err error) { + return doCompileTest(gopath, packagePath, nil, args...) +} + +/* +GetAndCompileTestIn is identical to GetAndCompileTest but allows you to specify a custom $GOPATH (the first argument). +*/ +func GetAndCompileTestIn(gopath string, packagePath string, args ...string) (compiledPath string, err error) { + if err := getForTest(gopath, packagePath, nil); err != nil { + return "", err + } + + return doCompileTest(gopath, packagePath, nil, args...) +} + +func isLocalPackage(packagePath string) bool { + return strings.HasPrefix(packagePath, ".") +} + +func getForTest(gopath, packagePath string, env []string) error { + if isLocalPackage(packagePath) { + return nil + } + + return doGet(gopath, packagePath, env, "-t") +} + +func doGet(gopath, packagePath string, env []string, args ...string) error { + args = append(args, packagePath) + args = append([]string{"get"}, args...) + + goGet := exec.Command("go", args...) + goGet.Dir = gopath + goGet.Env = replaceGoPath(os.Environ(), gopath) + goGet.Env = append(goGet.Env, env...) + + output, err := goGet.CombinedOutput() + if err != nil { + return fmt.Errorf("Failed to get %s:\n\nError:\n%s\n\nOutput:\n%s", packagePath, err, string(output)) + } + + return nil +} + +func doCompileTest(gopath, packagePath string, env []string, args ...string) (compiledPath string, err error) { + executable, err := newExecutablePath(gopath, packagePath, ".test") + if err != nil { + return "", err + } + + cmdArgs := append([]string{"test", "-c"}, args...) + cmdArgs = append(cmdArgs, "-o", executable, packagePath) + + build := exec.Command("go", cmdArgs...) + build.Env = replaceGoPath(os.Environ(), gopath) + build.Env = append(build.Env, env...) + + output, err := build.CombinedOutput() + if err != nil { + return "", fmt.Errorf("Failed to build %s:\n\nError:\n%s\n\nOutput:\n%s", packagePath, err, string(output)) + } + + return executable, nil +} + func replaceGoPath(environ []string, newGoPath string) []string { newEnviron := []string{} for _, v := range environ { @@ -56,7 +187,7 @@ func replaceGoPath(environ []string, newGoPath string) []string { return append(newEnviron, "GOPATH="+newGoPath) } -func doBuild(gopath, packagePath string, env []string, args ...string) (compiledPath string, err error) { +func newExecutablePath(gopath, packagePath string, suffixes ...string) (string, error) { tmpDir, err := temporaryDirectory() if err != nil { return "", err @@ -66,23 +197,14 @@ func doBuild(gopath, packagePath string, env []string, args ...string) (compiled return "", errors.New("$GOPATH not provided when building " + packagePath) } - executable := filepath.Join(tmpDir, path.Base(packagePath)) + hash := md5.Sum([]byte(packagePath)) + filename := fmt.Sprintf("%s-%x%s", path.Base(packagePath), hex.EncodeToString(hash[:]), strings.Join(suffixes, "")) + executable := filepath.Join(tmpDir, filename) + if runtime.GOOS == "windows" { executable += ".exe" } - cmdArgs := append([]string{"build"}, args...) - cmdArgs = append(cmdArgs, "-o", executable, packagePath) - - build := exec.Command("go", cmdArgs...) - build.Env = replaceGoPath(os.Environ(), gopath) - build.Env = append(build.Env, env...) - - output, err := build.CombinedOutput() - if err != nil { - return "", fmt.Errorf("Failed to build %s:\n\nError:\n%s\n\nOutput:\n%s", packagePath, err, string(output)) - } - return executable, nil } diff --git a/gexec/build_test.go b/gexec/build_test.go index 67b7f9000..99ee1e575 100644 --- a/gexec/build_test.go +++ b/gexec/build_test.go @@ -14,6 +14,31 @@ import ( var packagePath = "./_fixture/firefly" var _ = Describe(".Build", func() { + When("there have been previous calls to CompileTest", func() { + BeforeEach(func() { + _, err := gexec.CompileTest(packagePath) + Expect(err).ShouldNot(HaveOccurred()) + }) + + It("compiles the specified package", func() { + compiledPath, err := gexec.Build(packagePath) + Expect(err).ShouldNot(HaveOccurred()) + Expect(compiledPath).Should(BeAnExistingFile()) + }) + + Context("and CleanupBuildArtifacts has been called", func() { + BeforeEach(func() { + gexec.CleanupBuildArtifacts() + }) + + It("compiles the specified package", func() { + fireflyPath, err := gexec.Build(packagePath) + Expect(err).ShouldNot(HaveOccurred()) + Expect(fireflyPath).Should(BeAnExistingFile()) + }) + }) + }) + When("there have been previous calls to Build", func() { BeforeEach(func() { _, err := gexec.Build(packagePath) @@ -32,8 +57,7 @@ var _ = Describe(".Build", func() { }) It("compiles the specified package", func() { - var err error - fireflyPath, err = gexec.Build(packagePath) + fireflyPath, err := gexec.Build(packagePath) Expect(err).ShouldNot(HaveOccurred()) Expect(fireflyPath).Should(BeAnExistingFile()) }) @@ -93,8 +117,9 @@ var _ = Describe(".BuildIn", func() { }) It("appends the gopath env var", func() { - _, err := gexec.BuildIn(gopath, target) + compiledPath, err := gexec.BuildIn(gopath, target) Expect(err).NotTo(HaveOccurred()) + Expect(compiledPath).Should(BeAnExistingFile()) }) It("resets GOPATH to its original value", func() { @@ -104,6 +129,152 @@ var _ = Describe(".BuildIn", func() { }) }) +var _ = Describe(".CompileTest", func() { + Context("a remote package", func() { + const remotePackage = "github.com/onsi/ginkgo/types" + + It("compiles the specified test package", func() { + compiledPath, err := gexec.GetAndCompileTest(remotePackage) + Expect(err).ShouldNot(HaveOccurred()) + Expect(compiledPath).Should(BeAnExistingFile()) + }) + }) + + When("there have been previous calls to CompileTest", func() { + BeforeEach(func() { + _, err := gexec.CompileTest(packagePath) + Expect(err).ShouldNot(HaveOccurred()) + }) + + It("compiles the specified test package", func() { + compiledPath, err := gexec.CompileTest(packagePath) + Expect(err).ShouldNot(HaveOccurred()) + Expect(compiledPath).Should(BeAnExistingFile()) + }) + + Context("and CleanupBuildArtifacts has been called", func() { + BeforeEach(func() { + gexec.CleanupBuildArtifacts() + }) + + It("compiles the specified test package", func() { + fireflyTestPath, err := gexec.CompileTest(packagePath) + Expect(err).ShouldNot(HaveOccurred()) + Expect(fireflyTestPath).Should(BeAnExistingFile()) + }) + }) + }) + + When("there have been previous calls to Build", func() { + BeforeEach(func() { + _, err := gexec.Build(packagePath) + Expect(err).ShouldNot(HaveOccurred()) + }) + + It("compiles the specified test package", func() { + compiledPath, err := gexec.CompileTest(packagePath) + Expect(err).ShouldNot(HaveOccurred()) + Expect(compiledPath).Should(BeAnExistingFile()) + }) + + Context("and CleanupBuildArtifacts has been called", func() { + BeforeEach(func() { + gexec.CleanupBuildArtifacts() + }) + + It("compiles the specified test package", func() { + fireflyTestPath, err := gexec.CompileTest(packagePath) + Expect(err).ShouldNot(HaveOccurred()) + Expect(fireflyTestPath).Should(BeAnExistingFile()) + }) + }) + }) +}) + +var _ = Describe(".CompileTestWithEnvironment", func() { + var err error + env := []string{ + "GOOS=linux", + "GOARCH=amd64", + } + + Context("a remote package", func() { + const remotePackage = "github.com/onsi/ginkgo/types" + + It("compiles the specified test package with the specified env vars", func() { + compiledPath, err := gexec.GetAndCompileTestWithEnvironment(remotePackage, env) + Expect(err).ShouldNot(HaveOccurred()) + Expect(compiledPath).Should(BeAnExistingFile()) + }) + }) + + It("compiles the specified test package with the specified env vars", func() { + compiledPath, err := gexec.CompileTestWithEnvironment(packagePath, env) + Expect(err).ShouldNot(HaveOccurred()) + Expect(compiledPath).Should(BeAnExistingFile()) + }) + + It("returns the environment to a good state", func() { + _, err = gexec.CompileTestWithEnvironment(packagePath, env) + Expect(err).ShouldNot(HaveOccurred()) + Expect(os.Environ()).ShouldNot(ContainElement("GOOS=linux")) + }) +}) + +var _ = Describe(".CompiledTestIn", func() { + const ( + target = "github.com/onsi/gomega/gexec/_fixture/firefly" + ) + + var ( + original string + gopath string + ) + + BeforeEach(func() { + var err error + original = os.Getenv("GOPATH") + gopath, err = ioutil.TempDir("", "") + Expect(err).NotTo(HaveOccurred()) + copyFile(filepath.Join("_fixture", "firefly", "main.go"), filepath.Join(gopath, "src", target), "main.go") + Expect(os.Setenv("GOPATH", filepath.Join(os.TempDir(), "emptyFakeGopath"))).To(Succeed()) + Expect(os.Environ()).To(ContainElement(fmt.Sprintf("GOPATH=%s", filepath.Join(os.TempDir(), "emptyFakeGopath")))) + }) + + AfterEach(func() { + if original == "" { + Expect(os.Unsetenv("GOPATH")).To(Succeed()) + } else { + Expect(os.Setenv("GOPATH", original)).To(Succeed()) + } + if gopath != "" { + os.RemoveAll(gopath) + } + }) + + Context("a remote package", func() { + const remotePackage = "github.com/onsi/ginkgo/types" + + It("compiles the specified test package", func() { + compiledPath, err := gexec.GetAndCompileTestIn(gopath, remotePackage) + Expect(err).ShouldNot(HaveOccurred()) + Expect(compiledPath).Should(BeAnExistingFile()) + }) + }) + + It("appends the gopath env var", func() { + compiledPath, err := gexec.CompileTestIn(gopath, target) + Expect(err).NotTo(HaveOccurred()) + Expect(compiledPath).Should(BeAnExistingFile()) + }) + + It("resets GOPATH to its original value", func() { + _, err := gexec.CompileTestIn(gopath, target) + Expect(err).NotTo(HaveOccurred()) + Expect(os.Getenv("GOPATH")).To(Equal(filepath.Join(os.TempDir(), "emptyFakeGopath"))) + }) +}) + func copyFile(source, directory, basename string) { Expect(os.MkdirAll(directory, 0755)).To(Succeed()) content, err := ioutil.ReadFile(source) diff --git a/gexec/exit_matcher_test.go b/gexec/exit_matcher_test.go index 9abc3226f..68dfdc256 100644 --- a/gexec/exit_matcher_test.go +++ b/gexec/exit_matcher_test.go @@ -21,7 +21,9 @@ var _ = Describe("ExitMatcher", func() { var session *Session BeforeEach(func() { - var err error + fireflyPath, err := Build("./_fixture/firefly") + Expect(err).ShouldNot(HaveOccurred()) + command = exec.Command(fireflyPath, "0") session, err = Start(command, nil, nil) Expect(err).ShouldNot(HaveOccurred()) diff --git a/gexec/gexec_suite_test.go b/gexec/gexec_suite_test.go index dc8e1f40c..1d4ab51dc 100644 --- a/gexec/gexec_suite_test.go +++ b/gexec/gexec_suite_test.go @@ -8,15 +8,7 @@ import ( "testing" ) -var fireflyPath string - func TestGexec(t *testing.T) { - BeforeSuite(func() { - var err error - fireflyPath, err = gexec.Build("./_fixture/firefly") - Expect(err).ShouldNot(HaveOccurred()) - }) - AfterSuite(func() { gexec.CleanupBuildArtifacts() }) diff --git a/gexec/session_test.go b/gexec/session_test.go index 28ccbe3bd..1c8015b4e 100644 --- a/gexec/session_test.go +++ b/gexec/session_test.go @@ -17,314 +17,383 @@ import ( ) var _ = Describe("Session", func() { - var command *exec.Cmd - var session *Session + Context("firefly binary", func() { + var fireflyPath string + var command *exec.Cmd + var session *Session - var outWriter, errWriter io.Writer + var outWriter, errWriter io.Writer - BeforeEach(func() { - outWriter = nil - errWriter = nil - }) + BeforeEach(func() { + outWriter = nil + errWriter = nil - JustBeforeEach(func() { - command = exec.Command(fireflyPath) - var err error - session, err = Start(command, outWriter, errWriter) - Expect(err).ShouldNot(HaveOccurred()) - }) + var err error + fireflyPath, err = Build("./_fixture/firefly") + Expect(err).ShouldNot(HaveOccurred()) - Context("running a command", func() { - It("should start the process", func() { - Expect(command.Process).ShouldNot(BeNil()) }) - It("should wrap the process's stdout and stderr with gbytes buffers", func(done Done) { - Eventually(session.Out).Should(Say("We've done the impossible, and that makes us mighty")) - Eventually(session.Err).Should(Say("Ah, curse your sudden but inevitable betrayal!")) - defer session.Out.CancelDetects() - - select { - case <-session.Out.Detect("Can we maybe vote on the whole murdering people issue"): - Eventually(session).Should(Exit(0)) - case <-session.Out.Detect("I swear by my pretty floral bonnet, I will end you."): - Eventually(session).Should(Exit(1)) - case <-session.Out.Detect("My work's illegal, but at least it's honest."): - Eventually(session).Should(Exit(2)) - } - - close(done) + JustBeforeEach(func() { + command = exec.Command(fireflyPath) + var err error + session, err = Start(command, outWriter, errWriter) + Expect(err).ShouldNot(HaveOccurred()) }) - It("should satisfy the gbytes.BufferProvider interface, passing Stdout", func() { - Eventually(session).Should(Say("We've done the impossible, and that makes us mighty")) - Eventually(session).Should(Exit()) + Context("running a command", func() { + It("should start the process", func() { + Expect(command.Process).ShouldNot(BeNil()) + }) + + It("should wrap the process's stdout and stderr with gbytes buffers", func(done Done) { + Eventually(session.Out).Should(Say("We've done the impossible, and that makes us mighty")) + Eventually(session.Err).Should(Say("Ah, curse your sudden but inevitable betrayal!")) + defer session.Out.CancelDetects() + + select { + case <-session.Out.Detect("Can we maybe vote on the whole murdering people issue"): + Eventually(session).Should(Exit(0)) + case <-session.Out.Detect("I swear by my pretty floral bonnet, I will end you."): + Eventually(session).Should(Exit(1)) + case <-session.Out.Detect("My work's illegal, but at least it's honest."): + Eventually(session).Should(Exit(2)) + } + + close(done) + }) + + It("should satisfy the gbytes.BufferProvider interface, passing Stdout", func() { + Eventually(session).Should(Say("We've done the impossible, and that makes us mighty")) + Eventually(session).Should(Exit()) + }) }) - }) - Describe("providing the exit code", func() { - It("should provide the app's exit code", func() { - Expect(session.ExitCode()).Should(Equal(-1)) + Describe("providing the exit code", func() { + It("should provide the app's exit code", func() { + Expect(session.ExitCode()).Should(Equal(-1)) - Eventually(session).Should(Exit()) - Expect(session.ExitCode()).Should(BeNumerically(">=", 0)) - Expect(session.ExitCode()).Should(BeNumerically("<", 3)) + Eventually(session).Should(Exit()) + Expect(session.ExitCode()).Should(BeNumerically(">=", 0)) + Expect(session.ExitCode()).Should(BeNumerically("<", 3)) + }) }) - }) - Describe("wait", func() { - It("should wait till the command exits", func() { - Expect(session.ExitCode()).Should(Equal(-1)) - Expect(session.Wait().ExitCode()).Should(BeNumerically(">=", 0)) - Expect(session.Wait().ExitCode()).Should(BeNumerically("<", 3)) + Describe("wait", func() { + It("should wait till the command exits", func() { + Expect(session.ExitCode()).Should(Equal(-1)) + Expect(session.Wait().ExitCode()).Should(BeNumerically(">=", 0)) + Expect(session.Wait().ExitCode()).Should(BeNumerically("<", 3)) + }) }) - }) - Describe("exited", func() { - It("should close when the command exits", func() { - Eventually(session.Exited).Should(BeClosed()) - Expect(session.ExitCode()).ShouldNot(Equal(-1)) + Describe("exited", func() { + It("should close when the command exits", func() { + Eventually(session.Exited).Should(BeClosed()) + Expect(session.ExitCode()).ShouldNot(Equal(-1)) + }) }) - }) - Describe("kill", func() { - It("should kill the command", func() { - session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Expect(err).ShouldNot(HaveOccurred()) + Describe("kill", func() { + It("should kill the command", func() { + session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) + Expect(err).ShouldNot(HaveOccurred()) - session.Kill() - Eventually(session).Should(Exit(128 + 9)) + session.Kill() + Eventually(session).Should(Exit(128 + 9)) + }) }) - }) - Describe("interrupt", func() { - It("should interrupt the command", func() { - session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Expect(err).ShouldNot(HaveOccurred()) + Describe("interrupt", func() { + It("should interrupt the command", func() { + session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) + Expect(err).ShouldNot(HaveOccurred()) - session.Interrupt() - Eventually(session).Should(Exit(128 + 2)) + session.Interrupt() + Eventually(session).Should(Exit(128 + 2)) + }) }) - }) - Describe("terminate", func() { - It("should terminate the command", func() { - session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Expect(err).ShouldNot(HaveOccurred()) + Describe("terminate", func() { + It("should terminate the command", func() { + session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) + Expect(err).ShouldNot(HaveOccurred()) - session.Terminate() - Eventually(session).Should(Exit(128 + 15)) + session.Terminate() + Eventually(session).Should(Exit(128 + 15)) + }) }) - }) - Describe("signal", func() { - It("should send the signal to the command", func() { - session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Expect(err).ShouldNot(HaveOccurred()) + Describe("signal", func() { + It("should send the signal to the command", func() { + session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) + Expect(err).ShouldNot(HaveOccurred()) - session.Signal(syscall.SIGABRT) - Eventually(session).Should(Exit(128 + 6)) - }) + session.Signal(syscall.SIGABRT) + Eventually(session).Should(Exit(128 + 6)) + }) - It("should ignore sending a signal if the command did not start", func() { - session, err := Start(exec.Command("notexisting"), GinkgoWriter, GinkgoWriter) - Expect(err).To(HaveOccurred()) + It("should ignore sending a signal if the command did not start", func() { + session, err := Start(exec.Command("notexisting"), GinkgoWriter, GinkgoWriter) + Expect(err).To(HaveOccurred()) - Expect(func() { session.Signal(syscall.SIGUSR1) }).NotTo(Panic()) + Expect(func() { session.Signal(syscall.SIGUSR1) }).NotTo(Panic()) + }) }) - }) - Context("tracking sessions", func() { - BeforeEach(func() { - KillAndWait() - }) + Context("tracking sessions", func() { + BeforeEach(func() { + KillAndWait() + }) - Describe("kill", func() { - It("should kill all the started sessions", func() { - session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Expect(err).ShouldNot(HaveOccurred()) + Describe("kill", func() { + It("should kill all the started sessions", func() { + session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) + Expect(err).ShouldNot(HaveOccurred()) - session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Expect(err).ShouldNot(HaveOccurred()) + session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) + Expect(err).ShouldNot(HaveOccurred()) - session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Expect(err).ShouldNot(HaveOccurred()) + session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) + Expect(err).ShouldNot(HaveOccurred()) - Kill() + Kill() - Eventually(session1).Should(Exit(128 + 9)) - Eventually(session2).Should(Exit(128 + 9)) - Eventually(session3).Should(Exit(128 + 9)) - }) + Eventually(session1).Should(Exit(128 + 9)) + Eventually(session2).Should(Exit(128 + 9)) + Eventually(session3).Should(Exit(128 + 9)) + }) - It("should not track unstarted sessions", func() { - _, err := Start(exec.Command("does not exist", "10000000"), GinkgoWriter, GinkgoWriter) - Expect(err).Should(HaveOccurred()) + It("should not track unstarted sessions", func() { + _, err := Start(exec.Command("does not exist", "10000000"), GinkgoWriter, GinkgoWriter) + Expect(err).Should(HaveOccurred()) - session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Expect(err).ShouldNot(HaveOccurred()) + session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) + Expect(err).ShouldNot(HaveOccurred()) - session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Expect(err).ShouldNot(HaveOccurred()) + session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) + Expect(err).ShouldNot(HaveOccurred()) + + Kill() - Kill() + Eventually(session2).Should(Exit(128 + 9)) + Eventually(session3).Should(Exit(128 + 9)) + }) - Eventually(session2).Should(Exit(128 + 9)) - Eventually(session3).Should(Exit(128 + 9)) }) - }) + Describe("killAndWait", func() { + It("should kill all the started sessions and wait for them to finish", func() { + session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) + Expect(err).ShouldNot(HaveOccurred()) - Describe("killAndWait", func() { - It("should kill all the started sessions and wait for them to finish", func() { - session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Expect(err).ShouldNot(HaveOccurred()) + session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) + Expect(err).ShouldNot(HaveOccurred()) - session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Expect(err).ShouldNot(HaveOccurred()) + session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) + Expect(err).ShouldNot(HaveOccurred()) - session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Expect(err).ShouldNot(HaveOccurred()) + KillAndWait() + Expect(session1).Should(Exit(128+9), "Should have exited") + Expect(session2).Should(Exit(128+9), "Should have exited") + Expect(session3).Should(Exit(128+9), "Should have exited") + }) + }) - KillAndWait() - Expect(session1).Should(Exit(128+9), "Should have exited") - Expect(session2).Should(Exit(128+9), "Should have exited") - Expect(session3).Should(Exit(128+9), "Should have exited") + Describe("terminate", func() { + It("should terminate all the started sessions", func() { + session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) + Expect(err).ShouldNot(HaveOccurred()) + + session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) + Expect(err).ShouldNot(HaveOccurred()) + + session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) + Expect(err).ShouldNot(HaveOccurred()) + + Terminate() + + Eventually(session1).Should(Exit(128 + 15)) + Eventually(session2).Should(Exit(128 + 15)) + Eventually(session3).Should(Exit(128 + 15)) + }) }) - }) - Describe("terminate", func() { - It("should terminate all the started sessions", func() { - session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Expect(err).ShouldNot(HaveOccurred()) + Describe("terminateAndWait", func() { + It("should terminate all the started sessions, and wait for them to exit", func() { + session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) + Expect(err).ShouldNot(HaveOccurred()) - session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Expect(err).ShouldNot(HaveOccurred()) + session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) + Expect(err).ShouldNot(HaveOccurred()) - session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Expect(err).ShouldNot(HaveOccurred()) + session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) + Expect(err).ShouldNot(HaveOccurred()) - Terminate() + TerminateAndWait() - Eventually(session1).Should(Exit(128 + 15)) - Eventually(session2).Should(Exit(128 + 15)) - Eventually(session3).Should(Exit(128 + 15)) + Expect(session1).Should(Exit(128+15), "Should have exited") + Expect(session2).Should(Exit(128+15), "Should have exited") + Expect(session3).Should(Exit(128+15), "Should have exited") + }) }) - }) - Describe("terminateAndWait", func() { - It("should terminate all the started sessions, and wait for them to exit", func() { - session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Expect(err).ShouldNot(HaveOccurred()) + Describe("signal", func() { + It("should signal all the started sessions", func() { + session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) + Expect(err).ShouldNot(HaveOccurred()) - session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Expect(err).ShouldNot(HaveOccurred()) + session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) + Expect(err).ShouldNot(HaveOccurred()) - session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Expect(err).ShouldNot(HaveOccurred()) + session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) + Expect(err).ShouldNot(HaveOccurred()) - TerminateAndWait() + Signal(syscall.SIGABRT) - Expect(session1).Should(Exit(128+15), "Should have exited") - Expect(session2).Should(Exit(128+15), "Should have exited") - Expect(session3).Should(Exit(128+15), "Should have exited") + Eventually(session1).Should(Exit(128 + 6)) + Eventually(session2).Should(Exit(128 + 6)) + Eventually(session3).Should(Exit(128 + 6)) + }) }) - }) - Describe("signal", func() { - It("should signal all the started sessions", func() { - session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Expect(err).ShouldNot(HaveOccurred()) + Describe("interrupt", func() { + It("should interrupt all the started sessions, and not wait", func() { + session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) + Expect(err).ShouldNot(HaveOccurred()) - session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Expect(err).ShouldNot(HaveOccurred()) + session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) + Expect(err).ShouldNot(HaveOccurred()) - session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Expect(err).ShouldNot(HaveOccurred()) + session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) + Expect(err).ShouldNot(HaveOccurred()) - Signal(syscall.SIGABRT) + Interrupt() - Eventually(session1).Should(Exit(128 + 6)) - Eventually(session2).Should(Exit(128 + 6)) - Eventually(session3).Should(Exit(128 + 6)) + Eventually(session1).Should(Exit(128 + 2)) + Eventually(session2).Should(Exit(128 + 2)) + Eventually(session3).Should(Exit(128 + 2)) + }) }) }) - Describe("interrupt", func() { - It("should interrupt all the started sessions, and not wait", func() { - session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Expect(err).ShouldNot(HaveOccurred()) + When("the command exits", func() { + It("should close the buffers", func() { + Eventually(session).Should(Exit()) - session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Expect(err).ShouldNot(HaveOccurred()) + Expect(session.Out.Closed()).Should(BeTrue()) + Expect(session.Err.Closed()).Should(BeTrue()) - session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) - Expect(err).ShouldNot(HaveOccurred()) + Expect(session.Out).Should(Say("We've done the impossible, and that makes us mighty")) + }) - Interrupt() + var So = It - Eventually(session1).Should(Exit(128 + 2)) - Eventually(session2).Should(Exit(128 + 2)) - Eventually(session3).Should(Exit(128 + 2)) + So("this means that eventually should short circuit", func() { + t := time.Now() + failures := InterceptGomegaFailures(func() { + Eventually(session).Should(Say("blah blah blah blah blah")) + }) + Expect(time.Since(t)).Should(BeNumerically("<=", 500*time.Millisecond)) + Expect(failures).Should(HaveLen(1)) }) }) - }) - When("the command exits", func() { - It("should close the buffers", func() { - Eventually(session).Should(Exit()) + When("wrapping out and err", func() { + var ( + outWriterBuffer, errWriterBuffer *Buffer + ) - Expect(session.Out.Closed()).Should(BeTrue()) - Expect(session.Err.Closed()).Should(BeTrue()) + BeforeEach(func() { + outWriterBuffer = NewBuffer() + outWriter = outWriterBuffer + errWriterBuffer = NewBuffer() + errWriter = errWriterBuffer + }) - Expect(session.Out).Should(Say("We've done the impossible, and that makes us mighty")) - }) + It("should route to both the provided writers and the gbytes buffers", func() { + Eventually(session.Out).Should(Say("We've done the impossible, and that makes us mighty")) + Eventually(session.Err).Should(Say("Ah, curse your sudden but inevitable betrayal!")) - var So = It + Expect(outWriterBuffer.Contents()).Should(ContainSubstring("We've done the impossible, and that makes us mighty")) + Expect(errWriterBuffer.Contents()).Should(ContainSubstring("Ah, curse your sudden but inevitable betrayal!")) - So("this means that eventually should short circuit", func() { - t := time.Now() - failures := InterceptGomegaFailures(func() { - Eventually(session).Should(Say("blah blah blah blah blah")) + Eventually(session).Should(Exit()) + + Expect(outWriterBuffer.Contents()).Should(Equal(session.Out.Contents())) + Expect(errWriterBuffer.Contents()).Should(Equal(session.Err.Contents())) }) - Expect(time.Since(t)).Should(BeNumerically("<=", 500*time.Millisecond)) - Expect(failures).Should(HaveLen(1)) - }) - }) - When("wrapping out and err", func() { - var ( - outWriterBuffer, errWriterBuffer *Buffer - ) + When("discarding the output of the command", func() { + BeforeEach(func() { + outWriter = ioutil.Discard + errWriter = ioutil.Discard + }) - BeforeEach(func() { - outWriterBuffer = NewBuffer() - outWriter = outWriterBuffer - errWriterBuffer = NewBuffer() - errWriter = errWriterBuffer + It("executes succesfuly", func() { + Eventually(session).Should(Exit()) + }) + }) }) + }) - It("should route to both the provided writers and the gbytes buffers", func() { - Eventually(session.Out).Should(Say("We've done the impossible, and that makes us mighty")) - Eventually(session.Err).Should(Say("Ah, curse your sudden but inevitable betrayal!")) + Context("firefly tests", func() { + var fireflyTestPath string + var command *exec.Cmd + var session *Session - Expect(outWriterBuffer.Contents()).Should(ContainSubstring("We've done the impossible, and that makes us mighty")) - Expect(errWriterBuffer.Contents()).Should(ContainSubstring("Ah, curse your sudden but inevitable betrayal!")) + var outWriter, errWriter io.Writer - Eventually(session).Should(Exit()) + BeforeEach(func() { + outWriter = nil + errWriter = nil - Expect(outWriterBuffer.Contents()).Should(Equal(session.Out.Contents())) - Expect(errWriterBuffer.Contents()).Should(Equal(session.Err.Contents())) + var err error + fireflyTestPath, err = CompileTest("./_fixture/firefly") + Expect(err).ShouldNot(HaveOccurred()) }) - When("discarding the output of the command", func() { + JustBeforeEach(func() { + command = exec.Command(fireflyTestPath) + var err error + session, err = Start(command, outWriter, errWriter) + Expect(err).ShouldNot(HaveOccurred()) + }) + + When("wrapping out and err", func() { + var ( + outWriterBuffer, errWriterBuffer *Buffer + ) + BeforeEach(func() { - outWriter = ioutil.Discard - errWriter = ioutil.Discard + outWriterBuffer = NewBuffer() + outWriter = outWriterBuffer + errWriterBuffer = NewBuffer() + errWriter = errWriterBuffer }) - It("executes succesfuly", func() { + It("should route to both the provided writers and the gbytes buffers", func() { + Eventually(session.Out).Should(Say("PASS")) + Eventually(session.Err).Should(Say("")) + + Expect(outWriterBuffer.Contents()).Should(ContainSubstring("PASS")) + Expect(errWriterBuffer.Contents()).Should(BeEmpty()) + Eventually(session).Should(Exit()) + + Expect(outWriterBuffer.Contents()).Should(Equal(session.Out.Contents())) + Expect(errWriterBuffer.Contents()).Should(Equal(session.Err.Contents())) + }) + + When("discarding the output of the command", func() { + BeforeEach(func() { + outWriter = ioutil.Discard + errWriter = ioutil.Discard + }) + + It("executes succesfuly", func() { + Eventually(session).Should(Exit()) + }) }) }) })