package events import ( "os" "path/filepath" "strings" "testing" "time" ) func TestStoreAppendAndDedup(t *testing.T) { dir := t.TempDir() s, err := OpenStore(dir) if err != nil { t.Fatalf("OpenStore: %v", err) } base := Event{ Source: SourceGitea, Kind: "pr_approved", Action: ActionPipelineStep, ProviderID: "d-1", PayloadDigest: strings.Repeat("a", 64), ReceivedAt: testNow, } if stored, err := s.Append(base); err != nil || !stored { t.Fatalf("first append = stored=%v err=%v", stored, err) } if stored, err := s.Append(base); err != nil || stored { t.Fatalf("replay append = stored=%v err=%v (want dup)", stored, err) } sameIDOtherSource := base sameIDOtherSource.Source = SourceRedmine if stored, err := s.Append(sameIDOtherSource); err != nil || !stored { t.Fatalf("same provider id, other source = stored=%v err=%v (want stored)", stored, err) } if s.Len() != 2 { t.Errorf("Len = %d, want 2", s.Len()) } s.Close() data, err := os.ReadFile(filepath.Join(dir, "events.jsonl")) if err != nil { t.Fatalf("read log: %v", err) } lines := strings.Split(strings.TrimSpace(string(data)), "\n") if len(lines) != 2 { t.Fatalf("log has %d lines, want 2:\n%s", len(lines), data) } if !strings.Contains(lines[0], `"provider_id":"d-1"`) { t.Errorf("line 1 missing provider id: %s", lines[0]) } if !strings.Contains(lines[0], `"source":"gitea"`) { t.Errorf("line 1 wrong source: %s", lines[0]) } } func TestStoreDedupSurvivesRestart(t *testing.T) { dir := t.TempDir() s, err := OpenStore(dir) if err != nil { t.Fatal(err) } ev := Event{Source: SourceDiscourse, Kind: "post_created", ProviderID: "ev-9", ReceivedAt: time.Now()} if stored, _ := s.Append(ev); !stored { t.Fatal("first append must store") } s.Close() s2, err := OpenStore(dir) if err != nil { t.Fatal(err) } defer s2.Close() if stored, _ := s2.Append(ev); stored { t.Fatal("duplicate after restart must not store again") } if s2.Len() != 1 { t.Errorf("Len after restart = %d, want 1", s2.Len()) } } func TestStoreSkipsTornTailLine(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "events.jsonl") good := `{"source":"gitea","provider_id":"d-1","kind":"push"}` + "\n" torn := `{"source":"gitea","provider_id":"d-2","ki` if err := os.WriteFile(path, []byte(good+torn), 0o600); err != nil { t.Fatal(err) } s, err := OpenStore(dir) if err != nil { t.Fatalf("OpenStore with torn tail: %v", err) } defer s.Close() if s.Len() != 1 { t.Errorf("Len = %d, want 1 (torn line skipped)", s.Len()) } if stored, _ := s.Append(Event{Source: SourceGitea, ProviderID: "d-2", ReceivedAt: time.Now()}); !stored { t.Errorf("event from torn line must be appendable again") } } func TestStorePermissions(t *testing.T) { dir := t.TempDir() s, err := OpenStore(dir) if err != nil { t.Fatal(err) } s.Close() fi, err := os.Stat(filepath.Join(dir, "events.jsonl")) if err != nil { t.Fatal(err) } if fi.Mode().Perm() != 0o600 { t.Errorf("events.jsonl mode = %v, want 0600", fi.Mode().Perm()) } }