gotest.tools/gotestsum@v1.11.0/cmd/main_e2e_test.go (about) 1 package cmd 2 3 import ( 4 "bytes" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 "runtime" 9 "strings" 10 "sync" 11 "testing" 12 "time" 13 14 "gotest.tools/gotestsum/internal/text" 15 "gotest.tools/v3/assert" 16 "gotest.tools/v3/env" 17 "gotest.tools/v3/fs" 18 "gotest.tools/v3/golden" 19 "gotest.tools/v3/icmd" 20 "gotest.tools/v3/poll" 21 "gotest.tools/v3/skip" 22 ) 23 24 func TestMain(m *testing.M) { 25 code := m.Run() 26 binaryFixture.Cleanup() 27 os.Exit(code) 28 } 29 30 func TestE2E_RerunFails(t *testing.T) { 31 if testing.Short() { 32 t.Skip("too slow for short run") 33 } 34 t.Setenv("GITHUB_ACTIONS", "no") 35 36 type testCase struct { 37 name string 38 args []string 39 expectedErr string 40 } 41 fn := func(t *testing.T, tc testCase) { 42 tmpFile := fs.NewFile(t, t.Name()+"-seedfile", fs.WithContent("0")) 43 defer tmpFile.Remove() 44 45 envVars := osEnviron() 46 envVars["TEST_SEEDFILE"] = tmpFile.Path() 47 env.PatchAll(t, envVars) 48 49 flags, opts := setupFlags("gotestsum") 50 assert.NilError(t, flags.Parse(tc.args)) 51 opts.args = flags.Args() 52 53 bufStdout := new(bytes.Buffer) 54 opts.stdout = bufStdout 55 bufStderr := new(bytes.Buffer) 56 opts.stderr = bufStderr 57 58 err := run(opts) 59 if tc.expectedErr != "" { 60 assert.Error(t, err, tc.expectedErr) 61 } else { 62 assert.NilError(t, err) 63 } 64 out := text.ProcessLines(t, bufStdout, 65 text.OpRemoveSummaryLineElapsedTime, 66 text.OpRemoveTestElapsedTime, 67 filepath.ToSlash, // for windows 68 ) 69 golden.Assert(t, out, "e2e/expected/"+expectedFilename(t.Name())) 70 } 71 var testCases = []testCase{ 72 { 73 name: "reruns until success", 74 args: []string{ 75 "-f=testname", 76 "--rerun-fails=4", 77 "--packages=./testdata/e2e/flaky/", 78 "--", "-count=1", "-tags=testdata", 79 }, 80 }, 81 { 82 name: "reruns continues to fail", 83 args: []string{ 84 "-f=testname", 85 "--rerun-fails=2", 86 "--packages=./testdata/e2e/flaky/", 87 "--", "-count=1", "-tags=testdata", 88 }, 89 expectedErr: "exit status 1", 90 }, 91 { 92 name: "first run has errors, abort rerun", 93 args: []string{ 94 "-f=testname", 95 "--rerun-fails=2", 96 "--packages=../testjson/internal/broken", 97 "--", "-count=1", "-tags=stubpkg", 98 }, 99 expectedErr: "rerun aborted because previous run had errors", 100 }, 101 } 102 for _, tc := range testCases { 103 t.Run(tc.name, func(t *testing.T) { 104 fn(t, tc) 105 }) 106 } 107 } 108 109 // osEnviron returns os.Environ() as a map, with any GOTESTSUM_ env vars removed 110 // so that they do not alter the test results. 111 func osEnviron() map[string]string { 112 e := env.ToMap(os.Environ()) 113 for k := range e { 114 if strings.HasPrefix(k, "GOTESTSUM_") { 115 delete(e, k) 116 } 117 } 118 return e 119 } 120 121 func expectedFilename(name string) string { 122 ver := runtime.Version() 123 switch { 124 case isPreGo120(ver): 125 return name + "-go1.19" 126 default: 127 return name 128 } 129 } 130 131 // go1.20.0 changed how it prints messages from subtests. It seems the output 132 // has changed back to match the output from go1.14 and earlier. 133 func isPreGo120(ver string) bool { 134 return strings.HasPrefix(ver, "go1.1") 135 } 136 137 var binaryFixture pkgFixtureFile 138 139 type pkgFixtureFile struct { 140 filename string 141 once sync.Once 142 cleanup func() 143 } 144 145 func (p *pkgFixtureFile) Path() string { 146 return p.filename 147 } 148 149 func (p *pkgFixtureFile) Do(f func() string) { 150 p.once.Do(func() { 151 p.filename = f() 152 p.cleanup = func() { 153 os.RemoveAll(p.filename) // nolint: errcheck 154 } 155 }) 156 } 157 158 func (p *pkgFixtureFile) Cleanup() { 159 if p.cleanup != nil { 160 p.cleanup() 161 } 162 } 163 164 // compileBinary once the first time this function is called. Subsequent calls 165 // will return the path to the compiled binary. The binary is removed when all 166 // the tests in this package have completed. 167 func compileBinary(t *testing.T) string { 168 t.Helper() 169 if testing.Short() { 170 t.Skip("too slow for short run") 171 } 172 173 binaryFixture.Do(func() string { 174 tmpDir, err := ioutil.TempDir("", "gotestsum-binary") 175 assert.NilError(t, err) 176 177 path := filepath.Join(tmpDir, "gotestsum") 178 result := icmd.RunCommand("go", "build", "-o", path, "..") 179 result.Assert(t, icmd.Success) 180 return path 181 }) 182 183 if binaryFixture.Path() == "" { 184 t.Skip("previous attempt to compile the binary failed") 185 } 186 return binaryFixture.Path() 187 } 188 189 func TestE2E_SignalHandler(t *testing.T) { 190 skip.If(t, runtime.GOOS == "windows", "test timeout waiting for pidfile") 191 bin := compileBinary(t) 192 193 tmpDir := fs.NewDir(t, t.Name()) 194 defer tmpDir.Remove() 195 196 driver := tmpDir.Join("driver") 197 target := filepath.FromSlash("./internal/signalhandlerdriver/") 198 icmd.RunCommand("go", "build", "-o", driver, target). 199 Assert(t, icmd.Success) 200 201 pidFile := tmpDir.Join("pidfile") 202 args := []string{"--raw-command", "--", driver, pidFile} 203 result := icmd.StartCmd(icmd.Command(bin, args...)) 204 205 poll.WaitOn(t, poll.FileExists(pidFile), poll.WithTimeout(time.Second)) 206 assert.NilError(t, result.Cmd.Process.Signal(os.Interrupt)) 207 icmd.WaitOnCmd(2*time.Second, result) 208 209 result.Assert(t, icmd.Expected{ExitCode: 130}) 210 } 211 212 func TestE2E_MaxFails_EndTestRun(t *testing.T) { 213 if testing.Short() { 214 t.Skip("too slow for short run") 215 } 216 217 tmpFile := fs.NewFile(t, t.Name()+"-seedfile", fs.WithContent("0")) 218 defer tmpFile.Remove() 219 220 envVars := osEnviron() 221 envVars["TEST_SEEDFILE"] = tmpFile.Path() 222 env.PatchAll(t, envVars) 223 224 t.Setenv("GOTESTSUM_FORMAT", "pkgname") 225 flags, opts := setupFlags("gotestsum") 226 args := []string{"--max-fails=2", "--packages=./testdata/e2e/flaky/", "--", "-tags=testdata"} 227 assert.NilError(t, flags.Parse(args)) 228 opts.args = flags.Args() 229 230 bufStdout := new(bytes.Buffer) 231 opts.stdout = bufStdout 232 bufStderr := new(bytes.Buffer) 233 opts.stderr = bufStderr 234 235 err := run(opts) 236 assert.Error(t, err, "ending test run because max failures was reached") 237 out := text.ProcessLines(t, bufStdout, 238 text.OpRemoveSummaryLineElapsedTime, 239 text.OpRemoveTestElapsedTime, 240 filepath.ToSlash, // for windows 241 ) 242 golden.Assert(t, out, "e2e/expected/"+t.Name()) 243 } 244 245 func TestE2E_IgnoresWarnings(t *testing.T) { 246 if testing.Short() { 247 t.Skip("too slow for short run") 248 } 249 t.Setenv("GITHUB_ACTIONS", "no") 250 251 flags, opts := setupFlags("gotestsum") 252 args := []string{ 253 "--rerun-fails=1", 254 "--packages=./testdata/e2e/ignore_warnings/", 255 "--format=testname", 256 "--", "-tags=testdata", "-cover", "-coverpkg=./cmd/internal", 257 } 258 assert.NilError(t, flags.Parse(args)) 259 opts.args = flags.Args() 260 261 bufStdout := new(bytes.Buffer) 262 opts.stdout = bufStdout 263 bufStderr := new(bytes.Buffer) 264 opts.stderr = bufStderr 265 266 err := run(opts) 267 assert.Error(t, err, "exit status 1") 268 out := text.ProcessLines(t, bufStdout, 269 text.OpRemoveSummaryLineElapsedTime, 270 text.OpRemoveTestElapsedTime, 271 filepath.ToSlash, // for windows 272 ) 273 golden.Assert(t, out, "e2e/expected/"+t.Name()) 274 }