Files
RenewCMS/test/article_seo_index_support_test.go
T

163 lines
3.9 KiB
Go

package test
import (
"RenewCMS/internal/domain/article"
"reflect"
"slices"
)
var _ article.ListingRepository = &mockArticleRepo{}
type assessedVersion struct {
inputs article.Article
credits []uint32
}
func seoInputsOf(version article.Article) article.Article {
version.SEO = article.SEOSummary{}
version.SEOVersion = 0
version.UpdatedAt = version.UpdatedAt.UTC()
return version
}
func (m *mockArticleRepo) seoFresh(version article.Article) bool {
assessed, found := m.assessed[version.ID]
return found && !version.SEO.Stale() && reflect.DeepEqual(assessed.inputs, seoInputsOf(version)) && slices.Equal(assessed.credits, m.credits[version.ID])
}
func (m *mockArticleRepo) StaleSEO(afterID uint32, limit int) ([]article.Article, error) {
m.mu.Lock()
defer m.mu.Unlock()
if err := m.fail.trigger("StaleSEO"); err != nil {
return nil, err
}
stale := []article.Article{}
for _, id := range m.sortedIds() {
version := m.articles[id]
if id <= afterID || m.seoFresh(version) {
continue
}
version.SEO = article.SEOSummary{}
stale = append(stale, m.withAuthors(version))
if len(stale) == limit {
break
}
}
return stale, nil
}
func (m *mockArticleRepo) StoreSEO(records []article.SEORecord) error {
m.mu.Lock()
defer m.mu.Unlock()
if err := m.fail.trigger("StoreSEO"); err != nil {
return err
}
if m.assessed == nil {
m.assessed = map[uint32]assessedVersion{}
}
for _, record := range records {
version, found := m.articles[record.ArticleID]
if !found {
continue
}
version.SEO = record.Summary
m.articles[record.ArticleID] = version
m.assessed[record.ArticleID] = assessedVersion{inputs: seoInputsOf(version), credits: slices.Clone(m.credits[record.ArticleID])}
}
return nil
}
func (m *mockArticleRepo) MarkSiteSEOStale(siteID uint32) error {
m.mu.Lock()
defer m.mu.Unlock()
for id, version := range m.articles {
if version.SiteID == siteID {
delete(m.assessed, id)
}
}
return nil
}
func (m *mockArticleRepo) CountSuggestions(filters article.Filters) (int, error) {
m.mu.Lock()
defer m.mu.Unlock()
if err := m.fail.trigger("CountSuggestions"); err != nil {
return 0, err
}
total := 0
for _, version := range m.articles {
if mockVisible(version, filters.IsOnline != nil && *filters.IsOnline, filters.VisibleTo) && version.SEO.Status == article.SEOStatusSuggestions {
total++
}
}
return total, nil
}
func (m *mockArticleRepo) CountSuggestedStories(readable article.StoryFilters) (int, error) {
m.mu.Lock()
defer m.mu.Unlock()
m.listCalls++
if err := m.fail.trigger("CountSuggestedStories"); err != nil {
return 0, err
}
stories := map[uint32]bool{}
standalone := 0
for _, version := range m.articles {
if !mockVisible(version, readable.OnlyOnline, readable.VisibleTo) || version.SEO.Status != article.SEOStatusSuggestions {
continue
}
if version.StoryID == 0 {
standalone++
continue
}
stories[version.StoryID] = true
}
return len(stories) + standalone, nil
}
func mockVisible(version article.Article, onlineOnly bool, visibleTo *uint32) bool {
if version.IsOnline {
return true
}
if onlineOnly {
return false
}
return visibleTo == nil || version.CreatedBy == *visibleTo
}
func (m *mockArticleRepo) ListVersions(ids []uint32) ([]article.Article, error) {
m.mu.Lock()
defer m.mu.Unlock()
m.listCalls++
if err := m.fail.trigger("ListVersions"); err != nil {
return nil, err
}
found := []article.Article{}
for _, id := range ids {
if version, ok := m.articles[id]; ok {
found = append(found, m.withAuthors(version))
}
}
return found, nil
}
func (m *mockArticleRepo) DeleteStory(storyID uint32) error {
m.mu.Lock()
defer m.mu.Unlock()
if err := m.fail.trigger("DeleteStory"); err != nil {
return err
}
deleted := 0
for id, version := range m.articles {
if version.StoryID == storyID {
delete(m.articles, id)
delete(m.credits, id)
deleted++
}
}
if deleted == 0 {
return article.ErrArticleNotFound
}
return nil
}