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.
5 // Test broken pipes on Unix systems.
6 // +build !windows,!plan9,!nacl
20 func TestEPIPE(t
*testing
.T
) {
21 r
, w
, err
:= os
.Pipe()
25 if err
:= r
.Close(); err
!= nil {
29 // Every time we write to the pipe we should get an EPIPE.
30 for i
:= 0; i
< 20; i
++ {
31 _
, err
= w
.Write([]byte("hi"))
33 t
.Fatal("unexpected success of Write to broken pipe")
35 if pe
, ok
:= err
.(*os
.PathError
); ok
{
38 if se
, ok
:= err
.(*os
.SyscallError
); ok
{
41 if err
!= syscall
.EPIPE
{
42 t
.Errorf("iteration %d: got %v, expected EPIPE", i
, err
)
47 func TestStdPipe(t
*testing
.T
) {
48 testenv
.MustHaveExec(t
)
49 r
, w
, err
:= os
.Pipe()
53 if err
:= r
.Close(); err
!= nil {
56 // Invoke the test program to run the test and write to a closed pipe.
58 // writing to stdout or stderr should cause an immediate SIGPIPE;
59 // writing to descriptor 3 should fail with EPIPE and then exit 0.
61 // all writes should fail with EPIPE and then exit 0.
62 for _
, sig
:= range []bool{false, true} {
63 for dest
:= 1; dest
< 4; dest
++ {
64 cmd
:= osexec
.Command(os
.Args
[0], "-test.run", "TestStdPipeHelper")
67 cmd
.ExtraFiles
= []*os
.File
{w
}
68 cmd
.Env
= append(os
.Environ(), fmt
.Sprintf("GO_TEST_STD_PIPE_HELPER=%d", dest
))
70 cmd
.Env
= append(cmd
.Env
, "GO_TEST_STD_PIPE_HELPER_SIGNAL=1")
72 if err
:= cmd
.Run(); err
== nil {
74 t
.Errorf("unexpected success of write to closed pipe %d sig %t in child", dest
, sig
)
76 } else if ee
, ok
:= err
.(*osexec
.ExitError
); !ok
{
77 t
.Errorf("unexpected exec error type %T: %v", err
, err
)
78 } else if ws
, ok
:= ee
.Sys().(syscall
.WaitStatus
); !ok
{
79 t
.Errorf("unexpected wait status type %T: %v", ee
.Sys(), ee
.Sys())
80 } else if ws
.Signaled() && ws
.Signal() == syscall
.SIGPIPE
{
82 t
.Errorf("unexpected SIGPIPE signal for descriptor %d sig %t", dest
, sig
)
85 t
.Errorf("unexpected exit status %v for descriptor %ds sig %t", err
, dest
, sig
)
91 // This is a helper for TestStdPipe. It's not a test in itself.
92 func TestStdPipeHelper(t
*testing
.T
) {
93 if os
.Getenv("GO_TEST_STD_PIPE_HELPER_SIGNAL") != "" {
94 signal
.Notify(make(chan os
.Signal
, 1), syscall
.SIGPIPE
)
96 switch os
.Getenv("GO_TEST_STD_PIPE_HELPER") {
98 os
.Stdout
.Write([]byte("stdout"))
100 os
.Stderr
.Write([]byte("stderr"))
102 if _
, err
:= os
.NewFile(3, "3").Write([]byte("3")); err
== nil {
106 t
.Skip("skipping test helper")
108 // For stdout/stderr, we should have crashed with a broken pipe error.
109 // The caller will be looking for that exit status,
110 // so just exit normally here to cause a failure in the caller.
111 // For descriptor 3, a normal exit is expected.