auto-update-daily-20260202
  1package sources
  2
  3import (
  4	"os"
  5	"path/filepath"
  6	"testing"
  7	"time"
  8
  9	"github.com/vdemeester/home/tools/review-tool/internal/config"
 10)
 11
 12// Helper to create temp directory with test files
 13func setupTestHistoryDir(t *testing.T) string {
 14	t.Helper()
 15	dir := t.TempDir()
 16
 17	// Create directory structure
 18	sessionsDir := filepath.Join(dir, "sessions", "2026-01")
 19	learningsDir := filepath.Join(dir, "learnings", "2026-01")
 20	researchDir := filepath.Join(dir, "research", "2026-01")
 21
 22	for _, d := range []string{sessionsDir, learningsDir, researchDir} {
 23		if err := os.MkdirAll(d, 0o755); err != nil {
 24			t.Fatalf("failed to create dir: %v", err)
 25		}
 26	}
 27
 28	// Create test session file with metadata
 29	sessionContent := `# Terraform Branch Protection Implementation
 30
 31**Date:** 2026-01-21
 32**Repository:** tektoncd/plumbing
 33**Duration:** ~3 hours
 34
 35## Summary
 36Implemented branch protection automation.
 37`
 38	if err := os.WriteFile(filepath.Join(sessionsDir, "2026-01-21-terraform-session.md"), []byte(sessionContent), 0o644); err != nil {
 39		t.Fatalf("failed to write session file: %v", err)
 40	}
 41
 42	// Create session file without explicit date (date from filename)
 43	sessionNoDate := `# Mobile Development Planning
 44
 45## Summary
 46Discussed mobile dev workflow.
 47`
 48	if err := os.WriteFile(filepath.Join(sessionsDir, "2026-01-15-mobile-planning.md"), []byte(sessionNoDate), 0o644); err != nil {
 49		t.Fatalf("failed to write session file: %v", err)
 50	}
 51
 52	// Create learning file
 53	learningContent := `# SSH Config Required for Non-Standard Keys
 54
 55**Date:** 2026-01-18
 56**Duration:** ~45 minutes
 57**Commit:** adf33b32
 58
 59## Problem
 60SSH authentication failing with custom key paths.
 61
 62## Solution
 63Added proper Host blocks to ~/.ssh/config.
 64`
 65	if err := os.WriteFile(filepath.Join(learningsDir, "2026-01-18-ssh-config-learning.md"), []byte(learningContent), 0o644); err != nil {
 66		t.Fatalf("failed to write learning file: %v", err)
 67	}
 68
 69	// Create research file (org-mode)
 70	researchContent := `#+title: SelfCI Analysis
 71#+date: [2026-01-16 Thu]
 72#+filetags: :ci:research:
 73
 74* Summary
 75Research on local CI systems.
 76`
 77	if err := os.WriteFile(filepath.Join(researchDir, "selfci-analysis.org"), []byte(researchContent), 0o644); err != nil {
 78		t.Fatalf("failed to write research file: %v", err)
 79	}
 80
 81	return dir
 82}
 83
 84func TestClaudeSource_ParsesSessionWithMetadata(t *testing.T) {
 85	historyDir := setupTestHistoryDir(t)
 86
 87	cfg := &config.ClaudeConfig{
 88		Enabled:          true,
 89		HistoryDir:       historyDir,
 90		IncludeSessions:  true,
 91		IncludeLearnings: false,
 92		IncludeResearch:  false,
 93	}
 94
 95	source := NewClaudeSource(cfg)
 96
 97	// Query for January 2026
 98	start := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)
 99	end := time.Date(2026, 1, 31, 23, 59, 59, 0, time.UTC)
100
101	act, err := source.Fetch(t.Context(), start, end)
102	if err != nil {
103		t.Fatalf("Fetch() error = %v", err)
104	}
105
106	if len(act.Items) == 0 {
107		t.Fatal("expected at least one session item")
108	}
109
110	// Find the terraform session
111	var found bool
112	for _, item := range act.Items {
113		if item.Title == "Terraform Branch Protection Implementation" {
114			found = true
115			if item.Type != "session" {
116				t.Errorf("Type = %q, want %q", item.Type, "session")
117			}
118			// Date should be 2026-01-21
119			if item.Timestamp.Day() != 21 {
120				t.Errorf("Timestamp day = %d, want 21", item.Timestamp.Day())
121			}
122		}
123	}
124
125	if !found {
126		t.Error("terraform session not found in items")
127	}
128}
129
130func TestClaudeSource_ParsesDateFromFilename(t *testing.T) {
131	historyDir := setupTestHistoryDir(t)
132
133	cfg := &config.ClaudeConfig{
134		Enabled:          true,
135		HistoryDir:       historyDir,
136		IncludeSessions:  true,
137		IncludeLearnings: false,
138		IncludeResearch:  false,
139	}
140
141	source := NewClaudeSource(cfg)
142
143	start := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)
144	end := time.Date(2026, 1, 31, 23, 59, 59, 0, time.UTC)
145
146	act, err := source.Fetch(t.Context(), start, end)
147	if err != nil {
148		t.Fatalf("Fetch() error = %v", err)
149	}
150
151	// Find mobile planning session (no explicit date in content)
152	var found bool
153	for _, item := range act.Items {
154		if item.Title == "Mobile Development Planning" {
155			found = true
156			// Date should be extracted from filename: 2026-01-15
157			if item.Timestamp.Day() != 15 {
158				t.Errorf("Timestamp day = %d, want 15", item.Timestamp.Day())
159			}
160		}
161	}
162
163	if !found {
164		t.Error("mobile planning session not found")
165	}
166}
167
168func TestClaudeSource_ParsesLearnings(t *testing.T) {
169	historyDir := setupTestHistoryDir(t)
170
171	cfg := &config.ClaudeConfig{
172		Enabled:          true,
173		HistoryDir:       historyDir,
174		IncludeSessions:  false,
175		IncludeLearnings: true,
176		IncludeResearch:  false,
177	}
178
179	source := NewClaudeSource(cfg)
180
181	start := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)
182	end := time.Date(2026, 1, 31, 23, 59, 59, 0, time.UTC)
183
184	act, err := source.Fetch(t.Context(), start, end)
185	if err != nil {
186		t.Fatalf("Fetch() error = %v", err)
187	}
188
189	if len(act.Items) != 1 {
190		t.Fatalf("expected 1 learning item, got %d", len(act.Items))
191	}
192
193	item := act.Items[0]
194	if item.Type != "learning" {
195		t.Errorf("Type = %q, want %q", item.Type, "learning")
196	}
197	if item.Timestamp.Day() != 18 {
198		t.Errorf("Timestamp day = %d, want 18", item.Timestamp.Day())
199	}
200}
201
202func TestClaudeSource_ParsesResearchOrgMode(t *testing.T) {
203	historyDir := setupTestHistoryDir(t)
204
205	cfg := &config.ClaudeConfig{
206		Enabled:          true,
207		HistoryDir:       historyDir,
208		IncludeSessions:  false,
209		IncludeLearnings: false,
210		IncludeResearch:  true,
211	}
212
213	source := NewClaudeSource(cfg)
214
215	start := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)
216	end := time.Date(2026, 1, 31, 23, 59, 59, 0, time.UTC)
217
218	act, err := source.Fetch(t.Context(), start, end)
219	if err != nil {
220		t.Fatalf("Fetch() error = %v", err)
221	}
222
223	if len(act.Items) != 1 {
224		t.Fatalf("expected 1 research item, got %d", len(act.Items))
225	}
226
227	item := act.Items[0]
228	if item.Type != "research" {
229		t.Errorf("Type = %q, want %q", item.Type, "research")
230	}
231	if item.Title != "SelfCI Analysis" {
232		t.Errorf("Title = %q, want %q", item.Title, "SelfCI Analysis")
233	}
234}
235
236func TestClaudeSource_FiltersOutsideDateRange(t *testing.T) {
237	historyDir := setupTestHistoryDir(t)
238
239	cfg := &config.ClaudeConfig{
240		Enabled:          true,
241		HistoryDir:       historyDir,
242		IncludeSessions:  true,
243		IncludeLearnings: true,
244		IncludeResearch:  true,
245	}
246
247	source := NewClaudeSource(cfg)
248
249	// Query for December 2025 - should return nothing
250	start := time.Date(2025, 12, 1, 0, 0, 0, 0, time.UTC)
251	end := time.Date(2025, 12, 31, 23, 59, 59, 0, time.UTC)
252
253	act, err := source.Fetch(t.Context(), start, end)
254	if err != nil {
255		t.Fatalf("Fetch() error = %v", err)
256	}
257
258	if len(act.Items) != 0 {
259		t.Errorf("expected 0 items outside date range, got %d", len(act.Items))
260	}
261}