github.com/quic-go/quic-go@v0.44.0/config_test.go (about) 1 package quic 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "reflect" 8 "time" 9 10 "github.com/quic-go/quic-go/internal/protocol" 11 "github.com/quic-go/quic-go/logging" 12 "github.com/quic-go/quic-go/quicvarint" 13 14 . "github.com/onsi/ginkgo/v2" 15 . "github.com/onsi/gomega" 16 ) 17 18 var _ = Describe("Config", func() { 19 Context("validating", func() { 20 It("validates a nil config", func() { 21 Expect(validateConfig(nil)).To(Succeed()) 22 }) 23 24 It("validates a config with normal values", func() { 25 conf := populateConfig(&Config{ 26 MaxIncomingStreams: 5, 27 MaxStreamReceiveWindow: 10, 28 }) 29 Expect(validateConfig(conf)).To(Succeed()) 30 Expect(conf.MaxIncomingStreams).To(BeEquivalentTo(5)) 31 Expect(conf.MaxStreamReceiveWindow).To(BeEquivalentTo(10)) 32 }) 33 34 It("clips too large values for the stream limits", func() { 35 conf := &Config{ 36 MaxIncomingStreams: 1<<60 + 1, 37 MaxIncomingUniStreams: 1<<60 + 2, 38 } 39 Expect(validateConfig(conf)).To(Succeed()) 40 Expect(conf.MaxIncomingStreams).To(BeEquivalentTo(int64(1 << 60))) 41 Expect(conf.MaxIncomingUniStreams).To(BeEquivalentTo(int64(1 << 60))) 42 }) 43 44 It("clips too large values for the flow control windows", func() { 45 conf := &Config{ 46 MaxStreamReceiveWindow: quicvarint.Max + 1, 47 MaxConnectionReceiveWindow: quicvarint.Max + 2, 48 } 49 Expect(validateConfig(conf)).To(Succeed()) 50 Expect(conf.MaxStreamReceiveWindow).To(BeEquivalentTo(uint64(quicvarint.Max))) 51 Expect(conf.MaxConnectionReceiveWindow).To(BeEquivalentTo(uint64(quicvarint.Max))) 52 }) 53 54 It("increases too small packet sizes", func() { 55 conf := &Config{InitialPacketSize: 10} 56 Expect(validateConfig(conf)).To(Succeed()) 57 Expect(conf.InitialPacketSize).To(BeEquivalentTo(1200)) 58 }) 59 60 It("clips too large packet sizes", func() { 61 conf := &Config{InitialPacketSize: protocol.MaxPacketBufferSize + 1} 62 Expect(validateConfig(conf)).To(Succeed()) 63 Expect(conf.InitialPacketSize).To(BeEquivalentTo(protocol.MaxPacketBufferSize)) 64 }) 65 66 It("doesn't modify the InitialPacketSize if it is unset", func() { 67 conf := &Config{InitialPacketSize: 0} 68 Expect(validateConfig(conf)).To(Succeed()) 69 Expect(conf.InitialPacketSize).To(BeZero()) 70 }) 71 }) 72 73 configWithNonZeroNonFunctionFields := func() *Config { 74 c := &Config{} 75 v := reflect.ValueOf(c).Elem() 76 77 typ := v.Type() 78 for i := 0; i < typ.NumField(); i++ { 79 f := v.Field(i) 80 if !f.CanSet() { 81 // unexported field; not cloned. 82 continue 83 } 84 85 switch fn := typ.Field(i).Name; fn { 86 case "GetConfigForClient", "RequireAddressValidation", "GetLogWriter", "AllowConnectionWindowIncrease", "Tracer": 87 // Can't compare functions. 88 case "Versions": 89 f.Set(reflect.ValueOf([]Version{1, 2, 3})) 90 case "ConnectionIDLength": 91 f.Set(reflect.ValueOf(8)) 92 case "ConnectionIDGenerator": 93 f.Set(reflect.ValueOf(&protocol.DefaultConnectionIDGenerator{ConnLen: protocol.DefaultConnectionIDLength})) 94 case "HandshakeIdleTimeout": 95 f.Set(reflect.ValueOf(time.Second)) 96 case "MaxIdleTimeout": 97 f.Set(reflect.ValueOf(time.Hour)) 98 case "TokenStore": 99 f.Set(reflect.ValueOf(NewLRUTokenStore(2, 3))) 100 case "InitialStreamReceiveWindow": 101 f.Set(reflect.ValueOf(uint64(1234))) 102 case "MaxStreamReceiveWindow": 103 f.Set(reflect.ValueOf(uint64(9))) 104 case "InitialConnectionReceiveWindow": 105 f.Set(reflect.ValueOf(uint64(4321))) 106 case "MaxConnectionReceiveWindow": 107 f.Set(reflect.ValueOf(uint64(10))) 108 case "MaxIncomingStreams": 109 f.Set(reflect.ValueOf(int64(11))) 110 case "MaxIncomingUniStreams": 111 f.Set(reflect.ValueOf(int64(12))) 112 case "StatelessResetKey": 113 f.Set(reflect.ValueOf(&StatelessResetKey{1, 2, 3, 4})) 114 case "KeepAlivePeriod": 115 f.Set(reflect.ValueOf(time.Second)) 116 case "EnableDatagrams": 117 f.Set(reflect.ValueOf(true)) 118 case "DisableVersionNegotiationPackets": 119 f.Set(reflect.ValueOf(true)) 120 case "InitialPacketSize": 121 f.Set(reflect.ValueOf(uint16(1350))) 122 case "DisablePathMTUDiscovery": 123 f.Set(reflect.ValueOf(true)) 124 case "Allow0RTT": 125 f.Set(reflect.ValueOf(true)) 126 default: 127 Fail(fmt.Sprintf("all fields must be accounted for, but saw unknown field %q", fn)) 128 } 129 } 130 return c 131 } 132 133 It("uses twice the handshake idle timeouts for the handshake timeout", func() { 134 c := &Config{HandshakeIdleTimeout: time.Second * 11 / 2} 135 Expect(c.handshakeTimeout()).To(Equal(11 * time.Second)) 136 }) 137 138 Context("cloning", func() { 139 It("clones function fields", func() { 140 var calledAllowConnectionWindowIncrease, calledTracer bool 141 c1 := &Config{ 142 GetConfigForClient: func(info *ClientHelloInfo) (*Config, error) { return nil, errors.New("nope") }, 143 AllowConnectionWindowIncrease: func(Connection, uint64) bool { calledAllowConnectionWindowIncrease = true; return true }, 144 Tracer: func(context.Context, logging.Perspective, ConnectionID) *logging.ConnectionTracer { 145 calledTracer = true 146 return nil 147 }, 148 } 149 c2 := c1.Clone() 150 c2.AllowConnectionWindowIncrease(nil, 1234) 151 Expect(calledAllowConnectionWindowIncrease).To(BeTrue()) 152 _, err := c2.GetConfigForClient(&ClientHelloInfo{}) 153 Expect(err).To(MatchError("nope")) 154 c2.Tracer(context.Background(), logging.PerspectiveClient, protocol.ConnectionID{}) 155 Expect(calledTracer).To(BeTrue()) 156 }) 157 158 It("clones non-function fields", func() { 159 c := configWithNonZeroNonFunctionFields() 160 Expect(c.Clone()).To(Equal(c)) 161 }) 162 163 It("returns a copy", func() { 164 c1 := &Config{MaxIncomingStreams: 100} 165 c2 := c1.Clone() 166 c2.MaxIncomingStreams = 200 167 168 Expect(c1.MaxIncomingStreams).To(BeEquivalentTo(100)) 169 }) 170 }) 171 172 Context("populating", func() { 173 It("copies non-function fields", func() { 174 c := configWithNonZeroNonFunctionFields() 175 Expect(populateConfig(c)).To(Equal(c)) 176 }) 177 178 It("populates empty fields with default values", func() { 179 c := populateConfig(&Config{}) 180 Expect(c.Versions).To(Equal(protocol.SupportedVersions)) 181 Expect(c.HandshakeIdleTimeout).To(Equal(protocol.DefaultHandshakeIdleTimeout)) 182 Expect(c.InitialStreamReceiveWindow).To(BeEquivalentTo(protocol.DefaultInitialMaxStreamData)) 183 Expect(c.MaxStreamReceiveWindow).To(BeEquivalentTo(protocol.DefaultMaxReceiveStreamFlowControlWindow)) 184 Expect(c.InitialConnectionReceiveWindow).To(BeEquivalentTo(protocol.DefaultInitialMaxData)) 185 Expect(c.MaxConnectionReceiveWindow).To(BeEquivalentTo(protocol.DefaultMaxReceiveConnectionFlowControlWindow)) 186 Expect(c.MaxIncomingStreams).To(BeEquivalentTo(protocol.DefaultMaxIncomingStreams)) 187 Expect(c.MaxIncomingUniStreams).To(BeEquivalentTo(protocol.DefaultMaxIncomingUniStreams)) 188 Expect(c.DisablePathMTUDiscovery).To(BeFalse()) 189 Expect(c.GetConfigForClient).To(BeNil()) 190 }) 191 }) 192 })