github.com/metacubex/quic-go@v0.44.1-0.20240520163451-20b689a59136/qlog/connection_tracer_test.go (about) 1 package qlog 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "io" 7 "net" 8 "net/netip" 9 "time" 10 11 "github.com/metacubex/quic-go" 12 "github.com/metacubex/quic-go/internal/protocol" 13 "github.com/metacubex/quic-go/internal/qerr" 14 "github.com/metacubex/quic-go/internal/utils" 15 "github.com/metacubex/quic-go/logging" 16 17 . "github.com/onsi/ginkgo/v2" 18 . "github.com/onsi/gomega" 19 ) 20 21 type nopWriteCloserImpl struct{ io.Writer } 22 23 func (nopWriteCloserImpl) Close() error { return nil } 24 25 func nopWriteCloser(w io.Writer) io.WriteCloser { 26 return &nopWriteCloserImpl{Writer: w} 27 } 28 29 type entry struct { 30 Time time.Time 31 Name string 32 Event map[string]interface{} 33 } 34 35 func exportAndParse(buf *bytes.Buffer) []entry { 36 m := make(map[string]interface{}) 37 line, err := buf.ReadBytes('\n') 38 Expect(err).ToNot(HaveOccurred()) 39 Expect(json.Unmarshal(line, &m)).To(Succeed()) 40 Expect(m).To(HaveKey("trace")) 41 var entries []entry 42 trace := m["trace"].(map[string]interface{}) 43 Expect(trace).To(HaveKey("common_fields")) 44 commonFields := trace["common_fields"].(map[string]interface{}) 45 Expect(commonFields).To(HaveKey("reference_time")) 46 referenceTime := time.Unix(0, int64(commonFields["reference_time"].(float64)*1e6)) 47 Expect(trace).ToNot(HaveKey("events")) 48 49 for buf.Len() > 0 { 50 line, err := buf.ReadBytes('\n') 51 Expect(err).ToNot(HaveOccurred()) 52 ev := make(map[string]interface{}) 53 Expect(json.Unmarshal(line, &ev)).To(Succeed()) 54 Expect(ev).To(HaveLen(3)) 55 Expect(ev).To(HaveKey("time")) 56 Expect(ev).To(HaveKey("name")) 57 Expect(ev).To(HaveKey("data")) 58 entries = append(entries, entry{ 59 Time: referenceTime.Add(time.Duration(ev["time"].(float64)*1e6) * time.Nanosecond), 60 Name: ev["name"].(string), 61 Event: ev["data"].(map[string]interface{}), 62 }) 63 } 64 return entries 65 } 66 67 func exportAndParseSingle(buf *bytes.Buffer) entry { 68 entries := exportAndParse(buf) 69 Expect(entries).To(HaveLen(1)) 70 return entries[0] 71 } 72 73 var _ = Describe("Tracing", func() { 74 var ( 75 tracer *logging.ConnectionTracer 76 buf *bytes.Buffer 77 ) 78 79 BeforeEach(func() { 80 buf = &bytes.Buffer{} 81 tracer = NewConnectionTracer( 82 nopWriteCloser(buf), 83 logging.PerspectiveServer, 84 protocol.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef}), 85 ) 86 }) 87 88 It("exports a trace that has the right metadata", func() { 89 tracer.Close() 90 91 m := make(map[string]interface{}) 92 Expect(json.Unmarshal(buf.Bytes(), &m)).To(Succeed()) 93 Expect(m).To(HaveKeyWithValue("qlog_version", "draft-02")) 94 Expect(m).To(HaveKey("title")) 95 Expect(m).To(HaveKey("trace")) 96 trace := m["trace"].(map[string]interface{}) 97 Expect(trace).To(HaveKey("common_fields")) 98 commonFields := trace["common_fields"].(map[string]interface{}) 99 Expect(commonFields).To(HaveKeyWithValue("ODCID", "deadbeef")) 100 Expect(commonFields).To(HaveKeyWithValue("group_id", "deadbeef")) 101 Expect(commonFields).To(HaveKey("reference_time")) 102 referenceTime := time.Unix(0, int64(commonFields["reference_time"].(float64)*1e6)) 103 Expect(referenceTime).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 104 Expect(commonFields).To(HaveKeyWithValue("time_format", "relative")) 105 Expect(trace).To(HaveKey("vantage_point")) 106 vantagePoint := trace["vantage_point"].(map[string]interface{}) 107 Expect(vantagePoint).To(HaveKeyWithValue("type", "server")) 108 }) 109 110 Context("Events", func() { 111 It("records connection starts", func() { 112 tracer.StartedConnection( 113 &net.UDPAddr{IP: net.IPv4(192, 168, 13, 37), Port: 42}, 114 &net.UDPAddr{IP: net.IPv4(192, 168, 12, 34), Port: 24}, 115 protocol.ParseConnectionID([]byte{1, 2, 3, 4}), 116 protocol.ParseConnectionID([]byte{5, 6, 7, 8}), 117 ) 118 tracer.Close() 119 entry := exportAndParseSingle(buf) 120 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 121 Expect(entry.Name).To(Equal("transport:connection_started")) 122 ev := entry.Event 123 Expect(ev).To(HaveKeyWithValue("ip_version", "ipv4")) 124 Expect(ev).To(HaveKeyWithValue("src_ip", "192.168.13.37")) 125 Expect(ev).To(HaveKeyWithValue("src_port", float64(42))) 126 Expect(ev).To(HaveKeyWithValue("dst_ip", "192.168.12.34")) 127 Expect(ev).To(HaveKeyWithValue("dst_port", float64(24))) 128 Expect(ev).To(HaveKeyWithValue("src_cid", "01020304")) 129 Expect(ev).To(HaveKeyWithValue("dst_cid", "05060708")) 130 }) 131 132 It("records the version, if no version negotiation happened", func() { 133 tracer.NegotiatedVersion(0x1337, nil, nil) 134 tracer.Close() 135 entry := exportAndParseSingle(buf) 136 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 137 Expect(entry.Name).To(Equal("transport:version_information")) 138 ev := entry.Event 139 Expect(ev).To(HaveLen(1)) 140 Expect(ev).To(HaveKeyWithValue("chosen_version", "1337")) 141 }) 142 143 It("records the version, if version negotiation happened", func() { 144 tracer.NegotiatedVersion(0x1337, []logging.VersionNumber{1, 2, 3}, []logging.VersionNumber{4, 5, 6}) 145 tracer.Close() 146 entry := exportAndParseSingle(buf) 147 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 148 Expect(entry.Name).To(Equal("transport:version_information")) 149 ev := entry.Event 150 Expect(ev).To(HaveLen(3)) 151 Expect(ev).To(HaveKeyWithValue("chosen_version", "1337")) 152 Expect(ev).To(HaveKey("client_versions")) 153 Expect(ev["client_versions"].([]interface{})).To(Equal([]interface{}{"1", "2", "3"})) 154 Expect(ev).To(HaveKey("server_versions")) 155 Expect(ev["server_versions"].([]interface{})).To(Equal([]interface{}{"4", "5", "6"})) 156 }) 157 158 It("records idle timeouts", func() { 159 tracer.ClosedConnection(&quic.IdleTimeoutError{}) 160 tracer.Close() 161 entry := exportAndParseSingle(buf) 162 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 163 Expect(entry.Name).To(Equal("transport:connection_closed")) 164 ev := entry.Event 165 Expect(ev).To(HaveLen(2)) 166 Expect(ev).To(HaveKeyWithValue("owner", "local")) 167 Expect(ev).To(HaveKeyWithValue("trigger", "idle_timeout")) 168 }) 169 170 It("records handshake timeouts", func() { 171 tracer.ClosedConnection(&quic.HandshakeTimeoutError{}) 172 tracer.Close() 173 entry := exportAndParseSingle(buf) 174 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 175 Expect(entry.Name).To(Equal("transport:connection_closed")) 176 ev := entry.Event 177 Expect(ev).To(HaveLen(2)) 178 Expect(ev).To(HaveKeyWithValue("owner", "local")) 179 Expect(ev).To(HaveKeyWithValue("trigger", "handshake_timeout")) 180 }) 181 182 It("records a received stateless reset packet", func() { 183 tracer.ClosedConnection(&quic.StatelessResetError{ 184 Token: protocol.StatelessResetToken{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}, 185 }) 186 tracer.Close() 187 entry := exportAndParseSingle(buf) 188 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 189 Expect(entry.Name).To(Equal("transport:connection_closed")) 190 ev := entry.Event 191 Expect(ev).To(HaveLen(3)) 192 Expect(ev).To(HaveKeyWithValue("owner", "remote")) 193 Expect(ev).To(HaveKeyWithValue("trigger", "stateless_reset")) 194 Expect(ev).To(HaveKeyWithValue("stateless_reset_token", "00112233445566778899aabbccddeeff")) 195 }) 196 197 It("records connection closing due to version negotiation failure", func() { 198 tracer.ClosedConnection(&quic.VersionNegotiationError{}) 199 tracer.Close() 200 entry := exportAndParseSingle(buf) 201 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 202 Expect(entry.Name).To(Equal("transport:connection_closed")) 203 ev := entry.Event 204 Expect(ev).To(HaveLen(1)) 205 Expect(ev).To(HaveKeyWithValue("trigger", "version_mismatch")) 206 }) 207 208 It("records application errors", func() { 209 tracer.ClosedConnection(&quic.ApplicationError{ 210 Remote: true, 211 ErrorCode: 1337, 212 ErrorMessage: "foobar", 213 }) 214 tracer.Close() 215 entry := exportAndParseSingle(buf) 216 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 217 Expect(entry.Name).To(Equal("transport:connection_closed")) 218 ev := entry.Event 219 Expect(ev).To(HaveLen(3)) 220 Expect(ev).To(HaveKeyWithValue("owner", "remote")) 221 Expect(ev).To(HaveKeyWithValue("application_code", float64(1337))) 222 Expect(ev).To(HaveKeyWithValue("reason", "foobar")) 223 }) 224 225 It("records transport errors", func() { 226 tracer.ClosedConnection(&quic.TransportError{ 227 ErrorCode: qerr.AEADLimitReached, 228 ErrorMessage: "foobar", 229 }) 230 tracer.Close() 231 entry := exportAndParseSingle(buf) 232 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 233 Expect(entry.Name).To(Equal("transport:connection_closed")) 234 ev := entry.Event 235 Expect(ev).To(HaveLen(3)) 236 Expect(ev).To(HaveKeyWithValue("owner", "local")) 237 Expect(ev).To(HaveKeyWithValue("connection_code", "aead_limit_reached")) 238 Expect(ev).To(HaveKeyWithValue("reason", "foobar")) 239 }) 240 241 It("records sent transport parameters", func() { 242 rcid := protocol.ParseConnectionID([]byte{0xde, 0xca, 0xfb, 0xad}) 243 tracer.SentTransportParameters(&logging.TransportParameters{ 244 InitialMaxStreamDataBidiLocal: 1000, 245 InitialMaxStreamDataBidiRemote: 2000, 246 InitialMaxStreamDataUni: 3000, 247 InitialMaxData: 4000, 248 MaxBidiStreamNum: 10, 249 MaxUniStreamNum: 20, 250 MaxAckDelay: 123 * time.Millisecond, 251 AckDelayExponent: 12, 252 DisableActiveMigration: true, 253 MaxUDPPayloadSize: 1234, 254 MaxIdleTimeout: 321 * time.Millisecond, 255 StatelessResetToken: &protocol.StatelessResetToken{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00}, 256 OriginalDestinationConnectionID: protocol.ParseConnectionID([]byte{0xde, 0xad, 0xc0, 0xde}), 257 InitialSourceConnectionID: protocol.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef}), 258 RetrySourceConnectionID: &rcid, 259 ActiveConnectionIDLimit: 7, 260 MaxDatagramFrameSize: protocol.InvalidByteCount, 261 }) 262 tracer.Close() 263 entry := exportAndParseSingle(buf) 264 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 265 Expect(entry.Name).To(Equal("transport:parameters_set")) 266 ev := entry.Event 267 Expect(ev).To(HaveKeyWithValue("owner", "local")) 268 Expect(ev).To(HaveKeyWithValue("original_destination_connection_id", "deadc0de")) 269 Expect(ev).To(HaveKeyWithValue("initial_source_connection_id", "deadbeef")) 270 Expect(ev).To(HaveKeyWithValue("retry_source_connection_id", "decafbad")) 271 Expect(ev).To(HaveKeyWithValue("stateless_reset_token", "112233445566778899aabbccddeeff00")) 272 Expect(ev).To(HaveKeyWithValue("max_idle_timeout", float64(321))) 273 Expect(ev).To(HaveKeyWithValue("max_udp_payload_size", float64(1234))) 274 Expect(ev).To(HaveKeyWithValue("ack_delay_exponent", float64(12))) 275 Expect(ev).To(HaveKeyWithValue("active_connection_id_limit", float64(7))) 276 Expect(ev).To(HaveKeyWithValue("initial_max_data", float64(4000))) 277 Expect(ev).To(HaveKeyWithValue("initial_max_stream_data_bidi_local", float64(1000))) 278 Expect(ev).To(HaveKeyWithValue("initial_max_stream_data_bidi_remote", float64(2000))) 279 Expect(ev).To(HaveKeyWithValue("initial_max_stream_data_uni", float64(3000))) 280 Expect(ev).To(HaveKeyWithValue("initial_max_streams_bidi", float64(10))) 281 Expect(ev).To(HaveKeyWithValue("initial_max_streams_uni", float64(20))) 282 Expect(ev).ToNot(HaveKey("preferred_address")) 283 Expect(ev).ToNot(HaveKey("max_datagram_frame_size")) 284 }) 285 286 It("records the server's transport parameters, without a stateless reset token", func() { 287 tracer.SentTransportParameters(&logging.TransportParameters{ 288 OriginalDestinationConnectionID: protocol.ParseConnectionID([]byte{0xde, 0xad, 0xc0, 0xde}), 289 ActiveConnectionIDLimit: 7, 290 }) 291 tracer.Close() 292 entry := exportAndParseSingle(buf) 293 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 294 Expect(entry.Name).To(Equal("transport:parameters_set")) 295 ev := entry.Event 296 Expect(ev).ToNot(HaveKey("stateless_reset_token")) 297 }) 298 299 It("records transport parameters without retry_source_connection_id", func() { 300 tracer.SentTransportParameters(&logging.TransportParameters{ 301 StatelessResetToken: &protocol.StatelessResetToken{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00}, 302 }) 303 tracer.Close() 304 entry := exportAndParseSingle(buf) 305 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 306 Expect(entry.Name).To(Equal("transport:parameters_set")) 307 ev := entry.Event 308 Expect(ev).To(HaveKeyWithValue("owner", "local")) 309 Expect(ev).ToNot(HaveKey("retry_source_connection_id")) 310 }) 311 312 It("records transport parameters with a preferred address", func() { 313 tracer.SentTransportParameters(&logging.TransportParameters{ 314 PreferredAddress: &logging.PreferredAddress{ 315 IPv4: netip.AddrPortFrom(netip.AddrFrom4([4]byte{12, 34, 56, 78}), 123), 316 IPv6: netip.AddrPortFrom(netip.AddrFrom16([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}), 456), 317 ConnectionID: protocol.ParseConnectionID([]byte{8, 7, 6, 5, 4, 3, 2, 1}), 318 StatelessResetToken: protocol.StatelessResetToken{15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}, 319 }, 320 }) 321 tracer.Close() 322 entry := exportAndParseSingle(buf) 323 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 324 Expect(entry.Name).To(Equal("transport:parameters_set")) 325 ev := entry.Event 326 Expect(ev).To(HaveKeyWithValue("owner", "local")) 327 Expect(ev).To(HaveKey("preferred_address")) 328 pa := ev["preferred_address"].(map[string]interface{}) 329 Expect(pa).To(HaveKeyWithValue("ip_v4", "12.34.56.78")) 330 Expect(pa).To(HaveKeyWithValue("port_v4", float64(123))) 331 Expect(pa).To(HaveKeyWithValue("ip_v6", "102:304:506:708:90a:b0c:d0e:f10")) 332 Expect(pa).To(HaveKeyWithValue("port_v6", float64(456))) 333 Expect(pa).To(HaveKeyWithValue("connection_id", "0807060504030201")) 334 Expect(pa).To(HaveKeyWithValue("stateless_reset_token", "0f0e0d0c0b0a09080706050403020100")) 335 }) 336 337 It("records transport parameters that enable the datagram extension", func() { 338 tracer.SentTransportParameters(&logging.TransportParameters{ 339 MaxDatagramFrameSize: 1337, 340 }) 341 tracer.Close() 342 entry := exportAndParseSingle(buf) 343 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 344 Expect(entry.Name).To(Equal("transport:parameters_set")) 345 ev := entry.Event 346 Expect(ev).To(HaveKeyWithValue("max_datagram_frame_size", float64(1337))) 347 }) 348 349 It("records received transport parameters", func() { 350 tracer.ReceivedTransportParameters(&logging.TransportParameters{}) 351 tracer.Close() 352 entry := exportAndParseSingle(buf) 353 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 354 Expect(entry.Name).To(Equal("transport:parameters_set")) 355 ev := entry.Event 356 Expect(ev).To(HaveKeyWithValue("owner", "remote")) 357 Expect(ev).ToNot(HaveKey("original_destination_connection_id")) 358 }) 359 360 It("records restored transport parameters", func() { 361 tracer.RestoredTransportParameters(&logging.TransportParameters{ 362 InitialMaxStreamDataBidiLocal: 100, 363 InitialMaxStreamDataBidiRemote: 200, 364 InitialMaxStreamDataUni: 300, 365 InitialMaxData: 400, 366 MaxIdleTimeout: 123 * time.Millisecond, 367 }) 368 tracer.Close() 369 entry := exportAndParseSingle(buf) 370 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 371 Expect(entry.Name).To(Equal("transport:parameters_restored")) 372 ev := entry.Event 373 Expect(ev).ToNot(HaveKey("owner")) 374 Expect(ev).ToNot(HaveKey("original_destination_connection_id")) 375 Expect(ev).ToNot(HaveKey("stateless_reset_token")) 376 Expect(ev).ToNot(HaveKey("retry_source_connection_id")) 377 Expect(ev).ToNot(HaveKey("initial_source_connection_id")) 378 Expect(ev).To(HaveKeyWithValue("max_idle_timeout", float64(123))) 379 Expect(ev).To(HaveKeyWithValue("initial_max_data", float64(400))) 380 Expect(ev).To(HaveKeyWithValue("initial_max_stream_data_bidi_local", float64(100))) 381 Expect(ev).To(HaveKeyWithValue("initial_max_stream_data_bidi_remote", float64(200))) 382 Expect(ev).To(HaveKeyWithValue("initial_max_stream_data_uni", float64(300))) 383 }) 384 385 It("records a sent long header packet, without an ACK", func() { 386 tracer.SentLongHeaderPacket( 387 &logging.ExtendedHeader{ 388 Header: logging.Header{ 389 Type: protocol.PacketTypeHandshake, 390 DestConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5, 6, 7, 8}), 391 SrcConnectionID: protocol.ParseConnectionID([]byte{4, 3, 2, 1}), 392 Length: 1337, 393 Version: protocol.Version1, 394 }, 395 PacketNumber: 1337, 396 }, 397 987, 398 logging.ECNCE, 399 nil, 400 []logging.Frame{ 401 &logging.MaxStreamDataFrame{StreamID: 42, MaximumStreamData: 987}, 402 &logging.StreamFrame{StreamID: 123, Offset: 1234, Length: 6, Fin: true}, 403 }, 404 ) 405 tracer.Close() 406 entry := exportAndParseSingle(buf) 407 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 408 Expect(entry.Name).To(Equal("transport:packet_sent")) 409 ev := entry.Event 410 Expect(ev).To(HaveKey("raw")) 411 raw := ev["raw"].(map[string]interface{}) 412 Expect(raw).To(HaveKeyWithValue("length", float64(987))) 413 Expect(raw).To(HaveKeyWithValue("payload_length", float64(1337))) 414 Expect(ev).To(HaveKey("header")) 415 hdr := ev["header"].(map[string]interface{}) 416 Expect(hdr).To(HaveKeyWithValue("packet_type", "handshake")) 417 Expect(hdr).To(HaveKeyWithValue("packet_number", float64(1337))) 418 Expect(hdr).To(HaveKeyWithValue("scid", "04030201")) 419 Expect(ev).To(HaveKey("frames")) 420 Expect(ev).To(HaveKeyWithValue("ecn", "CE")) 421 frames := ev["frames"].([]interface{}) 422 Expect(frames).To(HaveLen(2)) 423 Expect(frames[0].(map[string]interface{})).To(HaveKeyWithValue("frame_type", "max_stream_data")) 424 Expect(frames[1].(map[string]interface{})).To(HaveKeyWithValue("frame_type", "stream")) 425 }) 426 427 It("records a sent short header packet, without an ACK", func() { 428 tracer.SentShortHeaderPacket( 429 &logging.ShortHeader{ 430 DestConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4}), 431 PacketNumber: 1337, 432 }, 433 123, 434 logging.ECNUnsupported, 435 &logging.AckFrame{AckRanges: []logging.AckRange{{Smallest: 1, Largest: 10}}}, 436 []logging.Frame{&logging.MaxDataFrame{MaximumData: 987}}, 437 ) 438 tracer.Close() 439 entry := exportAndParseSingle(buf) 440 ev := entry.Event 441 raw := ev["raw"].(map[string]interface{}) 442 Expect(raw).To(HaveKeyWithValue("length", float64(123))) 443 Expect(raw).ToNot(HaveKey("payload_length")) 444 Expect(ev).To(HaveKey("header")) 445 Expect(ev).ToNot(HaveKey("ecn")) 446 hdr := ev["header"].(map[string]interface{}) 447 Expect(hdr).To(HaveKeyWithValue("packet_type", "1RTT")) 448 Expect(hdr).To(HaveKeyWithValue("packet_number", float64(1337))) 449 Expect(ev).To(HaveKey("frames")) 450 frames := ev["frames"].([]interface{}) 451 Expect(frames).To(HaveLen(2)) 452 Expect(frames[0].(map[string]interface{})).To(HaveKeyWithValue("frame_type", "ack")) 453 Expect(frames[1].(map[string]interface{})).To(HaveKeyWithValue("frame_type", "max_data")) 454 }) 455 456 It("records a received Long Header packet", func() { 457 tracer.ReceivedLongHeaderPacket( 458 &logging.ExtendedHeader{ 459 Header: logging.Header{ 460 Type: protocol.PacketTypeInitial, 461 DestConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5, 6, 7, 8}), 462 SrcConnectionID: protocol.ParseConnectionID([]byte{4, 3, 2, 1}), 463 Token: []byte{0xde, 0xad, 0xbe, 0xef}, 464 Length: 1234, 465 Version: protocol.Version1, 466 }, 467 PacketNumber: 1337, 468 }, 469 789, 470 logging.ECT0, 471 []logging.Frame{ 472 &logging.MaxStreamDataFrame{StreamID: 42, MaximumStreamData: 987}, 473 &logging.StreamFrame{StreamID: 123, Offset: 1234, Length: 6, Fin: true}, 474 }, 475 ) 476 tracer.Close() 477 entry := exportAndParseSingle(buf) 478 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 479 Expect(entry.Name).To(Equal("transport:packet_received")) 480 ev := entry.Event 481 Expect(ev).To(HaveKey("raw")) 482 raw := ev["raw"].(map[string]interface{}) 483 Expect(raw).To(HaveKeyWithValue("length", float64(789))) 484 Expect(raw).To(HaveKeyWithValue("payload_length", float64(1234))) 485 Expect(ev).To(HaveKeyWithValue("ecn", "ECT(0)")) 486 Expect(ev).To(HaveKey("header")) 487 hdr := ev["header"].(map[string]interface{}) 488 Expect(hdr).To(HaveKeyWithValue("packet_type", "initial")) 489 Expect(hdr).To(HaveKeyWithValue("packet_number", float64(1337))) 490 Expect(hdr).To(HaveKeyWithValue("scid", "04030201")) 491 Expect(hdr).To(HaveKey("token")) 492 token := hdr["token"].(map[string]interface{}) 493 Expect(token).To(HaveKeyWithValue("data", "deadbeef")) 494 Expect(ev).To(HaveKey("frames")) 495 Expect(ev["frames"].([]interface{})).To(HaveLen(2)) 496 }) 497 498 It("records a received Short Header packet", func() { 499 shdr := &logging.ShortHeader{ 500 DestConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5, 6, 7, 8}), 501 PacketNumber: 1337, 502 PacketNumberLen: protocol.PacketNumberLen3, 503 KeyPhase: protocol.KeyPhaseZero, 504 } 505 tracer.ReceivedShortHeaderPacket( 506 shdr, 507 789, 508 logging.ECT1, 509 []logging.Frame{ 510 &logging.MaxStreamDataFrame{StreamID: 42, MaximumStreamData: 987}, 511 &logging.StreamFrame{StreamID: 123, Offset: 1234, Length: 6, Fin: true}, 512 }, 513 ) 514 tracer.Close() 515 entry := exportAndParseSingle(buf) 516 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 517 Expect(entry.Name).To(Equal("transport:packet_received")) 518 ev := entry.Event 519 Expect(ev).To(HaveKey("raw")) 520 raw := ev["raw"].(map[string]interface{}) 521 Expect(raw).To(HaveKeyWithValue("length", float64(789))) 522 Expect(raw).To(HaveKeyWithValue("payload_length", float64(789-(1+8+3)))) 523 Expect(ev).To(HaveKeyWithValue("ecn", "ECT(1)")) 524 Expect(ev).To(HaveKey("header")) 525 hdr := ev["header"].(map[string]interface{}) 526 Expect(hdr).To(HaveKeyWithValue("packet_type", "1RTT")) 527 Expect(hdr).To(HaveKeyWithValue("packet_number", float64(1337))) 528 Expect(hdr).To(HaveKeyWithValue("key_phase_bit", "0")) 529 Expect(ev).To(HaveKey("frames")) 530 Expect(ev["frames"].([]interface{})).To(HaveLen(2)) 531 }) 532 533 It("records a received Retry packet", func() { 534 tracer.ReceivedRetry( 535 &logging.Header{ 536 Type: protocol.PacketTypeRetry, 537 DestConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5, 6, 7, 8}), 538 SrcConnectionID: protocol.ParseConnectionID([]byte{4, 3, 2, 1}), 539 Token: []byte{0xde, 0xad, 0xbe, 0xef}, 540 Version: protocol.Version1, 541 }, 542 ) 543 tracer.Close() 544 entry := exportAndParseSingle(buf) 545 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 546 Expect(entry.Name).To(Equal("transport:packet_received")) 547 ev := entry.Event 548 Expect(ev).ToNot(HaveKey("raw")) 549 Expect(ev).To(HaveKey("header")) 550 header := ev["header"].(map[string]interface{}) 551 Expect(header).To(HaveKeyWithValue("packet_type", "retry")) 552 Expect(header).ToNot(HaveKey("packet_number")) 553 Expect(header).To(HaveKey("version")) 554 Expect(header).To(HaveKey("dcid")) 555 Expect(header).To(HaveKey("scid")) 556 Expect(header).To(HaveKey("token")) 557 token := header["token"].(map[string]interface{}) 558 Expect(token).To(HaveKeyWithValue("data", "deadbeef")) 559 Expect(ev).ToNot(HaveKey("frames")) 560 }) 561 562 It("records a received Version Negotiation packet", func() { 563 tracer.ReceivedVersionNegotiationPacket( 564 protocol.ArbitraryLenConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, 565 protocol.ArbitraryLenConnectionID{4, 3, 2, 1}, 566 []protocol.Version{0xdeadbeef, 0xdecafbad}, 567 ) 568 tracer.Close() 569 entry := exportAndParseSingle(buf) 570 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 571 Expect(entry.Name).To(Equal("transport:packet_received")) 572 ev := entry.Event 573 Expect(ev).To(HaveKey("header")) 574 Expect(ev).ToNot(HaveKey("frames")) 575 Expect(ev).To(HaveKey("supported_versions")) 576 Expect(ev["supported_versions"].([]interface{})).To(Equal([]interface{}{"deadbeef", "decafbad"})) 577 header := ev["header"] 578 Expect(header).To(HaveKeyWithValue("packet_type", "version_negotiation")) 579 Expect(header).ToNot(HaveKey("packet_number")) 580 Expect(header).ToNot(HaveKey("version")) 581 Expect(header).To(HaveKeyWithValue("dcid", "0102030405060708")) 582 Expect(header).To(HaveKeyWithValue("scid", "04030201")) 583 }) 584 585 It("records buffered packets", func() { 586 tracer.BufferedPacket(logging.PacketTypeHandshake, 1337) 587 tracer.Close() 588 entry := exportAndParseSingle(buf) 589 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 590 Expect(entry.Name).To(Equal("transport:packet_buffered")) 591 ev := entry.Event 592 Expect(ev).To(HaveKey("header")) 593 hdr := ev["header"].(map[string]interface{}) 594 Expect(hdr).To(HaveLen(1)) 595 Expect(hdr).To(HaveKeyWithValue("packet_type", "handshake")) 596 Expect(ev).To(HaveKey("raw")) 597 Expect(ev["raw"].(map[string]interface{})).To(HaveKeyWithValue("length", float64(1337))) 598 Expect(ev).To(HaveKeyWithValue("trigger", "keys_unavailable")) 599 }) 600 601 It("records dropped packets", func() { 602 tracer.DroppedPacket(logging.PacketTypeRetry, protocol.InvalidPacketNumber, 1337, logging.PacketDropPayloadDecryptError) 603 tracer.Close() 604 entry := exportAndParseSingle(buf) 605 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 606 Expect(entry.Name).To(Equal("transport:packet_dropped")) 607 ev := entry.Event 608 Expect(ev).To(HaveKey("raw")) 609 Expect(ev["raw"].(map[string]interface{})).To(HaveKeyWithValue("length", float64(1337))) 610 Expect(ev).To(HaveKey("header")) 611 hdr := ev["header"].(map[string]interface{}) 612 Expect(hdr).To(HaveLen(1)) 613 Expect(hdr).To(HaveKeyWithValue("packet_type", "retry")) 614 Expect(ev).To(HaveKeyWithValue("trigger", "payload_decrypt_error")) 615 }) 616 617 It("records dropped packets with a packet number", func() { 618 tracer.DroppedPacket(logging.PacketTypeHandshake, 42, 1337, logging.PacketDropDuplicate) 619 tracer.Close() 620 entry := exportAndParseSingle(buf) 621 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 622 Expect(entry.Name).To(Equal("transport:packet_dropped")) 623 ev := entry.Event 624 Expect(ev).To(HaveKey("raw")) 625 Expect(ev["raw"].(map[string]interface{})).To(HaveKeyWithValue("length", float64(1337))) 626 Expect(ev).To(HaveKey("header")) 627 hdr := ev["header"].(map[string]interface{}) 628 Expect(hdr).To(HaveLen(2)) 629 Expect(hdr).To(HaveKeyWithValue("packet_type", "handshake")) 630 Expect(hdr).To(HaveKeyWithValue("packet_number", float64(42))) 631 Expect(ev).To(HaveKeyWithValue("trigger", "duplicate")) 632 }) 633 634 It("records metrics updates", func() { 635 now := time.Now() 636 rttStats := utils.NewRTTStats() 637 rttStats.UpdateRTT(15*time.Millisecond, 0, now) 638 rttStats.UpdateRTT(20*time.Millisecond, 0, now) 639 rttStats.UpdateRTT(25*time.Millisecond, 0, now) 640 Expect(rttStats.MinRTT()).To(Equal(15 * time.Millisecond)) 641 Expect(rttStats.SmoothedRTT()).To(And( 642 BeNumerically(">", 15*time.Millisecond), 643 BeNumerically("<", 25*time.Millisecond), 644 )) 645 Expect(rttStats.LatestRTT()).To(Equal(25 * time.Millisecond)) 646 tracer.UpdatedMetrics( 647 rttStats, 648 4321, 649 1234, 650 42, 651 ) 652 tracer.Close() 653 entry := exportAndParseSingle(buf) 654 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 655 Expect(entry.Name).To(Equal("recovery:metrics_updated")) 656 ev := entry.Event 657 Expect(ev).To(HaveKeyWithValue("min_rtt", float64(15))) 658 Expect(ev).To(HaveKeyWithValue("latest_rtt", float64(25))) 659 Expect(ev).To(HaveKey("smoothed_rtt")) 660 Expect(time.Duration(ev["smoothed_rtt"].(float64)) * time.Millisecond).To(BeNumerically("~", rttStats.SmoothedRTT(), time.Millisecond)) 661 Expect(ev).To(HaveKey("rtt_variance")) 662 Expect(time.Duration(ev["rtt_variance"].(float64)) * time.Millisecond).To(BeNumerically("~", rttStats.MeanDeviation(), time.Millisecond)) 663 Expect(ev).To(HaveKeyWithValue("congestion_window", float64(4321))) 664 Expect(ev).To(HaveKeyWithValue("bytes_in_flight", float64(1234))) 665 Expect(ev).To(HaveKeyWithValue("packets_in_flight", float64(42))) 666 }) 667 668 It("only logs the diff between two metrics updates", func() { 669 now := time.Now() 670 rttStats := utils.NewRTTStats() 671 rttStats.UpdateRTT(15*time.Millisecond, 0, now) 672 rttStats.UpdateRTT(20*time.Millisecond, 0, now) 673 rttStats.UpdateRTT(25*time.Millisecond, 0, now) 674 Expect(rttStats.MinRTT()).To(Equal(15 * time.Millisecond)) 675 676 rttStats2 := utils.NewRTTStats() 677 rttStats2.UpdateRTT(15*time.Millisecond, 0, now) 678 rttStats2.UpdateRTT(15*time.Millisecond, 0, now) 679 rttStats2.UpdateRTT(15*time.Millisecond, 0, now) 680 Expect(rttStats2.MinRTT()).To(Equal(15 * time.Millisecond)) 681 682 Expect(rttStats.LatestRTT()).To(Equal(25 * time.Millisecond)) 683 tracer.UpdatedMetrics( 684 rttStats, 685 4321, 686 1234, 687 42, 688 ) 689 tracer.UpdatedMetrics( 690 rttStats2, 691 4321, 692 12345, // changed 693 42, 694 ) 695 tracer.Close() 696 entries := exportAndParse(buf) 697 Expect(entries).To(HaveLen(2)) 698 Expect(entries[0].Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 699 Expect(entries[0].Name).To(Equal("recovery:metrics_updated")) 700 Expect(entries[0].Event).To(HaveLen(7)) 701 Expect(entries[1].Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 702 Expect(entries[1].Name).To(Equal("recovery:metrics_updated")) 703 ev := entries[1].Event 704 Expect(ev).ToNot(HaveKey("min_rtt")) 705 Expect(ev).ToNot(HaveKey("congestion_window")) 706 Expect(ev).ToNot(HaveKey("packets_in_flight")) 707 Expect(ev).To(HaveKeyWithValue("bytes_in_flight", float64(12345))) 708 Expect(ev).To(HaveKeyWithValue("smoothed_rtt", float64(15))) 709 }) 710 711 It("records lost packets", func() { 712 tracer.LostPacket(protocol.EncryptionHandshake, 42, logging.PacketLossReorderingThreshold) 713 tracer.Close() 714 entry := exportAndParseSingle(buf) 715 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 716 Expect(entry.Name).To(Equal("recovery:packet_lost")) 717 ev := entry.Event 718 Expect(ev).To(HaveKey("header")) 719 hdr := ev["header"].(map[string]interface{}) 720 Expect(hdr).To(HaveLen(2)) 721 Expect(hdr).To(HaveKeyWithValue("packet_type", "handshake")) 722 Expect(hdr).To(HaveKeyWithValue("packet_number", float64(42))) 723 Expect(ev).To(HaveKeyWithValue("trigger", "reordering_threshold")) 724 }) 725 726 It("records MTU discovery updates", func() { 727 tracer.UpdatedMTU(1337, true) 728 tracer.Close() 729 entry := exportAndParseSingle(buf) 730 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 731 Expect(entry.Name).To(Equal("recovery:mtu_updated")) 732 ev := entry.Event 733 Expect(ev).To(HaveKeyWithValue("mtu", float64(1337))) 734 Expect(ev).To(HaveKeyWithValue("done", true)) 735 }) 736 737 It("records congestion state updates", func() { 738 tracer.UpdatedCongestionState(logging.CongestionStateCongestionAvoidance) 739 tracer.Close() 740 entry := exportAndParseSingle(buf) 741 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 742 Expect(entry.Name).To(Equal("recovery:congestion_state_updated")) 743 ev := entry.Event 744 Expect(ev).To(HaveKeyWithValue("new", "congestion_avoidance")) 745 }) 746 747 It("records PTO changes", func() { 748 tracer.UpdatedPTOCount(42) 749 tracer.Close() 750 entry := exportAndParseSingle(buf) 751 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 752 Expect(entry.Name).To(Equal("recovery:metrics_updated")) 753 Expect(entry.Event).To(HaveKeyWithValue("pto_count", float64(42))) 754 }) 755 756 It("records TLS key updates", func() { 757 tracer.UpdatedKeyFromTLS(protocol.EncryptionHandshake, protocol.PerspectiveClient) 758 tracer.Close() 759 entry := exportAndParseSingle(buf) 760 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 761 Expect(entry.Name).To(Equal("security:key_updated")) 762 ev := entry.Event 763 Expect(ev).To(HaveKeyWithValue("key_type", "client_handshake_secret")) 764 Expect(ev).To(HaveKeyWithValue("trigger", "tls")) 765 Expect(ev).ToNot(HaveKey("key_phase")) 766 Expect(ev).ToNot(HaveKey("old")) 767 Expect(ev).ToNot(HaveKey("new")) 768 }) 769 770 It("records TLS key updates, for 1-RTT keys", func() { 771 tracer.UpdatedKeyFromTLS(protocol.Encryption1RTT, protocol.PerspectiveServer) 772 tracer.Close() 773 entry := exportAndParseSingle(buf) 774 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 775 Expect(entry.Name).To(Equal("security:key_updated")) 776 ev := entry.Event 777 Expect(ev).To(HaveKeyWithValue("key_type", "server_1rtt_secret")) 778 Expect(ev).To(HaveKeyWithValue("trigger", "tls")) 779 Expect(ev).To(HaveKeyWithValue("key_phase", float64(0))) 780 Expect(ev).ToNot(HaveKey("old")) 781 Expect(ev).ToNot(HaveKey("new")) 782 }) 783 784 It("records QUIC key updates", func() { 785 tracer.UpdatedKey(1337, true) 786 tracer.Close() 787 entries := exportAndParse(buf) 788 Expect(entries).To(HaveLen(2)) 789 var keyTypes []string 790 for _, entry := range entries { 791 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 792 Expect(entry.Name).To(Equal("security:key_updated")) 793 ev := entry.Event 794 Expect(ev).To(HaveKeyWithValue("key_phase", float64(1337))) 795 Expect(ev).To(HaveKeyWithValue("trigger", "remote_update")) 796 Expect(ev).To(HaveKey("key_type")) 797 keyTypes = append(keyTypes, ev["key_type"].(string)) 798 } 799 Expect(keyTypes).To(ContainElement("server_1rtt_secret")) 800 Expect(keyTypes).To(ContainElement("client_1rtt_secret")) 801 }) 802 803 It("records dropped encryption levels", func() { 804 tracer.DroppedEncryptionLevel(protocol.EncryptionInitial) 805 tracer.Close() 806 entries := exportAndParse(buf) 807 Expect(entries).To(HaveLen(2)) 808 var keyTypes []string 809 for _, entry := range entries { 810 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 811 Expect(entry.Name).To(Equal("security:key_discarded")) 812 ev := entry.Event 813 Expect(ev).To(HaveKeyWithValue("trigger", "tls")) 814 Expect(ev).To(HaveKey("key_type")) 815 keyTypes = append(keyTypes, ev["key_type"].(string)) 816 } 817 Expect(keyTypes).To(ContainElement("server_initial_secret")) 818 Expect(keyTypes).To(ContainElement("client_initial_secret")) 819 }) 820 821 It("records dropped 0-RTT keys", func() { 822 tracer.DroppedEncryptionLevel(protocol.Encryption0RTT) 823 tracer.Close() 824 entries := exportAndParse(buf) 825 Expect(entries).To(HaveLen(1)) 826 entry := entries[0] 827 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 828 Expect(entry.Name).To(Equal("security:key_discarded")) 829 ev := entry.Event 830 Expect(ev).To(HaveKeyWithValue("trigger", "tls")) 831 Expect(ev).To(HaveKeyWithValue("key_type", "server_0rtt_secret")) 832 }) 833 834 It("records dropped keys", func() { 835 tracer.DroppedKey(42) 836 tracer.Close() 837 entries := exportAndParse(buf) 838 Expect(entries).To(HaveLen(2)) 839 var keyTypes []string 840 for _, entry := range entries { 841 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 842 Expect(entry.Name).To(Equal("security:key_discarded")) 843 ev := entry.Event 844 Expect(ev).To(HaveKeyWithValue("key_phase", float64(42))) 845 Expect(ev).ToNot(HaveKey("trigger")) 846 Expect(ev).To(HaveKey("key_type")) 847 keyTypes = append(keyTypes, ev["key_type"].(string)) 848 } 849 Expect(keyTypes).To(ContainElement("server_1rtt_secret")) 850 Expect(keyTypes).To(ContainElement("client_1rtt_secret")) 851 }) 852 853 It("records when the timer is set", func() { 854 timeout := time.Now().Add(137 * time.Millisecond) 855 tracer.SetLossTimer(logging.TimerTypePTO, protocol.EncryptionHandshake, timeout) 856 tracer.Close() 857 entry := exportAndParseSingle(buf) 858 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 859 Expect(entry.Name).To(Equal("recovery:loss_timer_updated")) 860 ev := entry.Event 861 Expect(ev).To(HaveLen(4)) 862 Expect(ev).To(HaveKeyWithValue("event_type", "set")) 863 Expect(ev).To(HaveKeyWithValue("timer_type", "pto")) 864 Expect(ev).To(HaveKeyWithValue("packet_number_space", "handshake")) 865 Expect(ev).To(HaveKey("delta")) 866 delta := time.Duration(ev["delta"].(float64)*1e6) * time.Nanosecond 867 Expect(entry.Time.Add(delta)).To(BeTemporally("~", timeout, scaleDuration(10*time.Microsecond))) 868 }) 869 870 It("records when the loss timer expires", func() { 871 tracer.LossTimerExpired(logging.TimerTypeACK, protocol.Encryption1RTT) 872 tracer.Close() 873 entry := exportAndParseSingle(buf) 874 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 875 Expect(entry.Name).To(Equal("recovery:loss_timer_updated")) 876 ev := entry.Event 877 Expect(ev).To(HaveLen(3)) 878 Expect(ev).To(HaveKeyWithValue("event_type", "expired")) 879 Expect(ev).To(HaveKeyWithValue("timer_type", "ack")) 880 Expect(ev).To(HaveKeyWithValue("packet_number_space", "application_data")) 881 }) 882 883 It("records when the timer is canceled", func() { 884 tracer.LossTimerCanceled() 885 tracer.Close() 886 entry := exportAndParseSingle(buf) 887 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 888 Expect(entry.Name).To(Equal("recovery:loss_timer_updated")) 889 ev := entry.Event 890 Expect(ev).To(HaveLen(1)) 891 Expect(ev).To(HaveKeyWithValue("event_type", "cancelled")) 892 }) 893 894 It("records an ECN state transition, without a trigger", func() { 895 tracer.ECNStateUpdated(logging.ECNStateUnknown, logging.ECNTriggerNoTrigger) 896 tracer.Close() 897 entry := exportAndParseSingle(buf) 898 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 899 Expect(entry.Name).To(Equal("recovery:ecn_state_updated")) 900 ev := entry.Event 901 Expect(ev).To(HaveLen(1)) 902 Expect(ev).To(HaveKeyWithValue("new", "unknown")) 903 }) 904 905 It("records an ECN state transition, with a trigger", func() { 906 tracer.ECNStateUpdated(logging.ECNStateFailed, logging.ECNFailedNoECNCounts) 907 tracer.Close() 908 entry := exportAndParseSingle(buf) 909 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 910 Expect(entry.Name).To(Equal("recovery:ecn_state_updated")) 911 ev := entry.Event 912 Expect(ev).To(HaveLen(2)) 913 Expect(ev).To(HaveKeyWithValue("new", "failed")) 914 Expect(ev).To(HaveKeyWithValue("trigger", "ACK doesn't contain ECN marks")) 915 }) 916 917 It("records a generic event", func() { 918 tracer.Debug("foo", "bar") 919 tracer.Close() 920 entry := exportAndParseSingle(buf) 921 Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) 922 Expect(entry.Name).To(Equal("transport:foo")) 923 ev := entry.Event 924 Expect(ev).To(HaveLen(1)) 925 Expect(ev).To(HaveKeyWithValue("details", "bar")) 926 }) 927 }) 928 })