check / check (push) Failing after 2s
New tests only. The basic auth in front of /metrics answers 401 with a challenge without credentials or with a wrong username or password, and lets the configured ones through. A CORS preflight request gets the same Access-Control-Allow-Origin as a GET. A POST / whose form carries the signing key leaves the key out of the log line. The router records requests, and /metrics reports them, only when the metrics username is set; that test is the one in internal/server allowed to set up the process-wide Prometheus registry. The pinned basicauth-go already compares the password in constant time with crypto/subtle, so no code changes. Model: opus-5-5
63 lines
2.1 KiB
Go
63 lines
2.1 KiB
Go
package server
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
|
)
|
|
|
|
// TestMetricsRecordRequestsOnlyWithMetricsUsername checks that the router
|
|
// records nothing about the requests it serves while no metrics username is
|
|
// set, and that with one set /metrics reports a request it served. The two
|
|
// halves are one test, run in this order, because the router records into
|
|
// the process-wide Prometheus registry, which only one test in this package
|
|
// can set up and which keeps what is recorded in it.
|
|
func TestMetricsRecordRequestsOnlyWithMetricsUsername(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// The line /metrics shows once the router has served one GET /robots.txt.
|
|
const robotsRequestCount = `http_request_duration_seconds_count{` +
|
|
`code="200",handler="/robots.txt",method="GET",service=""} 1`
|
|
|
|
s := newTestServer(t)
|
|
s.ServeHTTP(httptest.NewRecorder(), httptest.NewRequestWithContext(
|
|
t.Context(), http.MethodGet, "/robots.txt", nil))
|
|
|
|
// With no metrics username the router serves no /metrics, so the
|
|
// registry is read directly.
|
|
registry := httptest.NewRecorder()
|
|
promhttp.Handler().ServeHTTP(registry, httptest.NewRequestWithContext(
|
|
t.Context(), http.MethodGet, "/metrics", nil))
|
|
|
|
if strings.Contains(registry.Body.String(), "http_request_duration_seconds") {
|
|
t.Errorf("with no metrics username a request was recorded:\n%s",
|
|
registry.Body.String())
|
|
}
|
|
|
|
s.config.MetricsUsername = "metricsuser"
|
|
s.config.MetricsPassword = "metricspass"
|
|
s.SetupRoutes()
|
|
|
|
s.ServeHTTP(httptest.NewRecorder(), httptest.NewRequestWithContext(
|
|
t.Context(), http.MethodGet, "/robots.txt", nil))
|
|
|
|
req := httptest.NewRequestWithContext(
|
|
t.Context(), http.MethodGet, "/metrics", nil)
|
|
req.SetBasicAuth("metricsuser", "metricspass")
|
|
|
|
rec := httptest.NewRecorder()
|
|
s.ServeHTTP(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("GET /metrics status = %d, want %d", rec.Code, http.StatusOK)
|
|
}
|
|
|
|
if !strings.Contains(rec.Body.String(), robotsRequestCount) {
|
|
t.Errorf("/metrics does not report the GET /robots.txt served; "+
|
|
"want the line %q in:\n%s", robotsRequestCount, rec.Body.String())
|
|
}
|
|
}
|