flake-update-20260201
  1package sources
  2
  3import (
  4	"os/exec"
  5	"testing"
  6	"time"
  7
  8	"github.com/vdemeester/home/tools/review-tool/internal/activity"
  9	"github.com/vdemeester/home/tools/review-tool/internal/config"
 10)
 11
 12func TestGitHubSource_ParsePRJSON(t *testing.T) {
 13	// Test JSON parsing logic directly
 14	jsonData := `[{"closedAt":"2026-01-27T10:44:31Z","number":9305,"repository":{"name":"pipeline","nameWithOwner":"tektoncd/pipeline"},"title":"Fix CI workflow","url":"https://github.com/tektoncd/pipeline/pull/9305"}]`
 15
 16	items, err := parsePRJSON([]byte(jsonData), "pr_merged")
 17	if err != nil {
 18		t.Fatalf("parsePRJSON() error = %v", err)
 19	}
 20
 21	if len(items) != 1 {
 22		t.Fatalf("expected 1 item, got %d", len(items))
 23	}
 24
 25	item := items[0]
 26	if item.Title != "Fix CI workflow" {
 27		t.Errorf("Title = %q, want %q", item.Title, "Fix CI workflow")
 28	}
 29	if item.Type != "pr_merged" {
 30		t.Errorf("Type = %q, want %q", item.Type, "pr_merged")
 31	}
 32	if item.Category != activity.CategoryGitHub {
 33		t.Errorf("Category = %q, want %q", item.Category, activity.CategoryGitHub)
 34	}
 35	if item.URL != "https://github.com/tektoncd/pipeline/pull/9305" {
 36		t.Errorf("URL = %q, want correct URL", item.URL)
 37	}
 38	if item.Metadata["repository"] != "tektoncd/pipeline" {
 39		t.Errorf("repository = %q, want %q", item.Metadata["repository"], "tektoncd/pipeline")
 40	}
 41}
 42
 43func TestGitHubSource_ParseMultiplePRs(t *testing.T) {
 44	jsonData := `[
 45		{"closedAt":"2026-01-27T10:00:00Z","number":1,"repository":{"nameWithOwner":"org/repo1"},"title":"PR 1","url":"https://github.com/org/repo1/pull/1"},
 46		{"closedAt":"2026-01-26T09:00:00Z","number":2,"repository":{"nameWithOwner":"org/repo2"},"title":"PR 2","url":"https://github.com/org/repo2/pull/2"}
 47	]`
 48
 49	items, err := parsePRJSON([]byte(jsonData), "pr_merged")
 50	if err != nil {
 51		t.Fatalf("parsePRJSON() error = %v", err)
 52	}
 53
 54	if len(items) != 2 {
 55		t.Fatalf("expected 2 items, got %d", len(items))
 56	}
 57}
 58
 59func TestGitHubSource_FilterByDateRange(t *testing.T) {
 60	// Create items with different dates
 61	items := []activity.ActivityItem{
 62		{Title: "Old PR", Timestamp: time.Date(2026, 1, 10, 0, 0, 0, 0, time.UTC)},
 63		{Title: "Recent PR", Timestamp: time.Date(2026, 1, 25, 0, 0, 0, 0, time.UTC)},
 64		{Title: "Future PR", Timestamp: time.Date(2026, 2, 1, 0, 0, 0, 0, time.UTC)},
 65	}
 66
 67	start := time.Date(2026, 1, 20, 0, 0, 0, 0, time.UTC)
 68	end := time.Date(2026, 1, 31, 23, 59, 59, 0, time.UTC)
 69
 70	filtered := filterByDateRange(items, start, end)
 71
 72	if len(filtered) != 1 {
 73		t.Errorf("expected 1 item in range, got %d", len(filtered))
 74	}
 75	if len(filtered) > 0 && filtered[0].Title != "Recent PR" {
 76		t.Errorf("expected 'Recent PR', got %q", filtered[0].Title)
 77	}
 78}
 79
 80func TestGitHubSource_ParseDiscussionJSON(t *testing.T) {
 81	jsonData := `[
 82		{
 83			"title": "How to configure CI/CD?",
 84			"url": "https://github.com/tektoncd/pipeline/discussions/123",
 85			"createdAt": "2026-01-25T14:30:00Z",
 86			"repository": "tektoncd/pipeline",
 87			"category": "Q&A"
 88		}
 89	]`
 90
 91	items, err := parseDiscussionJSON([]byte(jsonData))
 92	if err != nil {
 93		t.Fatalf("parseDiscussionJSON() error = %v", err)
 94	}
 95
 96	if len(items) != 1 {
 97		t.Fatalf("expected 1 item, got %d", len(items))
 98	}
 99
100	item := items[0]
101	if item.Title != "How to configure CI/CD?" {
102		t.Errorf("Title = %q, want %q", item.Title, "How to configure CI/CD?")
103	}
104	if item.Type != "discussion" {
105		t.Errorf("Type = %q, want %q", item.Type, "discussion")
106	}
107	if item.Category != activity.CategoryGitHub {
108		t.Errorf("Category = %q, want %q", item.Category, activity.CategoryGitHub)
109	}
110	if item.Metadata["category"] != "Q&A" {
111		t.Errorf("category = %q, want %q", item.Metadata["category"], "Q&A")
112	}
113}
114
115func TestGitHubSource_ParseCommentJSON(t *testing.T) {
116	jsonData := `[
117		{
118			"body": "Thanks for the fix!",
119			"url": "https://github.com/tektoncd/pipeline/issues/456#issuecomment-123",
120			"createdAt": "2026-01-26T10:15:00Z",
121			"repository": "tektoncd/pipeline",
122			"issueTitle": "Bug in pipeline controller",
123			"issueNumber": 456
124		}
125	]`
126
127	items, err := parseCommentJSON([]byte(jsonData))
128	if err != nil {
129		t.Fatalf("parseCommentJSON() error = %v", err)
130	}
131
132	if len(items) != 1 {
133		t.Fatalf("expected 1 item, got %d", len(items))
134	}
135
136	item := items[0]
137	if item.Title != "Comment on: Bug in pipeline controller" {
138		t.Errorf("Title = %q, want %q", item.Title, "Comment on: Bug in pipeline controller")
139	}
140	if item.Type != "comment" {
141		t.Errorf("Type = %q, want %q", item.Type, "comment")
142	}
143	if item.Metadata["issue_number"] != "456" {
144		t.Errorf("issue_number = %q, want %q", item.Metadata["issue_number"], "456")
145	}
146}
147
148// Integration test - requires gh CLI
149func TestGitHubSource_RealData(t *testing.T) {
150	// Check if gh CLI is available
151	if _, err := exec.LookPath("gh"); err != nil {
152		t.Skip("gh CLI not found, skipping integration test")
153	}
154
155	cfg := &config.GitHubConfig{
156		Enabled:        true,
157		IncludePRs:     true,
158		IncludeIssues:  false,
159		IncludeReviews: false,
160		IncludeCommits: false,
161	}
162
163	source := NewGitHubSource(cfg)
164
165	// Last 7 days
166	now := time.Now()
167	start := time.Date(now.Year(), now.Month(), now.Day()-7, 0, 0, 0, 0, now.Location())
168
169	act, err := source.Fetch(t.Context(), start, now)
170	if err != nil {
171		t.Fatalf("Fetch error: %v", err)
172	}
173
174	t.Logf("Found %d GitHub items", len(act.Items))
175	for i, item := range act.Items {
176		if i < 5 {
177			t.Logf("  [%s] %s (%s)", item.Type, item.Title, item.Metadata["repository"])
178		}
179	}
180}
181
182// Integration test for discussions and comments
183func TestGitHubSource_DiscussionsAndComments(t *testing.T) {
184	if _, err := exec.LookPath("gh"); err != nil {
185		t.Skip("gh CLI not found, skipping integration test")
186	}
187
188	cfg := &config.GitHubConfig{
189		Enabled:            true,
190		IncludePRs:         false,
191		IncludeIssues:      false,
192		IncludeReviews:     false,
193		IncludeCommits:     false,
194		IncludeDiscussions: true,
195		IncludeComments:    true,
196	}
197
198	source := NewGitHubSource(cfg)
199
200	// Last 7 days
201	now := time.Now()
202	start := time.Date(now.Year(), now.Month(), now.Day()-7, 0, 0, 0, 0, now.Location())
203
204	act, err := source.Fetch(t.Context(), start, now)
205	if err != nil {
206		t.Fatalf("Fetch error: %v", err)
207	}
208
209	t.Logf("Found %d discussion/comment items", len(act.Items))
210	for i, item := range act.Items {
211		if i < 10 {
212			t.Logf("  [%s] %s (%s)", item.Type, item.Title, item.Metadata["repository"])
213		}
214	}
215}