Files

3.3 KiB

QA procedure: user_roles

Package: test (black-box). Reuse mockUserRepo, stubHasher, mockMailRepo, mockInviteRepo. No live server, no real SQLite file, no real SMTP.

Setup shared by every case

  1. Call validator.InitValidator() once.
  2. Use cases: NewGetUserUseCase, NewCreateInviteUseCase, NewListUsersAndInvitesUseCase, NewCreateUserUseCase, NewAcceptInviteUseCase over the fakes.
  3. Router mirrors NewUserRouter: jwtauth.Verifier + Authenticator with jwtauth.New("HS256", []byte("test-secret"), nil), RequireCurrentToken, RequireVerifiedUser, GET /, and a group with RequireOwner(getUser), TrustedProxyRealIP(nil), NewRateLimiter(2, time.Minute), POST /invite. A second router mirrors NewAuthRouter for /register, /invite/accept and /me.
  4. Seed: owner id 1 "marta" (role owner), admin id 2 "jonas" (role admin), both verified. Cookies carry user_id and token_version, and never a role.

Roles at creation

  1. Empty repo, POST /v1/auth/register -> 200, the stored user has Role == user.RoleOwner.
  2. Pending invite with a known code (stubHasher), POST /v1/auth/invite/accept -> 200, the stored user has Role == user.RoleAdmin, and user 1 is still owner.
  3. Use-case level: CreateUser returns a user with RoleOwner; AcceptInvite returns RoleAdmin.

GET /v1/auth/me

  1. Table over owner and admin: 200, decode into map[string]json.RawMessage, key role equals the stored role.
  2. Unverified owner -> 200, role "owner", is_verified false.
  3. The key set of the public user is exactly the eight fields, and POST /v1/auth/verify returns the same eight.

GET /v1/user/

  1. Seed three users plus a pending invite. 200; user items have exactly the keys id, kind, username, display_name, email, role, status, created_at; email and role match the seed. The invite item has exactly id, kind, email, status, created_at. No forbidden key appears anywhere.
  2. Cookie of admin 2 -> 200.

POST /v1/user/invite

  1. Owner cookie, valid body -> 201, one invite, one "invitation" mail.
  2. Admin cookie, valid body -> 403, body exactly apperr.OwnerRequiredErrorMessage, Content-Type is not JSON-decoded (plain text), no invite, no mail.
  3. Admin cookie with {"email":"not-an-email"} and with not json -> 403 both.
  4. Rate limit 2: admin sends 3 requests -> 403, 403, 403.
  5. Flip user 2's stored role from owner to admin between two requests with the same cookie -> second request 403.
  6. Existing auth table from invitations.qa.md (no cookie 401, unverified 403, stale token 401) is unchanged; the unverified 403 body remains apperr.VerificationRequiredErrorMessage.

Use case level

  1. RequireOwner with a user id that no longer exists -> 401 apperr.UnauthorizedErrorMessage; with an unexpected repository error -> 500.

Manual verification (not exercised by the Go tests)

  • Persistence backfill: copy a SQLite file from before this change with 3 users and no role column. Start the app: the column exists, the lowest id is owner, the others admin. Restart: nothing changes. Start against a fresh file: registering creates an owner.
  • Layering check by review: Role and the sentinel/constants live in internal/domain/user; GORM tags only in persistence/models, converted by the mapper.