http3: migrate the datagram tests away from Ginkgo (#5076)

This commit is contained in:
Marten Seemann
2025-04-24 14:23:56 +08:00
committed by GitHub
parent d678f9a86c
commit 7437cff1e0

View File

@@ -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)
}