| | |
| | |
| | |
| |
|
| | |
| | package scripttest |
| |
|
| | import ( |
| | "bytes" |
| | "cmd/internal/script" |
| | "context" |
| | "fmt" |
| | "internal/testenv" |
| | "internal/txtar" |
| | "os" |
| | "os/exec" |
| | "path/filepath" |
| | "runtime" |
| | "strings" |
| | "testing" |
| | "time" |
| | ) |
| |
|
| | |
| | |
| | type ToolReplacement struct { |
| | ToolName string |
| | ReplacementPath string |
| | EnvVar string |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | func RunToolScriptTest(t *testing.T, repls []ToolReplacement, scriptsdir string, fixReadme bool) { |
| | |
| | |
| | testenv.MustHaveGoBuild(t) |
| |
|
| | |
| | |
| | if runtime.GOOS == "plan9" { |
| | t.Skipf("no symlinks on plan9") |
| | } |
| |
|
| | |
| | gotool, err := testenv.GoTool() |
| | if err != nil { |
| | t.Fatalf("locating go tool: %v", err) |
| | } |
| |
|
| | goEnv := func(name string) string { |
| | out, err := exec.Command(gotool, "env", name).CombinedOutput() |
| | if err != nil { |
| | t.Fatalf("go env %s: %v\n%s", name, err, out) |
| | } |
| | return strings.TrimSpace(string(out)) |
| | } |
| |
|
| | |
| | |
| | cmds := DefaultCmds() |
| | conds := DefaultConds() |
| |
|
| | addcmd := func(name string, cmd script.Cmd) { |
| | if _, ok := cmds[name]; ok { |
| | panic(fmt.Sprintf("command %q is already registered", name)) |
| | } |
| | cmds[name] = cmd |
| | } |
| |
|
| | prependToPath := func(env []string, dir string) { |
| | found := false |
| | for k := range env { |
| | ev := env[k] |
| | if !strings.HasPrefix(ev, "PATH=") { |
| | continue |
| | } |
| | oldpath := ev[5:] |
| | env[k] = "PATH=" + dir + string(filepath.ListSeparator) + oldpath |
| | found = true |
| | break |
| | } |
| | if !found { |
| | t.Fatalf("could not update PATH") |
| | } |
| | } |
| |
|
| | setenv := func(env []string, varname, val string) []string { |
| | pref := varname + "=" |
| | found := false |
| | for k := range env { |
| | if !strings.HasPrefix(env[k], pref) { |
| | continue |
| | } |
| | env[k] = pref + val |
| | found = true |
| | break |
| | } |
| | if !found { |
| | env = append(env, varname+"="+val) |
| | } |
| | return env |
| | } |
| |
|
| | interrupt := func(cmd *exec.Cmd) error { |
| | return cmd.Process.Signal(os.Interrupt) |
| | } |
| | gracePeriod := 60 * time.Second |
| |
|
| | |
| | |
| | |
| | goroot := goEnv("GOROOT") |
| | tmpdir := t.TempDir() |
| | tgr := SetupTestGoRoot(t, tmpdir, goroot) |
| |
|
| | |
| | for _, repl := range repls { |
| | ReplaceGoToolInTestGoRoot(t, tgr, repl.ToolName, repl.ReplacementPath) |
| | } |
| |
|
| | |
| | testgo := filepath.Join(tgr, "bin", "go") |
| | gocmd := script.Program(testgo, interrupt, gracePeriod) |
| | addcmd("go", gocmd) |
| | cmdExec := cmds["exec"] |
| | addcmd("cc", scriptCC(cmdExec, goEnv("CC"))) |
| |
|
| | |
| | goHostOS, goHostArch := goEnv("GOHOSTOS"), goEnv("GOHOSTARCH") |
| | AddToolChainScriptConditions(t, conds, goHostOS, goHostArch) |
| |
|
| | |
| | env := os.Environ() |
| | prependToPath(env, filepath.Join(tgr, "bin")) |
| | env = setenv(env, "GOROOT", tgr) |
| | |
| | env = setenv(env, "GOOS", runtime.GOOS) |
| | env = setenv(env, "GOARCH", runtime.GOARCH) |
| | for _, repl := range repls { |
| | |
| | chunks := strings.Split(repl.EnvVar, "=") |
| | if len(chunks) != 2 { |
| | t.Fatalf("malformed env var setting: %s", repl.EnvVar) |
| | } |
| | env = append(env, repl.EnvVar) |
| | } |
| |
|
| | |
| | engine := &script.Engine{ |
| | Conds: conds, |
| | Cmds: cmds, |
| | Quiet: !testing.Verbose(), |
| | } |
| |
|
| | t.Run("README", func(t *testing.T) { |
| | checkScriptReadme(t, engine, env, scriptsdir, gotool, fixReadme) |
| | }) |
| |
|
| | |
| | ctx := context.Background() |
| | pattern := filepath.Join(scriptsdir, "*.txt") |
| | RunTests(t, ctx, engine, env, pattern) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | func RunTests(t *testing.T, ctx context.Context, engine *script.Engine, env []string, pattern string) { |
| | gracePeriod := 100 * time.Millisecond |
| | if deadline, ok := t.Deadline(); ok { |
| | timeout := time.Until(deadline) |
| |
|
| | |
| | |
| | if gp := timeout / 20; gp > gracePeriod { |
| | gracePeriod = gp |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | timeout -= 2 * gracePeriod |
| |
|
| | var cancel context.CancelFunc |
| | ctx, cancel = context.WithTimeout(ctx, timeout) |
| | t.Cleanup(cancel) |
| | } |
| |
|
| | files, _ := filepath.Glob(pattern) |
| | if len(files) == 0 { |
| | t.Fatal("no testdata") |
| | } |
| | for _, file := range files { |
| | file := file |
| | name := strings.TrimSuffix(filepath.Base(file), ".txt") |
| | t.Run(name, func(t *testing.T) { |
| | t.Parallel() |
| |
|
| | workdir := t.TempDir() |
| | s, err := script.NewState(ctx, workdir, env) |
| | if err != nil { |
| | t.Fatal(err) |
| | } |
| |
|
| | |
| | a, err := txtar.ParseFile(file) |
| | if err != nil { |
| | t.Fatal(err) |
| | } |
| | initScriptDirs(t, s) |
| | if err := s.ExtractFiles(a); err != nil { |
| | t.Fatal(err) |
| | } |
| |
|
| | t.Log(time.Now().UTC().Format(time.RFC3339)) |
| | work, _ := s.LookupEnv("WORK") |
| | t.Logf("$WORK=%s", work) |
| |
|
| | |
| | |
| | |
| | |
| | |
| | Run(t, engine, s, file, bytes.NewReader(a.Comment)) |
| | }) |
| | } |
| | } |
| |
|
| | func initScriptDirs(t testing.TB, s *script.State) { |
| | must := func(err error) { |
| | if err != nil { |
| | t.Helper() |
| | t.Fatal(err) |
| | } |
| | } |
| |
|
| | work := s.Getwd() |
| | must(s.Setenv("WORK", work)) |
| | must(os.MkdirAll(filepath.Join(work, "tmp"), 0777)) |
| | must(s.Setenv(tempEnvName(), filepath.Join(work, "tmp"))) |
| | } |
| |
|
| | func tempEnvName() string { |
| | switch runtime.GOOS { |
| | case "windows": |
| | return "TMP" |
| | case "plan9": |
| | return "TMPDIR" |
| | default: |
| | return "TMPDIR" |
| | } |
| | } |
| |
|
| | |
| | func scriptCC(cmdExec script.Cmd, ccexe string) script.Cmd { |
| | return script.Command( |
| | script.CmdUsage{ |
| | Summary: "run the platform C compiler", |
| | Args: "args...", |
| | }, |
| | func(s *script.State, args ...string) (script.WaitFunc, error) { |
| | return cmdExec.Run(s, append([]string{ccexe}, args...)...) |
| | }) |
| | } |
| |
|