forked from quic-go/quic-go
use synctest to make the send queue tests fully deterministic (#5302)
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/quic-go/quic-go/internal/protocol"
|
"github.com/quic-go/quic-go/internal/protocol"
|
||||||
|
"github.com/quic-go/quic-go/internal/synctest"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@@ -20,6 +21,7 @@ func getPacketWithContents(b []byte) *packetBuffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSendQueueSendOnePacket(t *testing.T) {
|
func TestSendQueueSendOnePacket(t *testing.T) {
|
||||||
|
synctest.Test(t, func(t *testing.T) {
|
||||||
mockCtrl := gomock.NewController(t)
|
mockCtrl := gomock.NewController(t)
|
||||||
c := NewMockSendConn(mockCtrl)
|
c := NewMockSendConn(mockCtrl)
|
||||||
q := newSendQueue(c)
|
q := newSendQueue(c)
|
||||||
@@ -36,22 +38,27 @@ func TestSendQueueSendOnePacket(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
q.Send(getPacketWithContents([]byte("foobar")), 10, protocol.ECT1)
|
q.Send(getPacketWithContents([]byte("foobar")), 10, protocol.ECT1)
|
||||||
|
synctest.Wait()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-written:
|
case <-written:
|
||||||
case <-time.After(time.Second):
|
default:
|
||||||
t.Fatal("timeout")
|
t.Fatal("write should have returned")
|
||||||
}
|
}
|
||||||
|
|
||||||
q.Close()
|
q.Close()
|
||||||
|
synctest.Wait()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-done:
|
case <-done:
|
||||||
case <-time.After(time.Second):
|
default:
|
||||||
t.Fatal("timeout")
|
t.Fatal("Run should have returned")
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendQueueBlocking(t *testing.T) {
|
func TestSendQueueBlocking(t *testing.T) {
|
||||||
|
synctest.Test(t, func(t *testing.T) {
|
||||||
mockCtrl := gomock.NewController(t)
|
mockCtrl := gomock.NewController(t)
|
||||||
c := NewMockSendConn(mockCtrl)
|
c := NewMockSendConn(mockCtrl)
|
||||||
q := newSendQueue(c)
|
q := newSendQueue(c)
|
||||||
@@ -76,7 +83,7 @@ func TestSendQueueBlocking(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// +1, since one packet will be queued in the Write call
|
// +1, since one packet will be queued in the Write call
|
||||||
for i := 0; i < sendQueueCapacity+1; i++ {
|
for i := range sendQueueCapacity + 1 {
|
||||||
require.False(t, q.WouldBlock())
|
require.False(t, q.WouldBlock())
|
||||||
q.Send(getPacketWithContents([]byte("foobar")), 10, protocol.ECT1)
|
q.Send(getPacketWithContents([]byte("foobar")), 10, protocol.ECT1)
|
||||||
// make sure that the first packet is actually enqueued in the Write call
|
// make sure that the first packet is actually enqueued in the Write call
|
||||||
@@ -117,28 +124,34 @@ func TestSendQueueBlocking(t *testing.T) {
|
|||||||
close(closed)
|
close(closed)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
synctest.Wait()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-closed:
|
case <-closed:
|
||||||
t.Fatal("Close should have blocked")
|
t.Fatal("Close should have blocked")
|
||||||
case <-time.After(scaleDuration(10 * time.Millisecond)):
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < sendQueueCapacity; i++ {
|
for range sendQueueCapacity {
|
||||||
blockWrite <- struct{}{}
|
blockWrite <- struct{}{}
|
||||||
}
|
}
|
||||||
|
synctest.Wait()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-closed:
|
case <-closed:
|
||||||
case <-time.After(time.Second):
|
default:
|
||||||
t.Fatal("timeout")
|
t.Fatal("Close should have returned")
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case <-done:
|
case <-done:
|
||||||
case <-time.After(time.Second):
|
default:
|
||||||
t.Fatal("timeout")
|
t.Fatal("Run should have returned")
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendQueueWriteError(t *testing.T) {
|
func TestSendQueueWriteError(t *testing.T) {
|
||||||
|
synctest.Test(t, func(t *testing.T) {
|
||||||
mockCtrl := gomock.NewController(t)
|
mockCtrl := gomock.NewController(t)
|
||||||
c := NewMockSendConn(mockCtrl)
|
c := NewMockSendConn(mockCtrl)
|
||||||
q := newSendQueue(c)
|
q := newSendQueue(c)
|
||||||
@@ -149,27 +162,32 @@ func TestSendQueueWriteError(t *testing.T) {
|
|||||||
errChan := make(chan error, 1)
|
errChan := make(chan error, 1)
|
||||||
go func() { errChan <- q.Run() }()
|
go func() { errChan <- q.Run() }()
|
||||||
|
|
||||||
|
synctest.Wait()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case err := <-errChan:
|
case err := <-errChan:
|
||||||
require.ErrorIs(t, err, assert.AnError)
|
require.ErrorIs(t, err, assert.AnError)
|
||||||
case <-time.After(time.Second):
|
default:
|
||||||
t.Fatal("timeout")
|
t.Fatal("Run should have returned")
|
||||||
}
|
}
|
||||||
|
|
||||||
// further calls to Send should not block
|
// further calls to Send should not block
|
||||||
sent := make(chan struct{})
|
sent := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
defer close(sent)
|
defer close(sent)
|
||||||
for i := 0; i < 2*sendQueueCapacity; i++ {
|
for range 2 * sendQueueCapacity {
|
||||||
q.Send(getPacketWithContents([]byte("raboof")), 6, protocol.ECNNon)
|
q.Send(getPacketWithContents([]byte("raboof")), 6, protocol.ECNNon)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
synctest.Wait()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-sent:
|
case <-sent:
|
||||||
case <-time.After(time.Second):
|
default:
|
||||||
t.Fatal("timeout")
|
t.Fatal("Send should have returned")
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendQueueSendProbe(t *testing.T) {
|
func TestSendQueueSendProbe(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user