forked from hswaw/hscloud
159 lines
3.9 KiB
Go
159 lines
3.9 KiB
Go
|
package ident
|
||
|
|
||
|
import (
|
||
|
"bufio"
|
||
|
"context"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"net"
|
||
|
"strings"
|
||
|
"testing"
|
||
|
)
|
||
|
|
||
|
// loopback sets up a net.Listener on any available TCP port and returns it and
|
||
|
// a dialer function that returns open connections to that listener.
|
||
|
func loopback(t *testing.T) (net.Listener, func() net.Conn) {
|
||
|
t.Helper()
|
||
|
|
||
|
lis, err := net.Listen("tcp", "127.0.0.1:0")
|
||
|
if err != nil {
|
||
|
t.Fatalf("Listen: %v", err)
|
||
|
}
|
||
|
|
||
|
return lis, func() net.Conn {
|
||
|
t.Helper()
|
||
|
conn, err := net.Dial("tcp", lis.Addr().String())
|
||
|
if err != nil {
|
||
|
t.Fatalf("Dial: %v", err)
|
||
|
}
|
||
|
return conn
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// dumbHandler is a handler that returns USERID:UNIX:q3k for every request.
|
||
|
func dumbHandler(ctx context.Context, w ResponseWriter, r *Request) {
|
||
|
w.SendIdent(&IdentResponse{
|
||
|
UserID: "q3k",
|
||
|
})
|
||
|
}
|
||
|
|
||
|
// reqRessps send an ident query to the conn and expects a response with
|
||
|
// USERID:UNIX:q3k on the scanner.
|
||
|
func reqResp(t *testing.T, conn net.Conn, scanner *bufio.Scanner, client, server uint16) {
|
||
|
t.Helper()
|
||
|
if _, err := fmt.Fprintf(conn, "%d,%d\r\n", client, server); err != nil {
|
||
|
t.Fatalf("Write: %v", err)
|
||
|
}
|
||
|
if !scanner.Scan() {
|
||
|
t.Fatalf("Scan: %v", scanner.Err())
|
||
|
}
|
||
|
if want, got := fmt.Sprintf("%d,%d:USERID:UNIX:q3k", client, server), scanner.Text(); want != got {
|
||
|
t.Fatalf("Wanted %q, got %q", want, got)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// TestServeSimple exercises the basic Server functionality: responding to
|
||
|
// ident requests.
|
||
|
func TestServeSimple(t *testing.T) {
|
||
|
lis, dial := loopback(t)
|
||
|
defer lis.Close()
|
||
|
|
||
|
isrv := NewServer()
|
||
|
isrv.HandleFunc(dumbHandler)
|
||
|
go isrv.Serve(lis)
|
||
|
|
||
|
conn := dial()
|
||
|
defer conn.Close()
|
||
|
scanner := bufio.NewScanner(conn)
|
||
|
|
||
|
// Send a request, expect response.
|
||
|
reqResp(t, conn, scanner, 123, 234)
|
||
|
// Send another request on the same conn, expect response.
|
||
|
reqResp(t, conn, scanner, 234, 345)
|
||
|
|
||
|
// Send another request in parallel, expect response.
|
||
|
conn2 := dial()
|
||
|
defer conn2.Close()
|
||
|
scanner2 := bufio.NewScanner(conn2)
|
||
|
reqResp(t, conn2, scanner2, 345, 456)
|
||
|
}
|
||
|
|
||
|
// TestServeError exercises situations where the server has to deal with
|
||
|
// nasty/broken clients.
|
||
|
func TestServeErrors(t *testing.T) {
|
||
|
lis, dial := loopback(t)
|
||
|
defer lis.Close()
|
||
|
|
||
|
isrv := NewServer()
|
||
|
isrv.HandleFunc(dumbHandler)
|
||
|
go isrv.Serve(lis)
|
||
|
|
||
|
conn := dial()
|
||
|
defer conn.Close()
|
||
|
|
||
|
// Send something that's not ident.
|
||
|
fmt.Fprintf(conn, "GET / HTTP/1.1\r\n\r\n")
|
||
|
// Expect EOF on read.
|
||
|
data := make([]byte, 100)
|
||
|
_, err := conn.Read(data)
|
||
|
if want, got := io.EOF, err; want != got {
|
||
|
t.Fatalf("Expected %v, got %v", want, got)
|
||
|
}
|
||
|
|
||
|
conn = dial()
|
||
|
defer conn.Close()
|
||
|
|
||
|
// Send a very long request line, expect to not be served.
|
||
|
fmt.Fprintf(conn, "123,%s123\r\n", strings.Repeat(" ", 4096))
|
||
|
data = make([]byte, 100)
|
||
|
_, err = conn.Read(data)
|
||
|
// In a large write, the connection will be closed by the server before
|
||
|
// we're finished writing. That will cause the connection to be reset, not
|
||
|
// just EOF'd as above.
|
||
|
if err == nil {
|
||
|
t.Fatalf("Read did not fail")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// TestServerRestart ensures that the server's serve/stop logic works as expected.
|
||
|
func TestServerRestart(t *testing.T) {
|
||
|
lis, dial := loopback(t)
|
||
|
defer lis.Close()
|
||
|
|
||
|
isrv := NewServer()
|
||
|
isrv.HandleFunc(dumbHandler)
|
||
|
|
||
|
// Stop the server before it's even started.
|
||
|
isrv.Stop()
|
||
|
|
||
|
// The server should now exit immediately.
|
||
|
if err := isrv.Serve(lis); err != nil {
|
||
|
t.Fatalf("Serve: %v", err)
|
||
|
}
|
||
|
|
||
|
// On a subsequent run it should, however, start and serve.
|
||
|
go isrv.Serve(lis)
|
||
|
|
||
|
conn := dial()
|
||
|
defer conn.Close()
|
||
|
scanner := bufio.NewScanner(conn)
|
||
|
|
||
|
// Send a request, expect response.
|
||
|
reqResp(t, conn, scanner, 123, 234)
|
||
|
|
||
|
// Attempting another simultaneous Serve() shoud fail.
|
||
|
if err := isrv.Serve(lis); err == nil {
|
||
|
t.Fatal("Serve() returned nil, wanted error")
|
||
|
}
|
||
|
|
||
|
// Send a request, expect response.
|
||
|
reqResp(t, conn, scanner, 234, 345)
|
||
|
|
||
|
// Stop server, restart server.
|
||
|
isrv.Stop()
|
||
|
go isrv.Serve(lis)
|
||
|
|
||
|
// Send a request, expect response.
|
||
|
reqResp(t, conn, scanner, 345, 456)
|
||
|
}
|