Track per-page/per-channel view counts and a privacy-preserving daily unique-visitor estimate (salted IP+UA hash, salt rotated daily and never persisted). No third-party analytics, no JS beacon. Surfaced via the admin-gated !petestats Matrix command (named to avoid an existing !stats bot in the rooms).
43 lines
1.1 KiB
Go
43 lines
1.1 KiB
Go
package storage
|
|
|
|
import "testing"
|
|
|
|
func TestMetrics_ViewsAndUniques(t *testing.T) {
|
|
setupTestDB(t)
|
|
|
|
// Three views on home, two on gaming.
|
|
RecordPageView("home")
|
|
RecordPageView("home")
|
|
RecordPageView("home")
|
|
RecordPageView("gaming")
|
|
RecordPageView("gaming")
|
|
|
|
// Two distinct visitors today; the repeat token must not double-count.
|
|
RecordVisitor("tok-a")
|
|
RecordVisitor("tok-a")
|
|
RecordVisitor("tok-b")
|
|
|
|
m := GetMetricsSummary()
|
|
|
|
if m.TotalViews != 5 {
|
|
t.Errorf("TotalViews = %d, want 5", m.TotalViews)
|
|
}
|
|
if m.ViewsToday != 5 {
|
|
t.Errorf("ViewsToday = %d, want 5", m.ViewsToday)
|
|
}
|
|
if m.UniquesToday != 2 {
|
|
t.Errorf("UniquesToday = %d, want 2 (deduped)", m.UniquesToday)
|
|
}
|
|
if len(m.Pages) == 0 || m.Pages[0].Path != "home" || m.Pages[0].Total != 3 {
|
|
t.Errorf("Pages[0] = %+v, want home with 3 views first", m.Pages)
|
|
}
|
|
}
|
|
|
|
func TestMetrics_EmptyIsZero(t *testing.T) {
|
|
setupTestDB(t)
|
|
m := GetMetricsSummary()
|
|
if m.TotalViews != 0 || m.ViewsToday != 0 || m.UniquesToday != 0 || len(m.Pages) != 0 {
|
|
t.Errorf("expected zero-value summary, got %+v", m)
|
|
}
|
|
}
|