532 lines
18 KiB
Go
532 lines
18 KiB
Go
package gotool
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
type goPreparationRecord struct {
|
|
Arguments []string
|
|
Directory string
|
|
Workspace string
|
|
Toolchain string
|
|
Proxy string
|
|
Private string
|
|
NoSumDB string
|
|
ModuleCache string
|
|
}
|
|
|
|
func TestMain(m *testing.M) {
|
|
if os.Getenv("RELEASEKIT_GO_FIXTURE") == "1" {
|
|
os.Exit(runGoPreparationFixture())
|
|
}
|
|
os.Exit(m.Run())
|
|
}
|
|
|
|
func runGoPreparationFixture() int {
|
|
record := goPreparationRecord{
|
|
Arguments: os.Args[1:], Directory: mustGetwd(),
|
|
Workspace: os.Getenv("GOWORK"), Toolchain: os.Getenv("GOTOOLCHAIN"),
|
|
Proxy: os.Getenv("GOPROXY"), Private: os.Getenv("GOPRIVATE"),
|
|
NoSumDB: os.Getenv("GONOSUMDB"), ModuleCache: os.Getenv("GOMODCACHE"),
|
|
}
|
|
contents, err := json.Marshal(record)
|
|
if err != nil {
|
|
return 10
|
|
}
|
|
if err := os.WriteFile(os.Getenv("RELEASEKIT_GO_FIXTURE_RECORD"), contents, 0o600); err != nil {
|
|
return 11
|
|
}
|
|
switch os.Getenv("RELEASEKIT_GO_FIXTURE_MODE") {
|
|
case "discovery":
|
|
settings := make(map[string]string)
|
|
for _, key := range os.Args[3:] {
|
|
settings[key] = os.Getenv(key)
|
|
}
|
|
settings["GOHOSTOS"] = runtime.GOOS
|
|
settings["GOHOSTARCH"] = runtime.GOARCH
|
|
fmt.Fprintln(os.Stderr, "fixture discovery diagnostic")
|
|
if err := json.NewEncoder(os.Stdout).Encode(settings); err != nil {
|
|
return 12
|
|
}
|
|
return 0
|
|
case "fail":
|
|
fmt.Fprintln(os.Stderr, "fixture dependency failure")
|
|
return 23
|
|
case "output":
|
|
fmt.Fprintln(os.Stdout, "fixture stdout")
|
|
fmt.Fprintln(os.Stderr, "fixture stderr")
|
|
return 0
|
|
case "large-fail":
|
|
_, _ = fmt.Fprint(os.Stdout, strings.Repeat("x", 8<<20))
|
|
fmt.Fprintln(os.Stderr, "fixture large failure")
|
|
return 23
|
|
case "wait":
|
|
for {
|
|
time.Sleep(time.Second)
|
|
}
|
|
default:
|
|
return 0
|
|
}
|
|
}
|
|
|
|
func TestDiscoveryAcceptsDiagnosticsWithValidConfiguration(t *testing.T) {
|
|
repository, _ := installGoPreparationFixture(t)
|
|
t.Setenv("RELEASEKIT_GO_FIXTURE_MODE", "discovery")
|
|
cache := filepath.Join(t.TempDir(), "cache")
|
|
t.Setenv("GOCACHE", cache)
|
|
tool, err := New(context.Background(), repository)
|
|
if err != nil {
|
|
t.Fatalf("New() rejected successful discovery: %v", err)
|
|
}
|
|
if tool.HostTarget() != (Target{OS: runtime.GOOS, Arch: runtime.GOARCH}) || tool.settings["GOCACHE"] != cache {
|
|
t.Fatalf("discovered host=%v cache=%q", tool.HostTarget(), tool.settings["GOCACHE"])
|
|
}
|
|
}
|
|
|
|
func TestDiscoveryPreservesFailureDiagnosticsAndCause(t *testing.T) {
|
|
repository, _ := installGoPreparationFixture(t)
|
|
t.Setenv("RELEASEKIT_GO_FIXTURE_MODE", "fail")
|
|
_, err := New(context.Background(), repository)
|
|
var exitError *exec.ExitError
|
|
if !errors.As(err, &exitError) || exitError.ExitCode() != 23 || !strings.Contains(err.Error(), "fixture dependency failure") {
|
|
t.Fatalf("New() error = %v", err)
|
|
}
|
|
}
|
|
|
|
func mustGetwd() string {
|
|
directory, err := os.Getwd()
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return directory
|
|
}
|
|
|
|
func installGoPreparationFixture(t *testing.T) (repository, recordPath string) {
|
|
t.Helper()
|
|
directory := t.TempDir()
|
|
repository = t.TempDir()
|
|
executable, err := os.Executable()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
contents, err := os.ReadFile(executable)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
name := "go"
|
|
if runtime.GOOS == "windows" {
|
|
name += ".exe"
|
|
}
|
|
if err := os.WriteFile(filepath.Join(directory, name), contents, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
recordPath = filepath.Join(t.TempDir(), "go-command.json")
|
|
t.Setenv("PATH", directory+string(os.PathListSeparator)+os.Getenv("PATH"))
|
|
t.Setenv("RELEASEKIT_GO_FIXTURE", "1")
|
|
t.Setenv("RELEASEKIT_GO_FIXTURE_RECORD", recordPath)
|
|
return repository, recordPath
|
|
}
|
|
|
|
func TestPrepareBuildDependenciesPreservesPreparationEnvironment(t *testing.T) {
|
|
repository, recordPath := installGoPreparationFixture(t)
|
|
moduleCache := filepath.Join(t.TempDir(), "module-cache")
|
|
t.Setenv("GOWORK", filepath.Join(t.TempDir(), "go.work"))
|
|
t.Setenv("GOTOOLCHAIN", "auto")
|
|
t.Setenv("GOPROXY", "https://proxy.example.invalid")
|
|
t.Setenv("GOPRIVATE", "example.invalid/private")
|
|
t.Setenv("GONOSUMDB", "example.invalid/private")
|
|
t.Setenv("GOMODCACHE", moduleCache)
|
|
|
|
if err := PrepareBuildDependencies(context.Background(), repository); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
contents, err := os.ReadFile(recordPath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var record goPreparationRecord
|
|
if err := json.Unmarshal(contents, &record); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if strings.Join(record.Arguments, " ") != "mod download" || record.Directory != repository {
|
|
t.Fatalf("Go invocation = %#v", record)
|
|
}
|
|
if record.Workspace != "off" || record.Toolchain != "local" {
|
|
t.Fatalf("preparation Go settings = %#v", record)
|
|
}
|
|
if record.Proxy != "https://proxy.example.invalid" || record.Private != "example.invalid/private" || record.NoSumDB != "example.invalid/private" || record.ModuleCache != moduleCache {
|
|
t.Fatalf("caller dependency settings were not preserved: %#v", record)
|
|
}
|
|
}
|
|
|
|
func TestPrepareBuildDependenciesPropagatesCommandFailure(t *testing.T) {
|
|
repository, _ := installGoPreparationFixture(t)
|
|
t.Setenv("RELEASEKIT_GO_FIXTURE_MODE", "fail")
|
|
err := PrepareBuildDependencies(context.Background(), repository)
|
|
var exitError *exec.ExitError
|
|
if !errors.As(err, &exitError) || exitError.ExitCode() != 23 || !strings.Contains(err.Error(), "fixture dependency failure") {
|
|
t.Fatalf("PrepareBuildDependencies() error = %v", err)
|
|
}
|
|
}
|
|
|
|
func TestPrepareBuildDependenciesPropagatesCancellation(t *testing.T) {
|
|
repository, recordPath := installGoPreparationFixture(t)
|
|
t.Setenv("RELEASEKIT_GO_FIXTURE_MODE", "wait")
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
done := make(chan error, 1)
|
|
go func() { done <- PrepareBuildDependencies(ctx, repository) }()
|
|
|
|
deadline := time.Now().Add(5 * time.Second)
|
|
for {
|
|
if _, err := os.Stat(recordPath); err == nil {
|
|
break
|
|
}
|
|
if time.Now().After(deadline) {
|
|
t.Fatal("Go fixture did not start")
|
|
}
|
|
time.Sleep(10 * time.Millisecond)
|
|
}
|
|
cancel()
|
|
select {
|
|
case err := <-done:
|
|
if !errors.Is(err, context.Canceled) {
|
|
t.Fatalf("PrepareBuildDependencies() error = %v; want cancellation", err)
|
|
}
|
|
case <-time.After(5 * time.Second):
|
|
t.Fatal("Go fixture did not stop after cancellation")
|
|
}
|
|
}
|
|
|
|
func TestNativeAndStaticCommandsUseOwnedBaseline(t *testing.T) {
|
|
clearGoSettings(t)
|
|
t.Setenv("GOENV", "off")
|
|
t.Setenv("GOFLAGS", "-run=^$")
|
|
t.Setenv("GOOS", "windows")
|
|
t.Setenv("GOARCH", "arm64")
|
|
t.Setenv("GOAMD64", "v2")
|
|
t.Setenv("GOEXPERIMENT", "loopvar")
|
|
|
|
tool, err := New(context.Background(), t.TempDir())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if tool.HostTarget() != (Target{OS: runtime.GOOS, Arch: runtime.GOARCH}) {
|
|
t.Fatalf("Go host = %#v, want runtime host %s/%s", tool.HostTarget(), runtime.GOOS, runtime.GOARCH)
|
|
}
|
|
|
|
native := readSettings(t, tool, Native, Target{}, "GOENV", "GOOS", "GOARCH", "GOFLAGS", "GOAMD64", "GOEXPERIMENT", "CGO_ENABLED")
|
|
if native["GOENV"] != "" || native["GOOS"] != runtime.GOOS || native["GOARCH"] != runtime.GOARCH {
|
|
t.Fatalf("native environment = %#v", native)
|
|
}
|
|
if native["GOFLAGS"] != "-mod=readonly" || native["GOAMD64"] == "v2" || native["GOEXPERIMENT"] != "" {
|
|
t.Fatalf("native Go settings = %#v", native)
|
|
}
|
|
if native["CGO_ENABLED"] == "" {
|
|
t.Fatalf("native cgo setting was not resolved: %#v", native)
|
|
}
|
|
|
|
static := readSettings(t, tool, Static, Target{OS: "linux", Arch: "amd64"}, "GOOS", "GOARCH", "GOFLAGS", "CGO_ENABLED", "GOAMD64", "GOEXPERIMENT")
|
|
if static["GOOS"] != "linux" || static["GOARCH"] != "amd64" || static["CGO_ENABLED"] != "0" {
|
|
t.Fatalf("static environment = %#v", static)
|
|
}
|
|
if static["GOFLAGS"] != "-mod=readonly" || static["GOAMD64"] != "v1" || static["GOEXPERIMENT"] != "" {
|
|
t.Fatalf("static baseline settings = %#v", static)
|
|
}
|
|
}
|
|
|
|
func TestPersistentSettingsPreserveCachesAndNativeCTools(t *testing.T) {
|
|
clearGoSettings(t)
|
|
cache := filepath.Join(t.TempDir(), "configured-cache")
|
|
moduleCache := filepath.Join(t.TempDir(), "configured-module-cache")
|
|
temporary := filepath.Join(t.TempDir(), "configured-temporary")
|
|
if err := os.Mkdir(temporary, 0o700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
goEnv := filepath.Join(t.TempDir(), "go-env")
|
|
contents := strings.Join([]string{
|
|
"GOFLAGS=-run=^$",
|
|
"GOOS=windows",
|
|
"GOARCH=arm64",
|
|
"GOAMD64=v2",
|
|
"GOEXPERIMENT=loopvar",
|
|
"GOCACHE=" + cache,
|
|
"GOMODCACHE=" + moduleCache,
|
|
"GOTMPDIR=" + temporary,
|
|
"CGO_ENABLED=1",
|
|
"CC=releasekit-test-cc",
|
|
"CXX=releasekit-test-cxx",
|
|
"CGO_CFLAGS=-O0 -g",
|
|
"PKG_CONFIG=releasekit-test-pkg-config",
|
|
}, "\n") + "\n"
|
|
if err := os.WriteFile(goEnv, []byte(contents), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Setenv("GOENV", goEnv)
|
|
|
|
tool, err := New(context.Background(), t.TempDir())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if tool.HostTarget() != (Target{OS: runtime.GOOS, Arch: runtime.GOARCH}) {
|
|
t.Fatalf("Go host = %#v, want runtime host %s/%s", tool.HostTarget(), runtime.GOOS, runtime.GOARCH)
|
|
}
|
|
native := readSettings(t, tool, Native, Target{}, "GOENV", "GOOS", "GOARCH", "GOFLAGS", "GOAMD64", "GOEXPERIMENT", "CGO_ENABLED", "CC", "CXX", "CGO_CFLAGS", "GOCACHE", "GOMODCACHE", "GOTMPDIR", "PKG_CONFIG")
|
|
if native["GOENV"] != "" || native["GOOS"] != runtime.GOOS || native["GOARCH"] != runtime.GOARCH {
|
|
t.Fatalf("native environment = %#v", native)
|
|
}
|
|
if native["GOFLAGS"] != "-mod=readonly" || native["GOAMD64"] == "v2" || native["GOEXPERIMENT"] != "" {
|
|
t.Fatalf("persisted overrides were not cleared: %#v", native)
|
|
}
|
|
if native["CGO_ENABLED"] != "1" || native["CC"] != "releasekit-test-cc" || native["CXX"] != "releasekit-test-cxx" || native["CGO_CFLAGS"] != "-O0 -g" || native["PKG_CONFIG"] != "releasekit-test-pkg-config" {
|
|
t.Fatalf("persistent native C settings = %#v", native)
|
|
}
|
|
if native["GOCACHE"] != cache || native["GOMODCACHE"] != moduleCache || native["GOTMPDIR"] != temporary {
|
|
t.Fatalf("persistent cache settings = %#v", native)
|
|
}
|
|
static := readSettings(t, tool, Static, Target{OS: "linux", Arch: "amd64"}, "GOENV", "GOOS", "GOARCH", "GOFLAGS", "CGO_ENABLED", "GOAMD64", "GOEXPERIMENT", "GOCACHE")
|
|
if static["GOENV"] != "" || static["GOOS"] != "linux" || static["GOARCH"] != "amd64" || static["CGO_ENABLED"] != "0" || static["GOAMD64"] != "v1" || static["GOEXPERIMENT"] != "" || static["GOCACHE"] != cache {
|
|
t.Fatalf("persistent static environment = %#v", static)
|
|
}
|
|
}
|
|
|
|
func TestOwnerReusesSettingsUntilInheritedEnvironmentChanges(t *testing.T) {
|
|
clearGoSettings(t)
|
|
t.Setenv("GOENV", "off")
|
|
owner := NewOwner(t.TempDir())
|
|
|
|
first, err := owner.Acquire(context.Background())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
second, err := owner.Acquire(context.Background())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if first != second {
|
|
t.Fatal("unchanged Go inputs caused settings discovery to be repeated")
|
|
}
|
|
|
|
cache := filepath.Join(t.TempDir(), "changed-cache")
|
|
t.Setenv("GOCACHE", cache)
|
|
third, err := owner.Acquire(context.Background())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if third == first || third.settings["GOCACHE"] != cache {
|
|
t.Fatalf("changed inherited environment kept stale settings: tool=%p GOCACHE=%q", third, third.settings["GOCACHE"])
|
|
}
|
|
}
|
|
|
|
func TestOwnerAcceptsGoConfigurationWithoutReadableSnapshot(t *testing.T) {
|
|
clearGoSettings(t)
|
|
t.Setenv("GOENV", t.TempDir())
|
|
directory := t.TempDir()
|
|
if _, err := New(context.Background(), directory); err != nil {
|
|
t.Fatalf("underlying Go discovery rejected fixture: %v", err)
|
|
}
|
|
owner := NewOwner(directory)
|
|
first, err := owner.Acquire(context.Background())
|
|
if err != nil {
|
|
t.Fatalf("owner added a snapshot prerequisite: %v", err)
|
|
}
|
|
second, err := owner.Acquire(context.Background())
|
|
if err != nil || first == second {
|
|
t.Fatalf("unavailable snapshot should rediscover on demand: first=%p second=%p error=%v", first, second, err)
|
|
}
|
|
}
|
|
|
|
func TestOwnerRefreshesWhenPersistentSettingsChange(t *testing.T) {
|
|
clearGoSettings(t)
|
|
firstCache := filepath.Join(t.TempDir(), "first-cache")
|
|
secondCache := filepath.Join(t.TempDir(), "second-cache")
|
|
settingsFile := filepath.Join(t.TempDir(), "go-env")
|
|
writeSettings := func(cache string) {
|
|
t.Helper()
|
|
if err := os.WriteFile(settingsFile, []byte("GOCACHE="+cache+"\n"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
writeSettings(firstCache)
|
|
t.Setenv("GOENV", settingsFile)
|
|
owner := NewOwner(t.TempDir())
|
|
|
|
first, err := owner.Acquire(context.Background())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if first.settings["GOCACHE"] != firstCache {
|
|
t.Fatalf("initial GOCACHE = %q, want %q", first.settings["GOCACHE"], firstCache)
|
|
}
|
|
writeSettings(secondCache)
|
|
second, err := owner.Acquire(context.Background())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if second == first || second.settings["GOCACHE"] != secondCache {
|
|
t.Fatalf("changed persistent settings were not rediscovered: tool=%p GOCACHE=%q", second, second.settings["GOCACHE"])
|
|
}
|
|
}
|
|
|
|
func readSettings(t *testing.T, tool *Tool, mode Mode, target Target, names ...string) map[string]string {
|
|
t.Helper()
|
|
args := append([]string{"env", "-json"}, names...)
|
|
output, err := tool.Output(context.Background(), t.TempDir(), mode, target, nil, args...)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var settings map[string]string
|
|
if err := json.Unmarshal(output, &settings); err != nil {
|
|
t.Fatalf("decode Go environment %q: %v", output, err)
|
|
}
|
|
return settings
|
|
}
|
|
|
|
func TestOutputReturnsAndForwardsCombinedOutput(t *testing.T) {
|
|
repository, _ := installGoPreparationFixture(t)
|
|
t.Setenv("RELEASEKIT_GO_FIXTURE_MODE", "output")
|
|
tool := fixtureTool()
|
|
var forwarded bytes.Buffer
|
|
|
|
output, err := tool.Output(context.Background(), repository, Native, Target{}, &forwarded, "version")
|
|
if err != nil {
|
|
t.Fatalf("Output() error = %v", err)
|
|
}
|
|
if !bytes.Contains(output, []byte("fixture stdout")) || !bytes.Contains(output, []byte("fixture stderr")) {
|
|
t.Fatalf("combined output = %q", output)
|
|
}
|
|
if !bytes.Equal(forwarded.Bytes(), output) {
|
|
t.Fatalf("forwarded output differs from capture: forwarded %d bytes, captured %d", forwarded.Len(), len(output))
|
|
}
|
|
}
|
|
|
|
func TestRunForwardsOutputWithoutReturningCapture(t *testing.T) {
|
|
repository, _ := installGoPreparationFixture(t)
|
|
t.Setenv("RELEASEKIT_GO_FIXTURE_MODE", "output")
|
|
tool := fixtureTool()
|
|
var forwarded bytes.Buffer
|
|
|
|
if err := tool.Run(context.Background(), repository, Native, Target{}, &forwarded, "version"); err != nil {
|
|
t.Fatalf("Run() error = %v", err)
|
|
}
|
|
if !bytes.Contains(forwarded.Bytes(), []byte("fixture stdout")) || !bytes.Contains(forwarded.Bytes(), []byte("fixture stderr")) {
|
|
t.Fatalf("forwarded output = %q", forwarded.String())
|
|
}
|
|
}
|
|
|
|
func TestRunPreservesFailureDiagnosticsAndCause(t *testing.T) {
|
|
repository, _ := installGoPreparationFixture(t)
|
|
t.Setenv("RELEASEKIT_GO_FIXTURE_MODE", "fail")
|
|
tool := fixtureTool()
|
|
|
|
err := tool.Run(context.Background(), repository, Native, Target{}, nil, "version")
|
|
var exitError *exec.ExitError
|
|
if !errors.As(err, &exitError) || exitError.ExitCode() != 23 || !strings.Contains(err.Error(), "fixture dependency failure") {
|
|
t.Fatalf("Run() error = %v", err)
|
|
}
|
|
}
|
|
|
|
func TestOutputReturnsLargeFailureDiagnosticsAndCause(t *testing.T) {
|
|
repository, _ := installGoPreparationFixture(t)
|
|
t.Setenv("RELEASEKIT_GO_FIXTURE_MODE", "large-fail")
|
|
tool := fixtureTool()
|
|
|
|
output, err := tool.Output(context.Background(), repository, Native, Target{}, nil, "version")
|
|
var exitError *exec.ExitError
|
|
wantSize := (8 << 20) + len("fixture large failure\n")
|
|
if len(output) != wantSize {
|
|
t.Fatalf("captured output = %d bytes, want %d", len(output), wantSize)
|
|
}
|
|
if !errors.As(err, &exitError) || exitError.ExitCode() != 23 || !strings.Contains(err.Error(), "fixture large failure") {
|
|
t.Fatalf("Output() error = %v", err)
|
|
}
|
|
}
|
|
|
|
func TestOutputReturnsCancellation(t *testing.T) {
|
|
repository, recordPath := installGoPreparationFixture(t)
|
|
t.Setenv("RELEASEKIT_GO_FIXTURE_MODE", "wait")
|
|
tool := fixtureTool()
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
done := make(chan error, 1)
|
|
go func() {
|
|
_, err := tool.Output(ctx, repository, Native, Target{}, nil, "version")
|
|
done <- err
|
|
}()
|
|
|
|
deadline := time.Now().Add(5 * time.Second)
|
|
for {
|
|
if _, err := os.Stat(recordPath); err == nil {
|
|
break
|
|
}
|
|
if time.Now().After(deadline) {
|
|
t.Fatal("Go fixture did not start")
|
|
}
|
|
time.Sleep(10 * time.Millisecond)
|
|
}
|
|
cancel()
|
|
select {
|
|
case err := <-done:
|
|
if !errors.Is(err, context.Canceled) {
|
|
t.Fatalf("Output() error = %v; want cancellation", err)
|
|
}
|
|
case <-time.After(5 * time.Second):
|
|
t.Fatal("Go fixture did not stop after cancellation")
|
|
}
|
|
}
|
|
|
|
func TestOutputPreservesForwardingWriterFailure(t *testing.T) {
|
|
repository, _ := installGoPreparationFixture(t)
|
|
t.Setenv("RELEASEKIT_GO_FIXTURE_MODE", "output")
|
|
tool := fixtureTool()
|
|
writerErr := errors.New("fixture output writer failed")
|
|
|
|
output, err := tool.Output(context.Background(), repository, Native, Target{}, failingOutputWriter{err: writerErr}, "version")
|
|
if !errors.Is(err, writerErr) || !strings.Contains(err.Error(), "go version") {
|
|
t.Fatalf("Output() error = %v; want wrapped writer error and command", err)
|
|
}
|
|
if len(output) == 0 {
|
|
t.Fatal("Output() returned no captured bytes after forwarding failed")
|
|
}
|
|
}
|
|
|
|
type failingOutputWriter struct{ err error }
|
|
|
|
func (writer failingOutputWriter) Write([]byte) (int, error) { return 0, writer.err }
|
|
|
|
func fixtureTool() *Tool {
|
|
return &Tool{host: Target{OS: runtime.GOOS, Arch: runtime.GOARCH}, settings: map[string]string{}}
|
|
}
|
|
|
|
func clearGoSettings(t *testing.T) {
|
|
t.Helper()
|
|
for _, key := range []string{
|
|
"GOENV", "GOFLAGS", "GOWORK", "GOTOOLCHAIN", "GOPROXY", "GONOPROXY", "GOSUMDB",
|
|
"GOOS", "GOARCH", "GOEXPERIMENT", "GOAMD64", "GOARM", "GOARM64", "GO386", "GOMIPS", "GOMIPS64", "GOPPC64", "GORISCV64", "GOWASM",
|
|
"CGO_ENABLED", "CC", "CXX", "CGO_CFLAGS", "CGO_CPPFLAGS", "CGO_CXXFLAGS", "CGO_LDFLAGS", "GOCACHE", "GOCACHEPROG", "GOMODCACHE", "GOPATH", "GOROOT", "GOTMPDIR", "PKG_CONFIG",
|
|
} {
|
|
value, exists := os.LookupEnv(key)
|
|
if err := os.Unsetenv(key); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() {
|
|
if exists {
|
|
_ = os.Setenv(key, value)
|
|
} else {
|
|
_ = os.Unsetenv(key)
|
|
}
|
|
})
|
|
}
|
|
}
|