refac: migration crash, real-database tests, site deleted during create, ruels out of the repo, lists
This commit is contained in:
1 parent
680b9a1308
commit
9d284e65a9
62 files changed
+1858
-987
No files matched your search
@@ -0,0 +1,167 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
domainArticle "RenewCMS/internal/domain/article"
|
||||
entity "RenewCMS/internal/infrastructure/persistence/models"
|
||||
persistence "RenewCMS/internal/infrastructure/persistence/repositories"
|
||||
"RenewCMS/internal/infrastructure/useCases"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
const (
|
||||
seoScaleVersions = 40_001
|
||||
seoScaleBatch = 500
|
||||
seoScaleHiddenEvery = 1000
|
||||
seoScalePageSize = 25
|
||||
seoScaleStoryOffset = 500_000
|
||||
seoScaleTitledEvery = 7
|
||||
seoScaleTitleFragment = "Lighthouse"
|
||||
)
|
||||
|
||||
type countingStoryRepository struct {
|
||||
*persistence.ArticleRepository
|
||||
titleSearches int
|
||||
pageLoads int
|
||||
}
|
||||
|
||||
func (r *countingStoryRepository) FindTitleMatches(q string, readable domainArticle.StoryFilters) ([]uint32, error) {
|
||||
r.titleSearches++
|
||||
return r.ArticleRepository.FindTitleMatches(q, readable)
|
||||
}
|
||||
|
||||
func (r *countingStoryRepository) FindPage(filters domainArticle.Filters) (domainArticle.PageResult, error) {
|
||||
r.pageLoads++
|
||||
return r.ArticleRepository.FindPage(filters)
|
||||
}
|
||||
|
||||
func seoScaleTitle(index int) string {
|
||||
if index%seoScaleTitledEvery == 0 {
|
||||
return fmt.Sprintf("%s %d", seoScaleTitleFragment, index)
|
||||
}
|
||||
return fmt.Sprintf("Harbour %d", index)
|
||||
}
|
||||
|
||||
func seedSEOScale(t *testing.T, db *gorm.DB, siteID uint32) {
|
||||
t.Helper()
|
||||
rows := make([]entity.Article, 0, seoScaleVersions)
|
||||
for index := 0; index < seoScaleVersions; index++ {
|
||||
rows = append(rows, entity.Article{
|
||||
Title: seoScaleTitle(index),
|
||||
Body: "<p>Short body.</p>",
|
||||
SiteID: siteID,
|
||||
Slug: fmt.Sprintf("scale-%d", index),
|
||||
StoryID: uint32(seoScaleStoryOffset + index),
|
||||
IsOnline: true,
|
||||
Noindex: index%seoScaleHiddenEvery == 0,
|
||||
})
|
||||
}
|
||||
if err := db.CreateInBatches(rows, seoScaleBatch).Error; err != nil {
|
||||
t.Fatalf("bulk insert: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func expectedSEOScale(hidden bool, titled bool) int {
|
||||
total := 0
|
||||
for index := 0; index < seoScaleVersions; index++ {
|
||||
if (index%seoScaleHiddenEvery == 0) == hidden && (!titled || index%seoScaleTitledEvery == 0) {
|
||||
total++
|
||||
}
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
func TestArticleStoryListSEOFilterAtScaleSQLite(t *testing.T) {
|
||||
db := openContractSQLite(t)
|
||||
site := storageDefaultSite(t, db)
|
||||
seedSEOScale(t, db, site.ID)
|
||||
repository := &countingStoryRepository{ArticleRepository: persistence.NewArticleRepository(db)}
|
||||
list := useCases.NewListArticlesUseCase(repository, &fakeBodyRenderer{}, persistence.NewSiteRepository(db), persistence.NewLocalizationRepository(db))
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
seo string
|
||||
q string
|
||||
hidden bool
|
||||
titled bool
|
||||
}{
|
||||
{"More versions with suggestions than the database accepts bind parameters", domainArticle.SEOStatusSuggestions, "", false, false},
|
||||
{"The hidden versions among them", domainArticle.SEOStatusHidden, "", true, false},
|
||||
{"The SEO filter combines with a title search run once", domainArticle.SEOStatusSuggestions, seoScaleTitleFragment, false, true},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
repository.titleSearches, repository.pageLoads = 0, 0
|
||||
want := expectedSEOScale(c.hidden, c.titled)
|
||||
|
||||
page, err := list.ListStoriesPage(useCases.ListStoriesCommand{Caller: ownerCaller(1), Page: 2, Size: seoScalePageSize, SEO: c.seo, Q: c.q})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("list: %v", err)
|
||||
}
|
||||
if page.Total != want || page.Counts.All != want {
|
||||
t.Errorf("total %d, counts %+v, want %d", page.Total, page.Counts, want)
|
||||
}
|
||||
if len(page.Rows) != min(seoScalePageSize, max(want-seoScalePageSize, 0)) {
|
||||
t.Errorf("rows = %d", len(page.Rows))
|
||||
}
|
||||
for _, row := range page.Rows {
|
||||
if row.SEO.Status != c.seo || row.Article.Body == "" {
|
||||
t.Errorf("row %d: status %q body %q", row.Article.ID, row.SEO.Status, row.Article.Body)
|
||||
}
|
||||
}
|
||||
wantSearches := 0
|
||||
if c.q != "" {
|
||||
wantSearches = 1
|
||||
}
|
||||
if repository.titleSearches != wantSearches || repository.pageLoads != 1 {
|
||||
t.Errorf("title searches %d, page loads %d per request", repository.titleSearches, repository.pageLoads)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestArticleRepositoryListByStoriesSkipsBodiesAndUnreadableDrafts(t *testing.T) {
|
||||
db := openContractSQLite(t)
|
||||
site := storageDefaultSite(t, db)
|
||||
story := fixtureStory()
|
||||
versions := []entity.Article{
|
||||
{Title: "Published", Body: "<p>Published body</p>", SiteID: site.ID, Lang: "en", StoryID: story, Slug: uniqueTestSlug(), IsOnline: true, CreatedBy: localizationOtherUserID},
|
||||
{Title: "Own draft", Body: "<p>Own body</p>", SiteID: site.ID, Lang: "fr", StoryID: story, Slug: uniqueTestSlug(), CreatedBy: localizationWriterID},
|
||||
{Title: "Foreign draft", Body: "<p>Foreign body</p>", SiteID: site.ID, Lang: "de", StoryID: story, Slug: uniqueTestSlug(), CreatedBy: localizationOtherUserID},
|
||||
}
|
||||
if err := db.Create(&versions).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
repository := persistence.NewArticleRepository(db)
|
||||
writer := localizationWriterID
|
||||
cases := []struct {
|
||||
name string
|
||||
readable domainArticle.StoryFilters
|
||||
titles []string
|
||||
}{
|
||||
{"An editor reads every version", domainArticle.StoryFilters{}, []string{"Published", "Own draft", "Foreign draft"}},
|
||||
{"An own-scope caller reads the published versions and their drafts", domainArticle.StoryFilters{VisibleTo: &writer}, []string{"Published", "Own draft"}},
|
||||
{"A reader reads the published versions only", domainArticle.StoryFilters{OnlyOnline: true}, []string{"Published"}},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
loaded, err := repository.ListByStories([]uint32{story}, c.readable)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
titles := []string{}
|
||||
for _, version := range loaded {
|
||||
titles = append(titles, version.Title)
|
||||
if version.Body != "" {
|
||||
t.Errorf("version %q carries its body", version.Title)
|
||||
}
|
||||
}
|
||||
if fmt.Sprint(titles) != fmt.Sprint(c.titles) {
|
||||
t.Errorf("titles = %v, want %v", titles, c.titles)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user