package rpc import ( "io" "net" "sync" "testing" ) func readStream(t *testing.T, s io.Reader) string { var data [1024]byte n, err := s.Read(data[:]) if err != nil { t.Fatalf("err: %s", err) } return string(data[0:n]) } func testMux(t *testing.T) (client *MuxConn, server *MuxConn) { l, err := net.Listen("tcp", ":0") if err != nil { t.Fatalf("err: %s", err) } // Server side doneCh := make(chan struct{}) go func() { defer close(doneCh) conn, err := l.Accept() l.Close() if err != nil { t.Fatalf("err: %s", err) } server = NewMuxConn(conn) }() // Client side conn, err := net.Dial("tcp", l.Addr().String()) if err != nil { t.Fatalf("err: %s", err) } client = NewMuxConn(conn) // Wait for the server <-doneCh return } func TestMuxConn(t *testing.T) { client, server := testMux(t) defer client.Close() defer server.Close() // When the server is done doneCh := make(chan struct{}) // The server side go func() { defer close(doneCh) s0, err := server.Accept(0) if err != nil { t.Fatalf("err: %s", err) } s1, err := server.Dial(1) if err != nil { t.Fatalf("err: %s", err) } var wg sync.WaitGroup wg.Add(2) go func() { defer wg.Done() data := readStream(t, s1) if data != "another" { t.Fatalf("bad: %#v", data) } }() go func() { defer wg.Done() data := readStream(t, s0) if data != "hello" { t.Fatalf("bad: %#v", data) } }() wg.Wait() }() s0, err := client.Dial(0) if err != nil { t.Fatalf("err: %s", err) } s1, err := client.Accept(1) if err != nil { t.Fatalf("err: %s", err) } if _, err := s0.Write([]byte("hello")); err != nil { t.Fatalf("err: %s", err) } if _, err := s1.Write([]byte("another")); err != nil { t.Fatalf("err: %s", err) } // Wait for the server to be done <-doneCh } // This tests that even when the client end is closed, data can be // read from the server. func TestMuxConn_clientCloseRead(t *testing.T) { client, server := testMux(t) defer client.Close() defer server.Close() // This channel will be closed when we close waitCh := make(chan struct{}) go func() { conn, err := server.Accept(0) if err != nil { t.Fatalf("err: %s", err) } <-waitCh _, err = conn.Write([]byte("foo")) if err != nil { t.Fatalf("err: %s", err) } conn.Close() }() s0, err := client.Dial(0) if err != nil { t.Fatalf("err: %s", err) } if err := s0.Close(); err != nil { t.Fatalf("bad: %s", err) } // Close this to continue on on the server-side close(waitCh) var data [1024]byte n, err := s0.Read(data[:]) if string(data[:n]) != "foo" { t.Fatalf("bad: %#v", string(data[:n])) } } func TestMuxConn_socketClose(t *testing.T) { client, server := testMux(t) defer client.Close() defer server.Close() go func() { _, err := server.Accept(0) if err != nil { t.Fatalf("err: %s", err) } server.rwc.Close() }() s0, err := client.Dial(0) if err != nil { t.Fatalf("err: %s", err) } var data [1024]byte _, err = s0.Read(data[:]) if err != io.EOF { t.Fatalf("err: %s", err) } } func TestMuxConn_clientClosesStreams(t *testing.T) { client, server := testMux(t) defer client.Close() defer server.Close() go func() { conn, err := server.Accept(0) if err != nil { t.Fatalf("err: %s", err) } conn.Close() }() s0, err := client.Dial(0) if err != nil { t.Fatalf("err: %s", err) } var data [1024]byte _, err = s0.Read(data[:]) if err != io.EOF { t.Fatalf("err: %s", err) } } func TestMuxConn_serverClosesStreams(t *testing.T) { client, server := testMux(t) defer client.Close() defer server.Close() go server.Accept(0) s0, err := client.Dial(0) if err != nil { t.Fatalf("err: %s", err) } if err := server.Close(); err != nil { t.Fatalf("err: %s", err) } // This should block forever since we never write onto this stream. var data [1024]byte _, err = s0.Read(data[:]) if err != io.EOF { t.Fatalf("err: %s", err) } } func TestMuxConnNextId(t *testing.T) { client, server := testMux(t) defer client.Close() defer server.Close() a := client.NextId() b := client.NextId() if a != 1 || b != 2 { t.Fatalf("IDs should increment") } a = server.NextId() b = server.NextId() if a != 1 || b != 2 { t.Fatalf("IDs should increment: %d %d", a, b) } }