зеркало из https://github.com/golang/build.git
303 строки
6.5 KiB
Go
303 строки
6.5 KiB
Go
// Copyright 2015 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 revdial
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"io"
|
|
"io/ioutil"
|
|
"net"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"golang.org/x/net/nettest"
|
|
)
|
|
|
|
func TestDialer(t *testing.T) {
|
|
pr, pw := io.Pipe()
|
|
var out bytes.Buffer
|
|
d := NewDialer(bufio.NewReadWriter(
|
|
bufio.NewReader(pr),
|
|
bufio.NewWriter(&out),
|
|
), ioutil.NopCloser(nil))
|
|
|
|
c, err := d.Dial()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if c.(*conn).id != 1 {
|
|
t.Fatalf("first id = %d; want 1", c.(*conn).id)
|
|
}
|
|
c.Close() // to verify incoming write frames don't block
|
|
|
|
c, err = d.Dial()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if c.(*conn).id != 2 {
|
|
t.Fatalf("second id = %d; want 2", c.(*conn).id)
|
|
}
|
|
|
|
if g, w := len(d.conns), 1; g != w {
|
|
t.Errorf("size of conns map after dial+close+dial = %v; want %v", g, w)
|
|
}
|
|
|
|
go func() {
|
|
// Write "b" and then "ar", and read it as "bar"
|
|
pw.Write([]byte{byte(frameWrite), 0, 0, 0, 2, 0, 1, 'b'})
|
|
pw.Write([]byte{byte(frameWrite), 0, 0, 0, 1, 0, 1, 'x'}) // verify doesn't block first conn
|
|
pw.Write([]byte{byte(frameWrite), 0, 0, 0, 2, 0, 2, 'a', 'r'})
|
|
}()
|
|
buf := make([]byte, 3)
|
|
if n, err := io.ReadFull(c, buf); err != nil {
|
|
t.Fatalf("ReadFul = %v (%q), %v", n, buf[:n], err)
|
|
}
|
|
if string(buf) != "bar" {
|
|
t.Fatalf("read = %q; want bar", buf)
|
|
}
|
|
if _, err := io.WriteString(c, "hello, world"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
got := out.String()
|
|
want := "N\x00\x00\x00\x01\x00\x00" +
|
|
"C\x00\x00\x00\x01\x00\x00" +
|
|
"N\x00\x00\x00\x02\x00\x00" +
|
|
"W\x00\x00\x00\x02\x00\fhello, world"
|
|
if got != want {
|
|
t.Errorf("Written on wire differs.\nWrote: %q\n Want: %q", got, want)
|
|
}
|
|
}
|
|
|
|
func TestListener(t *testing.T) {
|
|
pr, pw := io.Pipe()
|
|
var out bytes.Buffer
|
|
ln := NewListener(bufio.NewReadWriter(
|
|
bufio.NewReader(pr),
|
|
bufio.NewWriter(&out),
|
|
))
|
|
go io.WriteString(pw, "N\x00\x00\x00\x42\x00\x00")
|
|
c, err := ln.Accept()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if g, w := c.(*conn).id, uint32(0x42); g != w {
|
|
t.Errorf("conn id = %d; want %d", g, w)
|
|
}
|
|
go func() {
|
|
io.WriteString(pw, "W\x00\x00\x00\x42\x00\x03"+"foo")
|
|
io.WriteString(pw, "W\x00\x00\x00\x42\x00\x03"+"bar")
|
|
io.WriteString(pw, "C\x00\x00\x00\x42\x00\x00")
|
|
}()
|
|
slurp, err := ioutil.ReadAll(c)
|
|
if g, w := string(slurp), "foobar"; g != w {
|
|
t.Errorf("Read %q; want %q", g, w)
|
|
}
|
|
if err != nil {
|
|
t.Errorf("Read = %v", err)
|
|
}
|
|
ln.Close()
|
|
if _, err := ln.Accept(); err == nil {
|
|
t.Fatalf("Accept after Closed returned nil error; want error")
|
|
}
|
|
|
|
io.WriteString(c, "first write")
|
|
io.WriteString(c, "second write")
|
|
c.Close()
|
|
got := out.String()
|
|
want := "W\x00\x00\x00B\x00\vfirst write" +
|
|
"W\x00\x00\x00B\x00\fsecond write" +
|
|
"C\x00\x00\x00B\x00\x00"
|
|
if got != want {
|
|
t.Errorf("Wrote: %q\n Want: %q", got, want)
|
|
}
|
|
}
|
|
|
|
func TestInterop(t *testing.T) {
|
|
var na, nb net.Conn
|
|
if true {
|
|
tln, err := net.Listen("tcp", "127.0.0.1:0")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer tln.Close()
|
|
na, err = net.Dial("tcp", tln.Addr().String())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
nb, err = tln.Accept()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
} else {
|
|
// TODO(bradfitz): also run this way
|
|
na, nb = net.Pipe()
|
|
}
|
|
defer na.Close()
|
|
defer nb.Close()
|
|
ln := NewListener(bufio.NewReadWriter(
|
|
bufio.NewReader(na),
|
|
bufio.NewWriter(na),
|
|
))
|
|
defer ln.Close()
|
|
d := NewDialer(bufio.NewReadWriter(
|
|
bufio.NewReader(nb),
|
|
bufio.NewWriter(nb),
|
|
), ioutil.NopCloser(nil))
|
|
defer d.Close()
|
|
|
|
var wg sync.WaitGroup
|
|
for i := 0; i < 10; i++ {
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
c, err := d.Dial()
|
|
if err != nil {
|
|
t.Errorf("Dial: %v", err)
|
|
return
|
|
}
|
|
defer c.Close()
|
|
sc, err := ln.Accept()
|
|
if err != nil {
|
|
t.Errorf("Accept: %v", err)
|
|
return
|
|
}
|
|
defer sc.Close()
|
|
const cmsg = "Some client message"
|
|
const smsg = "Some server message"
|
|
io.WriteString(c, cmsg) // TODO(bradfitz): why the 3/500 failure rate when these are "go io.WriteString"?
|
|
io.WriteString(sc, smsg)
|
|
buf := make([]byte, len(cmsg))
|
|
if n, err := io.ReadFull(c, buf); err != nil {
|
|
t.Errorf("reading from client conn: (%d %q, %v)", n, buf[:n], err)
|
|
return
|
|
}
|
|
if string(buf) != smsg {
|
|
t.Errorf("client read %q; want %q", buf, smsg)
|
|
}
|
|
if _, err := io.ReadFull(sc, buf); err != nil {
|
|
t.Errorf("reading from server conn: %v", err)
|
|
return
|
|
}
|
|
if string(buf) != cmsg {
|
|
t.Errorf("server read %q; want %q", buf, cmsg)
|
|
}
|
|
}()
|
|
}
|
|
wg.Wait()
|
|
}
|
|
|
|
// Verify that the server (e.g. the buildlet dialing the coordinator)
|
|
// going away unblocks all connections active back to it.
|
|
func TestServerEOFKillsConns(t *testing.T) {
|
|
pr, pw := io.Pipe()
|
|
var out bytes.Buffer
|
|
d := NewDialer(bufio.NewReadWriter(
|
|
bufio.NewReader(pr),
|
|
bufio.NewWriter(&out),
|
|
), ioutil.NopCloser(nil))
|
|
|
|
c, err := d.Dial()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
readErr := make(chan error, 1)
|
|
go func() {
|
|
_, err := c.Read([]byte{0})
|
|
readErr <- err
|
|
}()
|
|
pw.Close()
|
|
|
|
select {
|
|
case err := <-readErr:
|
|
if err == nil {
|
|
t.Fatal("got nil read error; want non-nil")
|
|
}
|
|
case <-time.After(2 * time.Second):
|
|
t.Error("timeout waiting for Read")
|
|
}
|
|
|
|
select {
|
|
case <-d.Done():
|
|
case <-time.After(2 * time.Second):
|
|
t.Error("timeout waiting for Done channel")
|
|
}
|
|
}
|
|
|
|
func TestConnAgainstNetTest(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skipf("testing in short mode")
|
|
}
|
|
t.Logf("warning: the revdial's SetWriteDeadline support is not complete; some tests involving write deadlines known to be flaky")
|
|
nettest.TestConn(t, func() (c1, c2 net.Conn, stop func(), err error) {
|
|
tln, err := net.Listen("tcp", "127.0.0.1:0")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
return
|
|
}
|
|
cc, err := net.Dial("tcp", tln.Addr().String())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
return
|
|
}
|
|
sc, err := tln.Accept()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
return
|
|
}
|
|
|
|
rd := NewDialer(bufio.NewReadWriter(
|
|
bufio.NewReader(sc),
|
|
bufio.NewWriter(sc),
|
|
), ioutil.NopCloser(nil))
|
|
|
|
rl := NewListener(bufio.NewReadWriter(
|
|
bufio.NewReader(cc),
|
|
bufio.NewWriter(cc),
|
|
))
|
|
|
|
c1c := make(chan interface{}, 1)
|
|
c2c := make(chan interface{}, 1)
|
|
go func() {
|
|
c, err := rd.Dial()
|
|
if err != nil {
|
|
c1c <- err
|
|
return
|
|
}
|
|
c1c <- c
|
|
}()
|
|
go func() {
|
|
c, err := rl.Accept()
|
|
if err != nil {
|
|
c2c <- err
|
|
return
|
|
}
|
|
c2c <- c
|
|
}()
|
|
switch v := (<-c1c).(type) {
|
|
case net.Conn:
|
|
c1 = v
|
|
case error:
|
|
t.Fatalf("revdial.Dial: %v", v)
|
|
}
|
|
switch v := (<-c2c).(type) {
|
|
case net.Conn:
|
|
c2 = v
|
|
case error:
|
|
t.Fatalf("revdial.Accept: %v", v)
|
|
}
|
|
|
|
stop = func() {
|
|
tln.Close()
|
|
cc.Close()
|
|
sc.Close()
|
|
}
|
|
return
|
|
})
|
|
}
|