go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/common/system/exec2/exec2_test.go (about) 1 // Copyright 2019 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package exec2 16 17 import ( 18 "context" 19 "os/exec" 20 "path/filepath" 21 "runtime" 22 "testing" 23 "time" 24 25 "go.chromium.org/luci/common/system/environ" 26 27 . "github.com/smartystreets/goconvey/convey" 28 . "go.chromium.org/luci/common/testing/assertions" 29 ) 30 31 func build(src, tmpdir string) (string, error) { 32 binary := filepath.Join(tmpdir, "exe.exe") 33 cmd := exec.Command("go", "build", "-o", binary, src) 34 if err := cmd.Run(); err != nil { 35 return "", err 36 } 37 return binary, nil 38 } 39 40 func TestExec(t *testing.T) { 41 t.Parallel() 42 43 Convey("TestExec", t, func() { 44 ctx := context.Background() 45 46 tmpdir := t.TempDir() 47 48 errCh := make(chan error, 1) 49 50 Convey("exit", func() { 51 testBinary, err := build(filepath.Join("testdata", "exit.go"), tmpdir) 52 So(err, ShouldBeNil) 53 54 Convey("exit 0", func() { 55 cmd := CommandContext(ctx, testBinary) 56 So(cmd.Start(), ShouldBeNil) 57 58 So(cmd.Wait(), ShouldBeNil) 59 60 So(cmd.ProcessState.ExitCode(), ShouldEqual, 0) 61 }) 62 63 Convey("exit 42", func() { 64 cmd := CommandContext(ctx, testBinary, "42") 65 So(cmd.Start(), ShouldBeNil) 66 67 So(cmd.Wait(), ShouldBeError, "exit status 42") 68 69 So(cmd.ProcessState.ExitCode(), ShouldEqual, 42) 70 }) 71 }) 72 73 Convey("timeout", func() { 74 testBinary, err := build(filepath.Join("testdata", "timeout.go"), tmpdir) 75 So(err, ShouldBeNil) 76 77 cmd := CommandContext(ctx, testBinary) 78 rc, err := cmd.StdoutPipe() 79 So(err, ShouldBeNil) 80 81 So(cmd.Start(), ShouldBeNil) 82 83 expected := []byte("I'm alive!") 84 buf := make([]byte, len(expected)) 85 n, err := rc.Read(buf) 86 So(err, ShouldBeNil) 87 So(n, ShouldEqual, len(expected)) 88 So(buf, ShouldResemble, expected) 89 90 So(rc.Close(), ShouldBeNil) 91 92 go func() { 93 errCh <- cmd.Wait() 94 }() 95 96 select { 97 case err := <-errCh: 98 Print(err) 99 So("should not reach here", ShouldBeNil) 100 case <-time.After(time.Millisecond): 101 } 102 103 So(cmd.Terminate(), ShouldBeNil) 104 105 select { 106 case err := <-errCh: 107 if runtime.GOOS == "windows" { 108 So(err, ShouldErrLike, "exit status") 109 } else { 110 So(err, ShouldErrLike, "signal: terminated") 111 } 112 // The value of the exit code depends on GOOS and version of Go runtime. 113 So(cmd.ProcessState.ExitCode(), ShouldNotEqual, 0) 114 case <-time.After(time.Minute): 115 Print(err) 116 So("should not reach here", ShouldBeNil) 117 } 118 }) 119 120 Convey("context timeout", func() { 121 testBinary, err := build(filepath.Join("testdata", "timeout.go"), tmpdir) 122 So(err, ShouldBeNil) 123 124 if runtime.GOOS == "windows" { 125 // TODO(tikuta): support context timeout on windows 126 return 127 } 128 129 ctx, cancel := context.WithTimeout(ctx, time.Millisecond) 130 defer cancel() 131 132 cmd := CommandContext(ctx, testBinary) 133 134 So(cmd.Start(), ShouldBeNil) 135 136 So(cmd.Wait(), ShouldBeError, "signal: killed") 137 138 So(cmd.ProcessState.ExitCode(), ShouldEqual, -1) 139 }) 140 141 }) 142 } 143 144 func TestSetEnv(t *testing.T) { 145 t.Parallel() 146 147 Convey("TestSetEnv", t, func() { 148 ctx := context.Background() 149 150 tmpdir := t.TempDir() 151 152 testBinary, err := build(filepath.Join("testdata", "env.go"), tmpdir) 153 So(err, ShouldBeNil) 154 155 cmd := CommandContext(ctx, testBinary) 156 env := environ.System() 157 env.Set("envvar", "envvar") 158 cmd.Env = env.Sorted() 159 160 So(cmd.Start(), ShouldBeNil) 161 162 So(cmd.Wait(), ShouldBeNil) 163 164 So(cmd.ProcessState.ExitCode(), ShouldEqual, 0) 165 }) 166 }