github.com/apernet/quic-go@v0.43.1-0.20240515053213-5e9e635fd9f0/qlog/frame_test.go (about)

     1  package qlog
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"time"
     7  
     8  	"github.com/apernet/quic-go/internal/protocol"
     9  	"github.com/apernet/quic-go/internal/qerr"
    10  	"github.com/apernet/quic-go/logging"
    11  
    12  	"github.com/francoispqt/gojay"
    13  	. "github.com/onsi/ginkgo/v2"
    14  	. "github.com/onsi/gomega"
    15  )
    16  
    17  var _ = Describe("Frames", func() {
    18  	check := func(f logging.Frame, expected map[string]interface{}) {
    19  		buf := &bytes.Buffer{}
    20  		enc := gojay.NewEncoder(buf)
    21  		ExpectWithOffset(1, enc.Encode(frame{Frame: f})).To(Succeed())
    22  		data := buf.Bytes()
    23  		ExpectWithOffset(1, json.Valid(data)).To(BeTrue())
    24  		checkEncoding(data, expected)
    25  	}
    26  
    27  	It("marshals PING frames", func() {
    28  		check(
    29  			&logging.PingFrame{},
    30  			map[string]interface{}{
    31  				"frame_type": "ping",
    32  			},
    33  		)
    34  	})
    35  
    36  	It("marshals ACK frames with a range acknowledging a single packet", func() {
    37  		check(
    38  			&logging.AckFrame{
    39  				DelayTime: 86 * time.Millisecond,
    40  				AckRanges: []logging.AckRange{{Smallest: 120, Largest: 120}},
    41  			},
    42  			map[string]interface{}{
    43  				"frame_type":   "ack",
    44  				"ack_delay":    86,
    45  				"acked_ranges": [][]float64{{120}},
    46  			},
    47  		)
    48  	})
    49  
    50  	It("marshals ACK frames without a delay", func() {
    51  		check(
    52  			&logging.AckFrame{
    53  				AckRanges: []logging.AckRange{{Smallest: 120, Largest: 120}},
    54  			},
    55  			map[string]interface{}{
    56  				"frame_type":   "ack",
    57  				"acked_ranges": [][]float64{{120}},
    58  			},
    59  		)
    60  	})
    61  
    62  	It("marshals ACK frames with ECN counts", func() {
    63  		check(
    64  			&logging.AckFrame{
    65  				AckRanges: []logging.AckRange{{Smallest: 120, Largest: 120}},
    66  				ECT0:      10,
    67  				ECT1:      100,
    68  				ECNCE:     1000,
    69  			},
    70  			map[string]interface{}{
    71  				"frame_type":   "ack",
    72  				"acked_ranges": [][]float64{{120}},
    73  				"ect0":         10,
    74  				"ect1":         100,
    75  				"ce":           1000,
    76  			},
    77  		)
    78  	})
    79  
    80  	It("marshals ACK frames with a range acknowledging ranges of packets", func() {
    81  		check(
    82  			&logging.AckFrame{
    83  				DelayTime: 86 * time.Millisecond,
    84  				AckRanges: []logging.AckRange{
    85  					{Smallest: 5, Largest: 50},
    86  					{Smallest: 100, Largest: 120},
    87  				},
    88  			},
    89  			map[string]interface{}{
    90  				"frame_type": "ack",
    91  				"ack_delay":  86,
    92  				"acked_ranges": [][]float64{
    93  					{5, 50},
    94  					{100, 120},
    95  				},
    96  			},
    97  		)
    98  	})
    99  
   100  	It("marshals RESET_STREAM frames", func() {
   101  		check(
   102  			&logging.ResetStreamFrame{
   103  				StreamID:  987,
   104  				FinalSize: 1234,
   105  				ErrorCode: 42,
   106  			},
   107  			map[string]interface{}{
   108  				"frame_type": "reset_stream",
   109  				"stream_id":  987,
   110  				"error_code": 42,
   111  				"final_size": 1234,
   112  			},
   113  		)
   114  	})
   115  
   116  	It("marshals STOP_SENDING frames", func() {
   117  		check(
   118  			&logging.StopSendingFrame{
   119  				StreamID:  987,
   120  				ErrorCode: 42,
   121  			},
   122  			map[string]interface{}{
   123  				"frame_type": "stop_sending",
   124  				"stream_id":  987,
   125  				"error_code": 42,
   126  			},
   127  		)
   128  	})
   129  
   130  	It("marshals CRYPTO frames", func() {
   131  		check(
   132  			&logging.CryptoFrame{
   133  				Offset: 1337,
   134  				Length: 6,
   135  			},
   136  			map[string]interface{}{
   137  				"frame_type": "crypto",
   138  				"offset":     1337,
   139  				"length":     6,
   140  			},
   141  		)
   142  	})
   143  
   144  	It("marshals NEW_TOKEN frames", func() {
   145  		check(
   146  			&logging.NewTokenFrame{
   147  				Token: []byte{0xde, 0xad, 0xbe, 0xef},
   148  			},
   149  			map[string]interface{}{
   150  				"frame_type": "new_token",
   151  				"token":      map[string]interface{}{"data": "deadbeef"},
   152  			},
   153  		)
   154  	})
   155  
   156  	It("marshals STREAM frames with FIN", func() {
   157  		check(
   158  			&logging.StreamFrame{
   159  				StreamID: 42,
   160  				Offset:   1337,
   161  				Fin:      true,
   162  				Length:   9876,
   163  			},
   164  			map[string]interface{}{
   165  				"frame_type": "stream",
   166  				"stream_id":  42,
   167  				"offset":     1337,
   168  				"fin":        true,
   169  				"length":     9876,
   170  			},
   171  		)
   172  	})
   173  
   174  	It("marshals STREAM frames without FIN", func() {
   175  		check(
   176  			&logging.StreamFrame{
   177  				StreamID: 42,
   178  				Offset:   1337,
   179  				Length:   3,
   180  			},
   181  			map[string]interface{}{
   182  				"frame_type": "stream",
   183  				"stream_id":  42,
   184  				"offset":     1337,
   185  				"length":     3,
   186  			},
   187  		)
   188  	})
   189  
   190  	It("marshals MAX_DATA frames", func() {
   191  		check(
   192  			&logging.MaxDataFrame{
   193  				MaximumData: 1337,
   194  			},
   195  			map[string]interface{}{
   196  				"frame_type": "max_data",
   197  				"maximum":    1337,
   198  			},
   199  		)
   200  	})
   201  
   202  	It("marshals MAX_STREAM_DATA frames", func() {
   203  		check(
   204  			&logging.MaxStreamDataFrame{
   205  				StreamID:          1234,
   206  				MaximumStreamData: 1337,
   207  			},
   208  			map[string]interface{}{
   209  				"frame_type": "max_stream_data",
   210  				"stream_id":  1234,
   211  				"maximum":    1337,
   212  			},
   213  		)
   214  	})
   215  
   216  	It("marshals MAX_STREAMS frames", func() {
   217  		check(
   218  			&logging.MaxStreamsFrame{
   219  				Type:         protocol.StreamTypeBidi,
   220  				MaxStreamNum: 42,
   221  			},
   222  			map[string]interface{}{
   223  				"frame_type":  "max_streams",
   224  				"stream_type": "bidirectional",
   225  				"maximum":     42,
   226  			},
   227  		)
   228  	})
   229  
   230  	It("marshals DATA_BLOCKED frames", func() {
   231  		check(
   232  			&logging.DataBlockedFrame{
   233  				MaximumData: 1337,
   234  			},
   235  			map[string]interface{}{
   236  				"frame_type": "data_blocked",
   237  				"limit":      1337,
   238  			},
   239  		)
   240  	})
   241  
   242  	It("marshals STREAM_DATA_BLOCKED frames", func() {
   243  		check(
   244  			&logging.StreamDataBlockedFrame{
   245  				StreamID:          42,
   246  				MaximumStreamData: 1337,
   247  			},
   248  			map[string]interface{}{
   249  				"frame_type": "stream_data_blocked",
   250  				"stream_id":  42,
   251  				"limit":      1337,
   252  			},
   253  		)
   254  	})
   255  
   256  	It("marshals STREAMS_BLOCKED frames", func() {
   257  		check(
   258  			&logging.StreamsBlockedFrame{
   259  				Type:        protocol.StreamTypeUni,
   260  				StreamLimit: 123,
   261  			},
   262  			map[string]interface{}{
   263  				"frame_type":  "streams_blocked",
   264  				"stream_type": "unidirectional",
   265  				"limit":       123,
   266  			},
   267  		)
   268  	})
   269  
   270  	It("marshals NEW_CONNECTION_ID frames", func() {
   271  		check(
   272  			&logging.NewConnectionIDFrame{
   273  				SequenceNumber:      42,
   274  				RetirePriorTo:       24,
   275  				ConnectionID:        protocol.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef}),
   276  				StatelessResetToken: protocol.StatelessResetToken{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf},
   277  			},
   278  			map[string]interface{}{
   279  				"frame_type":            "new_connection_id",
   280  				"sequence_number":       42,
   281  				"retire_prior_to":       24,
   282  				"length":                4,
   283  				"connection_id":         "deadbeef",
   284  				"stateless_reset_token": "000102030405060708090a0b0c0d0e0f",
   285  			},
   286  		)
   287  	})
   288  
   289  	It("marshals RETIRE_CONNECTION_ID frames", func() {
   290  		check(
   291  			&logging.RetireConnectionIDFrame{
   292  				SequenceNumber: 1337,
   293  			},
   294  			map[string]interface{}{
   295  				"frame_type":      "retire_connection_id",
   296  				"sequence_number": 1337,
   297  			},
   298  		)
   299  	})
   300  
   301  	It("marshals PATH_CHALLENGE frames", func() {
   302  		check(
   303  			&logging.PathChallengeFrame{
   304  				Data: [8]byte{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xc0, 0x01},
   305  			},
   306  			map[string]interface{}{
   307  				"frame_type": "path_challenge",
   308  				"data":       "deadbeefcafec001",
   309  			},
   310  		)
   311  	})
   312  
   313  	It("marshals PATH_RESPONSE frames", func() {
   314  		check(
   315  			&logging.PathResponseFrame{
   316  				Data: [8]byte{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xc0, 0x01},
   317  			},
   318  			map[string]interface{}{
   319  				"frame_type": "path_response",
   320  				"data":       "deadbeefcafec001",
   321  			},
   322  		)
   323  	})
   324  
   325  	It("marshals CONNECTION_CLOSE frames, for application error codes", func() {
   326  		check(
   327  			&logging.ConnectionCloseFrame{
   328  				IsApplicationError: true,
   329  				ErrorCode:          1337,
   330  				ReasonPhrase:       "lorem ipsum",
   331  			},
   332  			map[string]interface{}{
   333  				"frame_type":     "connection_close",
   334  				"error_space":    "application",
   335  				"error_code":     1337,
   336  				"raw_error_code": 1337,
   337  				"reason":         "lorem ipsum",
   338  			},
   339  		)
   340  	})
   341  
   342  	It("marshals CONNECTION_CLOSE frames, for transport error codes", func() {
   343  		check(
   344  			&logging.ConnectionCloseFrame{
   345  				ErrorCode:    uint64(qerr.FlowControlError),
   346  				ReasonPhrase: "lorem ipsum",
   347  			},
   348  			map[string]interface{}{
   349  				"frame_type":     "connection_close",
   350  				"error_space":    "transport",
   351  				"error_code":     "flow_control_error",
   352  				"raw_error_code": int(qerr.FlowControlError),
   353  				"reason":         "lorem ipsum",
   354  			},
   355  		)
   356  	})
   357  
   358  	It("marshals HANDSHAKE_DONE frames", func() {
   359  		check(
   360  			&logging.HandshakeDoneFrame{},
   361  			map[string]interface{}{
   362  				"frame_type": "handshake_done",
   363  			},
   364  		)
   365  	})
   366  
   367  	It("marshals DATAGRAM frames", func() {
   368  		check(
   369  			&logging.DatagramFrame{Length: 1337},
   370  			map[string]interface{}{
   371  				"frame_type": "datagram",
   372  				"length":     1337,
   373  			},
   374  		)
   375  	})
   376  })