package events
import "testing"
// A family reads back keyed by what follows the prefix, and stops at the
// family's edge: a page showing "who cloned" must not also sweep in the
// client breakdown, or every reader would be counted twice.
func TestAFamilyReadsBackWholeAndNoWider(t *testing.T) {
s := testServer(t)
for name, n := range map[string]int64{
"clone": 341,
"clone.anon": 293,
"clone.auth.zeitgeist": 31,
"clone.auth.alice": 8,
"clone.claim.dave": 2,
"clone.client.zit.22900": 271,
"fetch.auth.alice": 97,
} {
if err := s.Count("alpha", name, n); err != nil {
t.Fatal(err)
}
}
got, err := s.Totals("alpha", "clone.auth")
if err != nil {
t.Fatal(err)
}
want := map[string]int64{"zeitgeist": 31, "alice": 8}
if len(got) != len(want) {
t.Fatalf("FAIL: clone.auth = %v, want %v", got, want)
}
for k, v := range want {
if got[k] != v {
t.Fatalf("FAIL: clone.auth = %v, want %v", got, want)
}
}
// A family whose members carry their own structure keeps it: the
// client family is kind and version, and the caller splits it.
if got, _ := s.Totals("alpha", "clone.client"); got["zit.22900"] != 271 || len(got) != 1 {
t.Errorf("FAIL: clone.client = %v, want one zit.22900 at 271", got)
}
// The same family under a different verb is a different family.
if got, _ := s.Totals("alpha", "fetch.auth"); got["alice"] != 97 || len(got) != 1 {
t.Errorf("FAIL: fetch.auth = %v, want one alice at 97", got)
}
// And a family nobody has touched is empty, not an error: "nobody
// has claimed anything here" is an answer.
got, err = s.Totals("alpha", "clone.claim")
if err != nil || got["dave"] != 2 {
t.Errorf("FAIL: clone.claim = %v, %v; want dave at 2", got, err)
}
if got, err := s.Totals("beta", "clone.auth"); err != nil || len(got) != 0 {
t.Errorf("FAIL: an untouched family = %v, %v; want empty and no error", got, err)
}
}
// A counter subject is built from names quarry does not control. Subject
// grammar is not the place to be relaxed: a dot would graft a level onto
// the tree, and a > would turn a stored subject into a wildcard matching
// its siblings.
func TestATokenCannotReshapeTheSubjectTree(t *testing.T) {
for in, want := range map[string]string{
"alice": "alice",
"zeit-geist_1": "zeit-geist_1",
"a.b": "a_b",
"a>b": "a_b",
"a*b": "a_b",
"a b": "a_b",
"": "_",
"..": "__",
} {
if got := CounterToken(in); got != want {
t.Errorf("FAIL: CounterToken(%q) = %q, want %q", in, got, want)
}
}
}
// A name that sanitizes into a subject must still land in its own family
// and be readable back — the sanitizer is not allowed to produce a
// subject the reader then cannot find.
func TestASanitizedNameStillCountsAndReadsBack(t *testing.T) {
s := testServer(t)
if err := s.Count("alpha", "clone.auth."+CounterToken("weird.name>here"), 4); err != nil {
t.Fatal(err)
}
got, err := s.Totals("alpha", "clone.auth")
if err != nil {
t.Fatal(err)
}
if got["weird_name_here"] != 4 {
t.Errorf("FAIL: clone.auth = %v, want weird_name_here at 4", got)
}
}
func TestTotalsRefusesAnUnnamedFamily(t *testing.T) {
s := testServer(t)
if _, err := s.Totals("alpha", ""); err == nil {
t.Error("FAIL: a family with no prefix was accepted")
}
if _, err := s.Totals("", "clone.auth"); err == nil {
t.Error("FAIL: a family with no repo was accepted")
}
}