@@ -5,18 +5,16 @@ package runtime_test
5
5
import (
6
6
"bufio"
7
7
"bytes"
8
- "context"
9
8
"fmt"
10
9
"internal/testenv"
11
- "net"
12
10
"os"
13
11
"os/exec"
14
12
"path/filepath"
15
13
"runtime"
14
+ "strconv"
16
15
"strings"
17
16
"syscall"
18
17
"testing"
19
- "time"
20
18
)
21
19
22
20
func TestVectoredHandlerDontCrashOnLibrary (t * testing.T ) {
@@ -96,50 +94,60 @@ func TestCtrlHandler(t *testing.T) {
96
94
t .Fatalf ("failed to build go exe: %v\n %s" , err , out )
97
95
}
98
96
99
- // udp socket for synchronization
100
- conn , err := net .ListenPacket ("udp" , "[::1]:0" )
97
+ // run test program
98
+ cmd = exec .Command (exe )
99
+ var stderr bytes.Buffer
100
+ cmd .Stderr = & stderr
101
+ outPipe , err := cmd .StdoutPipe ()
101
102
if err != nil {
102
- t .Fatalf ("ListenPacket failed : %v" , err )
103
+ t .Fatalf ("Failed to create stdout pipe : %v" , err )
103
104
}
104
- defer conn .Close ()
105
- conn .SetDeadline (time .Now ().Add (5 * time .Second ))
106
-
107
- ctx , cancel := context .WithTimeout (context .TODO (), 5 * time .Second )
108
- defer cancel ()
105
+ outReader := bufio .NewReader (outPipe )
109
106
110
- // run test program, in a new command window
111
- cmd = exec .CommandContext (ctx , "cmd.exe" , "/c" , "start" , "Test Command Window" , "/wait" , exe , conn .LocalAddr ().String ())
107
+ // in a new command window
108
+ const CREATE_NEW_CONSOLE = 0x00000010
109
+ cmd .SysProcAttr = & syscall.SysProcAttr {
110
+ CreationFlags : CREATE_NEW_CONSOLE ,
111
+ }
112
112
if err := cmd .Start (); err != nil {
113
113
t .Fatalf ("Start failed: %v" , err )
114
114
}
115
115
116
- // read pid of the test program
117
- // cmd.Process.Pid is the pid of cmd.exe, not test.exe
118
- // also ensures the test program is ready to receive signals
119
- var data [512 ]byte
120
- n , _ , err := conn .ReadFrom (data [:])
121
- if err != nil {
122
- t .Fatalf ("ReadFrom failed: %v" , err )
123
- }
116
+ errCh := make (chan error , 1 )
117
+ go func () {
118
+ // wait for child to be ready to receive signals
119
+ if line , err := outReader .ReadString ('\n' ); err != nil {
120
+ errCh <- fmt .Errorf ("could not read stdout: %w" , err )
121
+ return
122
+ } else if strings .TrimSpace (line ) != "ready" {
123
+ errCh <- fmt .Errorf ("unexpected message: %v" , line )
124
+ return
125
+ }
124
126
125
- // gracefully kill pid, this closes the command window
126
- err = exec .Command ("taskkill.exe" , "/pid" , string ( data [: n ] )).Run ()
127
- if err != nil {
128
- t . Fatalf ( "failed to kill: %v" , err )
129
- }
127
+ // gracefully kill pid, this closes the command window
128
+ if err : = exec .Command ("taskkill.exe" , "/pid" , strconv . Itoa ( cmd . Process . Pid )).Run (); err != nil {
129
+ errCh <- fmt . Errorf ( "failed to kill: %w" , err )
130
+ return
131
+ }
130
132
131
- // check child received, handled SIGTERM
132
- n , _ , err = conn .ReadFrom (data [:])
133
- if err != nil {
134
- t .Fatalf ("ReadFrom failed: %v" , err )
135
- }
136
- if expected , got := syscall .SIGTERM .String (), string (data [:n ]); expected != got {
137
- t .Fatalf ("Expected '%s' got: %s" , expected , got )
138
- }
133
+ // check child received, handled SIGTERM
134
+ if line , err := outReader .ReadString ('\n' ); err != nil {
135
+ errCh <- fmt .Errorf ("could not read stdout: %w" , err )
136
+ return
137
+ } else if expected , got := syscall .SIGTERM .String (), strings .TrimSpace (line ); expected != got {
138
+ errCh <- fmt .Errorf ("Expected '%s' got: %s" , expected , got )
139
+ return
140
+ }
141
+
142
+ errCh <- nil
143
+ }()
139
144
140
- // check child exited gracefully (exit code 0, didn't timeout)
145
+ if err := <- errCh ; err != nil {
146
+ t .Fatal (err )
147
+ }
148
+ // check child exited gracefully, did not timeout
141
149
if err := cmd .Wait (); err != nil {
142
- t .Fatalf ("Program exited with error: %v" , err )
150
+ t .Fatalf ("Program exited with error: %v\n %s " , err , & stderr )
143
151
}
144
152
}
145
153
0 commit comments