Files
golang.net/http2/pipe_test.go
Michael Fraenkel 2ba7206551 http2: track unread bytes when the pipe is broken
Once the pipe is broken, any remaining data needs to be reported as well
as any data that is written but dropped.

The client side flow control can eventually run out of available bytes
to be sent since no WINDOW_UPDATE is sent to reflect the data that is
never read in the pipe.

Updates golang/go#28634

Change-Id: I83f3c9d3614cd92517af2687489d2ccbf3a65456
Reviewed-on: https://go-review.googlesource.com/c/net/+/187377
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2019-10-14 20:34:26 +00:00

143 lines
3.0 KiB
Go

// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package http2
import (
"bytes"
"errors"
"io"
"io/ioutil"
"testing"
)
func TestPipeClose(t *testing.T) {
var p pipe
p.b = new(bytes.Buffer)
a := errors.New("a")
b := errors.New("b")
p.CloseWithError(a)
p.CloseWithError(b)
_, err := p.Read(make([]byte, 1))
if err != a {
t.Errorf("err = %v want %v", err, a)
}
}
func TestPipeDoneChan(t *testing.T) {
var p pipe
done := p.Done()
select {
case <-done:
t.Fatal("done too soon")
default:
}
p.CloseWithError(io.EOF)
select {
case <-done:
default:
t.Fatal("should be done")
}
}
func TestPipeDoneChan_ErrFirst(t *testing.T) {
var p pipe
p.CloseWithError(io.EOF)
done := p.Done()
select {
case <-done:
default:
t.Fatal("should be done")
}
}
func TestPipeDoneChan_Break(t *testing.T) {
var p pipe
done := p.Done()
select {
case <-done:
t.Fatal("done too soon")
default:
}
p.BreakWithError(io.EOF)
select {
case <-done:
default:
t.Fatal("should be done")
}
}
func TestPipeDoneChan_Break_ErrFirst(t *testing.T) {
var p pipe
p.BreakWithError(io.EOF)
done := p.Done()
select {
case <-done:
default:
t.Fatal("should be done")
}
}
func TestPipeCloseWithError(t *testing.T) {
p := &pipe{b: new(bytes.Buffer)}
const body = "foo"
io.WriteString(p, body)
a := errors.New("test error")
p.CloseWithError(a)
all, err := ioutil.ReadAll(p)
if string(all) != body {
t.Errorf("read bytes = %q; want %q", all, body)
}
if err != a {
t.Logf("read error = %v, %v", err, a)
}
if p.Len() != 0 {
t.Errorf("pipe should have 0 unread bytes")
}
// Read and Write should fail.
if n, err := p.Write([]byte("abc")); err != errClosedPipeWrite || n != 0 {
t.Errorf("Write(abc) after close\ngot %v, %v\nwant 0, %v", n, err, errClosedPipeWrite)
}
if n, err := p.Read(make([]byte, 1)); err == nil || n != 0 {
t.Errorf("Read() after close\ngot %v, nil\nwant 0, %v", n, errClosedPipeWrite)
}
if p.Len() != 0 {
t.Errorf("pipe should have 0 unread bytes")
}
}
func TestPipeBreakWithError(t *testing.T) {
p := &pipe{b: new(bytes.Buffer)}
io.WriteString(p, "foo")
a := errors.New("test err")
p.BreakWithError(a)
all, err := ioutil.ReadAll(p)
if string(all) != "" {
t.Errorf("read bytes = %q; want empty string", all)
}
if err != a {
t.Logf("read error = %v, %v", err, a)
}
if p.b != nil {
t.Errorf("buffer should be nil after BreakWithError")
}
if p.Len() != 3 {
t.Errorf("pipe should have 3 unread bytes")
}
// Write should succeed silently.
if n, err := p.Write([]byte("abc")); err != nil || n != 3 {
t.Errorf("Write(abc) after break\ngot %v, %v\nwant 0, nil", n, err)
}
if p.b != nil {
t.Errorf("buffer should be nil after Write")
}
if p.Len() != 6 {
t.Errorf("pipe should have 6 unread bytes")
}
// Read should fail.
if n, err := p.Read(make([]byte, 1)); err == nil || n != 0 {
t.Errorf("Read() after close\ngot %v, nil\nwant 0, not nil", n)
}
}