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 }