package authz import ( "os" "path/filepath" "testing" "time" ) func TestMemoryNonceStore(t *testing.T) { m := NewMemoryNonceStore() exp := time.Now().Add(time.Hour) if m.SeenOrRecord("a", exp) { t.Fatal("first record should be unseen") } if !m.SeenOrRecord("a", exp) { t.Fatal("second record should be seen") } if m.SeenOrRecord("b", exp) { t.Fatal("distinct nonce should be unseen") } } func TestFileNonceStore_RecordAndReload(t *testing.T) { path := filepath.Join(t.TempDir(), "nonces.log") exp := refNow.Add(time.Hour) s1, err := OpenFileNonceStore(path) if err != nil { t.Fatal(err) } if s1.SeenOrRecord("dead", exp) { t.Fatal("first record should be unseen") } if err := s1.Close(); err != nil { t.Fatal(err) } // Reopen: the recorded nonce must still be seen (durable across restart). s2, err := OpenFileNonceStore(path) if err != nil { t.Fatal(err) } defer s2.Close() if !s2.SeenOrRecord("dead", exp) { t.Fatal("nonce not durable across reopen") } } func TestFileNonceStore_CompactionPrunesExpiredOnly(t *testing.T) { path := filepath.Join(t.TempDir(), "nonces.log") s, err := OpenFileNonceStore(path) if err != nil { t.Fatal(err) } s.now = func() time.Time { return refNow } s.CompactEvery = 2 // force a compaction after two appends s.SeenOrRecord("expired", refNow.Add(-time.Hour)) // exp in the past s.SeenOrRecord("live", refNow.Add(time.Hour)) // triggers compaction if err := s.Close(); err != nil { t.Fatal(err) } // Reopen: the live nonce survived, the expired one was pruned (housekeeping; // an expired op is rejected by the time check before the nonce check anyway). s2, err := OpenFileNonceStore(path) if err != nil { t.Fatal(err) } defer s2.Close() if !s2.SeenOrRecord("live", refNow.Add(time.Hour)) { t.Error("live nonce should have survived compaction") } if s2.SeenOrRecord("expired", refNow.Add(-time.Hour)) { t.Error("expired nonce should have been pruned (was still present)") } } func TestFileNonceStore_SkipsTornLine(t *testing.T) { path := filepath.Join(t.TempDir(), "nonces.log") // a valid record line + a torn/garbage trailing line from a hypothetical crash content := `{"n":"good","e":"` + refNow.Add(time.Hour).Format(time.RFC3339Nano) + `"}` + "\n" + `{"n":"tor` if err := os.WriteFile(path, []byte(content), 0o600); err != nil { t.Fatal(err) } s, err := OpenFileNonceStore(path) if err != nil { t.Fatalf("open with torn line should not fail: %v", err) } defer s.Close() if !s.SeenOrRecord("good", refNow.Add(time.Hour)) { t.Error("valid record before the torn line should have loaded") } }