refac: article reads, story delete, no leaks, stored SEO status, rate limit, cleanup (%site%, article repo split, old lang repos, one default per site rule to domain)
This commit is contained in:
1 parent
9d284e65a9
commit
7c15206170
85 files changed
+1788
-593
No files matched your search
@@ -6,7 +6,8 @@ Order of work is part of the procedure: the repository query and its real-databa
|
||||
|
||||
1. Seed the "Journal" dataset (8 stories, 17 versions, bylines, updated_at as in the feature) and the "hidden-version" variant through the real `ArticleRepository` on a temp SQLite file with `database.Migrate`. Drive the new grouped query through `article.Repository` with the new filter fields (group, lang, tab, author) and assert, table-driven over the feature's Examples: story ids per page, `total`, representative per story, coverage order, `missing_langs`, `story_updated_at`, `story_authors`, counts.
|
||||
2. Access filter inside the query: for a caller with scope `own`, `all`-online and `online only`, assert the hidden-version dataset yields the same ids, totals and counts as a database where the hidden articles do not exist. Also check page boundaries (a hidden version must not shift a page: 5 per page of readable stories).
|
||||
3. Filter semantics: the "single readable version satisfies all version-level filters" cases (status+author, status+q, author+seo), the "story_authors is the union" case, the "missing" cases (no readable version, site not enabling the language, disabled language, unassigned articles) and accent-insensitive q in grouped, language and not-in modes.
|
||||
3. Filter semantics: the "single readable version satisfies all version-level filters" cases (status+author, status+q, author+seo), the "story_authors is the union" case, the "missing" cases (no readable version, site not enabling the language, disabled language, unassigned-only stories never listed, mixed stories listed: TestArticleListLocalization* "Missing membership and counts agree with the missing_langs of the rows") and accent-insensitive q in grouped, language and not-in modes.
|
||||
3b. Stored SEO status: TestArticleStoryListSEOFilterAtScaleSQLite runs the startup backfill once over 40,001 versions, then asserts per request zero stale versions read, zero FindPage calls and one title search with q. TestArticleSEOIndex* (SQLite, MySQL, PostgreSQL) asserts that each write path clears the stored status and the refresh recomputes it, that a status computed before a concurrent write is not stored, and that the site description counts for the default language only and follows a default change.
|
||||
4. Sort whitelist and stability: each sort of the feature, ties by story_id descending, no overlap or gap between pages 1 to 3 on a 12-story set.
|
||||
|
||||
## Automated, real databases (task test:mysql, task test:postgres)
|
||||
@@ -21,7 +22,7 @@ Repeat items 1 to 4 against MySQL 8.4, MariaDB 11 and PostgreSQL. Compare ids, t
|
||||
|
||||
6. `article.NewHandler(...)` over the real use cases and fakes, a fresh `chi.NewRouter()` mirroring `NewArticleRouter` in `api/router.go` (GET / under `jwtauth.Verifier` only), `validator.InitValidator()` first, `httptest`, jwt cookies signed with a test `jwtauth.New("HS256", ...)` secret (owner, reader, restricted writer, unverified user, expired, none).
|
||||
7. "Public lists are unchanged": bare request and a public request keep the flat keys exactly (compare the key set and values with a golden produced before the slice); `lang=fr` and `author` narrow the flat list; `group=story` for the three public callers and every invalid query in the Examples answer 400 with `apperr.BodyErrorMessage` and the fake repository records no call.
|
||||
8. Grouped response shape: decode and assert `items[]` keys (flat item keys plus `story_updated_at`, `story_authors`, `coverage`, `missing_langs`, `capabilities`), `total`, `page`, `size`, `counts` keys (all, online, draft, suggestions, missing), `items` `[]` not null, snake_case, errors plain text. Repository failure and count failure answer 500 "Failed to retrieve articles". Docs: `docs/` gains the grouped contract (parameters, shape, counts, errors) so the SPA mocks `/v1` from it.
|
||||
8. Grouped response shape: decode and assert `items[]` keys (flat item keys plus `story_updated_at`, `story_authors`, `coverage`, `missing_langs`, `excluded_from_public`, `capabilities`; coverage entries carry `excluded_from_public` and `source_article_id`), `total`, `page`, `size`, `counts` keys (all, online, draft, suggestions, missing), `items` `[]` not null, snake_case, errors plain text. Repository failure and count failure answer 500 "Failed to retrieve articles". Docs: `docs/` gains the grouped contract (parameters, shape, counts, errors) so the SPA mocks `/v1` from it.
|
||||
|
||||
## Automated, SPA (Vitest + Vue Test Utils, task test:web)
|
||||
|
||||
|
||||
Reference in new issue
Block a user