329 строки
7.7 KiB
Go
329 строки
7.7 KiB
Go
/*
|
|
*
|
|
* Copyright 2017 gRPC authors.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*/
|
|
|
|
package bufconn
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"net"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
"google.golang.org/grpc/internal/grpctest"
|
|
)
|
|
|
|
type s struct {
|
|
grpctest.Tester
|
|
}
|
|
|
|
func Test(t *testing.T) {
|
|
grpctest.RunSubTests(t, s{})
|
|
}
|
|
|
|
func testRW(r io.Reader, w io.Writer) error {
|
|
for i := 0; i < 20; i++ {
|
|
d := make([]byte, i)
|
|
for j := 0; j < i; j++ {
|
|
d[j] = byte(i - j)
|
|
}
|
|
var rn int
|
|
var rerr error
|
|
b := make([]byte, i)
|
|
done := make(chan struct{})
|
|
go func() {
|
|
for rn < len(b) && rerr == nil {
|
|
var x int
|
|
x, rerr = r.Read(b[rn:])
|
|
rn += x
|
|
}
|
|
close(done)
|
|
}()
|
|
wn, werr := w.Write(d)
|
|
if wn != i || werr != nil {
|
|
return fmt.Errorf("%v: w.Write(%v) = %v, %v; want %v, nil", i, d, wn, werr, i)
|
|
}
|
|
select {
|
|
case <-done:
|
|
case <-time.After(500 * time.Millisecond):
|
|
return fmt.Errorf("%v: r.Read never returned", i)
|
|
}
|
|
if rn != i || rerr != nil {
|
|
return fmt.Errorf("%v: r.Read = %v, %v; want %v, nil", i, rn, rerr, i)
|
|
}
|
|
if !reflect.DeepEqual(b, d) {
|
|
return fmt.Errorf("%v: r.Read read %v; want %v", i, b, d)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s) TestPipe(t *testing.T) {
|
|
p := newPipe(10)
|
|
if err := testRW(p, p); err != nil {
|
|
t.Fatalf(err.Error())
|
|
}
|
|
}
|
|
|
|
func (s) TestPipeClose(t *testing.T) {
|
|
p := newPipe(10)
|
|
p.Close()
|
|
if _, err := p.Write(nil); err != io.ErrClosedPipe {
|
|
t.Fatalf("p.Write = _, %v; want _, %v", err, io.ErrClosedPipe)
|
|
}
|
|
if _, err := p.Read(nil); err != io.ErrClosedPipe {
|
|
t.Fatalf("p.Read = _, %v; want _, %v", err, io.ErrClosedPipe)
|
|
}
|
|
}
|
|
|
|
func (s) TestConn(t *testing.T) {
|
|
p1, p2 := newPipe(10), newPipe(10)
|
|
c1, c2 := &conn{p1, p2}, &conn{p2, p1}
|
|
|
|
if err := testRW(c1, c2); err != nil {
|
|
t.Fatalf(err.Error())
|
|
}
|
|
if err := testRW(c2, c1); err != nil {
|
|
t.Fatalf(err.Error())
|
|
}
|
|
}
|
|
|
|
func (s) TestConnCloseWithData(t *testing.T) {
|
|
lis := Listen(7)
|
|
errChan := make(chan error, 1)
|
|
var lisConn net.Conn
|
|
go func() {
|
|
var err error
|
|
if lisConn, err = lis.Accept(); err != nil {
|
|
errChan <- err
|
|
}
|
|
close(errChan)
|
|
}()
|
|
dialConn, err := lis.Dial()
|
|
if err != nil {
|
|
t.Fatalf("Dial error: %v", err)
|
|
}
|
|
if err := <-errChan; err != nil {
|
|
t.Fatalf("Listen error: %v", err)
|
|
}
|
|
|
|
// Write some data on both sides of the connection.
|
|
n, err := dialConn.Write([]byte("hello"))
|
|
if n != 5 || err != nil {
|
|
t.Fatalf("dialConn.Write([]byte{\"hello\"}) = %v, %v; want 5, <nil>", n, err)
|
|
}
|
|
n, err = lisConn.Write([]byte("hello"))
|
|
if n != 5 || err != nil {
|
|
t.Fatalf("lisConn.Write([]byte{\"hello\"}) = %v, %v; want 5, <nil>", n, err)
|
|
}
|
|
|
|
// Close dial-side; writes from either side should fail.
|
|
dialConn.Close()
|
|
if _, err := lisConn.Write([]byte("hello")); err != io.ErrClosedPipe {
|
|
t.Fatalf("lisConn.Write() = _, <nil>; want _, <non-nil>")
|
|
}
|
|
if _, err := dialConn.Write([]byte("hello")); err != io.ErrClosedPipe {
|
|
t.Fatalf("dialConn.Write() = _, <nil>; want _, <non-nil>")
|
|
}
|
|
|
|
// Read from both sides; reads on lisConn should work, but dialConn should
|
|
// fail.
|
|
buf := make([]byte, 6)
|
|
if _, err := dialConn.Read(buf); err != io.ErrClosedPipe {
|
|
t.Fatalf("dialConn.Read(buf) = %v, %v; want _, io.ErrClosedPipe", n, err)
|
|
}
|
|
n, err = lisConn.Read(buf)
|
|
if n != 5 || err != nil {
|
|
t.Fatalf("lisConn.Read(buf) = %v, %v; want 5, <nil>", n, err)
|
|
}
|
|
}
|
|
|
|
func (s) TestListener(t *testing.T) {
|
|
l := Listen(7)
|
|
var s net.Conn
|
|
var serr error
|
|
done := make(chan struct{})
|
|
go func() {
|
|
s, serr = l.Accept()
|
|
close(done)
|
|
}()
|
|
c, cerr := l.Dial()
|
|
<-done
|
|
if cerr != nil || serr != nil {
|
|
t.Fatalf("cerr = %v, serr = %v; want nil, nil", cerr, serr)
|
|
}
|
|
if err := testRW(c, s); err != nil {
|
|
t.Fatalf(err.Error())
|
|
}
|
|
if err := testRW(s, c); err != nil {
|
|
t.Fatalf(err.Error())
|
|
}
|
|
}
|
|
|
|
func (s) TestCloseWhileDialing(t *testing.T) {
|
|
l := Listen(7)
|
|
var c net.Conn
|
|
var err error
|
|
done := make(chan struct{})
|
|
go func() {
|
|
c, err = l.Dial()
|
|
close(done)
|
|
}()
|
|
l.Close()
|
|
<-done
|
|
if c != nil || err != errClosed {
|
|
t.Fatalf("c, err = %v, %v; want nil, %v", c, err, errClosed)
|
|
}
|
|
}
|
|
|
|
func (s) TestCloseWhileAccepting(t *testing.T) {
|
|
l := Listen(7)
|
|
var c net.Conn
|
|
var err error
|
|
done := make(chan struct{})
|
|
go func() {
|
|
c, err = l.Accept()
|
|
close(done)
|
|
}()
|
|
l.Close()
|
|
<-done
|
|
if c != nil || err != errClosed {
|
|
t.Fatalf("c, err = %v, %v; want nil, %v", c, err, errClosed)
|
|
}
|
|
}
|
|
|
|
func (s) TestDeadline(t *testing.T) {
|
|
sig := make(chan error, 2)
|
|
blockingWrite := func(conn net.Conn) {
|
|
_, err := conn.Write([]byte("0123456789"))
|
|
sig <- err
|
|
}
|
|
|
|
blockingRead := func(conn net.Conn) {
|
|
_, err := conn.Read(make([]byte, 10))
|
|
sig <- err
|
|
}
|
|
|
|
p1, p2 := newPipe(5), newPipe(5)
|
|
c1, c2 := &conn{p1, p1}, &conn{p2, p2}
|
|
defer c1.Close()
|
|
defer c2.Close()
|
|
|
|
// Test with deadline
|
|
c1.SetWriteDeadline(time.Now())
|
|
|
|
go blockingWrite(c1)
|
|
select {
|
|
case <-time.After(100 * time.Millisecond):
|
|
t.Fatalf("Write timeout timed out, c = %v", c1)
|
|
case err := <-sig:
|
|
if netErr, ok := err.(net.Error); ok {
|
|
if !netErr.Timeout() {
|
|
t.Fatalf("Write returned unexpected error, c = %v, err = %v", c1, netErr)
|
|
}
|
|
} else {
|
|
t.Fatalf("Write returned unexpected error, c = %v, err = %v", c1, err)
|
|
}
|
|
}
|
|
|
|
c2.SetReadDeadline(time.Now())
|
|
|
|
go blockingRead(c2)
|
|
select {
|
|
case <-time.After(100 * time.Millisecond):
|
|
t.Fatalf("Read timeout timed out, c = %v", c2)
|
|
case err := <-sig:
|
|
if netErr, ok := err.(net.Error); ok {
|
|
if !netErr.Timeout() {
|
|
t.Fatalf("Read returned unexpected error, c = %v, err = %v", c2, netErr)
|
|
}
|
|
} else {
|
|
t.Fatalf("Read returned unexpected error, c = %v, err = %v", c2, err)
|
|
}
|
|
}
|
|
|
|
// Test timing out pending reads/writes
|
|
c1.SetWriteDeadline(time.Time{})
|
|
c2.SetReadDeadline(time.Time{})
|
|
|
|
go blockingWrite(c1)
|
|
select {
|
|
case <-time.After(100 * time.Millisecond):
|
|
case err := <-sig:
|
|
t.Fatalf("Write returned before timeout, err = %v", err)
|
|
}
|
|
|
|
c1.SetWriteDeadline(time.Now())
|
|
select {
|
|
case <-time.After(100 * time.Millisecond):
|
|
t.Fatalf("Write timeout timed out, c = %v", c1)
|
|
case err := <-sig:
|
|
if netErr, ok := err.(net.Error); ok {
|
|
if !netErr.Timeout() {
|
|
t.Fatalf("Write returned unexpected error, c = %v, err = %v", c1, netErr)
|
|
}
|
|
} else {
|
|
t.Fatalf("Write returned unexpected error, c = %v, err = %v", c1, err)
|
|
}
|
|
}
|
|
|
|
go blockingRead(c2)
|
|
select {
|
|
case <-time.After(100 * time.Millisecond):
|
|
case err := <-sig:
|
|
t.Fatalf("Read returned before timeout, err = %v", err)
|
|
}
|
|
|
|
c2.SetReadDeadline(time.Now())
|
|
select {
|
|
case <-time.After(100 * time.Millisecond):
|
|
t.Fatalf("Read timeout timed out, c = %v", c2)
|
|
case err := <-sig:
|
|
if netErr, ok := err.(net.Error); ok {
|
|
if !netErr.Timeout() {
|
|
t.Fatalf("Read returned unexpected error, c = %v, err = %v", c2, netErr)
|
|
}
|
|
} else {
|
|
t.Fatalf("Read returned unexpected error, c = %v, err = %v", c2, err)
|
|
}
|
|
}
|
|
|
|
// Test non-blocking read/write
|
|
c1, c2 = &conn{p1, p2}, &conn{p2, p1}
|
|
|
|
c1.SetWriteDeadline(time.Now().Add(10 * time.Second))
|
|
c2.SetReadDeadline(time.Now().Add(10 * time.Second))
|
|
|
|
// Not blocking here
|
|
go blockingWrite(c1)
|
|
go blockingRead(c2)
|
|
|
|
// Read response from both routines
|
|
for i := 0; i < 2; i++ {
|
|
select {
|
|
case <-time.After(100 * time.Millisecond):
|
|
t.Fatalf("Read/Write timed out, c1 = %v, c2 = %v", c1, c2)
|
|
case err := <-sig:
|
|
if err != nil {
|
|
t.Fatalf("Read/Write failed to complete, c1 = %v, c2 = %v, err = %v", c1, c2, err)
|
|
}
|
|
}
|
|
}
|
|
}
|