diff options
| author | Paul Buetow <paul@buetow.org> | 2026-03-04 10:50:07 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-03-04 10:50:07 +0200 |
| commit | 97aa8a6f666f5f40859c8a9aa4948bde435cf18f (patch) | |
| tree | 0cb5928cd6a1220607dbf64e234a2522acac2848 /internal/worktime/integrity_test.go | |
| parent | c25c9002f3214e07b041aefa26d5d13c26757839 (diff) | |
Rename project to timesamurai and release v0.5.0v0.5.0
Diffstat (limited to 'internal/worktime/integrity_test.go')
| -rw-r--r-- | internal/worktime/integrity_test.go | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/internal/worktime/integrity_test.go b/internal/worktime/integrity_test.go new file mode 100644 index 0000000..8239d49 --- /dev/null +++ b/internal/worktime/integrity_test.go @@ -0,0 +1,77 @@ +package worktime + +import ( + "testing" + "time" +) + +func TestCheckEntriesIntegrityDetectsIssues(t *testing.T) { + entries := []Entry{ + {Action: "login", What: "work", Epoch: 100, Source: "host-a"}, + {Action: "login", What: "work", Epoch: 110, Source: "host-a"}, // double login + {Action: "logout", What: "work", Epoch: 120, Source: "host-a"}, // matches first login + {Action: "logout", What: "work", Epoch: 130, Source: "host-a"}, // logout without login + {Action: "login", What: "off", Epoch: 200, Source: "host-b"}, // open session warning + {Action: "login", What: "bank", Epoch: 300, Source: "host-c"}, + {Action: "logout", What: "bank", Epoch: 300 + int64((16*time.Hour)/time.Second), Source: "host-c"}, // too long + } + + issues := CheckEntriesIntegrity(entries, DefaultMaxSessionSpan) + if len(issues) != 3 { + t.Fatalf("issues len = %d, want 3", len(issues)) + } + + kinds := map[string]bool{} + for _, issue := range issues { + kinds[issue.Kind] = true + } + for _, kind := range []string{ + "double-login", + "logout-without-login", + "session-too-long", + } { + if !kinds[kind] { + t.Fatalf("missing expected issue kind %q", kind) + } + } +} + +func TestOpenSessionsReturnsActiveLogins(t *testing.T) { + entries := []Entry{ + {Action: "login", What: "work", Epoch: 100, Source: "host-a"}, + {Action: "logout", What: "work", Epoch: 200, Source: "host-a"}, + {Action: "login", What: "off", Epoch: 300, Source: "host-b"}, + {Action: "login", What: "bank", Epoch: 400, Source: "host-c"}, + } + + sessions := OpenSessions(entries) + if len(sessions) != 2 { + t.Fatalf("sessions len = %d, want 2", len(sessions)) + } + + if sessions[0].Category != "bank" || sessions[0].Login.Source != "host-c" { + t.Fatalf("unexpected first session: %+v", sessions[0]) + } + if sessions[1].Category != "off" || sessions[1].Login.Source != "host-b" { + t.Fatalf("unexpected second session: %+v", sessions[1]) + } +} + +func TestCheckEntriesIntegrityPassesValidFlow(t *testing.T) { + entries := []Entry{ + {Action: "login", What: "work", Epoch: 100, Source: "host-a"}, + {Action: "logout", What: "work", Epoch: 200, Source: "host-a"}, + {Action: "add", What: "off", Epoch: 300, Source: "host-a", Value: 8 * 3600}, + } + + issues := CheckEntriesIntegrity(entries, DefaultMaxSessionSpan) + if len(issues) != 0 { + t.Fatalf("issues len = %d, want 0 (%v)", len(issues), issues) + } +} + +func TestCheckIntegrityValidation(t *testing.T) { + if _, err := CheckIntegrity(t.TempDir(), 0); err == nil { + t.Fatal("CheckIntegrity() with non-positive max span should fail") + } +} |
