-
-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathmain_write_errors_test.go
More file actions
88 lines (74 loc) · 2.7 KB
/
Copy pathmain_write_errors_test.go
File metadata and controls
88 lines (74 loc) · 2.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package main
import (
"context"
"errors"
"net/http"
"net/http/httptest"
"testing"
"github.com/go-chi/chi/v5"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)
// failingWriter accepts headers but fails every Write, reaching the "error
// writing response" branches. Same as a client disconnecting after the status.
type failingWriter struct {
header http.Header
code int
}
func newFailingWriter() *failingWriter {
return &failingWriter{header: make(http.Header)}
}
func (f *failingWriter) Header() http.Header { return f.header }
func (f *failingWriter) WriteHeader(code int) { f.code = code }
func (f *failingWriter) Write([]byte) (int, error) { return 0, errors.New("simulated write failure") }
// requestWithService carries a chi route parameter so a handler can be called
// directly. Required: the router owns its ResponseWriter, so a failing one can
// only be injected by invoking the handler.
func requestWithService(t *testing.T, service string) *http.Request {
t.Helper()
req := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/", nil)
rctx := chi.NewRouteContext()
rctx.URLParams.Add("service", service)
return req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx))
}
// The handlers log and return on a write failure, so the assertion is that
// they neither panic nor report success through the writer.
func TestHandlerWriteErrors(t *testing.T) {
_, pgDB, _ := newTestRouter(t)
for _, tt := range []struct {
name string
handler http.HandlerFunc
}{
{"healthz", healthzHandler()},
{"robotsTxt", robotsTxtHandler()},
{"corsPreflight", corsPreflightHandler()},
{"getReports", getReportsHandler(pgDB)},
{"getServices", getServicesHandler(pgDB)},
{"getAnalytics", getAnalyticsHandler(pgDB)},
{"apiVitals", apiVitalsHandler(pgDB)},
{"apiReports", apiReportsHandler(pgDB)},
} {
t.Run(tt.name, func(t *testing.T) {
w := newFailingWriter()
tt.handler(w, requestWithService(t, "svc"))
if w.code >= 500 {
t.Errorf("status = %d, want the write failure to be logged, not a 5xx", w.code)
}
})
}
}
// routeTag's labeler branch is skipped unless an otelhttp labeler is present.
func TestRouteTagAddsRoutePattern(t *testing.T) {
var called bool
inner := http.HandlerFunc(func(http.ResponseWriter, *http.Request) { called = true })
r := chi.NewRouter()
r.Use(routeTag)
r.Get("/view/{service}", inner)
req := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/view/svc", nil)
ctx, _ := otelhttp.LabelerFromContext(req.Context())
req = req.WithContext(otelhttp.ContextWithLabeler(req.Context(), ctx))
rr := httptest.NewRecorder()
r.ServeHTTP(rr, req)
if !called {
t.Fatal("inner handler was not reached")
}
}