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  }