Source file src/cmd/go/internal/verylongtest/go_unix_test.go

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build unix
     6  
     7  package verylongtest
     8  
     9  import (
    10  	"bufio"
    11  	"context"
    12  	"internal/testenv"
    13  	"io"
    14  	"os"
    15  	"os/exec"
    16  	"path/filepath"
    17  	"strings"
    18  	"syscall"
    19  	"testing"
    20  )
    21  
    22  func TestGoBuildUmask(t *testing.T) {
    23  	testenv.MustHaveGoBuild(t)
    24  
    25  	// Do not use tg.parallel; avoid other tests seeing umask manipulation.
    26  	mask := syscall.Umask(0077) // prohibit low bits
    27  	defer syscall.Umask(mask)
    28  
    29  	gotool, err := testenv.GoTool()
    30  	if err != nil {
    31  		t.Fatal(err)
    32  	}
    33  
    34  	tmpdir, err := os.MkdirTemp("", "")
    35  	if err != nil {
    36  		t.Fatal(err)
    37  	}
    38  	t.Cleanup(func() {
    39  		if err := os.RemoveAll(tmpdir); err != nil {
    40  			t.Fatal(err)
    41  		}
    42  	})
    43  	err = os.WriteFile(filepath.Join(tmpdir, "x.go"), []byte(`package main; func main() {}`), 0666)
    44  	if err != nil {
    45  		t.Fatal(err)
    46  	}
    47  
    48  	// We have set a umask, but if the parent directory happens to have a default
    49  	// ACL, the umask may be ignored. To prevent spurious failures from an ACL,
    50  	// we compare the file created by "go build" against a file written explicitly
    51  	// by os.WriteFile.
    52  	//
    53  	// (See https://go.dev/issue/62724, https://go.dev/issue/17909.)
    54  	control := filepath.Join(tmpdir, "control")
    55  	if err := os.WriteFile(control, []byte("#!/bin/sh\nexit 0"), 0777); err != nil {
    56  		t.Fatal(err)
    57  	}
    58  	cfi, err := os.Stat(control)
    59  	if err != nil {
    60  		t.Fatal(err)
    61  	}
    62  
    63  	exe := filepath.Join(tmpdir, "x")
    64  	if err := exec.Command(gotool, "build", "-o", exe, filepath.Join(tmpdir, "x.go")).Run(); err != nil {
    65  		t.Fatal(err)
    66  	}
    67  	fi, err := os.Stat(exe)
    68  	if err != nil {
    69  		t.Fatal(err)
    70  	}
    71  	got, want := fi.Mode(), cfi.Mode()
    72  	if got == want {
    73  		t.Logf("wrote x with mode %v", got)
    74  	} else {
    75  		t.Fatalf("wrote x with mode %v, wanted no 0077 bits (%v)", got, want)
    76  	}
    77  }
    78  
    79  // TestTestInterrupt verifies the fix for issue #60203.
    80  //
    81  // If the whole process group for a 'go test' invocation receives
    82  // SIGINT (as would be sent by pressing ^C on a console),
    83  // it should return quickly, not deadlock.
    84  func TestTestInterrupt(t *testing.T) {
    85  	if testing.Short() {
    86  		t.Skipf("skipping in short mode: test executes many subprocesses")
    87  	}
    88  	testenv.MustHaveGoBuild(t)
    89  	// Don't run this test in parallel, for the same reason.
    90  
    91  	gotool, err := testenv.GoTool()
    92  	if err != nil {
    93  		t.Fatal(err)
    94  	}
    95  
    96  	ctx, cancel := context.WithCancel(context.Background())
    97  	cmd := testenv.CommandContext(t, ctx, gotool, "test", "std", "-short", "-count=1")
    98  
    99  	cmd.SysProcAttr = &syscall.SysProcAttr{
   100  		Setpgid: true,
   101  	}
   102  	cmd.Cancel = func() error {
   103  		pgid := cmd.Process.Pid
   104  		return syscall.Kill(-pgid, syscall.SIGINT)
   105  	}
   106  
   107  	pipe, err := cmd.StdoutPipe()
   108  	if err != nil {
   109  		t.Fatal(err)
   110  	}
   111  
   112  	t.Logf("running %v", cmd)
   113  	if err := cmd.Start(); err != nil {
   114  		t.Fatal(err)
   115  	}
   116  
   117  	stdout := new(strings.Builder)
   118  	r := bufio.NewReader(pipe)
   119  	line, err := r.ReadString('\n')
   120  	if err != nil {
   121  		t.Fatal(err)
   122  	}
   123  	stdout.WriteString(line)
   124  
   125  	// The output line for some test was written, so we know things are in progress.
   126  	//
   127  	// Cancel the rest of the run by sending SIGINT to the process group:
   128  	// it should finish up and exit with a nonzero status,
   129  	// not have to be killed with SIGKILL.
   130  	cancel()
   131  
   132  	io.Copy(stdout, r)
   133  	if stdout.Len() > 0 {
   134  		t.Logf("stdout:\n%s", stdout)
   135  	}
   136  	err = cmd.Wait()
   137  
   138  	ee, _ := err.(*exec.ExitError)
   139  	if ee == nil {
   140  		t.Fatalf("unexpectedly finished with nonzero status")
   141  	}
   142  	if len(ee.Stderr) > 0 {
   143  		t.Logf("stderr:\n%s", ee.Stderr)
   144  	}
   145  	if !ee.Exited() {
   146  		t.Fatalf("'go test' did not exit after interrupt: %v", err)
   147  	}
   148  
   149  	t.Logf("interrupted tests without deadlocking")
   150  }
   151  

View as plain text