| 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) |
| } |