github.com/MerlinKodo/quic-go@v0.39.2/datagram_queue_test.go (about)

     1  package quic
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  
     7  	"github.com/MerlinKodo/quic-go/internal/utils"
     8  	"github.com/MerlinKodo/quic-go/internal/wire"
     9  
    10  	. "github.com/onsi/ginkgo/v2"
    11  	. "github.com/onsi/gomega"
    12  )
    13  
    14  var _ = Describe("Datagram Queue", func() {
    15  	var queue *datagramQueue
    16  	var queued chan struct{}
    17  
    18  	BeforeEach(func() {
    19  		queued = make(chan struct{}, 100)
    20  		queue = newDatagramQueue(func() { queued <- struct{}{} }, utils.DefaultLogger)
    21  	})
    22  
    23  	Context("sending", func() {
    24  		It("returns nil when there's no datagram to send", func() {
    25  			Expect(queue.Peek()).To(BeNil())
    26  		})
    27  
    28  		It("queues a datagram", func() {
    29  			done := make(chan struct{})
    30  			frame := &wire.DatagramFrame{Data: []byte("foobar")}
    31  			go func() {
    32  				defer GinkgoRecover()
    33  				defer close(done)
    34  				Expect(queue.AddAndWait(frame)).To(Succeed())
    35  			}()
    36  
    37  			Eventually(queued).Should(HaveLen(1))
    38  			Consistently(done).ShouldNot(BeClosed())
    39  			f := queue.Peek()
    40  			Expect(f.Data).To(Equal([]byte("foobar")))
    41  			Eventually(done).Should(BeClosed())
    42  			queue.Pop()
    43  			Expect(queue.Peek()).To(BeNil())
    44  		})
    45  
    46  		It("returns the same datagram multiple times, when Pop isn't called", func() {
    47  			sent := make(chan struct{}, 1)
    48  			go func() {
    49  				defer GinkgoRecover()
    50  				Expect(queue.AddAndWait(&wire.DatagramFrame{Data: []byte("foo")})).To(Succeed())
    51  				sent <- struct{}{}
    52  				Expect(queue.AddAndWait(&wire.DatagramFrame{Data: []byte("bar")})).To(Succeed())
    53  				sent <- struct{}{}
    54  			}()
    55  
    56  			Eventually(queued).Should(HaveLen(1))
    57  			f := queue.Peek()
    58  			Expect(f.Data).To(Equal([]byte("foo")))
    59  			Eventually(sent).Should(Receive())
    60  			Expect(queue.Peek()).To(Equal(f))
    61  			Expect(queue.Peek()).To(Equal(f))
    62  			queue.Pop()
    63  			Eventually(func() *wire.DatagramFrame { f = queue.Peek(); return f }).ShouldNot(BeNil())
    64  			f = queue.Peek()
    65  			Expect(f.Data).To(Equal([]byte("bar")))
    66  		})
    67  
    68  		It("closes", func() {
    69  			errChan := make(chan error, 1)
    70  			go func() {
    71  				defer GinkgoRecover()
    72  				errChan <- queue.AddAndWait(&wire.DatagramFrame{Data: []byte("foobar")})
    73  			}()
    74  
    75  			Consistently(errChan).ShouldNot(Receive())
    76  			queue.CloseWithError(errors.New("test error"))
    77  			Eventually(errChan).Should(Receive(MatchError("test error")))
    78  		})
    79  	})
    80  
    81  	Context("receiving", func() {
    82  		It("receives DATAGRAM frames", func() {
    83  			queue.HandleDatagramFrame(&wire.DatagramFrame{Data: []byte("foo")})
    84  			queue.HandleDatagramFrame(&wire.DatagramFrame{Data: []byte("bar")})
    85  			data, err := queue.Receive(context.Background())
    86  			Expect(err).ToNot(HaveOccurred())
    87  			Expect(data).To(Equal([]byte("foo")))
    88  			data, err = queue.Receive(context.Background())
    89  			Expect(err).ToNot(HaveOccurred())
    90  			Expect(data).To(Equal([]byte("bar")))
    91  		})
    92  
    93  		It("blocks until a frame is received", func() {
    94  			c := make(chan []byte, 1)
    95  			go func() {
    96  				defer GinkgoRecover()
    97  				data, err := queue.Receive(context.Background())
    98  				Expect(err).ToNot(HaveOccurred())
    99  				c <- data
   100  			}()
   101  
   102  			Consistently(c).ShouldNot(Receive())
   103  			queue.HandleDatagramFrame(&wire.DatagramFrame{Data: []byte("foobar")})
   104  			Eventually(c).Should(Receive(Equal([]byte("foobar"))))
   105  		})
   106  
   107  		It("blocks until context is done", func() {
   108  			ctx, cancel := context.WithCancel(context.Background())
   109  			errChan := make(chan error)
   110  			go func() {
   111  				defer GinkgoRecover()
   112  				_, err := queue.Receive(ctx)
   113  				errChan <- err
   114  			}()
   115  
   116  			Consistently(errChan).ShouldNot(Receive())
   117  			cancel()
   118  			Eventually(errChan).Should(Receive(Equal(context.Canceled)))
   119  		})
   120  
   121  		It("closes", func() {
   122  			errChan := make(chan error, 1)
   123  			go func() {
   124  				defer GinkgoRecover()
   125  				_, err := queue.Receive(context.Background())
   126  				errChan <- err
   127  			}()
   128  
   129  			Consistently(errChan).ShouldNot(Receive())
   130  			queue.CloseWithError(errors.New("test error"))
   131  			Eventually(errChan).Should(Receive(MatchError("test error")))
   132  		})
   133  	})
   134  })