forked from quic-go/quic-go
http3: migrate the datagram tests away from Ginkgo (#5076)
This commit is contained in:
@@ -2,75 +2,105 @@ package http3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var _ = Describe("Datagrams", func() {
|
||||
It("receives a datagram", func() {
|
||||
dg := newDatagrammer(nil)
|
||||
dg.enqueue([]byte("foobar"))
|
||||
func TestDatagramReceiving(t *testing.T) {
|
||||
dg := newDatagrammer(nil)
|
||||
|
||||
type result struct {
|
||||
data []byte
|
||||
err error
|
||||
}
|
||||
|
||||
// Receive blocks until a datagram is received
|
||||
resultChan := make(chan result)
|
||||
go func() {
|
||||
defer close(resultChan)
|
||||
data, err := dg.Receive(context.Background())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(data).To(Equal([]byte("foobar")))
|
||||
})
|
||||
resultChan <- result{data: data, err: err}
|
||||
}()
|
||||
|
||||
It("queues up to 32 datagrams", func() {
|
||||
dg := newDatagrammer(nil)
|
||||
for i := 0; i < streamDatagramQueueLen+1; i++ {
|
||||
dg.enqueue([]byte{uint8(i)})
|
||||
}
|
||||
for i := 0; i < streamDatagramQueueLen; i++ {
|
||||
data, err := dg.Receive(context.Background())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(data[0]).To(BeEquivalentTo(i))
|
||||
}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
_, err := dg.Receive(ctx)
|
||||
Expect(err).To(MatchError(context.Canceled))
|
||||
})
|
||||
select {
|
||||
case <-time.After(scaleDuration(10 * time.Millisecond)):
|
||||
case <-resultChan:
|
||||
t.Fatal("should not have received a datagram")
|
||||
}
|
||||
dg.enqueue([]byte("foobar"))
|
||||
|
||||
It("blocks until a new datagram is received", func() {
|
||||
dg := newDatagrammer(nil)
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
defer close(done)
|
||||
data, err := dg.Receive(context.Background())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(data).To(Equal([]byte("foobar")))
|
||||
}()
|
||||
select {
|
||||
case res := <-resultChan:
|
||||
require.NoError(t, res.err)
|
||||
require.Equal(t, []byte("foobar"), res.data)
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("should have received a datagram")
|
||||
}
|
||||
|
||||
Consistently(done, 50*time.Millisecond).ShouldNot(BeClosed())
|
||||
dg.enqueue([]byte("foobar"))
|
||||
Eventually(done).Should(BeClosed())
|
||||
})
|
||||
|
||||
It("drops datagrams when the stream's receive side is closed", func() {
|
||||
dg := newDatagrammer(nil)
|
||||
dg.enqueue([]byte("foo"))
|
||||
testErr := errors.New("test error")
|
||||
dg.SetReceiveError(testErr)
|
||||
dg.enqueue([]byte("bar"))
|
||||
// up to 32 datagrams can be queued
|
||||
for i := range streamDatagramQueueLen + 1 {
|
||||
dg.enqueue([]byte{uint8(i)})
|
||||
}
|
||||
for i := range streamDatagramQueueLen {
|
||||
data, err := dg.Receive(context.Background())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(data).To(Equal([]byte("foo")))
|
||||
_, err = dg.Receive(context.Background())
|
||||
Expect(err).To(MatchError(testErr))
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []byte{uint8(i)}, data)
|
||||
}
|
||||
|
||||
It("sends datagrams", func() {
|
||||
var sent []byte
|
||||
testErr := errors.New("test error")
|
||||
dg := newDatagrammer(func(b []byte) error {
|
||||
sent = b
|
||||
return testErr
|
||||
})
|
||||
Expect(dg.Send([]byte("foobar"))).To(MatchError(testErr))
|
||||
Expect(sent).To(Equal([]byte("foobar")))
|
||||
// Receive respects the context
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
_, err := dg.Receive(ctx)
|
||||
require.ErrorIs(t, err, context.Canceled)
|
||||
}
|
||||
|
||||
func TestDatagramReceiveError(t *testing.T) {
|
||||
dg := newDatagrammer(nil)
|
||||
|
||||
errChan := make(chan error)
|
||||
go func() {
|
||||
_, err := dg.Receive(context.Background())
|
||||
errChan <- err
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-time.After(scaleDuration(10 * time.Millisecond)):
|
||||
case err := <-errChan:
|
||||
t.Fatalf("should not have received an error: %v", err)
|
||||
}
|
||||
|
||||
dg.SetReceiveError(assert.AnError)
|
||||
select {
|
||||
case err := <-errChan:
|
||||
require.ErrorIs(t, err, assert.AnError)
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("timeout")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||
defer cancel()
|
||||
_, err := dg.Receive(ctx)
|
||||
require.ErrorIs(t, err, assert.AnError)
|
||||
}
|
||||
|
||||
func TestDatagramSending(t *testing.T) {
|
||||
var sendQueue [][]byte
|
||||
errors := []error{nil, nil, assert.AnError}
|
||||
dg := newDatagrammer(func(b []byte) error {
|
||||
sendQueue = append(sendQueue, b)
|
||||
err := errors[0]
|
||||
errors = errors[1:]
|
||||
return err
|
||||
})
|
||||
})
|
||||
require.NoError(t, dg.Send([]byte("foo")))
|
||||
require.NoError(t, dg.Send([]byte("bar")))
|
||||
require.ErrorIs(t, dg.Send([]byte("baz")), assert.AnError)
|
||||
require.Equal(t, [][]byte{[]byte("foo"), []byte("bar"), []byte("baz")}, sendQueue)
|
||||
|
||||
dg.SetSendError(net.ErrClosed)
|
||||
require.ErrorIs(t, dg.Send([]byte("foobar")), net.ErrClosed)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user