1// Copyright 2016 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package http2
6
7import (
8	"fmt"
9	"math"
10	"reflect"
11	"testing"
12)
13
14func makeWriteNonStreamRequest() FrameWriteRequest {
15	return FrameWriteRequest{writeSettingsAck{}, nil, nil}
16}
17
18func makeWriteHeadersRequest(streamID uint32) FrameWriteRequest {
19	st := &stream{id: streamID}
20	return FrameWriteRequest{&writeResHeaders{streamID: streamID, httpResCode: 200}, st, nil}
21}
22
23func makeHandlerPanicRST(streamID uint32) FrameWriteRequest {
24	st := &stream{id: streamID}
25	return FrameWriteRequest{&handlerPanicRST{StreamID: streamID}, st, nil}
26}
27
28func checkConsume(wr FrameWriteRequest, nbytes int32, want []FrameWriteRequest) error {
29	consumed, rest, n := wr.Consume(nbytes)
30	var wantConsumed, wantRest FrameWriteRequest
31	switch len(want) {
32	case 0:
33	case 1:
34		wantConsumed = want[0]
35	case 2:
36		wantConsumed = want[0]
37		wantRest = want[1]
38	}
39	if !reflect.DeepEqual(consumed, wantConsumed) || !reflect.DeepEqual(rest, wantRest) || n != len(want) {
40		return fmt.Errorf("got %v, %v, %v\nwant %v, %v, %v", consumed, rest, n, wantConsumed, wantRest, len(want))
41	}
42	return nil
43}
44
45func TestFrameWriteRequestNonData(t *testing.T) {
46	wr := makeWriteNonStreamRequest()
47	if got, want := wr.DataSize(), 0; got != want {
48		t.Errorf("DataSize: got %v, want %v", got, want)
49	}
50
51	// Non-DATA frames are always consumed whole.
52	if err := checkConsume(wr, 0, []FrameWriteRequest{wr}); err != nil {
53		t.Errorf("Consume:\n%v", err)
54	}
55}
56
57func TestFrameWriteRequestData(t *testing.T) {
58	st := &stream{
59		id: 1,
60		sc: &serverConn{maxFrameSize: 16},
61	}
62	const size = 32
63	wr := FrameWriteRequest{&writeData{st.id, make([]byte, size), true}, st, make(chan error)}
64	if got, want := wr.DataSize(), size; got != want {
65		t.Errorf("DataSize: got %v, want %v", got, want)
66	}
67
68	// No flow-control bytes available: cannot consume anything.
69	if err := checkConsume(wr, math.MaxInt32, []FrameWriteRequest{}); err != nil {
70		t.Errorf("Consume(limited by flow control):\n%v", err)
71	}
72
73	// Add enough flow-control bytes to consume the entire frame,
74	// but we're now restricted by st.sc.maxFrameSize.
75	st.flow.add(size)
76	want := []FrameWriteRequest{
77		{
78			write:  &writeData{st.id, make([]byte, st.sc.maxFrameSize), false},
79			stream: st,
80			done:   nil,
81		},
82		{
83			write:  &writeData{st.id, make([]byte, size-st.sc.maxFrameSize), true},
84			stream: st,
85			done:   wr.done,
86		},
87	}
88	if err := checkConsume(wr, math.MaxInt32, want); err != nil {
89		t.Errorf("Consume(limited by maxFrameSize):\n%v", err)
90	}
91	rest := want[1]
92
93	// Consume 8 bytes from the remaining frame.
94	want = []FrameWriteRequest{
95		{
96			write:  &writeData{st.id, make([]byte, 8), false},
97			stream: st,
98			done:   nil,
99		},
100		{
101			write:  &writeData{st.id, make([]byte, size-st.sc.maxFrameSize-8), true},
102			stream: st,
103			done:   wr.done,
104		},
105	}
106	if err := checkConsume(rest, 8, want); err != nil {
107		t.Errorf("Consume(8):\n%v", err)
108	}
109	rest = want[1]
110
111	// Consume all remaining bytes.
112	want = []FrameWriteRequest{
113		{
114			write:  &writeData{st.id, make([]byte, size-st.sc.maxFrameSize-8), true},
115			stream: st,
116			done:   wr.done,
117		},
118	}
119	if err := checkConsume(rest, math.MaxInt32, want); err != nil {
120		t.Errorf("Consume(remainder):\n%v", err)
121	}
122}
123
124func TestFrameWriteRequest_StreamID(t *testing.T) {
125	const streamID = 123
126	wr := FrameWriteRequest{write: streamError(streamID, ErrCodeNo)}
127	if got := wr.StreamID(); got != streamID {
128		t.Errorf("FrameWriteRequest(StreamError) = %v; want %v", got, streamID)
129	}
130}
131