blob: 32cd5f38b3fdb9443ca9f0a20eadaaf1657f0119 [file] [log] [blame]
Tom Bergan10c134e2017-02-23 14:05:28 -08001// Copyright 2017 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
Tom Bergan10c134e2017-02-23 14:05:28 -08005package http2
6
7import (
8 "bytes"
9 "fmt"
10 "reflect"
11 "testing"
12)
13
14func fmtDataChunk(chunk []byte) string {
15 out := ""
16 var last byte
17 var count int
18 for _, c := range chunk {
19 if c != last {
20 if count > 0 {
21 out += fmt.Sprintf(" x %d ", count)
22 count = 0
23 }
24 out += string([]byte{c})
25 last = c
26 }
27 count++
28 }
29 if count > 0 {
30 out += fmt.Sprintf(" x %d", count)
31 }
32 return out
33}
34
35func fmtDataChunks(chunks [][]byte) string {
36 var out string
37 for _, chunk := range chunks {
38 out += fmt.Sprintf("{%q}", fmtDataChunk(chunk))
39 }
40 return out
41}
42
43func testDataBuffer(t *testing.T, wantBytes []byte, setup func(t *testing.T) *dataBuffer) {
44 // Run setup, then read the remaining bytes from the dataBuffer and check
45 // that they match wantBytes. We use different read sizes to check corner
46 // cases in Read.
47 for _, readSize := range []int{1, 2, 1 * 1024, 32 * 1024} {
48 t.Run(fmt.Sprintf("ReadSize=%d", readSize), func(t *testing.T) {
49 b := setup(t)
50 buf := make([]byte, readSize)
51 var gotRead bytes.Buffer
52 for {
53 n, err := b.Read(buf)
54 gotRead.Write(buf[:n])
55 if err == errReadEmpty {
56 break
57 }
58 if err != nil {
59 t.Fatalf("error after %v bytes: %v", gotRead.Len(), err)
60 }
61 }
62 if got, want := gotRead.Bytes(), wantBytes; !bytes.Equal(got, want) {
63 t.Errorf("FinalRead=%q, want %q", fmtDataChunk(got), fmtDataChunk(want))
64 }
65 })
66 }
67}
68
69func TestDataBufferAllocation(t *testing.T) {
70 writes := [][]byte{
71 bytes.Repeat([]byte("a"), 1*1024-1),
Mikio Hara51392902017-05-13 07:20:15 +090072 []byte("a"),
Tom Bergan10c134e2017-02-23 14:05:28 -080073 bytes.Repeat([]byte("b"), 4*1024-1),
Mikio Hara51392902017-05-13 07:20:15 +090074 []byte("b"),
Tom Bergan10c134e2017-02-23 14:05:28 -080075 bytes.Repeat([]byte("c"), 8*1024-1),
Mikio Hara51392902017-05-13 07:20:15 +090076 []byte("c"),
Tom Bergan10c134e2017-02-23 14:05:28 -080077 bytes.Repeat([]byte("d"), 16*1024-1),
Mikio Hara51392902017-05-13 07:20:15 +090078 []byte("d"),
Tom Bergan10c134e2017-02-23 14:05:28 -080079 bytes.Repeat([]byte("e"), 32*1024),
80 }
81 var wantRead bytes.Buffer
82 for _, p := range writes {
83 wantRead.Write(p)
84 }
85
86 testDataBuffer(t, wantRead.Bytes(), func(t *testing.T) *dataBuffer {
87 b := &dataBuffer{}
88 for _, p := range writes {
89 if n, err := b.Write(p); n != len(p) || err != nil {
90 t.Fatalf("Write(%q x %d)=%v,%v want %v,nil", p[:1], len(p), n, err, len(p))
91 }
92 }
93 want := [][]byte{
94 bytes.Repeat([]byte("a"), 1*1024),
95 bytes.Repeat([]byte("b"), 4*1024),
96 bytes.Repeat([]byte("c"), 8*1024),
97 bytes.Repeat([]byte("d"), 16*1024),
98 bytes.Repeat([]byte("e"), 16*1024),
99 bytes.Repeat([]byte("e"), 16*1024),
100 }
101 if !reflect.DeepEqual(b.chunks, want) {
102 t.Errorf("dataBuffer.chunks\ngot: %s\nwant: %s", fmtDataChunks(b.chunks), fmtDataChunks(want))
103 }
104 return b
105 })
106}
107
108func TestDataBufferAllocationWithExpected(t *testing.T) {
109 writes := [][]byte{
110 bytes.Repeat([]byte("a"), 1*1024), // allocates 16KB
111 bytes.Repeat([]byte("b"), 14*1024),
112 bytes.Repeat([]byte("c"), 15*1024), // allocates 16KB more
113 bytes.Repeat([]byte("d"), 2*1024),
114 bytes.Repeat([]byte("e"), 1*1024), // overflows 32KB expectation, allocates just 1KB
115 }
116 var wantRead bytes.Buffer
117 for _, p := range writes {
118 wantRead.Write(p)
119 }
120
121 testDataBuffer(t, wantRead.Bytes(), func(t *testing.T) *dataBuffer {
122 b := &dataBuffer{expected: 32 * 1024}
123 for _, p := range writes {
124 if n, err := b.Write(p); n != len(p) || err != nil {
125 t.Fatalf("Write(%q x %d)=%v,%v want %v,nil", p[:1], len(p), n, err, len(p))
126 }
127 }
128 want := [][]byte{
129 append(bytes.Repeat([]byte("a"), 1*1024), append(bytes.Repeat([]byte("b"), 14*1024), bytes.Repeat([]byte("c"), 1*1024)...)...),
130 append(bytes.Repeat([]byte("c"), 14*1024), bytes.Repeat([]byte("d"), 2*1024)...),
131 bytes.Repeat([]byte("e"), 1*1024),
132 }
133 if !reflect.DeepEqual(b.chunks, want) {
134 t.Errorf("dataBuffer.chunks\ngot: %s\nwant: %s", fmtDataChunks(b.chunks), fmtDataChunks(want))
135 }
136 return b
137 })
138}
139
140func TestDataBufferWriteAfterPartialRead(t *testing.T) {
141 testDataBuffer(t, []byte("cdxyz"), func(t *testing.T) *dataBuffer {
142 b := &dataBuffer{}
143 if n, err := b.Write([]byte("abcd")); n != 4 || err != nil {
144 t.Fatalf("Write(\"abcd\")=%v,%v want 4,nil", n, err)
145 }
146 p := make([]byte, 2)
147 if n, err := b.Read(p); n != 2 || err != nil || !bytes.Equal(p, []byte("ab")) {
148 t.Fatalf("Read()=%q,%v,%v want \"ab\",2,nil", p, n, err)
149 }
150 if n, err := b.Write([]byte("xyz")); n != 3 || err != nil {
151 t.Fatalf("Write(\"xyz\")=%v,%v want 3,nil", n, err)
152 }
153 return b
154 })
155}