package metrics import ( "testing" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/testutil" ) func TestMetrics(t *testing.T) { reg := prometheus.NewRegistry() m := New(reg) m.RecordRequest("out", "200", 0.001) m.RecordRequest("out", "200", 0.002) m.RecordRequest("in", "401", 0.0005) m.RecordIncrement("A", "o") m.RecordIncrement("A", "o") m.RecordIncrement("O", "i") m.RecordLimitReached("O", "o") m.RecordNotification("O", "sent") m.RecordNotification("A", "failed") m.RecordRedisError("incr") m.SetCDBDomains(93549) m.RecordReload(true) m.RecordReload(false) m.RecordReload(false) m.RecordDropped("/in") m.RecordDropped("/in") m.SetQueueDepth(7) m.ObserveQueueWait(0.01) checks := []struct { name string c prometheus.Collector want float64 }{ {"requests out 200", m.Requests.WithLabelValues("out", "200"), 2}, {"requests in 401", m.Requests.WithLabelValues("in", "401"), 1}, {"increments A o", m.Increments.WithLabelValues("A", "o"), 2}, {"increments O i", m.Increments.WithLabelValues("O", "i"), 1}, {"limit reached O o", m.LimitReached.WithLabelValues("O", "o"), 1}, {"notifications O sent", m.Notifications.WithLabelValues("O", "sent"), 1}, {"notifications A failed", m.Notifications.WithLabelValues("A", "failed"), 1}, {"redis errors incr", m.RedisErrors.WithLabelValues("incr"), 1}, {"cdb domains", m.CDBDomains, 93549}, {"reload success", m.CDBReloads.WithLabelValues("success"), 1}, {"reload failure", m.CDBReloads.WithLabelValues("failure"), 2}, {"dropped /in", m.Dropped.WithLabelValues("/in"), 2}, {"queue depth", m.QueueDepth, 7}, } for _, c := range checks { if got := testutil.ToFloat64(c.c); got != c.want { t.Errorf("%s = %v, want %v", c.name, got, c.want) } } families, err := reg.Gather() if err != nil { t.Fatal(err) } seen := map[string]bool{} for _, f := range families { seen[f.GetName()] = true if f.GetName() == "migadu_counters_request_duration_seconds" { for _, metric := range f.GetMetric() { for _, l := range metric.GetLabel() { if l.GetName() == "route" && l.GetValue() == "out" && metric.GetHistogram().GetSampleCount() != 2 { t.Errorf("duration histogram for out has %d samples, want 2", metric.GetHistogram().GetSampleCount()) } } } } } for _, name := range []string{ "migadu_counters_requests_total", "migadu_counters_request_duration_seconds", "migadu_counters_increments_total", "migadu_counters_limit_reached_total", "migadu_counters_notifications_total", "migadu_counters_redis_errors_total", "migadu_counters_cdb_domains", "migadu_counters_cdb_reloads_total", "migadu_counters_dropped_total", "migadu_counters_queue_depth", "migadu_counters_queue_wait_seconds", } { if !seen[name] { t.Errorf("metric %s not registered (have %v)", name, keys(seen)) } } } func keys(m map[string]bool) []string { out := make([]string, 0, len(m)) for k := range m { out = append(out, k) } return out } // Two daemons' worth of metrics (tests, counterctl) must not collide: each // registry gets its own collectors. func TestNew_SeparateRegistries(t *testing.T) { a := New(prometheus.NewRegistry()) b := New(prometheus.NewRegistry()) a.RecordRequest("in", "200", 0.1) if testutil.ToFloat64(b.Requests.WithLabelValues("in", "200")) != 0 { t.Error("registries share state") } }