Files
RenewCMS/features/write_not_found_errors.qa.md

66 lines
4.9 KiB
Markdown

# QA procedure: write_not_found_errors
Package: `test` (black-box, extending `article_test.go` / `user_test.go` / `image_test.go` / `not_found_errors_test.go`).
## Setup shared by every case
1. Call `validator.InitValidator()` once.
2. Update the in-memory fakes (`mockArticleRepo`, `mockUserRepo`, `mockImageRepo` in `test/`) so that:
- `mockArticleRepo.UpdateBody`, `UpdateIsOnline` and `AddImage` return `article.ErrArticleNotFound` /
`image.ErrImageNotFound` (per the missing id) instead of `gorm.ErrRecordNotFound`;
- `mockArticleRepo.Delete` returns `article.ErrArticleNotFound` when the id isn't in the map, instead of
silently succeeding;
- `mockUserRepo.UpdateVerificationStatus`, `UpdatePassword`, `UpdatePasswordResetCode` return
`user.ErrUserNotFound` instead of `gorm.ErrRecordNotFound`;
- `mockUserRepo.Delete` returns `user.ErrUserNotFound` when the id isn't in the map, instead of silently
succeeding;
- `mockImageRepo.Delete` returns `image.ErrImageNotFound` instead of `gorm.ErrRecordNotFound`.
No fake in `test/` should reference `gorm.ErrRecordNotFound` (or import `gorm.io/gorm`) after this slice,
except where still needed to assert a real repository's behavior in a repository-level test.
3. Wire the real use cases (`useCases.NewUpdateArticleUseCase`, `useCases.NewDeleteArticleUseCase`,
`useCases.NewUpdateUserUseCase`, `useCases.NewDeleteUserUseCase`, `useCases.NewDeleteImageUseCase`) over
the fakes for the use-case-level checks.
4. Build `article.NewHandler(...)` from the article use cases plus a test `jwtauth.New("HS256", []byte("test-secret"), nil)`,
and mount it under a `chi.NewRouter()` group wrapped by `jwtauth.Verifier(token)` + `jwtauth.Authenticator(token)`,
mirroring `api/router.go`. No live server.
## Repository-level checks (real persistence repositories, in-memory SQLite, no HTTP)
Use the existing `openInMemoryDb(t)` helper from `test/not_found_errors_test.go`.
5. `db.AutoMigrate(&models.Article{}, &models.Image{})`. Build a real `persistence.NewArticleRepository(db)` and
`persistence.NewImageRepository(db)`. Seed one article (id 1) and one image (id 1) via `Create`.
- `UpdateBody(9, "New body")` → assert `errors.Is(err, article.ErrArticleNotFound)` true,
`errors.Is(err, gorm.ErrRecordNotFound)` false.
- `UpdateIsOnline(9, true)` → same assertions.
- `Delete(9)` → same assertions. Then `Delete(1)` on the seeded article → assert `err == nil` and a
subsequent `Get(1)` returns `article.ErrArticleNotFound` (the row is actually gone).
- `AddImage(9, 1)` (unknown article, known image) → assert `errors.Is(err, article.ErrArticleNotFound)` true.
- `AddImage(1, 9)` (known article, unknown image) → assert `errors.Is(err, image.ErrImageNotFound)` true,
`errors.Is(err, gorm.ErrRecordNotFound)` false.
6. On the same or a fresh in-memory DB, `db.AutoMigrate(&models.User{})`. Build a real
`persistence.NewUserRepository(db)`, seed a user id 1.
- `UpdateVerificationStatus(9, true)`, `UpdatePassword(9, "x")`, `UpdatePasswordResetCode(9, "y")` → each
asserts `errors.Is(err, user.ErrUserNotFound)` true, `errors.Is(err, gorm.ErrRecordNotFound)` false.
- `Delete(9)` → same assertions. Then `Delete(1)` on the seeded user → assert `err == nil` and a
subsequent `Get(1)` returns `user.ErrUserNotFound`.
7. `db.AutoMigrate(&models.Image{})`. Build a real `persistence.NewImageRepository(db)`, seed one image via
direct DB insert (or `Create` with a fake `io.Reader` and `UPLOAD_DIR` pointed at `t.TempDir()`).
- `Delete(9)` → assert `errors.Is(err, image.ErrImageNotFound)` true, `errors.Is(err, gorm.ErrRecordNotFound)` false.
## Fake-level checks (mirrors the real repositories, package-internal, no HTTP)
8. For each of `mockArticleRepo`, `mockUserRepo`, `mockImageRepo`, call the write methods listed in step 2
against an id absent from the fake's map and assert they return the matching domain sentinel, never
`gorm.ErrRecordNotFound`.
## HTTP checks (fakes, per the shared setup above) — DELETE /v1/article/{id} only
9. Mint a valid jwt cookie for user id 1 (as in `not_found_errors_test.go`, step 8 there).
10. `DELETE /v1/article/9999` with that cookie, empty repo id 9999 → assert status `404`, body
`"Article not found\n"`.
11. `DELETE /v1/article/1` with that cookie, repo seeded with an article id 1 → assert status `204`, and that
the fake no longer holds id 1 afterward.
12. `DELETE /v1/article/9999` with **no** cookie → assert status `401` (regression: jwtauth still gates the route).
## Manual verification (not exercised by the Go test)
- None. `UpdateArticle`, `AddImage`, `UpdateUser`, `DeleteUser`, `CreateImage` and `DeleteImage` have no HTTP
route today (not mounted in `api/router.go`), so there is no SPA-visible behavior or manual HTTP check for
them in this slice — only the repository/fake-level checks above apply. No SMTP involvement.