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

View as plain text