Files
RenewCMS/features/write_not_found_errors.qa.md
T

4.9 KiB

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.

  1. 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.
  2. 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.
  3. 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)

  1. 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

  1. Mint a valid jwt cookie for user id 1 (as in not_found_errors_test.go, step 8 there).
  2. DELETE /v1/article/9999 with that cookie, empty repo id 9999 → assert status 404, body "Article not found\n".
  3. 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.
  4. 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.