forked from quic-go/quic-go
404 lines
8.2 KiB
Go
404 lines
8.2 KiB
Go
package qlog
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/francoispqt/gojay"
|
|
"github.com/quic-go/quic-go/internal/protocol"
|
|
"github.com/quic-go/quic-go/internal/qerr"
|
|
"github.com/quic-go/quic-go/logging"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func check(t *testing.T, f logging.Frame, expected map[string]interface{}) {
|
|
buf := &bytes.Buffer{}
|
|
enc := gojay.NewEncoder(buf)
|
|
err := enc.Encode(frame{Frame: f})
|
|
require.NoError(t, err)
|
|
data := buf.Bytes()
|
|
require.True(t, json.Valid(data))
|
|
checkEncoding(t, data, expected)
|
|
}
|
|
|
|
func TestPingFrame(t *testing.T) {
|
|
check(t,
|
|
&logging.PingFrame{},
|
|
map[string]interface{}{
|
|
"frame_type": "ping",
|
|
},
|
|
)
|
|
}
|
|
|
|
func TestAckFrame(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
frame *logging.AckFrame
|
|
expected map[string]interface{}
|
|
}{
|
|
{
|
|
name: "with delay and single packet range",
|
|
frame: &logging.AckFrame{
|
|
DelayTime: 86 * time.Millisecond,
|
|
AckRanges: []logging.AckRange{{Smallest: 120, Largest: 120}},
|
|
},
|
|
expected: map[string]interface{}{
|
|
"frame_type": "ack",
|
|
"ack_delay": 86,
|
|
"acked_ranges": [][]float64{{120}},
|
|
},
|
|
},
|
|
{
|
|
name: "without delay",
|
|
frame: &logging.AckFrame{
|
|
AckRanges: []logging.AckRange{{Smallest: 120, Largest: 120}},
|
|
},
|
|
expected: map[string]interface{}{
|
|
"frame_type": "ack",
|
|
"acked_ranges": [][]float64{{120}},
|
|
},
|
|
},
|
|
{
|
|
name: "with ECN counts",
|
|
frame: &logging.AckFrame{
|
|
AckRanges: []logging.AckRange{{Smallest: 120, Largest: 120}},
|
|
ECT0: 10,
|
|
ECT1: 100,
|
|
ECNCE: 1000,
|
|
},
|
|
expected: map[string]interface{}{
|
|
"frame_type": "ack",
|
|
"acked_ranges": [][]float64{{120}},
|
|
"ect0": 10,
|
|
"ect1": 100,
|
|
"ce": 1000,
|
|
},
|
|
},
|
|
{
|
|
name: "with multiple ranges",
|
|
frame: &logging.AckFrame{
|
|
DelayTime: 86 * time.Millisecond,
|
|
AckRanges: []logging.AckRange{
|
|
{Smallest: 5, Largest: 50},
|
|
{Smallest: 100, Largest: 120},
|
|
},
|
|
},
|
|
expected: map[string]interface{}{
|
|
"frame_type": "ack",
|
|
"ack_delay": 86,
|
|
"acked_ranges": [][]float64{
|
|
{5, 50},
|
|
{100, 120},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
check(t, tt.frame, tt.expected)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestResetStreamFrame(t *testing.T) {
|
|
check(t,
|
|
&logging.ResetStreamFrame{
|
|
StreamID: 987,
|
|
FinalSize: 1234,
|
|
ErrorCode: 42,
|
|
},
|
|
map[string]interface{}{
|
|
"frame_type": "reset_stream",
|
|
"stream_id": 987,
|
|
"error_code": 42,
|
|
"final_size": 1234,
|
|
},
|
|
)
|
|
}
|
|
|
|
func TestStopSendingFrame(t *testing.T) {
|
|
check(t,
|
|
&logging.StopSendingFrame{
|
|
StreamID: 987,
|
|
ErrorCode: 42,
|
|
},
|
|
map[string]interface{}{
|
|
"frame_type": "stop_sending",
|
|
"stream_id": 987,
|
|
"error_code": 42,
|
|
},
|
|
)
|
|
}
|
|
|
|
func TestCryptoFrame(t *testing.T) {
|
|
check(t,
|
|
&logging.CryptoFrame{
|
|
Offset: 1337,
|
|
Length: 6,
|
|
},
|
|
map[string]interface{}{
|
|
"frame_type": "crypto",
|
|
"offset": 1337,
|
|
"length": 6,
|
|
},
|
|
)
|
|
}
|
|
|
|
func TestNewTokenFrame(t *testing.T) {
|
|
check(t,
|
|
&logging.NewTokenFrame{
|
|
Token: []byte{0xde, 0xad, 0xbe, 0xef},
|
|
},
|
|
map[string]interface{}{
|
|
"frame_type": "new_token",
|
|
"token": map[string]interface{}{"data": "deadbeef"},
|
|
},
|
|
)
|
|
}
|
|
|
|
func TestStreamFrame(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
frame *logging.StreamFrame
|
|
expected map[string]interface{}
|
|
}{
|
|
{
|
|
name: "with FIN",
|
|
frame: &logging.StreamFrame{
|
|
StreamID: 42,
|
|
Offset: 1337,
|
|
Fin: true,
|
|
Length: 9876,
|
|
},
|
|
expected: map[string]interface{}{
|
|
"frame_type": "stream",
|
|
"stream_id": 42,
|
|
"offset": 1337,
|
|
"fin": true,
|
|
"length": 9876,
|
|
},
|
|
},
|
|
{
|
|
name: "without FIN",
|
|
frame: &logging.StreamFrame{
|
|
StreamID: 42,
|
|
Offset: 1337,
|
|
Length: 3,
|
|
},
|
|
expected: map[string]interface{}{
|
|
"frame_type": "stream",
|
|
"stream_id": 42,
|
|
"offset": 1337,
|
|
"length": 3,
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
check(t, tt.frame, tt.expected)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMaxDataFrame(t *testing.T) {
|
|
check(t,
|
|
&logging.MaxDataFrame{
|
|
MaximumData: 1337,
|
|
},
|
|
map[string]interface{}{
|
|
"frame_type": "max_data",
|
|
"maximum": 1337,
|
|
},
|
|
)
|
|
}
|
|
|
|
func TestMaxStreamDataFrame(t *testing.T) {
|
|
check(t,
|
|
&logging.MaxStreamDataFrame{
|
|
StreamID: 1234,
|
|
MaximumStreamData: 1337,
|
|
},
|
|
map[string]interface{}{
|
|
"frame_type": "max_stream_data",
|
|
"stream_id": 1234,
|
|
"maximum": 1337,
|
|
},
|
|
)
|
|
}
|
|
|
|
func TestMaxStreamsFrame(t *testing.T) {
|
|
check(t,
|
|
&logging.MaxStreamsFrame{
|
|
Type: protocol.StreamTypeBidi,
|
|
MaxStreamNum: 42,
|
|
},
|
|
map[string]interface{}{
|
|
"frame_type": "max_streams",
|
|
"stream_type": "bidirectional",
|
|
"maximum": 42,
|
|
},
|
|
)
|
|
}
|
|
|
|
func TestDataBlockedFrame(t *testing.T) {
|
|
check(t,
|
|
&logging.DataBlockedFrame{
|
|
MaximumData: 1337,
|
|
},
|
|
map[string]interface{}{
|
|
"frame_type": "data_blocked",
|
|
"limit": 1337,
|
|
},
|
|
)
|
|
}
|
|
|
|
func TestStreamDataBlockedFrame(t *testing.T) {
|
|
check(t,
|
|
&logging.StreamDataBlockedFrame{
|
|
StreamID: 42,
|
|
MaximumStreamData: 1337,
|
|
},
|
|
map[string]interface{}{
|
|
"frame_type": "stream_data_blocked",
|
|
"stream_id": 42,
|
|
"limit": 1337,
|
|
},
|
|
)
|
|
}
|
|
|
|
func TestStreamsBlockedFrame(t *testing.T) {
|
|
check(t,
|
|
&logging.StreamsBlockedFrame{
|
|
Type: protocol.StreamTypeUni,
|
|
StreamLimit: 123,
|
|
},
|
|
map[string]interface{}{
|
|
"frame_type": "streams_blocked",
|
|
"stream_type": "unidirectional",
|
|
"limit": 123,
|
|
},
|
|
)
|
|
}
|
|
|
|
func TestNewConnectionIDFrame(t *testing.T) {
|
|
check(t,
|
|
&logging.NewConnectionIDFrame{
|
|
SequenceNumber: 42,
|
|
RetirePriorTo: 24,
|
|
ConnectionID: protocol.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef}),
|
|
StatelessResetToken: protocol.StatelessResetToken{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf},
|
|
},
|
|
map[string]interface{}{
|
|
"frame_type": "new_connection_id",
|
|
"sequence_number": 42,
|
|
"retire_prior_to": 24,
|
|
"length": 4,
|
|
"connection_id": "deadbeef",
|
|
"stateless_reset_token": "000102030405060708090a0b0c0d0e0f",
|
|
},
|
|
)
|
|
}
|
|
|
|
func TestRetireConnectionIDFrame(t *testing.T) {
|
|
check(t,
|
|
&logging.RetireConnectionIDFrame{
|
|
SequenceNumber: 1337,
|
|
},
|
|
map[string]interface{}{
|
|
"frame_type": "retire_connection_id",
|
|
"sequence_number": 1337,
|
|
},
|
|
)
|
|
}
|
|
|
|
func TestPathChallengeFrame(t *testing.T) {
|
|
check(t,
|
|
&logging.PathChallengeFrame{
|
|
Data: [8]byte{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xc0, 0x01},
|
|
},
|
|
map[string]interface{}{
|
|
"frame_type": "path_challenge",
|
|
"data": "deadbeefcafec001",
|
|
},
|
|
)
|
|
}
|
|
|
|
func TestPathResponseFrame(t *testing.T) {
|
|
check(t,
|
|
&logging.PathResponseFrame{
|
|
Data: [8]byte{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xc0, 0x01},
|
|
},
|
|
map[string]interface{}{
|
|
"frame_type": "path_response",
|
|
"data": "deadbeefcafec001",
|
|
},
|
|
)
|
|
}
|
|
|
|
func TestConnectionCloseFrame(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
frame *logging.ConnectionCloseFrame
|
|
expected map[string]interface{}
|
|
}{
|
|
{
|
|
name: "application error code",
|
|
frame: &logging.ConnectionCloseFrame{
|
|
IsApplicationError: true,
|
|
ErrorCode: 1337,
|
|
ReasonPhrase: "lorem ipsum",
|
|
},
|
|
expected: map[string]interface{}{
|
|
"frame_type": "connection_close",
|
|
"error_space": "application",
|
|
"error_code": 1337,
|
|
"raw_error_code": 1337,
|
|
"reason": "lorem ipsum",
|
|
},
|
|
},
|
|
{
|
|
name: "transport error code",
|
|
frame: &logging.ConnectionCloseFrame{
|
|
ErrorCode: uint64(qerr.FlowControlError),
|
|
ReasonPhrase: "lorem ipsum",
|
|
},
|
|
expected: map[string]interface{}{
|
|
"frame_type": "connection_close",
|
|
"error_space": "transport",
|
|
"error_code": "flow_control_error",
|
|
"raw_error_code": int(qerr.FlowControlError),
|
|
"reason": "lorem ipsum",
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
check(t, tt.frame, tt.expected)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestHandshakeDoneFrame(t *testing.T) {
|
|
check(t,
|
|
&logging.HandshakeDoneFrame{},
|
|
map[string]interface{}{
|
|
"frame_type": "handshake_done",
|
|
},
|
|
)
|
|
}
|
|
|
|
func TestDatagramFrame(t *testing.T) {
|
|
check(t,
|
|
&logging.DatagramFrame{Length: 1337},
|
|
map[string]interface{}{
|
|
"frame_type": "datagram",
|
|
"length": 1337,
|
|
},
|
|
)
|
|
}
|