Skip to content

Commit d0781cc

Browse files
nshalmangopherbot
authored andcommitted
unix: make solaris syscall tests less flaky
Fixes golang/go#58259 Change-Id: I1e8a83ed6ee3be8165c771b81a3cbdd474216c02 Reviewed-on: https://go-review.googlesource.com/c/sys/+/465055 Auto-Submit: Ian Lance Taylor <iant@google.com> Run-TryBot: Ian Lance Taylor <iant@google.com> Auto-Submit: Bryan Mills <bcmills@google.com> Run-TryBot: Bryan Mills <bcmills@google.com> Reviewed-by: Bryan Mills <bcmills@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@google.com>
1 parent ff18efa commit d0781cc

File tree

2 files changed

+93
-21
lines changed

2 files changed

+93
-21
lines changed

unix/syscall_internal_solaris_test.go

+39-5
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,40 @@ func (e *EventPort) checkInternals(t *testing.T, fds, paths, cookies, pending in
2828
}
2929
}
3030

31+
// getOneRetry wraps EventPort.GetOne which in turn wraps a syscall that can be
32+
// interrupted causing us to receive EINTR.
33+
// To prevent our tests from flaking, we retry the syscall until it works
34+
// rather than get unexpected results in our tests.
35+
func getOneRetry(t *testing.T, p *EventPort, timeout *Timespec) (e *PortEvent, err error) {
36+
t.Helper()
37+
for {
38+
e, err = p.GetOne(timeout)
39+
if err != EINTR {
40+
break
41+
}
42+
}
43+
return e, err
44+
}
45+
46+
// getRetry wraps EventPort.Get which in turn wraps a syscall that can be
47+
// interrupted causing us to receive EINTR.
48+
// To prevent our tests from flaking, we retry the syscall until it works
49+
// rather than get unexpected results in our tests.
50+
func getRetry(t *testing.T, p *EventPort, s []PortEvent, min int, timeout *Timespec) (n int, err error) {
51+
t.Helper()
52+
for {
53+
n, err = p.Get(s, min, timeout)
54+
if err != EINTR {
55+
break
56+
}
57+
// If we did get EINTR, make sure we got 0 events
58+
if n != 0 {
59+
t.Fatalf("EventPort.Get returned events on EINTR.\ngot: %d\nexpected: 0", n)
60+
}
61+
}
62+
return n, err
63+
}
64+
3165
// Regression test for DissociatePath returning ENOENT
3266
// This test is intended to create a linear worst
3367
// case scenario of events being associated and
@@ -143,7 +177,7 @@ func TestEventPortDissociateAlreadyGone(t *testing.T) {
143177
runtime.GC()
144178

145179
// Before the fix, this would cause a nil pointer exception
146-
e, err := port.GetOne(nil)
180+
e, err := getOneRetry(t, port, nil)
147181
if err != nil {
148182
t.Errorf("failed to get an event: %v", err)
149183
}
@@ -152,7 +186,7 @@ func TestEventPortDissociateAlreadyGone(t *testing.T) {
152186
t.Errorf(`expected "cookie1", got "%v"`, e.Cookie)
153187
}
154188
// Make sure that a cookie of the same value doesn't cause removal from the paths map incorrectly
155-
e, err = port.GetOne(nil)
189+
e, err = getOneRetry(t, port, nil)
156190
if err != nil {
157191
t.Errorf("failed to get an event: %v", err)
158192
}
@@ -167,7 +201,7 @@ func TestEventPortDissociateAlreadyGone(t *testing.T) {
167201
}
168202
// Event has fired, but until processed it should still be in the map
169203
port.checkInternals(t, 0, 1, 1, 1)
170-
e, err = port.GetOne(nil)
204+
e, err = getOneRetry(t, port, nil)
171205
if err != nil {
172206
t.Errorf("failed to get an event: %v", err)
173207
}
@@ -221,12 +255,12 @@ func TestEventPortGetAfterClose(t *testing.T) {
221255
port.paths = nil
222256
port.cookies = nil
223257
// Ensure that we get back reasonable errors rather than panic
224-
_, err = port.GetOne(nil)
258+
_, err = getOneRetry(t, port, nil)
225259
if err == nil || err.Error() != "this EventPort is already closed" {
226260
t.Errorf("didn't receive expected error of 'this EventPort is already closed'; got: %v", err)
227261
}
228262
events := make([]PortEvent, 2)
229-
n, err = port.Get(events, 1, nil)
263+
n, err = getRetry(t, port, events, 1, nil)
230264
if n != 0 {
231265
t.Errorf("expected to get back 0 events, got %d", n)
232266
}

unix/syscall_solaris_test.go

+54-16
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,40 @@ import (
1818
"golang.org/x/sys/unix"
1919
)
2020

21+
// getOneRetry wraps EventPort.GetOne which in turn wraps a syscall that can be
22+
// interrupted causing us to receive EINTR.
23+
// To prevent our tests from flaking, we retry the syscall until it works
24+
// rather than get unexpected results in our tests.
25+
func getOneRetry(t *testing.T, p *unix.EventPort, timeout *unix.Timespec) (e *unix.PortEvent, err error) {
26+
t.Helper()
27+
for {
28+
e, err = p.GetOne(timeout)
29+
if err != unix.EINTR {
30+
break
31+
}
32+
}
33+
return e, err
34+
}
35+
36+
// getRetry wraps EventPort.Get which in turn wraps a syscall that can be
37+
// interrupted causing us to receive EINTR.
38+
// To prevent our tests from flaking, we retry the syscall until it works
39+
// rather than get unexpected results in our tests.
40+
func getRetry(t *testing.T, p *unix.EventPort, s []unix.PortEvent, min int, timeout *unix.Timespec) (n int, err error) {
41+
t.Helper()
42+
for {
43+
n, err = p.Get(s, min, timeout)
44+
if err != unix.EINTR {
45+
break
46+
}
47+
// If we did get EINTR, make sure we got 0 events
48+
if n != 0 {
49+
t.Fatalf("EventPort.Get returned events on EINTR.\ngot: %d\nexpected: 0", n)
50+
}
51+
}
52+
return n, err
53+
}
54+
2155
func TestStatvfs(t *testing.T) {
2256
if err := unix.Statvfs("", nil); err == nil {
2357
t.Fatal(`Statvfs("") expected failure`)
@@ -84,13 +118,13 @@ func TestBasicEventPort(t *testing.T) {
84118
bs := []byte{42}
85119
tmpfile.Write(bs)
86120
timeout := new(unix.Timespec)
87-
timeout.Sec = 1
88-
pevent, err := port.GetOne(timeout)
121+
timeout.Nsec = 100
122+
pevent, err := getOneRetry(t, port, timeout)
89123
if err == unix.ETIME {
90124
t.Errorf("GetOne timed out: %v", err)
91125
}
92126
if err != nil {
93-
t.Errorf("GetOne failed: %v", err)
127+
t.Fatalf("GetOne failed: %v", err)
94128
}
95129
if pevent.Path != path {
96130
t.Errorf("Path mismatch: %v != %v", pevent.Path, path)
@@ -135,13 +169,13 @@ func TestEventPortFds(t *testing.T) {
135169
t.Errorf("Pending() failed: %v, %v", n, err)
136170
}
137171
timeout := new(unix.Timespec)
138-
timeout.Sec = 1
139-
pevent, err := port.GetOne(timeout)
172+
timeout.Nsec = 100
173+
pevent, err := getOneRetry(t, port, timeout)
140174
if err == unix.ETIME {
141175
t.Errorf("GetOne timed out: %v", err)
142176
}
143177
if err != nil {
144-
t.Errorf("GetOne failed: %v", err)
178+
t.Fatalf("GetOne failed: %v", err)
145179
}
146180
if pevent.Fd != fd {
147181
t.Errorf("Fd mismatch: %v != %v", pevent.Fd, fd)
@@ -181,26 +215,24 @@ func TestEventPortErrors(t *testing.T) {
181215
}
182216
timeout := new(unix.Timespec)
183217
timeout.Nsec = 1
184-
_, err = port.GetOne(timeout)
218+
_, err = getOneRetry(t, port, timeout)
185219
if err != unix.ETIME {
186-
// See https://go.dev/issue/58259
187-
// Perhaps we sometimes get EINTR ???
188220
t.Errorf("port.GetOne(%v) returned error %v, want %v", timeout, err, unix.ETIME)
189221
}
190222
err = port.DissociateFd(uintptr(0))
191223
if err == nil {
192224
t.Errorf("unexpected success dissociating unassociated fd")
193225
}
194226
events := make([]unix.PortEvent, 4)
195-
_, err = port.Get(events, 5, nil)
227+
_, err = getRetry(t, port, events, 5, nil)
196228
if err == nil {
197229
t.Errorf("unexpected success calling Get with min greater than len of slice")
198230
}
199-
_, err = port.Get(nil, 1, nil)
231+
_, err = getRetry(t, port, nil, 1, nil)
200232
if err == nil {
201233
t.Errorf("unexpected success calling Get with nil slice")
202234
}
203-
_, err = port.Get(nil, 0, nil)
235+
_, err = getRetry(t, port, nil, 0, nil)
204236
if err == nil {
205237
t.Errorf("unexpected success calling Get with nil slice")
206238
}
@@ -232,7 +264,13 @@ func ExamplePortEvent() {
232264
w.Write(bs)
233265
timeout := new(unix.Timespec)
234266
timeout.Sec = 1
235-
pevent, err := port.GetOne(timeout)
267+
var pevent *unix.PortEvent
268+
for {
269+
pevent, err = port.GetOne(timeout)
270+
if err != unix.EINTR {
271+
break
272+
}
273+
}
236274
if err != nil {
237275
fmt.Printf("didn't get the expected event: %v\n", err)
238276
}
@@ -278,7 +316,7 @@ func TestPortEventSlices(t *testing.T) {
278316
timeout := new(unix.Timespec)
279317
timeout.Nsec = 1
280318
events := make([]unix.PortEvent, 4)
281-
n, err = port.Get(events, 3, timeout)
319+
n, err = getRetry(t, port, events, 3, timeout)
282320
if err != nil {
283321
t.Errorf("Get failed: %v", err)
284322
}
@@ -291,7 +329,7 @@ func TestPortEventSlices(t *testing.T) {
291329
t.Errorf("unexpected event. got %v, expected %v", p.Events, unix.FILE_DELETE)
292330
}
293331
}
294-
n, err = port.Get(events, 3, timeout)
332+
n, err = getRetry(t, port, events, 3, timeout)
295333
if err != unix.ETIME {
296334
t.Errorf("unexpected error. got %v, expected %v", err, unix.ETIME)
297335
}
@@ -314,7 +352,7 @@ func TestPortEventSlices(t *testing.T) {
314352
bs := []byte{41}
315353
w.Write(bs)
316354

317-
n, err = port.Get(events, 1, timeout)
355+
n, err = getRetry(t, port, events, 1, timeout)
318356
if err != nil {
319357
t.Errorf("Get failed: %v", err)
320358
}

0 commit comments

Comments
 (0)