| 15 | ) |
| 16 | |
| 17 | func TestZeroResponseLogger(t *testing.T) { |
| 18 | const body = "Hello" |
| 19 | |
| 20 | s := http.Server{ |
| 21 | Handler: http.HandlerFunc(func(writer http.ResponseWriter, _ *http.Request) { |
| 22 | _, _ = writer.Write([]byte(body)) |
| 23 | }), |
| 24 | ReadTimeout: 0, |
| 25 | ReadHeaderTimeout: 1 * time.Second, |
| 26 | } |
| 27 | |
| 28 | ln, err := net.Listen("tcp", "localhost:0") |
| 29 | require.NoError(t, err) |
| 30 | |
| 31 | logBuf := concurrency.SyncBuffer{} |
| 32 | zrl := NewZeroResponseListener(ln, log.NewLogfmtLogger(&logBuf)) |
| 33 | |
| 34 | go func() { |
| 35 | _ = s.Serve(zrl) |
| 36 | }() |
| 37 | t.Cleanup(func() { |
| 38 | _ = ln.Close() |
| 39 | }) |
| 40 | |
| 41 | t.Run("multiple quick requests", func(t *testing.T) { |
| 42 | for i := 0; i < 10; i++ { |
| 43 | r, err := http.Get("http://" + ln.Addr().String()) |
| 44 | require.NoError(t, err) |
| 45 | defer func() { _ = r.Body.Close() }() |
| 46 | |
| 47 | require.Equal(t, 200, r.StatusCode) |
| 48 | read, err := io.ReadAll(r.Body) |
| 49 | require.NoError(t, err) |
| 50 | require.Equal(t, body, string(read)) |
| 51 | } |
| 52 | }) |
| 53 | |
| 54 | t.Run("slow request", func(t *testing.T) { |
| 55 | logBuf.Reset() |
| 56 | |
| 57 | c, err := net.Dial("tcp", ln.Addr().String()) |
| 58 | require.NoError(t, err) |
| 59 | defer func() { |
| 60 | _ = c.Close() |
| 61 | }() |
| 62 | |
| 63 | _, err = c.Write([]byte("GET / HTTP/1.1\r\nHost: somehost:12345\r\n")) // unfinished request |
| 64 | require.NoError(t, err) |
| 65 | |
| 66 | // HTTP server will close the connection in 1 second (see above config), without any response. |
| 67 | read, err := io.ReadAll(c) |
| 68 | require.NoError(t, err) |
| 69 | require.Equal(t, "", string(read)) |
| 70 | |
| 71 | // Wait a bit until connection is closed and log message logged. |
| 72 | test.Poll(t, 1*time.Second, true, func() interface{} { |
| 73 | return logBuf.String() != "" |
| 74 | }) |