Files
RenewCMS/features/hasher_domain_interface.qa.md

64 lines
4.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# QA procedure: hasher_domain_interface
Package: `test` (black-box, alongside the existing `article_test.go` / `user_test.go` /
`use_case_baseline_test.go` / `not_found_errors_test.go`).
## Fakes needed
1. A `fakeHasher` implementing `hash.Hasher`:
- `Hash(value string) (string, error)`: by default returns `"hashed:" + value, nil`;
configurable to return `("", someErr)` unconditionally.
- `Compare(hashed, value string) error`: by default returns `nil` when
`hashed == "hashed:"+value`, else a sentinel mismatch error; configurable to always
error, and to record whether it was called.
2. Extend the existing `mockUserRepo` (from `test/user_test.go` /
`not_found_errors_test.go`) with call-recording flags already used elsewhere in the
package (`createCalled`, `updatePasswordCalled`, etc.) if not already present, so tests
can assert a hashing failure short-circuits before the repository is touched.
## Use-case-level checks (fake hasher + fake repo, no HTTP)
3. `useCases.NewCreateUserUseCase(fakeRepo, fakeHasher)`, `CreateUser(...)`: assert the
`User` argument the fake repo's `Create` receives has `Password == "hashed:s3cretPassw0rd"`
and a `VerificationCode` that starts with `"hashed:"`; assert the `User` returned by the
use case has a `VerificationCode` that does **not** start with `"hashed:"` (it is the raw
UUID, unchanged from current behaviour).
4. Same use case with `fakeHasher` configured to always error on `Hash`: assert
`CreateUser` returns that error and `fakeRepo.Create` was never called.
7. `useCases.NewAuthenticateUserUseCase(fakeRepo, fakeHasher)` (new use case): seed
`fakeRepo` with a user "alice" whose stored `Password` is `"hashed:hunter2example"`.
- `Authenticate("alice", "hunter2example")` with `fakeHasher.Compare` returning `nil` →
assert the returned user matches and `err` is `nil`.
- `Authenticate("alice", "wrongpassword12")` with `fakeHasher.Compare` returning an error
→ assert `errors.Is(err, user.ErrInvalidCredentials)` is `true`.
- `Authenticate("bob", "hunter2example")` with no "bob" in the repo → assert
`errors.Is(err, user.ErrUserNotFound)` is `true` and `fakeHasher`'s `Compare` was never
invoked (record a `compareCalled` flag).
## HTTP checks (real BcryptHasher, in-memory fake repo, mirroring api/router.go)
8. Call `validator.InitValidator()`.
9. Build `hashing.NewBcryptHasher()`, wire `useCases.NewCreateUserUseCase(fakeRepo,
bcryptHasher)` and `useCases.NewAuthenticateUserUseCase(fakeRepo, bcryptHasher)` (plus
the existing `GetUserUseCase` / `ListUsersUseCase` the auth handler still needs), build
`auth.NewHandler(token, get, list, create, authenticate)` (constructor signature grows by
the new use case) with a test `jwtauth.New("HS256", []byte("test-secret"), nil)`, mount
its routes unprotected on a fresh `chi.NewRouter()` as in `api/router.go`.
10. Seed the fake user repo directly with a user "alice" whose `Password` field holds a real
`bcryptHasher.Hash("hunter2example")` result (not `bcrypt.GenerateFromPassword` called
from the test, so the test never imports bcrypt itself).
11. `POST /v1/auth/login` with `{"username":"alice","password":"wrongpassword12"}` → assert
status `403`, body `apperr.LogsErrorMessage + "\n"`, no `Set-Cookie: jwt=...` header.
12. `POST /v1/auth/login` with `{"username":"bob","password":"hunter2example"}` (no such
user) → assert identical status/body/no-cookie outcome to step 11 (regression, same as
`not_found_errors.qa.md` steps 13–14).
13. `POST /v1/auth/register` with `{"username":"alice","password":"s3cretPassw0rd","email":"alice@example.com"}`
against an empty fake repo → assert status `200`, a `Set-Cookie: jwt=...` header is
present, and the `Password` the fake repo's `Create` received is neither empty nor equal
to `"s3cretPassw0rd"`; assert `bcryptHasher.Compare(storedPassword, "s3cretPassw0rd")`
returns `nil`.
14. Rebuild the handler with a `fakeHasher` (from step 1) whose `Hash` always errors in
place of `bcryptHasher`, same empty fake repo. `POST /v1/auth/register` with the same
valid body → assert status `500`, no `Set-Cookie` header, and the fake repo's `Create`
was never called.
## Manual verification (not exercised by the Go test)
- None. This slice has no SPA-visible behaviour and no SMTP involvement.