Add a helper-function to testenv to make these skips more ergonomic.
Also update a few existing skips in cmd/go/... to use it.
Updates #25300
Change-Id: I4205b4fb2b685dfac1cff3c999f954bff7b0f3c1
Reviewed-on: https://go-review.googlesource.com/c/go/+/181538
Reviewed-by: Ian Lance Taylor <iant@golang.org>
}
func TestMoveGit(t *testing.T) {
+ testenv.MustHaveExecPath(t, "git")
testMove(t, "git", "rsc.io/pdf", "pdf", "rsc.io/pdf/.git/config")
}
func TestMoveHG(t *testing.T) {
+ testenv.MustHaveExecPath(t, "hg")
testMove(t, "hg", "vcs-test.golang.org/go/custom-hg-hello", "custom-hg-hello", "vcs-test.golang.org/go/custom-hg-hello/.hg/hgrc")
}
// cmd/go: custom import path checking should not apply to Go packages without import comment.
func TestIssue10952(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
- if _, err := exec.LookPath("git"); err != nil {
- t.Skip("skipping because git binary not found")
- }
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
func TestIssue16471(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
- if _, err := exec.LookPath("git"); err != nil {
- t.Skip("skipping because git binary not found")
- }
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
// Test git clone URL that uses SCP-like syntax and custom import path checking.
func TestIssue11457(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
- if _, err := exec.LookPath("git"); err != nil {
- t.Skip("skipping because git binary not found")
- }
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
func TestGetGitDefaultBranch(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
- if _, err := exec.LookPath("git"); err != nil {
- t.Skip("skipping because git binary not found")
- }
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
// Security issue. Don't disable. See golang.org/issue/22125.
func TestAccidentalGitCheckout(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
- if _, err := exec.LookPath("git"); err != nil {
- t.Skip("skipping because git binary not found")
- }
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
func TestGoGetNonPkg(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
func TestGoGetTestOnlyPkg(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
func TestDefaultGOPATHGet(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
// Issue 8181.
func TestGoGetDashTIssue8181(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
func TestIssue11307(t *testing.T) {
// go get -u was not working except in checkout directory
testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
tg.run("env", "PKG_CONFIG")
pkgConfig := strings.TrimSpace(tg.getStdout())
+ testenv.MustHaveExecPath(t, pkgConfig)
if out, err := exec.Command(pkgConfig, "--atleast-pkgconfig-version", "0.24").CombinedOutput(); err != nil {
t.Skipf("%s --atleast-pkgconfig-version 0.24: %v\n%s", pkgConfig, err, out)
}
if !canCgo {
t.Skip("skipping because cgo not enabled")
}
- if _, err := exec.LookPath("gccgo"); err != nil {
- t.Skip("skipping because no gccgo compiler found")
- }
+ testenv.MustHaveExecPath(t, "gccgo")
tg := testgo(t)
defer tg.cleanup()
func TestGoGetCustomDomainWildcard(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
func TestGoGetInternalWildcard(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
// Issue 9767, 19769.
func TestGoGetDotSlashDownload(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
func TestGoGetInsecure(t *testing.T) {
test := func(t *testing.T, modules bool) {
testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
func TestGoGetUpdateInsecure(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
func TestGoGetUpdateUnknownProtocol(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
func TestGoGetInsecureCustomDomain(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
// former dependencies, not current ones.
testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
// Issue #20512.
func TestGoGetRace(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExecPath(t, "git")
if !canRace {
t.Skip("skipping because race detector not supported")
}
// go get foo.io (not foo.io/subdir) was not working consistently.
testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
// Issue 14450: go get -u .../ tried to import not downloaded package
func TestGoGetUpdateWithWildcard(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
t.Skip("skipping because cgo not enabled")
}
- if runtime.GOOS == "plan9" || runtime.GOOS == "windows" {
- t.Skipf("skipping because unix shell is not supported on %s", runtime.GOOS)
- }
+ testenv.MustHaveExecPath(t, "/usr/bin/env")
+ testenv.MustHaveExecPath(t, "bash")
tg := testgo(t)
defer tg.cleanup()
t.Skipf("skipping upx test on %s/%s", runtime.GOOS, runtime.GOARCH)
}
+ testenv.MustHaveExecPath(t, "upx")
out, err := exec.Command("upx", "--version").CombinedOutput()
if err != nil {
- t.Skip("skipping because upx is not available")
+ t.Fatalf("upx --version failed: %v", err)
}
// upx --version prints `upx <version>` in the first line of output:
re := regexp.MustCompile(`([[:digit:]]+)\.([[:digit:]]+)`)
upxVersion := re.FindStringSubmatch(string(out))
if len(upxVersion) != 3 {
- t.Errorf("bad upx version string: %s", upxVersion)
+ t.Fatalf("bad upx version string: %s", upxVersion)
}
major, err1 := strconv.Atoi(upxVersion[1])
minor, err2 := strconv.Atoi(upxVersion[2])
if err1 != nil || err2 != nil {
- t.Errorf("bad upx version string: %s", upxVersion[0])
+ t.Fatalf("bad upx version string: %s", upxVersion[0])
}
// Anything below 3.94 is known not to work with go binaries
src, obj := tg.path("main.go"), tg.path("main")
for _, arch := range testArchs {
- out, err := exec.Command("qemu-"+arch.qemu, "--version").CombinedOutput()
- if err != nil {
- t.Logf("Skipping %s test (qemu-%s not available)", arch.g, arch.qemu)
- continue
- }
+ arch := arch
+ t.Run(arch.g, func(t *testing.T) {
+ qemu := "qemu-" + arch.qemu
+ testenv.MustHaveExecPath(t, qemu)
+
+ out, err := exec.Command(qemu, "--version").CombinedOutput()
+ if err != nil {
+ t.Fatalf("%s --version failed: %v", qemu, err)
+ }
- tg.setenv("GOARCH", arch.g)
- tg.run("build", "-o", obj, src)
+ tg.setenv("GOARCH", arch.g)
+ tg.run("build", "-o", obj, src)
- out, err = exec.Command("qemu-"+arch.qemu, obj).CombinedOutput()
- if err != nil {
- t.Logf("qemu-%s output:\n%s\n", arch.qemu, out)
- t.Errorf("qemu-%s failed with %v", arch.qemu, err)
- continue
- }
- if want := "hello qemu-user"; string(out) != want {
- t.Errorf("bad output from qemu-%s:\ngot %s; want %s", arch.qemu, out, want)
- }
+ out, err = exec.Command(qemu, obj).CombinedOutput()
+ if err != nil {
+ t.Logf("%s output:\n%s\n", qemu, out)
+ t.Fatalf("%s failed with %v", qemu, err)
+ }
+ if want := "hello qemu-user"; string(out) != want {
+ t.Errorf("bad output from %s:\ngot %s; want %s", qemu, out, want)
+ }
+ })
}
-
}
func TestCacheListStale(t *testing.T) {
vgotest1hg = "vcs-test.golang.org/hg/vgotest1.hg"
)
-var altVgotests = []string{
- vgotest1hg,
+var altVgotests = map[string]string{
+ "hg": vgotest1hg,
}
type codeRepoTest struct {
+ vcs string
path string
lookerr string
mpath string
var codeRepoTests = []codeRepoTest{
{
+ vcs: "git",
path: "github.com/rsc/vgotest1",
rev: "v0.0.0",
version: "v0.0.0",
},
},
{
+ vcs: "git",
path: "github.com/rsc/vgotest1",
rev: "v1.0.0",
version: "v1.0.0",
},
},
{
+ vcs: "git",
path: "github.com/rsc/vgotest1/v2",
rev: "v2.0.0",
version: "v2.0.0",
ziperr: "missing github.com/rsc/vgotest1/go.mod and .../v2/go.mod at revision v2.0.0",
},
{
+ vcs: "git",
path: "github.com/rsc/vgotest1",
rev: "80d85c5",
version: "v1.0.0",
},
},
{
+ vcs: "git",
path: "github.com/rsc/vgotest1",
rev: "mytag",
version: "v1.0.0",
},
},
{
+ vcs: "git",
path: "github.com/rsc/vgotest1/v2",
rev: "45f53230a",
version: "v2.0.0",
ziperr: "missing github.com/rsc/vgotest1/go.mod and .../v2/go.mod at revision v2.0.0",
},
{
+ vcs: "git",
path: "github.com/rsc/vgotest1/v54321",
rev: "80d85c5",
version: "v54321.0.0-20180219231006-80d85c5d4d17",
ziperr: "missing github.com/rsc/vgotest1/go.mod and .../v54321/go.mod at revision 80d85c5d4d17",
},
{
+ vcs: "git",
path: "github.com/rsc/vgotest1/submod",
rev: "v1.0.0",
err: "unknown revision submod/v1.0.0",
},
{
+ vcs: "git",
path: "github.com/rsc/vgotest1/submod",
rev: "v1.0.3",
err: "unknown revision submod/v1.0.3",
},
{
+ vcs: "git",
path: "github.com/rsc/vgotest1/submod",
rev: "v1.0.4",
version: "v1.0.4",
},
},
{
+ vcs: "git",
path: "github.com/rsc/vgotest1",
rev: "v1.1.0",
version: "v1.1.0",
},
},
{
+ vcs: "git",
path: "github.com/rsc/vgotest1/v2",
rev: "v2.0.1",
version: "v2.0.1",
gomod: "module \"github.com/rsc/vgotest1/v2\" // root go.mod\n",
},
{
+ vcs: "git",
path: "github.com/rsc/vgotest1/v2",
rev: "v2.0.3",
version: "v2.0.3",
gomoderr: "github.com/rsc/vgotest1/v2/go.mod has non-.../v2 module path \"github.com/rsc/vgotest\" at revision v2.0.3",
},
{
+ vcs: "git",
path: "github.com/rsc/vgotest1/v2",
rev: "v2.0.4",
version: "v2.0.4",
gomoderr: "github.com/rsc/vgotest1/go.mod and .../v2/go.mod both have .../v2 module paths at revision v2.0.4",
},
{
+ vcs: "git",
path: "github.com/rsc/vgotest1/v2",
rev: "v2.0.5",
version: "v2.0.5",
},
{
// redirect to github
+ vcs: "git",
path: "rsc.io/quote",
rev: "v1.0.0",
version: "v1.0.0",
},
{
// redirect to static hosting proxy
+ vcs: "mod",
path: "swtch.com/testmod",
rev: "v1.0.0",
version: "v1.0.0",
},
{
// redirect to googlesource
+ vcs: "git",
path: "golang.org/x/text",
rev: "4e4a3210bb",
version: "v0.3.1-0.20180208041248-4e4a3210bb54",
time: time.Date(2018, 2, 8, 4, 12, 48, 0, time.UTC),
},
{
+ vcs: "git",
path: "github.com/pkg/errors",
rev: "v0.8.0",
version: "v0.8.0",
// package in subdirectory - custom domain
// In general we can't reject these definitively in Lookup,
// but gopkg.in is special.
+ vcs: "git",
path: "gopkg.in/yaml.v2/abc",
lookerr: "invalid module path \"gopkg.in/yaml.v2/abc\"",
},
{
// package in subdirectory - github
// Because it's a package, Stat should fail entirely.
+ vcs: "git",
path: "github.com/rsc/quote/buggy",
rev: "c4d4236f",
err: "missing github.com/rsc/quote/buggy/go.mod at revision c4d4236f9242",
},
{
+ vcs: "git",
path: "gopkg.in/yaml.v2",
rev: "d670f940",
version: "v2.0.0",
gomod: "module gopkg.in/yaml.v2\n",
},
{
+ vcs: "git",
path: "gopkg.in/check.v1",
rev: "20d25e280405",
version: "v1.0.0-20161208181325-20d25e280405",
gomod: "module gopkg.in/check.v1\n",
},
{
+ vcs: "git",
path: "gopkg.in/yaml.v2",
rev: "v2",
version: "v2.2.3-0.20190319135612-7b8349ac747c",
gomod: "module \"gopkg.in/yaml.v2\"\n\nrequire (\n\t\"gopkg.in/check.v1\" v0.0.0-20161208181325-20d25e280405\n)\n",
},
{
+ vcs: "git",
path: "vcs-test.golang.org/go/mod/gitrepo1",
rev: "master",
version: "v1.2.4-annotated",
gomod: "module vcs-test.golang.org/go/mod/gitrepo1\n",
},
{
+ vcs: "git",
path: "gopkg.in/natefinch/lumberjack.v2",
rev: "latest",
version: "v2.0.0-20170531160350-a96e63847dc3",
gomod: "module gopkg.in/natefinch/lumberjack.v2\n",
},
{
+ vcs: "git",
path: "gopkg.in/natefinch/lumberjack.v2",
// This repo has a v2.1 tag.
// We only allow semver references to tags that are fully qualified, as in v2.1.0.
gomod: "module gopkg.in/natefinch/lumberjack.v2\n",
},
{
+ vcs: "git",
path: "vcs-test.golang.org/go/v2module/v2",
rev: "v2.0.0",
version: "v2.0.0",
f := func(tt codeRepoTest) func(t *testing.T) {
return func(t *testing.T) {
t.Parallel()
+ if tt.vcs != "mod" {
+ testenv.MustHaveExecPath(t, tt.vcs)
+ }
repo, err := Lookup("direct", tt.path)
if tt.lookerr != "" {
}
t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.rev, f(tt))
if strings.HasPrefix(tt.path, vgotest1git) {
- for _, alt := range altVgotests {
+ for vcs, alt := range altVgotests {
// Note: Communicating with f through tt; should be cleaned up.
old := tt
+ tt.vcs = vcs
tt.path = alt + strings.TrimPrefix(tt.path, vgotest1git)
if strings.HasPrefix(tt.mpath, vgotest1git) {
tt.mpath = alt + strings.TrimPrefix(tt.mpath, vgotest1git)
}
var codeRepoVersionsTests = []struct {
+ vcs string
path string
prefix string
versions []string
}{
{
+ vcs: "git",
path: "github.com/rsc/vgotest1",
versions: []string{"v0.0.0", "v0.0.1", "v1.0.0", "v1.0.1", "v1.0.2", "v1.0.3", "v1.1.0", "v2.0.0+incompatible"},
},
{
+ vcs: "git",
path: "github.com/rsc/vgotest1",
prefix: "v1.0",
versions: []string{"v1.0.0", "v1.0.1", "v1.0.2", "v1.0.3"},
},
{
+ vcs: "git",
path: "github.com/rsc/vgotest1/v2",
versions: []string{"v2.0.0", "v2.0.1", "v2.0.2", "v2.0.3", "v2.0.4", "v2.0.5", "v2.0.6"},
},
{
+ vcs: "mod",
path: "swtch.com/testmod",
versions: []string{"v1.0.0", "v1.1.1"},
},
{
+ vcs: "git",
path: "gopkg.in/russross/blackfriday.v2",
versions: []string{"v2.0.0", "v2.0.1"},
},
{
+ vcs: "git",
path: "gopkg.in/natefinch/lumberjack.v2",
versions: []string{"v2.0.0"},
},
t.Run(strings.ReplaceAll(tt.path, "/", "_"), func(t *testing.T) {
tt := tt
t.Parallel()
+ if tt.vcs != "mod" {
+ testenv.MustHaveExecPath(t, tt.vcs)
+ }
repo, err := Lookup("direct", tt.path)
if err != nil {
}
var latestTests = []struct {
+ vcs string
path string
version string
err string
}{
{
+ vcs: "git",
path: "github.com/rsc/empty",
err: "no commits",
},
{
+ vcs: "git",
path: "github.com/rsc/vgotest1",
version: "v0.0.0-20180219223237-a08abb797a67",
},
{
+ vcs: "git",
path: "github.com/rsc/vgotest1/subdir",
err: "missing github.com/rsc/vgotest1/subdir/go.mod at revision a08abb797a67",
},
{
+ vcs: "mod",
path: "swtch.com/testmod",
version: "v1.1.1",
},
t.Run(name, func(t *testing.T) {
tt := tt
t.Parallel()
+ if tt.vcs != "mod" {
+ testenv.MustHaveExecPath(t, tt.vcs)
+ }
repo, err := Lookup("direct", tt.path)
if err != nil {
func TestImport(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExecPath(t, "git")
for _, tt := range importTests {
t.Run(strings.ReplaceAll(tt.path, "/", "_"), func(t *testing.T) {
func TestQuery(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExecPath(t, "git")
for _, tt := range queryTests {
allow := tt.allow
# golang.org/issue/13037: 'go get' was not parsing <meta> tags in 404 served over HTTPS.
[!net] skip
+[!exec:git] skip
env GO111MODULE=off
go get -d -insecure bazil.org/fuse/fs/fstestutil
# golang.org/issue/29591: 'go get' was following plain-HTTP redirects even without -insecure.
[!net] skip
+[!exec:git] skip
env GO111MODULE=on
env GOPROXY=direct
env GOPROXY=direct
env GOSUMDB=off
[!net] skip
+[!exec:git] skip
# fetch commit hash reachable from refs/heads/* and refs/tags/* is OK
go list -m golang.org/x/time@8be79e1e0910c292df4e79c241bb7e8f7e725959 # on master branch
-- go.mod --
module m
-
# and GONOPROXY bypasses proxy
[!net] skip
+[!exec:git] skip
env GONOPROXY='*/fortune'
! go get rsc.io/fortune # does not exist in real world, only on test proxy
stderr 'git ls-remote'
go list
[!net] skip
+[!exec:git] skip
env GOPROXY=direct
env GOSUMDB=off
# download direct from github
[!net] skip
+[!exec:git] skip
env GOSUMDB=sum.golang.org
env GOPROXY=direct
go get -d rsc.io/quote
func TestVendorGetUpdate(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
func TestVendorGetU(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
func TestVendorGetTU(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
func TestVendorGetBadVendor(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExecPath(t, "git")
for _, suffix := range []string{"bad/imp", "bad/imp2", "bad/imp3", "..."} {
t.Run(suffix, func(t *testing.T) {
func TestGetSubmodules(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
func TestVendorTest2(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
func TestVendorTest3(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
func TestVendorList(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
func TestLegacyModGet(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExecPath(t, "git")
tg := testgo(t)
defer tg.cleanup()
"runtime"
"strconv"
"strings"
+ "sync"
"testing"
)
}
}
+var execPaths sync.Map // path -> error
+
+// MustHaveExecPath checks that the current system can start the named executable
+// using os.StartProcess or (more commonly) exec.Command.
+// If not, MustHaveExecPath calls t.Skip with an explanation.
+func MustHaveExecPath(t testing.TB, path string) {
+ MustHaveExec(t)
+
+ err, found := execPaths.Load(path)
+ if !found {
+ _, err = exec.LookPath(path)
+ err, _ = execPaths.LoadOrStore(path, err)
+ }
+ if err != nil {
+ t.Skipf("skipping test: %s: %s", path, err)
+ }
+}
+
// HasExternalNetwork reports whether the current system can use
// external (non-localhost) networks.
func HasExternalNetwork() bool {