Browse Source

cmd/testwrapper: detect cached tests with coverage output (#18559)

Using -coverprofile was breaking the (cached) detection logic because
that adds extra information to the end of the line.

Updates tailscale/go#150

Change-Id: Ie1bf4e1e04e21db00a6829695098fb61d80a2641

Signed-off-by: Tom Proctor <[email protected]>
Tom Proctor 1 month ago
parent
commit
ce5c08e4cb
2 changed files with 62 additions and 1 deletions
  1. 4 1
      cmd/testwrapper/testwrapper.go
  2. 58 0
      cmd/testwrapper/testwrapper_test.go

+ 4 - 1
cmd/testwrapper/testwrapper.go

@@ -130,7 +130,10 @@ func runTests(ctx context.Context, attempt int, pt *packageTests, goTestArgs, te
 			resultMap[pkg] = pkgTests
 			resultMap[pkg] = pkgTests
 		}
 		}
 		if goOutput.Test == "" {
 		if goOutput.Test == "" {
-			if strings.HasSuffix(goOutput.Output, "\t(cached)\n") && goOutput.Package != "" {
+			// Detect output lines like:
+			// ok  \ttailscale.com/cmd/testwrapper\t(cached)
+			// ok  \ttailscale.com/cmd/testwrapper\t(cached)\tcoverage: 17.0% of statements
+			if goOutput.Package != "" && strings.Contains(goOutput.Output, fmt.Sprintf("%s\t(cached)", goOutput.Package)) {
 				pkgCached[goOutput.Package] = true
 				pkgCached[goOutput.Package] = true
 			}
 			}
 			switch goOutput.Action {
 			switch goOutput.Action {

+ 58 - 0
cmd/testwrapper/testwrapper_test.go

@@ -11,6 +11,7 @@ import (
 	"os/exec"
 	"os/exec"
 	"path/filepath"
 	"path/filepath"
 	"regexp"
 	"regexp"
+	"runtime"
 	"strings"
 	"strings"
 	"sync"
 	"sync"
 	"testing"
 	"testing"
@@ -214,6 +215,63 @@ func TestTimeout(t *testing.T) {
 	}
 	}
 }
 }
 
 
+func TestCached(t *testing.T) {
+	t.Parallel()
+
+	// Construct our trivial package.
+	pkgDir := t.TempDir()
+	goMod := fmt.Sprintf(`module example.com
+
+go %s
+`, runtime.Version()[2:]) // strip leading "go"
+
+	test := `package main
+import "testing"
+
+func TestCached(t *testing.T) {}
+`
+
+	for f, c := range map[string]string{
+		"go.mod":         goMod,
+		"cached_test.go": test,
+	} {
+		err := os.WriteFile(filepath.Join(pkgDir, f), []byte(c), 0o644)
+		if err != nil {
+			t.Fatalf("writing package: %s", err)
+		}
+	}
+
+	for name, args := range map[string][]string{
+		"without_flags":     {"./..."},
+		"with_short":        {"./...", "-short"},
+		"with_coverprofile": {"./...", "-coverprofile=" + filepath.Join(t.TempDir(), "coverage.out")},
+	} {
+		t.Run(name, func(t *testing.T) {
+			var (
+				out []byte
+				err error
+			)
+			for range 2 {
+				cmd := cmdTestwrapper(t, args...)
+				cmd.Dir = pkgDir
+				out, err = cmd.CombinedOutput()
+				if err != nil {
+					t.Fatalf("testwrapper ./...: expected no error but got: %v; output was:\n%s", err, out)
+				}
+			}
+
+			want := []byte("ok\texample.com\t(cached)")
+			if !bytes.Contains(out, want) {
+				t.Fatalf("wanted output containing %q but got:\n%s", want, out)
+			}
+
+			if testing.Verbose() {
+				t.Logf("success - output:\n%s", out)
+			}
+		})
+	}
+}
+
 func errExitCode(err error) (int, bool) {
 func errExitCode(err error) (int, bool) {
 	var exit *exec.ExitError
 	var exit *exec.ExitError
 	if errors.As(err, &exit) {
 	if errors.As(err, &exit) {