245 lines
5.9 KiB
Go
245 lines
5.9 KiB
Go
|
package mint
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"net"
|
||
|
"strings"
|
||
|
"testing"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
func newLocalListener(t *testing.T) net.Listener {
|
||
|
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||
|
if err != nil {
|
||
|
ln, err = net.Listen("tcp6", "[::1]:0")
|
||
|
}
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
return ln
|
||
|
}
|
||
|
|
||
|
func TestDialTimeout(t *testing.T) {
|
||
|
if testing.Short() {
|
||
|
t.Skip("skipping in short mode")
|
||
|
}
|
||
|
listener := newLocalListener(t)
|
||
|
|
||
|
addr := listener.Addr().String()
|
||
|
defer listener.Close()
|
||
|
|
||
|
complete := make(chan bool)
|
||
|
defer close(complete)
|
||
|
|
||
|
go func() {
|
||
|
conn, err := listener.Accept()
|
||
|
if err != nil {
|
||
|
t.Error(err)
|
||
|
return
|
||
|
}
|
||
|
<-complete
|
||
|
conn.Close()
|
||
|
}()
|
||
|
|
||
|
dialer := &net.Dialer{
|
||
|
Timeout: 10 * time.Millisecond,
|
||
|
}
|
||
|
|
||
|
var err error
|
||
|
if _, err = DialWithDialer(dialer, "tcp", addr, nil); err == nil {
|
||
|
t.Fatal("DialWithTimeout completed successfully")
|
||
|
}
|
||
|
|
||
|
if !strings.Contains(err.Error(), "timed out") {
|
||
|
t.Errorf("resulting error not a timeout: %s", err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestDialNonBlocking(t *testing.T) {
|
||
|
config := &Config{NonBlocking: true}
|
||
|
_, err := Dial("tcp", "localhost:1234", config)
|
||
|
assertEquals(t, err.Error(), "dialing not possible in non-blocking mode")
|
||
|
_, err = DialWithDialer(&net.Dialer{}, "tcp", "localhost:1234", config)
|
||
|
assertEquals(t, err.Error(), "dialing not possible in non-blocking mode")
|
||
|
}
|
||
|
|
||
|
func TestListenNonBlocking(t *testing.T) {
|
||
|
config := &Config{
|
||
|
NonBlocking: true,
|
||
|
Certificates: certificates,
|
||
|
}
|
||
|
_, err := Listen("tcp", "localhost:1234", config)
|
||
|
assertEquals(t, err.Error(), "listening not possible in non-blocking mode")
|
||
|
_, err = NewListener(newLocalListener(t), config)
|
||
|
assertEquals(t, err.Error(), "listening not possible in non-blocking mode")
|
||
|
}
|
||
|
|
||
|
// tests that Conn.Read returns (non-zero, io.EOF) instead of
|
||
|
// (non-zero, nil) when a Close (alertCloseNotify) is sitting right
|
||
|
// behind the application data in the buffer.
|
||
|
func DISABLEDTestConnReadNonzeroAndEOF(t *testing.T) {
|
||
|
// This test is racy: it assumes that after a write to a
|
||
|
// localhost TCP connection, the peer TCP connection can
|
||
|
// immediately read it. Because it's racy, we skip this test
|
||
|
// in short mode, and then retry it several times with an
|
||
|
// increasing sleep in between our final write (via srv.Close
|
||
|
// below) and the following read.
|
||
|
if testing.Short() {
|
||
|
t.Skip("skipping in short mode")
|
||
|
}
|
||
|
var err error
|
||
|
for delay := time.Millisecond; delay <= 64*time.Millisecond; delay *= 2 {
|
||
|
if err = testConnReadNonzeroAndEOF(t, delay); err == nil {
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
t.Error(err)
|
||
|
}
|
||
|
|
||
|
func testConnReadNonzeroAndEOF(t *testing.T, delay time.Duration) error {
|
||
|
ln := newLocalListener(t)
|
||
|
defer ln.Close()
|
||
|
|
||
|
srvCh := make(chan *Conn, 1)
|
||
|
var serr error
|
||
|
go func() {
|
||
|
sconn, err := ln.Accept()
|
||
|
if err != nil {
|
||
|
serr = err
|
||
|
srvCh <- nil
|
||
|
return
|
||
|
}
|
||
|
serverConfig := Config{ServerName: "example.com"}
|
||
|
srv := Server(sconn, &serverConfig)
|
||
|
if alert := srv.Handshake(); alert != AlertNoAlert {
|
||
|
serr = fmt.Errorf("handshake: %v", alert)
|
||
|
srvCh <- nil
|
||
|
return
|
||
|
}
|
||
|
srvCh <- srv
|
||
|
}()
|
||
|
|
||
|
clientConfig := Config{ServerName: "example.com"}
|
||
|
conn, err := Dial("tcp", ln.Addr().String(), &clientConfig)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
defer conn.Close()
|
||
|
|
||
|
srv := <-srvCh
|
||
|
if srv == nil {
|
||
|
return serr
|
||
|
}
|
||
|
|
||
|
buf := make([]byte, 16)
|
||
|
buf = buf[0:6]
|
||
|
|
||
|
// Consume NST.
|
||
|
zeroBuf := []byte{}
|
||
|
conn.Read(zeroBuf)
|
||
|
|
||
|
srv.Write([]byte("foobar"))
|
||
|
n, err := conn.Read(buf)
|
||
|
if n != 6 || err != nil || string(buf) != "foobar" {
|
||
|
return fmt.Errorf("Read = %d, %v, data %q; want 6, nil, foobar", n, err, buf)
|
||
|
}
|
||
|
|
||
|
srv.Write([]byte("foobartoo"))
|
||
|
n, err = conn.Read(buf)
|
||
|
if n != 6 || err != nil || string(buf) != "foobar" {
|
||
|
return fmt.Errorf("Read = %d, %v, data %q; want 6, nil, foobar", n, err, buf)
|
||
|
}
|
||
|
|
||
|
n, err = conn.Read(buf)
|
||
|
if n != 3 || err != nil || string(buf[0:3]) != "too" {
|
||
|
return fmt.Errorf("Read = %d, %v, data %q; want 3, nil, too", n, err, buf)
|
||
|
}
|
||
|
|
||
|
srv.Write([]byte("four"))
|
||
|
n, err = conn.Read(buf)
|
||
|
if n != 4 || err != nil || string(buf[0:4]) != "four" {
|
||
|
return fmt.Errorf("Read = %d, %v, data %q; want 4, nil, foor", n, err, buf)
|
||
|
}
|
||
|
|
||
|
srv.Write([]byte("abcdefgh"))
|
||
|
srv.Close()
|
||
|
time.Sleep(delay)
|
||
|
n, err = conn.Read(buf)
|
||
|
if n != 6 || string(buf) != "abcdef" {
|
||
|
return fmt.Errorf("Read = %d, buf= %q; want 6, abcdef", n, buf)
|
||
|
}
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("First Read error = %v; want nil", err)
|
||
|
}
|
||
|
|
||
|
n, err = conn.Read(buf)
|
||
|
if n != 2 || string(buf[0:2]) != "gh" {
|
||
|
return fmt.Errorf("Read = %d, buf= %q; want 2, gh", n, buf)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func TestExchangeData(t *testing.T) {
|
||
|
ln := newLocalListener(t)
|
||
|
defer ln.Close()
|
||
|
|
||
|
srvCh := make(chan *Conn, 1)
|
||
|
var serr error
|
||
|
go func() {
|
||
|
sconn, err := ln.Accept()
|
||
|
if err != nil {
|
||
|
serr = err
|
||
|
srvCh <- nil
|
||
|
return
|
||
|
}
|
||
|
serverConfig := Config{ServerName: "example.com"}
|
||
|
srv := Server(sconn, &serverConfig)
|
||
|
if alert := srv.Handshake(); alert != AlertNoAlert {
|
||
|
serr = fmt.Errorf("handshake: %v", alert)
|
||
|
srvCh <- nil
|
||
|
return
|
||
|
}
|
||
|
srvCh <- srv
|
||
|
}()
|
||
|
|
||
|
clientConfig := Config{ServerName: "example.com"}
|
||
|
conn, err := Dial("tcp", ln.Addr().String(), &clientConfig)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
defer conn.Close()
|
||
|
|
||
|
srv := <-srvCh
|
||
|
assertNotNil(t, srv, "Server should have completed handshake")
|
||
|
|
||
|
buf := make([]byte, 16)
|
||
|
buf = buf[0:6]
|
||
|
srv.Write([]byte("foobar"))
|
||
|
n, err := conn.Read(buf)
|
||
|
if n != 6 || err != nil || string(buf) != "foobar" {
|
||
|
t.Fatalf("Read = %d, %v, data %q; want 6, nil, foobar", n, err, buf)
|
||
|
return
|
||
|
}
|
||
|
srv.Write([]byte("foobartoo"))
|
||
|
n, err = conn.Read(buf)
|
||
|
if n != 6 || err != nil || string(buf) != "foobar" {
|
||
|
t.Fatalf("Read = %d, %v, data %q; want 6, nil, foobar", n, err, buf)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
n, err = conn.Read(buf)
|
||
|
if n != 3 || err != nil || string(buf[0:3]) != "too" {
|
||
|
t.Fatalf("Read = %d, %v, data %q; want 3, nil, too", n, err, buf)
|
||
|
return
|
||
|
}
|
||
|
srv.Write([]byte("four"))
|
||
|
n, err = conn.Read(buf)
|
||
|
if n != 4 || err != nil || string(buf[0:4]) != "four" {
|
||
|
t.Fatalf("Read = %d, %v, data %q; want 4, nil, four", n, err, buf)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
return
|
||
|
}
|