internal/testenv: add NeedsGo helper

Some tests and packages need the go command.
For example, go.dev/cl/499255 adds a package that uses `go mod
download` and some of its tests won't work if the test environment
doesn't have 'go' (e.g. android, ios, wasi/wasm builders).
NeedsGo skips the calling tests if 'go' isn't available.
x/tools and go projects have similar facilities already, but
this is simpler than golang.org/x/tools/internal/testenv's NeedsTool
or Go project's src/internal/testenv's MustHaveGoBuild.
We just check whether `go env GOROOT` returns something convincing.

Change-Id: I96b7e7ddb5a6b7feb02ab02fefd8e14451eecb82
Reviewed-on: https://go-review.googlesource.com/c/telemetry/+/499919
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Hyang-Ah Hana Kim <hyangah@gmail.com>
Reviewed-by: Peter Weinberger <pjw@google.com>
Reviewed-by: Jamal Carvalho <jamal@golang.org>
diff --git a/internal/testenv/testenv.go b/internal/testenv/testenv.go
index bd56ac0..cca5913 100644
--- a/internal/testenv/testenv.go
+++ b/internal/testenv/testenv.go
@@ -7,7 +7,11 @@
 package testenv
 
 import (
+	"bytes"
+	"fmt"
+	"os/exec"
 	"runtime"
+	"sync"
 	"testing"
 )
 
@@ -19,3 +23,32 @@
 		t.Skipf(`Listening on "localhost" fails on %s; see https://go.dev/issue/59718`, runtime.GOOS)
 	}
 }
+
+var (
+	hasGoOnce sync.Once
+	hasGoErr  error
+)
+
+func hasGo() error {
+	hasGoOnce.Do(func() {
+		cmd := exec.Command("go", "env", "GOROOT")
+		out, err := cmd.Output()
+		if err != nil { // cannot run go.
+			hasGoErr = fmt.Errorf("%v: %v", cmd, err)
+			return
+		}
+		out = bytes.TrimSpace(out)
+		if len(out) == 0 { // unusual, incomplete go installation.
+			hasGoErr = fmt.Errorf("%v: no GOROOT - incomplete go installation", cmd)
+		}
+	})
+	return hasGoErr
+}
+
+// NeedsGo skips t if the current system does not have 'go'  or
+// cannot run them with exec.Command.
+func NeedsGo(t testing.TB) {
+	if err := hasGo(); err != nil {
+		t.Skipf("skipping test: go is not available - %v", err)
+	}
+}
diff --git a/internal/testenv/testenv_test.go b/internal/testenv/testenv_test.go
new file mode 100644
index 0000000..727a943
--- /dev/null
+++ b/internal/testenv/testenv_test.go
@@ -0,0 +1,20 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package testenv
+
+import (
+	"bytes"
+	"os/exec"
+	"testing"
+)
+
+func TestNeedsGo(t *testing.T) {
+	NeedsGo(t)
+	out, err := exec.Command("go", "version").Output()
+	out = bytes.TrimSpace(out)
+	if err != nil || !bytes.HasPrefix(out, []byte("go version ")) {
+		t.Errorf("go version failed - %v: %s", err, out)
+	}
+}