3.9 KiB
3.9 KiB
QA procedure: not_found_errors
Package: test (black-box, alongside the existing article_test.go / user_test.go / use_case_baseline_test.go).
Setup shared by every case
- Call
validator.InitValidator()once. - Build in-memory fakes for
article.Repositoryanduser.Repository(extend the existingmockArticleRepo/mockUserRepopatterns intest/), updated so that a lookup by an unknown id/name/username/email now returnsarticle.ErrArticleNotFound/user.ErrUserNotFoundinstead ofgorm.ErrRecordNotFound— mirroring the fixed real repositories. - Wire the real use cases (
useCases.NewGetArticleUseCase,useCases.NewCreateArticleUseCaseif needed,useCases.NewGetUserUseCase,useCases.NewListUsersUseCase,useCases.NewCreateUserUseCase) over those fakes. - Build
article.NewHandler(...)andauth.NewHandler(...)from those use cases plus a testjwtauth.New("HS256", []byte("test-secret"), nil). - Mount a fresh
chi.NewRouter()mirroringapi/router.go: the article handler's routes inside a group wrapped byjwtauth.Verifier(token)+jwtauth.Authenticator(token), the auth handler's routes unprotected. No live server.
Repository-level checks (real persistence repositories, in-memory SQLite, no HTTP)
- Open a
gorm.DBwithsqlite.Open("file:" + t.Name() + "?mode=memory&cache=shared")(one named in-memory DB per test, so tests never share rows) (the project'sgithub.com/glebarez/sqlitedriver, never the realDB_FILE), anddb.AutoMigrate(&models.Article{}). Construct a realpersistence.NewArticleRepository(db), seed it with an article id 1 viaCreate. CallGet(9)directly; asserterrors.Is(err, article.ErrArticleNotFound)is true anderrors.Is(err, gorm.ErrRecordNotFound)is false. Repeat forGetByName("Unknown Title"). Close the in-memory DB (or let it drop) at the end of the test. - Open a second
gorm.DBthe same way withdb.AutoMigrate(&models.User{}). Construct a realpersistence.NewUserRepository(db), seed it with a user id 1 / username "alice" / email "alice@example.com" viaCreate. CallGet(9),GetByUsername("bob"),GetByEmail("bob@example.com")directly; assert each returnsuser.ErrUserNotFoundand notgorm.ErrRecordNotFound.
HTTP checks (fakes, per the shared setup above)
- Mint a valid jwt cookie for user id 1 with the test
jwtauth.JWTAuth(encode withtoken.Encode(map[string]any{"user_id": uint32(1)})and set it as thejwtcookie on thehttptest.NewRequest). GET /v1/article/9999with that cookie, empty repo id 9999 → assert status404, body"Article not found\n"(http.Error appends a trailing newline).GET /v1/article/2with that cookie, repo seeded with an offline article id 2 → assert status404, body"Article not found\n"(regression: unchanged from before this fix).GET /v1/article/1with that cookie, repo seeded with an online article id 1 → assert status200, body decodes to the article JSON with id 1.GET /v1/article/9999with no cookie → assert status401(regression: jwtauth still gates the route).POST /v1/auth/loginwith{"username":"alice","password":"wrongpassword12"}(repo seeded with user "alice"/bcrypt-hashed "hunter2example") → assert status403, body equalsapperr.LogsErrorMessage + "\n", noSet-Cookie: jwt=...header present.POST /v1/auth/loginwith{"username":"bob","password":"hunter2example"}(no such user in the repo) → assert status403, identical body to step 13, noSet-Cookieheader — proves the domain-error change didn't turn this into a distinguishable 404/500 and didn't start leaking existence.
Manual verification (not exercised by the Go test)
- None. This slice has no SPA-visible behavior and no SMTP involvement; the SPA's article-detail view already treats any non-2xx as "not found" generically (verify only if the SPA has an article-detail page — otherwise skip).