package db import ( "os" "path/filepath" "testing" "time" "git.pengzhan.dev/haopengzhan/rsspipe/internal/models" ) func TestDatabaseOperations(t *testing.T) { tempDir, err := os.MkdirTemp("", "rsspipe-test-*") if err != nil { t.Fatalf("failed to create temp dir: %v", err) } defer func() { _ = os.RemoveAll(tempDir) }() dbPath := filepath.Join(tempDir, "test.db") database, err := InitDB(dbPath) if err != nil { t.Fatalf("InitDB failed: %v", err) } defer func() { _ = database.Close() }() // 1. Test User u, err := database.CreateUser("admin", "$2a$10$dummyhashvalue") if err != nil { t.Fatalf("CreateUser failed: %v", err) } if u.Username != "admin" { t.Errorf("expected username admin, got %s", u.Username) } // 2. Test Category cat, err := database.CreateCategory("Tech News", nil) if err != nil { t.Fatalf("CreateCategory failed: %v", err) } // 3. Test Feed feed, err := database.CreateFeed("Hacker News", "https://news.ycombinator.com/rss", "https://news.ycombinator.com", "", &cat.ID) if err != nil { t.Fatalf("CreateFeed failed: %v", err) } // 4. Test Upsert Feed Entries entries := []models.FeedEntry{ { GUID: "item-1", URL: "https://example.com/1", Title: "Post One", Author: "Alice", Content: "

Content 1

", PublishedAt: time.Now().Add(-1 * time.Hour), }, { GUID: "item-2", URL: "https://example.com/2", Title: "Post Two", Author: "Bob", Content: "

Content 2

", PublishedAt: time.Now(), }, } inserted, err := database.UpsertFeedEntries(feed.ID, entries) if err != nil { t.Fatalf("UpsertFeedEntries failed: %v", err) } if len(inserted) != 2 { t.Fatalf("expected 2 inserted entries, got %d", len(inserted)) } // 5. List entries list, total, err := database.ListEntries(EntryFilter{View: "inbox"}) if err != nil { t.Fatalf("ListEntries failed: %v", err) } if total != 2 || len(list) != 2 { t.Errorf("expected 2 entries, got total %d, len %d", total, len(list)) } // 6. Update Read & Star firstID := list[0].ID if err := database.UpdateEntryRead(firstID, true); err != nil { t.Fatalf("UpdateEntryRead failed: %v", err) } if err := database.UpdateEntryStarred(firstID, true); err != nil { t.Fatalf("UpdateEntryStarred failed: %v", err) } // 7. Test Variant CRUD variant := models.EntryVariant{ EntryID: firstID, VariantKey: "readability_full_text", ContentType: "html", TextValue: "
Clean full text content
", Metadata: map[string]interface{}{ "scraped_at": time.Now().UTC().Format(time.RFC3339), "length": 100, }, } if err := database.SetVariant(variant); err != nil { t.Fatalf("SetVariant failed: %v", err) } fetchedVariant, err := database.GetVariant(firstID, "readability_full_text") if err != nil { t.Fatalf("GetVariant failed: %v", err) } if fetchedVariant.TextValue != "
Clean full text content
" { t.Fatalf("expected variant text, got %s", fetchedVariant.TextValue) } // Test GetEntry with variants entryWithVariants, err := database.GetEntry(firstID) if err != nil { t.Fatalf("GetEntry failed: %v", err) } if len(entryWithVariants.Variants) != 1 { t.Fatalf("expected 1 variant in GetEntry, got %d", len(entryWithVariants.Variants)) } // 8. Test Rules CRUD rule, err := database.CreateRule( "Auto Scrape Rule", "on_post_created", "all", []models.RuleCondition{ {Field: "feed_id", Operator: "eq", Value: feed.ID}, }, []models.RuleAction{ {Type: "readability_scrape"}, }, ) if err != nil { t.Fatalf("CreateRule failed: %v", err) } if rule.Name != "Auto Scrape Rule" { t.Errorf("expected rule name Auto Scrape Rule, got %s", rule.Name) } activeRules, err := database.GetActiveRules("on_post_created") if err != nil { t.Fatalf("GetActiveRules failed: %v", err) } if len(activeRules) != 1 { t.Fatalf("expected 1 active rule, got %d", len(activeRules)) } // 9. Verify Stats stats, err := database.GetStats() if err != nil { t.Fatalf("GetStats failed: %v", err) } if stats.TotalFeeds != 1 || stats.TotalUnread != 1 || stats.TotalStarred != 1 || stats.TotalRules != 1 { t.Errorf("unexpected stats: %+v", stats) } // 8. Test UpdateUserPassword newHash := "$2a$10$updatedhashvalue" if err := database.UpdateUserPassword(u.ID, newHash); err != nil { t.Fatalf("UpdateUserPassword failed: %v", err) } updatedUser, err := database.GetUserByUsername("admin") if err != nil { t.Fatalf("GetUserByUsername failed: %v", err) } if updatedUser.PasswordHash != newHash { t.Errorf("expected hash %s, got %s", newHash, updatedUser.PasswordHash) } }