65 lines
3.7 KiB
Markdown
65 lines
3.7 KiB
Markdown
# QA procedure: get_current_user
|
|
|
|
Package: `test` (black-box), extending `test/user_test.go` (`mockUserRepo`) and following the router
|
|
wiring pattern in `test/stale_token_invalidation_http_test.go`.
|
|
|
|
## Test infrastructure additions needed first
|
|
|
|
1. No new `mockUserRepo` methods are needed: `GetUser(id)` already exists and is already exercised
|
|
by other tests (e.g. `test/stale_token_invalidation_http_test.go`). `DELETE /v1/auth/register`
|
|
already deletes the row via `CancelRegistrationUseCase`, already used in
|
|
`test/cancel_pending_registration_http_test.go`.
|
|
|
|
## Setup shared by every case
|
|
|
|
2. Call `validator.InitValidator()` once.
|
|
3. Build `getUserUseCase := useCases.NewGetUserUseCase(userRepo)`.
|
|
4. Build `meHandler := auth.NewMeHandler(getUserUseCase)`.
|
|
5. Also build `verificationHandler := auth.NewVerificationHandler(useCases.NewVerifyUserUseCase(userRepo,
|
|
hasher), useCases.NewCancelRegistrationUseCase(userRepo), true)` so the "deleted account" scenario
|
|
can call `DELETE /v1/auth/register` on the same router.
|
|
6. Mount on a fresh `chi.NewRouter()`, mirroring `NewAuthRouter`'s protected group:
|
|
```go
|
|
r.Route("/v1/auth", func(r chi.Router) {
|
|
r.Group(func(r chi.Router) {
|
|
r.Use(jwtauth.Verifier(token))
|
|
r.Use(jwtauth.Authenticator(token))
|
|
r.Use(middleware.RequireCurrentToken(getUserUseCase))
|
|
r.Get("/me", meHandler.Me)
|
|
r.Delete("/register", verificationHandler.CancelRegistration)
|
|
})
|
|
})
|
|
```
|
|
with a test `token := jwtauth.New("HS256", []byte("test-secret"), nil)`. No live server.
|
|
7. Mint jwt cookies with `token.Encode(map[string]any{"user_id": uint32(id), "token_version":
|
|
uint32(v)})`, the same convention as `test/stale_token_invalidation_http_test.go`.
|
|
|
|
## HTTP-level checks
|
|
|
|
8. Seed `mockUserRepo` with user id 7, username "alice", email "alice@example.com",
|
|
`IsVerified: true`, `Role: owner`, `TokenVersion: 0`. Mint a cookie for user 7 with
|
|
`token_version: 0`. `GET /v1/auth/me` → assert status `200`, `Cache-Control` header equals
|
|
`"no-store"`, and the decoded JSON body has `id: 7`, `username: "alice"`,
|
|
`email: "alice@example.com"`, `is_verified: true`, `role: "owner"`.
|
|
9. Seed user id 8, username "bob", email "bob@example.com", `IsVerified: false`, `Role: owner`,
|
|
`TokenVersion: 0`. Mint a matching cookie. `GET /v1/auth/me` → assert status `200` (not 403),
|
|
`Cache-Control: no-store`, `is_verified: false` and `role: "owner"` in the body.
|
|
10. No `jwt` cookie at all against the router from step 6 → assert status `401` (produced by
|
|
`jwtauth.Authenticator` itself; don't assert an exact body for this case, same rationale as
|
|
`features/account_verification.qa.md` step 15).
|
|
11. Seed user id 7 with `TokenVersion: 1`. Mint a cookie encoding `token_version: 0` (stale).
|
|
`GET /v1/auth/me` → assert status `401` and body exactly `apperr.UnauthorizedErrorMessage`.
|
|
12. Seed user id 7, `IsVerified: false`, `TokenVersion: 0`. Mint a matching cookie.
|
|
`DELETE /v1/auth/register` with that cookie → assert status `200`. Then `GET /v1/auth/me` with
|
|
the same cookie → assert status `401` and body exactly `apperr.UnauthorizedErrorMessage`.
|
|
13. Seed user id 7, `IsVerified: true`, `TokenVersion: 0`, matching cookie. Send
|
|
`GET /v1/auth/me` 5 times in a row on the same router/repo → assert every response is `200`
|
|
and none is `429`.
|
|
|
|
## Manual verification (not exercised by the Go test)
|
|
|
|
- The SPA actually calling `GET /v1/auth/me` on load/refresh to restore session state and route an
|
|
unverified user to the pending-verification screen (rather than guessing from stored client state)
|
|
is out of scope for this slice's automated test and should be checked by hand against a running
|
|
dev build.
|