|
|
|
@@ -148,8 +148,8 @@ func TestMetricsCountTheTraffic(t *testing.T) {
|
|
|
|
|
wantStatus(t, get(t, addr, "/_smallwebwaf/nothing"), http.StatusNotFound)
|
|
|
|
|
out.requestLines(t, 2)
|
|
|
|
|
|
|
|
|
|
forward := `{action="forward",status_class="2xx"}`
|
|
|
|
|
notFound := `{action="admin",status_class="4xx"}`
|
|
|
|
|
forward := `{action="forward",instance="app",status_class="2xx"}`
|
|
|
|
|
notFound := `{action="admin",instance="app",status_class="4xx"}`
|
|
|
|
|
|
|
|
|
|
// The request for the metrics is itself under way.
|
|
|
|
|
metrics := scrape(t, addr)
|
|
|
|
@@ -159,11 +159,13 @@ func TestMetricsCountTheTraffic(t *testing.T) {
|
|
|
|
|
wantMetric(t, metrics, "smallwebwaf_response_bytes_total"+forward, 5)
|
|
|
|
|
wantMetric(t, metrics, "smallwebwaf_response_bytes_total"+notFound,
|
|
|
|
|
float64(len("Not Found\n")))
|
|
|
|
|
wantMetric(t, metrics, "smallwebwaf_request_duration_seconds_count", 2)
|
|
|
|
|
wantMetric(t, metrics, "smallwebwaf_upstream_duration_seconds_count", 1)
|
|
|
|
|
wantMetric(t, metrics, "smallwebwaf_requests_in_flight", 1)
|
|
|
|
|
metric(t, metrics, "go_goroutines")
|
|
|
|
|
metric(t, metrics, "process_start_time_seconds")
|
|
|
|
|
wantMetric(t, metrics,
|
|
|
|
|
`smallwebwaf_request_duration_seconds_count{instance="app"}`, 2)
|
|
|
|
|
wantMetric(t, metrics,
|
|
|
|
|
`smallwebwaf_upstream_duration_seconds_count{instance="app"}`, 1)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_requests_in_flight{instance="app"}`, 1)
|
|
|
|
|
metric(t, metrics, `go_goroutines{instance="app"}`)
|
|
|
|
|
metric(t, metrics, `process_start_time_seconds{instance="app"}`)
|
|
|
|
|
|
|
|
|
|
// A request the app holds is under way until it ends.
|
|
|
|
|
httpClient := newClient(t)
|
|
|
|
@@ -180,7 +182,7 @@ func TestMetricsCountTheTraffic(t *testing.T) {
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
<-arrived
|
|
|
|
|
wantMetric(t, scrape(t, addr), "smallwebwaf_requests_in_flight", 2)
|
|
|
|
|
wantMetric(t, scrape(t, addr), `smallwebwaf_requests_in_flight{instance="app"}`, 2)
|
|
|
|
|
releaseApp()
|
|
|
|
|
|
|
|
|
|
err := <-ended
|
|
|
|
@@ -189,7 +191,7 @@ func TestMetricsCountTheTraffic(t *testing.T) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out.requestLines(t, 5)
|
|
|
|
|
wantMetric(t, scrape(t, addr), "smallwebwaf_requests_in_flight", 1)
|
|
|
|
|
wantMetric(t, scrape(t, addr), `smallwebwaf_requests_in_flight{instance="app"}`, 1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestMetricsCountLimitsAndBans(t *testing.T) {
|
|
|
|
@@ -219,15 +221,16 @@ func TestMetricsCountLimitsAndBans(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
metrics := s.scrape(scraper)
|
|
|
|
|
wantMetric(t, metrics,
|
|
|
|
|
`smallwebwaf_requests_total{action="denied",status_class="none"}`, 1)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_rate_limit_hits_total{window="minute"}`, 1)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_offences_total{kind="limit"}`, 1)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_bans_made_total{cause="limit"}`, 1)
|
|
|
|
|
wantMetric(t, metrics, "smallwebwaf_active_bans", 1)
|
|
|
|
|
wantMetric(t, metrics, "smallwebwaf_permanent_bans", 0)
|
|
|
|
|
`smallwebwaf_requests_total{action="denied",instance="app",status_class="none"}`, 1)
|
|
|
|
|
wantMetric(t, metrics,
|
|
|
|
|
`smallwebwaf_rate_limit_hits_total{instance="app",window="minute"}`, 1)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_offences_total{instance="app",kind="limit"}`, 1)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_bans_made_total{cause="limit",instance="app"}`, 1)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_active_bans{instance="app"}`, 1)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_permanent_bans{instance="app"}`, 0)
|
|
|
|
|
|
|
|
|
|
clk.advance(time.Hour)
|
|
|
|
|
wantMetric(t, s.scrape(scraper), "smallwebwaf_active_bans", 0)
|
|
|
|
|
wantMetric(t, s.scrape(scraper), `smallwebwaf_active_bans{instance="app"}`, 0)
|
|
|
|
|
|
|
|
|
|
// A limit broken again right after would ban for three hours, longer
|
|
|
|
|
// than SWWAF_MAX_BAN_DURATION, so the ban is permanent.
|
|
|
|
@@ -235,13 +238,14 @@ func TestMetricsCountLimitsAndBans(t *testing.T) {
|
|
|
|
|
s.get(client, 0, requestlog.ActionRateLimited)
|
|
|
|
|
|
|
|
|
|
metrics = s.scrape(scraper)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_rate_limit_hits_total{window="minute"}`, 2)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_offences_total{kind="limit"}`, 2)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_bans_made_total{cause="limit"}`, 2)
|
|
|
|
|
wantMetric(t, metrics, "smallwebwaf_active_bans", 1)
|
|
|
|
|
wantMetric(t, metrics, "smallwebwaf_permanent_bans", 1)
|
|
|
|
|
wantMetric(t, metrics,
|
|
|
|
|
`smallwebwaf_rate_limit_hits_total{instance="app",window="minute"}`, 2)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_offences_total{instance="app",kind="limit"}`, 2)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_bans_made_total{cause="limit",instance="app"}`, 2)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_active_bans{instance="app"}`, 1)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_permanent_bans{instance="app"}`, 1)
|
|
|
|
|
// denied, client, and the scraper as of its earlier requests.
|
|
|
|
|
wantMetric(t, metrics, "smallwebwaf_tracked_clients", 3)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_tracked_clients{instance="app"}`, 3)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestMetricsCountTheBansAnAdminMakes(t *testing.T) {
|
|
|
|
@@ -255,7 +259,7 @@ func TestMetricsCountTheBansAnAdminMakes(t *testing.T) {
|
|
|
|
|
rateLimitExemptNets: scraper,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const admins = `smallwebwaf_bans_made_total{cause="admin"}`
|
|
|
|
|
const admins = `smallwebwaf_bans_made_total{cause="admin",instance="app"}`
|
|
|
|
|
|
|
|
|
|
wantMetric(t, s.scrape(scraper), admins, 0)
|
|
|
|
|
|
|
|
|
@@ -319,28 +323,42 @@ func TestMetricsByCountryKeepTheBusiestAndCountTheRestAsOther(t *testing.T) {
|
|
|
|
|
metrics := scrape(t, addr)
|
|
|
|
|
lines++
|
|
|
|
|
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_country_requests_total{country="KP"}`, 3)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_country_requests_total{country="DE"}`, 2)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_country_requests_total{country="other"}`, 1)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_country_list_refusals_total{country="KP"}`, 3)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_country_request_bytes_total{country="KP"}`, 0)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_country_request_bytes_total{country="DE"}`, 6)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_country_response_bytes_total{country="KP"}`,
|
|
|
|
|
wantMetric(t, metrics,
|
|
|
|
|
`smallwebwaf_country_requests_total{country="KP",instance="app"}`, 3)
|
|
|
|
|
wantMetric(t, metrics,
|
|
|
|
|
`smallwebwaf_country_requests_total{country="DE",instance="app"}`, 2)
|
|
|
|
|
wantMetric(t, metrics,
|
|
|
|
|
`smallwebwaf_country_requests_total{country="other",instance="app"}`, 1)
|
|
|
|
|
wantMetric(t, metrics,
|
|
|
|
|
`smallwebwaf_country_list_refusals_total{country="KP",instance="app"}`, 3)
|
|
|
|
|
wantMetric(t, metrics,
|
|
|
|
|
`smallwebwaf_country_request_bytes_total{country="KP",instance="app"}`, 0)
|
|
|
|
|
wantMetric(t, metrics,
|
|
|
|
|
`smallwebwaf_country_request_bytes_total{country="DE",instance="app"}`, 6)
|
|
|
|
|
wantMetric(t, metrics,
|
|
|
|
|
`smallwebwaf_country_response_bytes_total{country="KP",instance="app"}`,
|
|
|
|
|
float64(3*len("Forbidden\n")))
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_country_response_bytes_total{country="other"}`,
|
|
|
|
|
wantMetric(t, metrics,
|
|
|
|
|
`smallwebwaf_country_response_bytes_total{country="other",instance="app"}`,
|
|
|
|
|
float64(len("hello")))
|
|
|
|
|
wantNoSeries(t, metrics, `smallwebwaf_country_requests_total{country="FR"}`)
|
|
|
|
|
wantNoSeries(t, metrics,
|
|
|
|
|
`smallwebwaf_country_requests_total{country="FR",instance="app"}`)
|
|
|
|
|
|
|
|
|
|
// Once FR is busier than DE, it takes DE's place: its series counts
|
|
|
|
|
// from then on, and DE's is gone.
|
|
|
|
|
send(fromFR, 3, http.StatusOK)
|
|
|
|
|
|
|
|
|
|
metrics = scrape(t, addr)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_country_requests_total{country="KP"}`, 3)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_country_requests_total{country="FR"}`, 2)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_country_requests_total{country="other"}`, 2)
|
|
|
|
|
wantNoSeries(t, metrics, `smallwebwaf_country_requests_total{country="DE"}`)
|
|
|
|
|
wantNoSeries(t, metrics, `smallwebwaf_country_request_bytes_total{country="DE"}`)
|
|
|
|
|
wantMetric(t, metrics,
|
|
|
|
|
`smallwebwaf_country_requests_total{country="KP",instance="app"}`, 3)
|
|
|
|
|
wantMetric(t, metrics,
|
|
|
|
|
`smallwebwaf_country_requests_total{country="FR",instance="app"}`, 2)
|
|
|
|
|
wantMetric(t, metrics,
|
|
|
|
|
`smallwebwaf_country_requests_total{country="other",instance="app"}`, 2)
|
|
|
|
|
wantNoSeries(t, metrics,
|
|
|
|
|
`smallwebwaf_country_requests_total{country="DE",instance="app"}`)
|
|
|
|
|
wantNoSeries(t, metrics,
|
|
|
|
|
`smallwebwaf_country_request_bytes_total{country="DE",instance="app"}`)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestMetricsCountGeoJSRequestsAndFailures(t *testing.T) {
|
|
|
|
@@ -370,16 +388,16 @@ func TestMetricsCountGeoJSRequestsAndFailures(t *testing.T) {
|
|
|
|
|
deadline := time.Now().Add(waitLimit)
|
|
|
|
|
metrics := scrape(t, addr)
|
|
|
|
|
|
|
|
|
|
for metric(t, metrics, "smallwebwaf_geojs_failures_total") == 0 &&
|
|
|
|
|
for metric(t, metrics, `smallwebwaf_geojs_failures_total{instance="app"}`) == 0 &&
|
|
|
|
|
time.Now().Before(deadline) {
|
|
|
|
|
time.Sleep(pollInterval)
|
|
|
|
|
|
|
|
|
|
metrics = scrape(t, addr)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wantMetric(t, metrics, "smallwebwaf_geojs_requests_total", 1)
|
|
|
|
|
wantMetric(t, metrics, "smallwebwaf_geojs_failures_total", 1)
|
|
|
|
|
wantMetric(t, metrics, "smallwebwaf_geojs_unanswered_total", 1)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_geojs_requests_total{instance="app"}`, 1)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_geojs_failures_total{instance="app"}`, 1)
|
|
|
|
|
wantMetric(t, metrics, `smallwebwaf_geojs_unanswered_total{instance="app"}`, 1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// keptAnswer returns GeoJS's answer that the client at addr is in
|
|
|
|
@@ -422,8 +440,9 @@ func (s *sender) scrape(from string) string {
|
|
|
|
|
|
|
|
|
|
// metric returns the value of series in metrics, which are in the
|
|
|
|
|
// Prometheus text format. series is a name and its labels in the order of
|
|
|
|
|
// their names, such as smallwebwaf_offences_total{kind="limit"}. It fails
|
|
|
|
|
// the test if there is no such series.
|
|
|
|
|
// their names, such as
|
|
|
|
|
// smallwebwaf_offences_total{instance="app",kind="limit"}. It fails the
|
|
|
|
|
// test if there is no such series.
|
|
|
|
|
func metric(t *testing.T, metrics, series string) float64 {
|
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
|
@@ -471,7 +490,8 @@ func wantNoSeries(t *testing.T, metrics, series string) {
|
|
|
|
|
func wantLimitHits(t *testing.T, addr, limit string, hits int) {
|
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
|
|
series := `smallwebwaf_size_and_time_limit_hits_total{limit="` + limit + `"}`
|
|
|
|
|
series := `smallwebwaf_size_and_time_limit_hits_total{instance="app",limit="` +
|
|
|
|
|
limit + `"}`
|
|
|
|
|
metrics := scrape(t, addr)
|
|
|
|
|
|
|
|
|
|
if hits == 0 {
|
|
|
|
|