github.com/tumi8/quic-go@v0.37.4-tum/integrationtests/self/drop_test.go (about) 1 package self_test 2 3 import ( 4 "context" 5 "fmt" 6 "math/rand" 7 "net" 8 "sync/atomic" 9 "time" 10 11 "github.com/tumi8/quic-go" 12 quicproxy "github.com/tumi8/quic-go/integrationtests/tools/proxy" 13 14 . "github.com/onsi/ginkgo/v2" 15 . "github.com/onsi/gomega" 16 ) 17 18 func randomDuration(min, max time.Duration) time.Duration { 19 return min + time.Duration(rand.Int63n(int64(max-min))) 20 } 21 22 var _ = Describe("Drop Tests", func() { 23 var ( 24 proxy *quicproxy.QuicProxy 25 ln *quic.Listener 26 ) 27 28 startListenerAndProxy := func(dropCallback quicproxy.DropCallback) { 29 var err error 30 ln, err = quic.ListenAddr( 31 "localhost:0", 32 getTLSConfig(), 33 getQuicConfig(nil), 34 ) 35 Expect(err).ToNot(HaveOccurred()) 36 serverPort := ln.Addr().(*net.UDPAddr).Port 37 proxy, err = quicproxy.NewQuicProxy("localhost:0", &quicproxy.Opts{ 38 RemoteAddr: fmt.Sprintf("localhost:%d", serverPort), 39 DelayPacket: func(dir quicproxy.Direction, _ []byte) time.Duration { 40 return 5 * time.Millisecond // 10ms RTT 41 }, 42 DropPacket: dropCallback, 43 }, 44 ) 45 Expect(err).ToNot(HaveOccurred()) 46 } 47 48 AfterEach(func() { 49 Expect(proxy.Close()).To(Succeed()) 50 Expect(ln.Close()).To(Succeed()) 51 }) 52 53 for _, d := range directions { 54 direction := d 55 56 // The purpose of this test is to create a lot of tails, by sending 1 byte messages. 57 // The interval, the length of the drop period, and the time when the drop period starts are randomized. 58 // To cover different scenarios, repeat this test a few times. 59 for rep := 0; rep < 3; rep++ { 60 It(fmt.Sprintf("sends short messages, dropping packets in %s direction", direction), func() { 61 const numMessages = 15 62 63 messageInterval := randomDuration(10*time.Millisecond, 100*time.Millisecond) 64 dropDuration := randomDuration(messageInterval*3/2, 2*time.Second) 65 dropDelay := randomDuration(25*time.Millisecond, numMessages*messageInterval/2) // makes sure we don't interfere with the handshake 66 fmt.Fprintf(GinkgoWriter, "Sending a message every %s, %d times.\n", messageInterval, numMessages) 67 fmt.Fprintf(GinkgoWriter, "Dropping packets for %s, after a delay of %s\n", dropDuration, dropDelay) 68 startTime := time.Now() 69 70 var numDroppedPackets int32 71 startListenerAndProxy(func(d quicproxy.Direction, _ []byte) bool { 72 if !d.Is(direction) { 73 return false 74 } 75 drop := time.Now().After(startTime.Add(dropDelay)) && time.Now().Before(startTime.Add(dropDelay).Add(dropDuration)) 76 if drop { 77 atomic.AddInt32(&numDroppedPackets, 1) 78 } 79 return drop 80 }) 81 82 done := make(chan struct{}) 83 go func() { 84 defer GinkgoRecover() 85 conn, err := ln.Accept(context.Background()) 86 Expect(err).ToNot(HaveOccurred()) 87 str, err := conn.OpenStream() 88 Expect(err).ToNot(HaveOccurred()) 89 for i := uint8(1); i <= numMessages; i++ { 90 n, err := str.Write([]byte{i}) 91 Expect(err).ToNot(HaveOccurred()) 92 Expect(n).To(Equal(1)) 93 time.Sleep(messageInterval) 94 } 95 <-done 96 Expect(conn.CloseWithError(0, "")).To(Succeed()) 97 }() 98 99 conn, err := quic.DialAddr( 100 context.Background(), 101 fmt.Sprintf("localhost:%d", proxy.LocalPort()), 102 getTLSClientConfig(), 103 getQuicConfig(nil), 104 ) 105 Expect(err).ToNot(HaveOccurred()) 106 defer conn.CloseWithError(0, "") 107 str, err := conn.AcceptStream(context.Background()) 108 Expect(err).ToNot(HaveOccurred()) 109 for i := uint8(1); i <= numMessages; i++ { 110 b := []byte{0} 111 n, err := str.Read(b) 112 Expect(err).ToNot(HaveOccurred()) 113 Expect(n).To(Equal(1)) 114 Expect(b[0]).To(Equal(i)) 115 } 116 close(done) 117 numDropped := atomic.LoadInt32(&numDroppedPackets) 118 fmt.Fprintf(GinkgoWriter, "Dropped %d packets.\n", numDropped) 119 Expect(numDropped).To(BeNumerically(">", 0)) 120 }) 121 } 122 } 123 })