blob: 7cf53ae0493b28f6b0f95b5d4c6acbdbcc0cbdcb [file] [log] [blame]
Serge Bazanskice2737f2021-05-23 17:15:29 +02001package ident
2
3import (
4 "bufio"
5 "context"
6 "fmt"
7 "io"
8 "net"
9 "strings"
10 "testing"
11)
12
13// loopback sets up a net.Listener on any available TCP port and returns it and
14// a dialer function that returns open connections to that listener.
15func loopback(t *testing.T) (net.Listener, func() net.Conn) {
16 t.Helper()
17
18 lis, err := net.Listen("tcp", "127.0.0.1:0")
19 if err != nil {
20 t.Fatalf("Listen: %v", err)
21 }
22
23 return lis, func() net.Conn {
24 t.Helper()
25 conn, err := net.Dial("tcp", lis.Addr().String())
26 if err != nil {
27 t.Fatalf("Dial: %v", err)
28 }
29 return conn
30 }
31}
32
33// dumbHandler is a handler that returns USERID:UNIX:q3k for every request.
34func dumbHandler(ctx context.Context, w ResponseWriter, r *Request) {
35 w.SendIdent(&IdentResponse{
36 UserID: "q3k",
37 })
38}
39
40// reqRessps send an ident query to the conn and expects a response with
41// USERID:UNIX:q3k on the scanner.
42func reqResp(t *testing.T, conn net.Conn, scanner *bufio.Scanner, client, server uint16) {
43 t.Helper()
44 if _, err := fmt.Fprintf(conn, "%d,%d\r\n", client, server); err != nil {
45 t.Fatalf("Write: %v", err)
46 }
47 if !scanner.Scan() {
48 t.Fatalf("Scan: %v", scanner.Err())
49 }
50 if want, got := fmt.Sprintf("%d,%d:USERID:UNIX:q3k", client, server), scanner.Text(); want != got {
51 t.Fatalf("Wanted %q, got %q", want, got)
52 }
53}
54
55// TestServeSimple exercises the basic Server functionality: responding to
56// ident requests.
57func TestServeSimple(t *testing.T) {
58 lis, dial := loopback(t)
59 defer lis.Close()
60
61 isrv := NewServer()
62 isrv.HandleFunc(dumbHandler)
63 go isrv.Serve(lis)
64
65 conn := dial()
66 defer conn.Close()
67 scanner := bufio.NewScanner(conn)
68
69 // Send a request, expect response.
70 reqResp(t, conn, scanner, 123, 234)
71 // Send another request on the same conn, expect response.
72 reqResp(t, conn, scanner, 234, 345)
73
74 // Send another request in parallel, expect response.
75 conn2 := dial()
76 defer conn2.Close()
77 scanner2 := bufio.NewScanner(conn2)
78 reqResp(t, conn2, scanner2, 345, 456)
79}
80
81// TestServeError exercises situations where the server has to deal with
82// nasty/broken clients.
83func TestServeErrors(t *testing.T) {
84 lis, dial := loopback(t)
85 defer lis.Close()
86
87 isrv := NewServer()
88 isrv.HandleFunc(dumbHandler)
89 go isrv.Serve(lis)
90
91 conn := dial()
92 defer conn.Close()
93
94 // Send something that's not ident.
95 fmt.Fprintf(conn, "GET / HTTP/1.1\r\n\r\n")
96 // Expect EOF on read.
97 data := make([]byte, 100)
98 _, err := conn.Read(data)
99 if want, got := io.EOF, err; want != got {
100 t.Fatalf("Expected %v, got %v", want, got)
101 }
102
103 conn = dial()
104 defer conn.Close()
105
106 // Send a very long request line, expect to not be served.
107 fmt.Fprintf(conn, "123,%s123\r\n", strings.Repeat(" ", 4096))
108 data = make([]byte, 100)
109 _, err = conn.Read(data)
110 // In a large write, the connection will be closed by the server before
111 // we're finished writing. That will cause the connection to be reset, not
112 // just EOF'd as above.
113 if err == nil {
114 t.Fatalf("Read did not fail")
115 }
116}
117
118// TestServerRestart ensures that the server's serve/stop logic works as expected.
119func TestServerRestart(t *testing.T) {
120 lis, dial := loopback(t)
121 defer lis.Close()
122
123 isrv := NewServer()
124 isrv.HandleFunc(dumbHandler)
125
126 // Stop the server before it's even started.
127 isrv.Stop()
128
129 // The server should now exit immediately.
130 if err := isrv.Serve(lis); err != nil {
131 t.Fatalf("Serve: %v", err)
132 }
133
134 // On a subsequent run it should, however, start and serve.
135 go isrv.Serve(lis)
136
137 conn := dial()
138 defer conn.Close()
139 scanner := bufio.NewScanner(conn)
140
141 // Send a request, expect response.
142 reqResp(t, conn, scanner, 123, 234)
143
144 // Attempting another simultaneous Serve() shoud fail.
145 if err := isrv.Serve(lis); err == nil {
146 t.Fatal("Serve() returned nil, wanted error")
147 }
148
149 // Send a request, expect response.
150 reqResp(t, conn, scanner, 234, 345)
151
152 // Stop server, restart server.
153 isrv.Stop()
154 go isrv.Serve(lis)
155
156 // Send a request, expect response.
157 reqResp(t, conn, scanner, 345, 456)
158}