@@ -13,6 +13,7 @@ import (
13
13
"path/filepath"
14
14
"strings"
15
15
"testing"
16
+ "time"
16
17
17
18
"golang.org/x/sync/errgroup"
18
19
"golang.org/x/tools/internal/gocommand"
@@ -64,23 +65,34 @@ func TestRmdirAfterGoList_Runner(t *testing.T) {
64
65
// TestRmdirAfterGoList_Runner that executes go list directly, to
65
66
// control for the substantial logic of the gocommand package.
66
67
//
67
- // If this test ever fails, the go command itself has a bug; as of May
68
- // 2025 this has never been observed.
68
+ // It has two variants: the first does not set WaitDelay; the second
69
+ // sets it to 30s. If the first variant ever fails, the go command
70
+ // itself has a bug; as of May 2025 this has never been observed.
71
+ //
72
+ // If the second variant fails, it indicates that the WaitDelay
73
+ // mechanism is responsible for causing Wait to return before the
74
+ // child process has naturally finished. This is to confirm the
75
+ // hypothesis at https://github.com/golang/go/issues/73736#issuecomment-2885407104.
69
76
func TestRmdirAfterGoList_Direct (t * testing.T ) {
70
- testRmdirAfterGoList (t , func (ctx context.Context , dir string ) {
71
- cmd := exec .Command ("go" , "list" , "-json" , "example.com/p" )
72
- cmd .Dir = dir
73
- cmd .Stdout = new (strings.Builder )
74
- cmd .Stderr = new (strings.Builder )
75
- err := cmd .Run ()
76
- if ctx .Err () != nil {
77
- return // don't report error if canceled
78
- }
79
- if err != nil {
80
- t .Fatalf ("go list failed: %v (stdout=%s stderr=%s)" ,
81
- err , cmd .Stdout , cmd .Stderr )
82
- }
83
- })
77
+ for _ , delay := range []time.Duration {0 , 30 * time .Second } {
78
+ t .Run (delay .String (), func (t * testing.T ) {
79
+ testRmdirAfterGoList (t , func (ctx context.Context , dir string ) {
80
+ cmd := exec .Command ("go" , "list" , "-json" , "example.com/p" )
81
+ cmd .Dir = dir
82
+ cmd .Stdout = new (strings.Builder )
83
+ cmd .Stderr = new (strings.Builder )
84
+ cmd .WaitDelay = delay
85
+ err := cmd .Run ()
86
+ if ctx .Err () != nil {
87
+ return // don't report error if canceled
88
+ }
89
+ if err != nil {
90
+ t .Fatalf ("go list failed: %v (stdout=%s stderr=%s)" ,
91
+ err , cmd .Stdout , cmd .Stderr )
92
+ }
93
+ })
94
+ })
95
+ }
84
96
}
85
97
86
98
func testRmdirAfterGoList (t * testing.T , f func (ctx context.Context , dir string )) {
@@ -102,6 +114,7 @@ func testRmdirAfterGoList(t *testing.T, f func(ctx context.Context, dir string))
102
114
}
103
115
}
104
116
117
+ t0 := time .Now ()
105
118
g , ctx := errgroup .WithContext (context .Background ())
106
119
for range 10 {
107
120
g .Go (func () error {
@@ -110,7 +123,9 @@ func testRmdirAfterGoList(t *testing.T, f func(ctx context.Context, dir string))
110
123
return fmt .Errorf ("oops" )
111
124
})
112
125
}
113
- g .Wait () // ignore expected error
126
+ g .Wait () // ignore error (expected)
127
+
128
+ t .Logf ("10 concurrent executions (9 canceled) took %v" , time .Since (t0 ))
114
129
115
130
// This is the critical operation.
116
131
if err := os .RemoveAll (dir ); err != nil {
@@ -119,6 +134,6 @@ func testRmdirAfterGoList(t *testing.T, f func(ctx context.Context, dir string))
119
134
filepath .WalkDir (dir , func (path string , d fs.DirEntry , err error ) error {
120
135
t .Log (path , d , err )
121
136
return nil
122
- })
137
+ }) // ignore error
123
138
}
124
139
}
0 commit comments