Skip to content

Commit 9999f25

Browse files
committed
test(usb): synchronize ISO generation rejection fixture
1 parent ba9d6a7 commit 9999f25

1 file changed

Lines changed: 32 additions & 8 deletions

File tree

internal/server/usb/endpoint_scheduler_test.go

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ type schedulerTestDevice struct {
2828

2929
type generationSchedulerTestDevice struct {
3030
*schedulerTestDevice
31-
generation atomic.Uint64
32-
rejected atomic.Uint64
31+
generation atomic.Uint64
32+
rejected atomic.Uint64
33+
rejectedWake chan struct{}
3334
}
3435

3536
type fakeEndpointClock struct {
@@ -397,6 +398,12 @@ func (d *generationSchedulerTestDevice) HandleIsoOutTransfer(
397398
) bool {
398399
if generation != d.generation.Load() {
399400
d.rejected.Add(1)
401+
if d.rejectedWake != nil {
402+
select {
403+
case d.rejectedWake <- struct{}{}:
404+
default:
405+
}
406+
}
400407
return false
401408
}
402409
d.HandleTransfer(context.Background(), 1, usbip.DirOut, payload)
@@ -1157,13 +1164,16 @@ func TestIsoOutUnlinkReleasesLaterJobAndResetInvalidatesGeneration(t *testing.T)
11571164

11581165
func TestIsoOutDeviceGenerationRejectsResetRace(t *testing.T) {
11591166
base := &schedulerTestDevice{desc: testCompositeDescriptor()}
1160-
device := &generationSchedulerTestDevice{schedulerTestDevice: base}
1167+
device := &generationSchedulerTestDevice{
1168+
schedulerTestDevice: base, rejectedWake: make(chan struct{}, 1),
1169+
}
11611170
device.generation.Store(1)
1171+
clock := newFakeEndpointClock(time.Unix(250, 0))
11621172
recorder := newRecordingWriter()
11631173
ctx, cancel := context.WithCancel(context.Background())
1164-
worker := newEndpointWorker(
1174+
worker := newEndpointWorkerWithClock(
11651175
ctx, device, 1, usbip.DirOut, isoOutWorker, time.Millisecond,
1166-
192, newResponseWriter(recorder, nil), func(error) {},
1176+
192, newResponseWriter(recorder, nil), func(error) {}, clock,
11671177
)
11681178
defer func() {
11691179
cancel()
@@ -1172,21 +1182,35 @@ func TestIsoOutDeviceGenerationRejectsResetRace(t *testing.T) {
11721182
}()
11731183

11741184
packets := []usbip.IsoPacketDescriptor{{Length: 1}}
1185+
firstService := clock.Now().Add(4 * time.Millisecond)
11751186
require.True(t, worker.enqueueWithGeneration(
1176-
501, 1, []byte{0x51}, packets, time.Now().Add(4*time.Millisecond), 1,
1187+
501, 1, []byte{0x51}, packets, firstService, 1,
11771188
))
1189+
clock.waitForDeadline(t, firstService)
11781190
device.generation.Store(2) // Device reset wins the service-boundary race.
1179-
time.Sleep(10 * time.Millisecond)
1191+
clock.advance(4 * time.Millisecond)
1192+
// A wall-clock sleep cannot establish that the worker has run. Observe its
1193+
// actual rejection, while the fake clock makes reset-before-service exact.
1194+
select {
1195+
case <-device.rejectedWake:
1196+
case <-time.After(2 * time.Second):
1197+
t.Fatal("timed out waiting for old-generation ISO rejection")
1198+
}
11801199
recorder.mu.Lock()
11811200
require.Empty(t, recorder.writes)
11821201
recorder.mu.Unlock()
11831202
require.Equal(t, uint64(1), device.rejected.Load())
11841203

11851204
require.True(t, worker.enqueueWithGeneration(
1186-
502, 1, []byte{0x52}, packets, time.Now(), 2,
1205+
502, 1, []byte{0x52}, packets, clock.Now(), 2,
11871206
))
1207+
clock.waitForDeadline(t, clock.Now().Add(time.Millisecond))
1208+
clock.advance(time.Millisecond)
1209+
clock.waitForDeadline(t, clock.Now().Add(time.Millisecond))
1210+
clock.advance(time.Millisecond)
11881211
writes := recorder.waitForWrites(t, 1)
11891212
require.Equal(t, uint32(502), binary.BigEndian.Uint32(writes[0].packet[4:8]))
1213+
require.Equal(t, uint64(1), device.rejected.Load())
11901214
base.mu.Lock()
11911215
require.Equal(t, [][]byte{{0x52}}, base.isoOutPayloads)
11921216
base.mu.Unlock()

0 commit comments

Comments
 (0)