package handlers_test import ( "context" "html" "net/http" "net/http/httptest" "net/netip" "regexp" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "sneak.berlin/go/webhooker/internal/config" "sneak.berlin/go/webhooker/internal/handlers" "sneak.berlin/go/webhooker/internal/session" ) // settingsShown renders the Settings page over cfg as a logged-in user // and returns the value it shows for each variable name, plus the // whole page. func settingsShown( t *testing.T, cfg *config.Config, ) (map[string]string, string) { t.Helper() var h *handlers.Handlers var sess *session.Session app := newTestAppWithConfig(t, cfg, &h, &sess) app.RequireStart() t.Cleanup(app.RequireStop) req := httptest.NewRequestWithContext( context.Background(), http.MethodGet, "/settings", nil, ) for _, c := range authenticatedCookies(t, sess, "id", "admin") { req.AddCookie(c) } w := httptest.NewRecorder() h.HandleSettings().ServeHTTP(w, req) require.Equal(t, http.StatusOK, w.Code) body := w.Body.String() row := regexp.MustCompile( `]*>([A-Z_]+)\s*]*>([^<]*)`, ) shown := map[string]string{} for _, match := range row.FindAllStringSubmatch(body, -1) { shown[match[1]] = html.UnescapeString(match[2]) } return shown, body } func TestSettingsPageShowsLoadedConfiguration(t *testing.T) { t.Parallel() // Each of METRICS_USERNAME, METRICS_PASSWORD and SENTRY_DSN is the // only one of the three set in one of the content tests, so each // row is checked against its own field. cfg := &config.Config{ DataDir: t.TempDir(), Debug: true, Environment: config.EnvironmentDev, MetricsUsername: "scraper", MetricsPassword: "", Port: 9123, SentryDSN: "", BindAddress: "192.0.2.10", RetentionSweepInterval: 17 * time.Minute, SessionIdleTimeout: 3 * time.Hour, ReceiverRateLimit: 77, TrustedProxies: []netip.Prefix{ netip.MustParsePrefix("10.1.0.0/16"), }, AllowedEgressCIDRs: []netip.Prefix{ netip.MustParsePrefix("192.168.5.0/24"), netip.MustParsePrefix("fd00::/8"), }, } shown, body := settingsShown(t, cfg) assert.Equal(t, map[string]string{ "WEBHOOKER_ENVIRONMENT": "dev", "PORT": "9123", "BIND_ADDRESS": "192.0.2.10", "DATA_DIR": cfg.DataDir, "DEBUG": "true", "METRICS_USERNAME": "scraper", "METRICS_PASSWORD": "not set", "SENTRY_DSN": "not set", "RETENTION_SWEEP_INTERVAL": "17m0s", "SESSION_IDLE_TIMEOUT": "3h0m0s", "RECEIVER_RATE_LIMIT": "77", "TRUSTED_PROXIES": "10.1.0.0/16", "ALLOWED_EGRESS_CIDRS": "192.168.5.0/24, fd00::/8", }, shown) assert.Contains( t, body, `href="/settings"`, "the navigation bar links to the page", ) } func TestSettingsPageShowsUnsetValues(t *testing.T) { t.Parallel() const metricsPassword = "metrics-password-1f9a" shown, body := settingsShown(t, &config.Config{ DataDir: t.TempDir(), MetricsPassword: metricsPassword, }) assert.Equal(t, "not set", shown["METRICS_USERNAME"]) assert.Equal(t, "set", shown["METRICS_PASSWORD"]) assert.Equal(t, "not set", shown["SENTRY_DSN"]) assert.NotContains(t, body, metricsPassword) assert.Equal(t, "none", shown["TRUSTED_PROXIES"]) assert.Equal(t, "none", shown["ALLOWED_EGRESS_CIDRS"]) } func TestSettingsPageShowsSentryDSNOnlyAsSet(t *testing.T) { t.Parallel() const ( sentryKey = "dsnkey7c2e" sentryDSN = "https://" + sentryKey + "@errors.example.com/42" ) shown, body := settingsShown(t, &config.Config{ DataDir: t.TempDir(), SentryDSN: sentryDSN, }) assert.Equal(t, "not set", shown["METRICS_USERNAME"]) assert.Equal(t, "not set", shown["METRICS_PASSWORD"]) assert.Equal(t, "set", shown["SENTRY_DSN"]) assert.NotContains(t, body, sentryKey) }