502 lines
14 KiB
Go
502 lines
14 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/gochat/gochat/internal/model"
|
|
)
|
|
|
|
func newTestArticle(portalID uint, title string) *model.Article {
|
|
return &model.Article{
|
|
PortalID: portalID,
|
|
Title: title,
|
|
Slug: title + "-slug",
|
|
Content: "Test article content",
|
|
Status: string(model.ArticleStatusDraft),
|
|
Locale: "en",
|
|
}
|
|
}
|
|
|
|
// ========== Create ==========
|
|
|
|
func TestArticleRepo_Create(t *testing.T) {
|
|
db := setupTestDB(t, &model.Article{})
|
|
repo := NewArticleRepo(db)
|
|
|
|
article := newTestArticle(1, "TestArticle")
|
|
err := repo.Create(context.Background(), article)
|
|
require.NoError(t, err)
|
|
assert.NotZero(t, article.ID)
|
|
assert.Equal(t, uint(1), article.PortalID)
|
|
assert.Equal(t, string(model.ArticleStatusDraft), article.Status)
|
|
}
|
|
|
|
// ========== GetByID ==========
|
|
|
|
func TestArticleRepo_GetByID(t *testing.T) {
|
|
db := setupTestDB(t, &model.Article{})
|
|
repo := NewArticleRepo(db)
|
|
|
|
article := newTestArticle(1, "FindByIDArticle")
|
|
err := repo.Create(context.Background(), article)
|
|
require.NoError(t, err)
|
|
|
|
found, err := repo.GetByID(context.Background(), article.ID)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, article.ID, found.ID)
|
|
assert.Equal(t, article.Title, found.Title)
|
|
}
|
|
|
|
func TestArticleRepo_GetByID_NotFound(t *testing.T) {
|
|
db := setupTestDB(t, &model.Article{})
|
|
repo := NewArticleRepo(db)
|
|
|
|
found, err := repo.GetByID(context.Background(), 99999)
|
|
assert.Error(t, err)
|
|
assert.Nil(t, found)
|
|
}
|
|
|
|
// ========== Update ==========
|
|
|
|
func TestArticleRepo_Update(t *testing.T) {
|
|
db := setupTestDB(t, &model.Article{})
|
|
repo := NewArticleRepo(db)
|
|
|
|
article := newTestArticle(1, "BeforeUpdate")
|
|
err := repo.Create(context.Background(), article)
|
|
require.NoError(t, err)
|
|
|
|
article.Title = "AfterUpdate"
|
|
article.Status = string(model.ArticleStatusPublished)
|
|
err = repo.Update(context.Background(), article)
|
|
require.NoError(t, err)
|
|
|
|
found, err := repo.GetByID(context.Background(), article.ID)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "AfterUpdate", found.Title)
|
|
assert.Equal(t, string(model.ArticleStatusPublished), found.Status)
|
|
}
|
|
|
|
// ========== Delete ==========
|
|
|
|
func TestArticleRepo_Delete(t *testing.T) {
|
|
db := setupTestDB(t, &model.Article{})
|
|
repo := NewArticleRepo(db)
|
|
|
|
article := newTestArticle(1, "DeleteArticle")
|
|
err := repo.Create(context.Background(), article)
|
|
require.NoError(t, err)
|
|
|
|
err = repo.Delete(context.Background(), article.ID)
|
|
require.NoError(t, err)
|
|
|
|
found, err := repo.GetByID(context.Background(), article.ID)
|
|
assert.Error(t, err)
|
|
assert.Nil(t, found)
|
|
}
|
|
|
|
// ========== FindByPortalID ==========
|
|
|
|
func TestArticleRepo_FindByPortalID(t *testing.T) {
|
|
db := setupTestDB(t, &model.Article{})
|
|
repo := NewArticleRepo(db)
|
|
|
|
portalID := uint(10)
|
|
for i := 0; i < 3; i++ {
|
|
a := newTestArticle(portalID, "Article"+string(rune('A'+i)))
|
|
err := repo.Create(context.Background(), a)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
articles, count, err := repo.FindByPortalID(context.Background(), portalID, 0, 10)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, int64(3), count)
|
|
assert.Len(t, articles, 3)
|
|
}
|
|
|
|
// ========== FindByCategoryID ==========
|
|
|
|
func TestArticleRepo_FindByCategoryID(t *testing.T) {
|
|
db := setupTestDB(t, &model.Article{})
|
|
repo := NewArticleRepo(db)
|
|
|
|
categoryID := uint(5)
|
|
for i := 0; i < 2; i++ {
|
|
a := newTestArticle(1, "CatArticle"+string(rune('A'+i)))
|
|
a.CategoryID = &categoryID
|
|
err := repo.Create(context.Background(), a)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
articles, count, err := repo.FindByCategoryID(context.Background(), categoryID, 0, 10)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, int64(2), count)
|
|
assert.Len(t, articles, 2)
|
|
for _, a := range articles {
|
|
assert.Equal(t, categoryID, *a.CategoryID)
|
|
}
|
|
}
|
|
|
|
// ========== FindByFolderID ==========
|
|
|
|
func TestArticleRepo_FindByFolderID(t *testing.T) {
|
|
db := setupTestDB(t, &model.Article{})
|
|
repo := NewArticleRepo(db)
|
|
|
|
folderID := uint(7)
|
|
for i := 0; i < 2; i++ {
|
|
a := newTestArticle(1, "FolderArticle"+string(rune('A'+i)))
|
|
a.FolderID = &folderID
|
|
err := repo.Create(context.Background(), a)
|
|
require.NoError(t, err)
|
|
}
|
|
// Also create one without a folder
|
|
noFolder := newTestArticle(1, "NoFolderArticle")
|
|
require.NoError(t, repo.Create(context.Background(), noFolder))
|
|
|
|
articles, count, err := repo.FindByFolderID(context.Background(), folderID, 0, 10)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, int64(2), count)
|
|
assert.Len(t, articles, 2)
|
|
for _, a := range articles {
|
|
assert.Equal(t, folderID, *a.FolderID)
|
|
}
|
|
}
|
|
|
|
// ========== FindByStatus ==========
|
|
|
|
func TestArticleRepo_FindByStatus(t *testing.T) {
|
|
db := setupTestDB(t, &model.Article{})
|
|
repo := NewArticleRepo(db)
|
|
|
|
portalID := uint(10)
|
|
// Create 2 draft articles
|
|
for i := 0; i < 2; i++ {
|
|
a := newTestArticle(portalID, "DraftArticle"+string(rune('A'+i)))
|
|
err := repo.Create(context.Background(), a)
|
|
require.NoError(t, err)
|
|
}
|
|
// Create 1 published article
|
|
published := newTestArticle(portalID, "PublishedArticle")
|
|
published.Status = string(model.ArticleStatusPublished)
|
|
err := repo.Create(context.Background(), published)
|
|
require.NoError(t, err)
|
|
|
|
articles, count, err := repo.FindByStatus(context.Background(), portalID, model.ArticleStatusDraft, 0, 10)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, int64(2), count)
|
|
assert.Len(t, articles, 2)
|
|
for _, a := range articles {
|
|
assert.Equal(t, string(model.ArticleStatusDraft), a.Status)
|
|
}
|
|
}
|
|
|
|
// ========== FindBySlug ==========
|
|
|
|
func TestArticleRepo_FindBySlug(t *testing.T) {
|
|
db := setupTestDB(t, &model.Article{})
|
|
repo := NewArticleRepo(db)
|
|
|
|
article := newTestArticle(1, "SlugArticle")
|
|
err := repo.Create(context.Background(), article)
|
|
require.NoError(t, err)
|
|
|
|
found, err := repo.FindBySlug(context.Background(), article.Slug)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, article.ID, found.ID)
|
|
assert.Equal(t, article.Slug, found.Slug)
|
|
}
|
|
|
|
func TestArticleRepo_FindBySlug_NotFound(t *testing.T) {
|
|
db := setupTestDB(t, &model.Article{})
|
|
repo := NewArticleRepo(db)
|
|
|
|
found, err := repo.FindBySlug(context.Background(), "nonexistent-slug")
|
|
assert.Error(t, err)
|
|
assert.Nil(t, found)
|
|
}
|
|
|
|
// ========== Search ==========
|
|
|
|
func TestArticleRepo_Search_ByQuery(t *testing.T) {
|
|
skipIfSQLite(t) // ILIKE requires PG
|
|
|
|
db := setupTestDB(t, &model.Article{})
|
|
repo := NewArticleRepo(db)
|
|
|
|
portalID := uint(10)
|
|
a1 := newTestArticle(portalID, "Getting Started Guide")
|
|
a1.Description = "A guide to help you get started"
|
|
require.NoError(t, repo.Create(context.Background(), a1))
|
|
|
|
a2 := newTestArticle(portalID, "Advanced Configuration")
|
|
a2.Content = "Configure your advanced settings"
|
|
require.NoError(t, repo.Create(context.Background(), a2))
|
|
|
|
a3 := newTestArticle(portalID, "Troubleshooting Guide")
|
|
require.NoError(t, repo.Create(context.Background(), a3))
|
|
|
|
params := ArticleSearchParams{
|
|
PortalID: portalID,
|
|
Query: "guide",
|
|
Offset: 0,
|
|
Limit: 10,
|
|
}
|
|
|
|
articles, count, err := repo.Search(context.Background(), params)
|
|
require.NoError(t, err)
|
|
// Should match "Getting Started Guide" and "Troubleshooting Guide"
|
|
assert.Equal(t, int64(2), count)
|
|
assert.Len(t, articles, 2)
|
|
}
|
|
|
|
func TestArticleRepo_Search_ByStatus(t *testing.T) {
|
|
db := setupTestDB(t, &model.Article{})
|
|
repo := NewArticleRepo(db)
|
|
|
|
portalID := uint(10)
|
|
for i := 0; i < 3; i++ {
|
|
a := newTestArticle(portalID, "DraftSearch"+string(rune('A'+i)))
|
|
a.Status = string(model.ArticleStatusDraft)
|
|
require.NoError(t, repo.Create(context.Background(), a))
|
|
}
|
|
pub := newTestArticle(portalID, "PublishedSearch")
|
|
pub.Status = string(model.ArticleStatusPublished)
|
|
require.NoError(t, repo.Create(context.Background(), pub))
|
|
|
|
params := ArticleSearchParams{
|
|
PortalID: portalID,
|
|
Status: string(model.ArticleStatusDraft),
|
|
Offset: 0,
|
|
Limit: 10,
|
|
}
|
|
|
|
articles, count, err := repo.Search(context.Background(), params)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, int64(3), count)
|
|
assert.Len(t, articles, 3)
|
|
}
|
|
|
|
func TestArticleRepo_Search_ByLocale(t *testing.T) {
|
|
db := setupTestDB(t, &model.Article{})
|
|
repo := NewArticleRepo(db)
|
|
|
|
portalID := uint(10)
|
|
en := newTestArticle(portalID, "English Article")
|
|
en.Locale = "en"
|
|
require.NoError(t, repo.Create(context.Background(), en))
|
|
|
|
es := newTestArticle(portalID, "Spanish Article")
|
|
es.Locale = "es"
|
|
require.NoError(t, repo.Create(context.Background(), es))
|
|
|
|
params := ArticleSearchParams{
|
|
PortalID: portalID,
|
|
Locale: "en",
|
|
Offset: 0,
|
|
Limit: 10,
|
|
}
|
|
|
|
articles, count, err := repo.Search(context.Background(), params)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, int64(1), count)
|
|
assert.Len(t, articles, 1)
|
|
assert.Equal(t, "en", articles[0].Locale)
|
|
}
|
|
|
|
func TestArticleRepo_Search_EmptyParams(t *testing.T) {
|
|
db := setupTestDB(t, &model.Article{})
|
|
repo := NewArticleRepo(db)
|
|
|
|
portalID := uint(10)
|
|
for i := 0; i < 5; i++ {
|
|
a := newTestArticle(portalID, "AllArticles"+string(rune('A'+i)))
|
|
require.NoError(t, repo.Create(context.Background(), a))
|
|
}
|
|
|
|
params := ArticleSearchParams{
|
|
PortalID: portalID,
|
|
Offset: 0,
|
|
Limit: 10,
|
|
}
|
|
|
|
articles, count, err := repo.Search(context.Background(), params)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, int64(5), count)
|
|
assert.Len(t, articles, 5)
|
|
}
|
|
|
|
// ========== StatusCounts ==========
|
|
|
|
func TestArticleRepo_StatusCounts(t *testing.T) {
|
|
db := setupTestDB(t, &model.Article{})
|
|
repo := NewArticleRepo(db)
|
|
|
|
portalID := uint(10)
|
|
|
|
// Create 3 draft articles
|
|
for i := 0; i < 3; i++ {
|
|
a := newTestArticle(portalID, "DraftCount"+string(rune('A'+i)))
|
|
a.Status = string(model.ArticleStatusDraft)
|
|
require.NoError(t, repo.Create(context.Background(), a))
|
|
}
|
|
|
|
// Create 2 published articles
|
|
for i := 0; i < 2; i++ {
|
|
a := newTestArticle(portalID, "PublishedCount"+string(rune('A'+i)))
|
|
a.Status = string(model.ArticleStatusPublished)
|
|
require.NoError(t, repo.Create(context.Background(), a))
|
|
}
|
|
|
|
// Create 1 archived article
|
|
a := newTestArticle(portalID, "ArchivedCount")
|
|
a.Status = string(model.ArticleStatusArchived)
|
|
require.NoError(t, repo.Create(context.Background(), a))
|
|
|
|
counts, err := repo.StatusCounts(context.Background(), portalID)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, int64(6), counts["all_count"])
|
|
assert.Equal(t, int64(3), counts["draft_count"])
|
|
assert.Equal(t, int64(2), counts["published_count"])
|
|
assert.Equal(t, int64(1), counts["archived_count"])
|
|
}
|
|
|
|
func TestArticleRepo_StatusCounts_EmptyPortal(t *testing.T) {
|
|
db := setupTestDB(t, &model.Article{})
|
|
repo := NewArticleRepo(db)
|
|
|
|
counts, err := repo.StatusCounts(context.Background(), 99999)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, int64(0), counts["all_count"])
|
|
assert.Equal(t, int64(0), counts["draft_count"])
|
|
assert.Equal(t, int64(0), counts["published_count"])
|
|
assert.Equal(t, int64(0), counts["archived_count"])
|
|
}
|
|
|
|
// ========== UpdatePositions ==========
|
|
|
|
func TestArticleRepo_UpdatePositions(t *testing.T) {
|
|
db := setupTestDB(t, &model.Article{})
|
|
repo := NewArticleRepo(db)
|
|
|
|
portalID := uint(10)
|
|
a1 := newTestArticle(portalID, "PositionArticle1")
|
|
require.NoError(t, repo.Create(context.Background(), a1))
|
|
a2 := newTestArticle(portalID, "PositionArticle2")
|
|
require.NoError(t, repo.Create(context.Background(), a2))
|
|
|
|
positions := map[uint]int{
|
|
a1.ID: 5,
|
|
a2.ID: 10,
|
|
}
|
|
err := repo.UpdatePositions(context.Background(), positions)
|
|
require.NoError(t, err)
|
|
|
|
found1, err := repo.GetByID(context.Background(), a1.ID)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 5, found1.Position)
|
|
|
|
found2, err := repo.GetByID(context.Background(), a2.ID)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 10, found2.Position)
|
|
}
|
|
|
|
// ========== BulkUpdateStatus ==========
|
|
|
|
func TestArticleRepo_BulkUpdateStatus(t *testing.T) {
|
|
db := setupTestDB(t, &model.Article{})
|
|
repo := NewArticleRepo(db)
|
|
|
|
portalID := uint(10)
|
|
var ids []uint
|
|
for i := 0; i < 3; i++ {
|
|
a := newTestArticle(portalID, "BulkStatus"+string(rune('A'+i)))
|
|
a.Status = string(model.ArticleStatusDraft)
|
|
require.NoError(t, repo.Create(context.Background(), a))
|
|
ids = append(ids, a.ID)
|
|
}
|
|
|
|
err := repo.BulkUpdateStatus(context.Background(), ids, string(model.ArticleStatusPublished))
|
|
require.NoError(t, err)
|
|
|
|
for _, id := range ids {
|
|
found, err := repo.GetByID(context.Background(), id)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, string(model.ArticleStatusPublished), found.Status)
|
|
}
|
|
}
|
|
|
|
func TestArticleRepo_BulkUpdateStatus_EmptyIDs(t *testing.T) {
|
|
db := setupTestDB(t, &model.Article{})
|
|
repo := NewArticleRepo(db)
|
|
|
|
err := repo.BulkUpdateStatus(context.Background(), []uint{}, string(model.ArticleStatusPublished))
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// ========== BulkDelete ==========
|
|
|
|
func TestArticleRepo_BulkDelete(t *testing.T) {
|
|
db := setupTestDB(t, &model.Article{})
|
|
repo := NewArticleRepo(db)
|
|
|
|
portalID := uint(10)
|
|
var ids []uint
|
|
for i := 0; i < 3; i++ {
|
|
a := newTestArticle(portalID, "BulkDelete"+string(rune('A'+i)))
|
|
require.NoError(t, repo.Create(context.Background(), a))
|
|
ids = append(ids, a.ID)
|
|
}
|
|
|
|
// Create one that should NOT be deleted
|
|
keeper := newTestArticle(portalID, "KeeperArticle")
|
|
require.NoError(t, repo.Create(context.Background(), keeper))
|
|
|
|
err := repo.BulkDelete(context.Background(), ids)
|
|
require.NoError(t, err)
|
|
|
|
for _, id := range ids {
|
|
found, err := repo.GetByID(context.Background(), id)
|
|
assert.Error(t, err)
|
|
assert.Nil(t, found)
|
|
}
|
|
|
|
// Keeper should still exist
|
|
found, err := repo.GetByID(context.Background(), keeper.ID)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, keeper.ID, found.ID)
|
|
}
|
|
|
|
func TestArticleRepo_BulkDelete_EmptyIDs(t *testing.T) {
|
|
db := setupTestDB(t, &model.Article{})
|
|
repo := NewArticleRepo(db)
|
|
|
|
err := repo.BulkDelete(context.Background(), []uint{})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// ========== IncrementViews ==========
|
|
|
|
func TestArticleRepo_IncrementViews(t *testing.T) {
|
|
db := setupTestDB(t, &model.Article{})
|
|
repo := NewArticleRepo(db)
|
|
|
|
article := newTestArticle(1, "ViewArticle")
|
|
require.NoError(t, repo.Create(context.Background(), article))
|
|
assert.Equal(t, 0, article.Views)
|
|
|
|
// Increment twice
|
|
err := repo.IncrementViews(context.Background(), article.ID)
|
|
require.NoError(t, err)
|
|
|
|
err = repo.IncrementViews(context.Background(), article.ID)
|
|
require.NoError(t, err)
|
|
|
|
found, err := repo.GetByID(context.Background(), article.ID)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 2, found.Views)
|
|
} |