memory: count habits over self facts only, and skip retracted ones
The behaviour profile read the newest 2000 rows of the shared facts table and then discarded everything that was not kind=self, so the length of the window was set by the noisiest writer. mavpoll writes a wg_handshake row every time a peer rehandshakes, about every two minutes per peer, which is enough to reduce 2000 rows to under three days. A weekday habit needs two distinct Tuesdays, so that window can never hold one, and she answered that she knows no habits on a store holding a year of taps. RecentActiveFactsByKind filters kind in SQL, and also drops rows a later row voids along with the void marker itself. The old read counted both a retracted tap and its retraction, so a fact he explicitly took back still shaped what she said he usually does. A correction still counts, because a correction is a value he stands behind. Found in review of #59.
This commit is contained in:
@@ -424,3 +424,49 @@ func TestCalendarEventsIncludesAmbientSource(t *testing.T) {
|
||||
t.Error("a non-calendar source must not be read as a calendar event")
|
||||
}
|
||||
}
|
||||
|
||||
// TestRecentActiveFactsByKind — the behaviour profile's window. Env rows must
|
||||
// not spend it, and a retracted row must not be counted as something he did.
|
||||
func TestRecentActiveFactsByKind(t *testing.T) {
|
||||
s := newTestStore(t)
|
||||
ctx := context.Background()
|
||||
now := time.Now().UTC().Truncate(time.Millisecond)
|
||||
|
||||
// A noisy env writer, the way mavpoll writes handshakes.
|
||||
for i := 0; i < 50; i++ {
|
||||
if _, err := s.WriteFact(ctx, now.Add(-time.Duration(i)*time.Minute), KindEnv,
|
||||
"wg_handshake", "1", "poll:wireguard", 1.0, sql.NullInt64{}); err != nil {
|
||||
t.Fatalf("write env fact: %v", err)
|
||||
}
|
||||
}
|
||||
if _, err := s.WriteFact(ctx, now.Add(-2*time.Hour), KindSelf, "workout", "done", "tap:voice", 1.0, sql.NullInt64{}); err != nil {
|
||||
t.Fatalf("write self fact: %v", err)
|
||||
}
|
||||
if _, err := s.WriteFact(ctx, now.Add(-3*time.Hour), KindSelf, "walk", "done", "tap:voice", 1.0, sql.NullInt64{}); err != nil {
|
||||
t.Fatalf("write self fact: %v", err)
|
||||
}
|
||||
if _, _, err := s.VoidLatestFact(ctx, "walk", "tap:voice", now.Add(-time.Hour)); err != nil {
|
||||
t.Fatalf("VoidLatestFact: %v", err)
|
||||
}
|
||||
|
||||
got, err := s.RecentActiveFactsByKind(ctx, KindSelf, 10)
|
||||
if err != nil {
|
||||
t.Fatalf("RecentActiveFactsByKind: %v", err)
|
||||
}
|
||||
if len(got) != 1 {
|
||||
t.Fatalf("got %d facts, want 1 (workout): %+v", len(got), got)
|
||||
}
|
||||
if got[0].Key != "workout" {
|
||||
t.Errorf("key = %q, want workout", got[0].Key)
|
||||
}
|
||||
|
||||
// The window is spent on self rows only: a limit smaller than the env
|
||||
// traffic still returns the taps.
|
||||
got, err = s.RecentActiveFactsByKind(ctx, KindSelf, 1)
|
||||
if err != nil {
|
||||
t.Fatalf("RecentActiveFactsByKind: %v", err)
|
||||
}
|
||||
if len(got) != 1 || got[0].Key != "workout" {
|
||||
t.Fatalf("got %+v, want the newest self fact", got)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user