github.com/MerlinKodo/quic-go@v0.39.2/integrationtests/self/packetization_test.go (about)

     1  package self_test
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"net"
     7  	"time"
     8  
     9  	"github.com/MerlinKodo/quic-go"
    10  	quicproxy "github.com/MerlinKodo/quic-go/integrationtests/tools/proxy"
    11  	"github.com/MerlinKodo/quic-go/logging"
    12  
    13  	. "github.com/onsi/ginkgo/v2"
    14  	. "github.com/onsi/gomega"
    15  )
    16  
    17  var _ = Describe("Packetization", func() {
    18  	// In this test, the client sends 100 small messages. The server echoes these messages.
    19  	// This means that every endpoint will send 100 ack-eliciting packets in short succession.
    20  	// This test then tests that no more than 110 packets are sent in every direction, making sure that ACK are bundled.
    21  	It("bundles ACKs", func() {
    22  		const numMsg = 100
    23  
    24  		serverCounter, serverTracer := newPacketTracer()
    25  		server, err := quic.ListenAddr(
    26  			"localhost:0",
    27  			getTLSConfig(),
    28  			getQuicConfig(&quic.Config{
    29  				DisablePathMTUDiscovery: true,
    30  				Tracer:                  newTracer(serverTracer),
    31  			}),
    32  		)
    33  		Expect(err).ToNot(HaveOccurred())
    34  		defer server.Close()
    35  		serverAddr := fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port)
    36  
    37  		proxy, err := quicproxy.NewQuicProxy("localhost:0", &quicproxy.Opts{
    38  			RemoteAddr: serverAddr,
    39  			DelayPacket: func(dir quicproxy.Direction, _ []byte) time.Duration {
    40  				return 5 * time.Millisecond
    41  			},
    42  		})
    43  		Expect(err).ToNot(HaveOccurred())
    44  		defer proxy.Close()
    45  
    46  		clientCounter, clientTracer := newPacketTracer()
    47  		conn, err := quic.DialAddr(
    48  			context.Background(),
    49  			fmt.Sprintf("localhost:%d", proxy.LocalPort()),
    50  			getTLSClientConfig(),
    51  			getQuicConfig(&quic.Config{
    52  				DisablePathMTUDiscovery: true,
    53  				Tracer:                  newTracer(clientTracer),
    54  			}),
    55  		)
    56  		Expect(err).ToNot(HaveOccurred())
    57  		defer conn.CloseWithError(0, "")
    58  
    59  		go func() {
    60  			defer GinkgoRecover()
    61  			conn, err := server.Accept(context.Background())
    62  			Expect(err).ToNot(HaveOccurred())
    63  			str, err := conn.AcceptStream(context.Background())
    64  			Expect(err).ToNot(HaveOccurred())
    65  			b := make([]byte, 1)
    66  			// Echo every byte received from the client.
    67  			for {
    68  				if _, err := str.Read(b); err != nil {
    69  					break
    70  				}
    71  				_, err = str.Write(b)
    72  				Expect(err).ToNot(HaveOccurred())
    73  			}
    74  		}()
    75  
    76  		str, err := conn.OpenStreamSync(context.Background())
    77  		Expect(err).ToNot(HaveOccurred())
    78  		b := make([]byte, 1)
    79  		// Send numMsg 1-byte messages.
    80  		for i := 0; i < numMsg; i++ {
    81  			_, err = str.Write([]byte{uint8(i)})
    82  			Expect(err).ToNot(HaveOccurred())
    83  			_, err = str.Read(b)
    84  			Expect(err).ToNot(HaveOccurred())
    85  			Expect(b[0]).To(Equal(uint8(i)))
    86  		}
    87  		Expect(conn.CloseWithError(0, "")).To(Succeed())
    88  
    89  		countBundledPackets := func(packets []shortHeaderPacket) (numBundled int) {
    90  			for _, p := range packets {
    91  				var hasAck, hasStreamFrame bool
    92  				for _, f := range p.frames {
    93  					switch f.(type) {
    94  					case *logging.AckFrame:
    95  						hasAck = true
    96  					case *logging.StreamFrame:
    97  						hasStreamFrame = true
    98  					}
    99  				}
   100  				if hasAck && hasStreamFrame {
   101  					numBundled++
   102  				}
   103  			}
   104  			return
   105  		}
   106  
   107  		numBundledIncoming := countBundledPackets(clientCounter.getRcvdShortHeaderPackets())
   108  		numBundledOutgoing := countBundledPackets(serverCounter.getRcvdShortHeaderPackets())
   109  		fmt.Fprintf(GinkgoWriter, "bundled incoming packets: %d / %d\n", numBundledIncoming, numMsg)
   110  		fmt.Fprintf(GinkgoWriter, "bundled outgoing packets: %d / %d\n", numBundledOutgoing, numMsg)
   111  		Expect(numBundledIncoming).To(And(
   112  			BeNumerically("<=", numMsg),
   113  			BeNumerically(">", numMsg*9/10),
   114  		))
   115  		Expect(numBundledOutgoing).To(And(
   116  			BeNumerically("<=", numMsg),
   117  			BeNumerically(">", numMsg*9/10),
   118  		))
   119  	})
   120  })