refac: missing user or article is reported with a domain not-found error instead of a raw GORM error, and the API answers 404 for it
This commit is contained in:
1 parent
7c57173497
commit
8460a078e3
13 files changed
+426
-32
No files matched your search
@@ -0,0 +1,75 @@
|
||||
Feature: Domain not-found errors instead of raw GORM errors
|
||||
|
||||
As the maintainer of RenewCMS
|
||||
I want a missing article or user reported as a domain not-found error
|
||||
So that the API answers 404 for it instead of leaking a raw GORM error as a 500, and so that
|
||||
a caller can rely on errors.Is(err, article.ErrArticleNotFound) or errors.Is(err, user.ErrUserNotFound)
|
||||
|
||||
Background:
|
||||
Given internal/domain/article defines the sentinel article.ErrArticleNotFound
|
||||
And internal/domain/user defines the sentinel user.ErrUserNotFound
|
||||
And ArticleRepository.Get and ArticleRepository.GetByName return article.ErrArticleNotFound, not gorm.ErrRecordNotFound, when no row matches
|
||||
And UserRepository.Get, UserRepository.GetByUsername and UserRepository.GetByEmail return user.ErrUserNotFound, not gorm.ErrRecordNotFound, when no row matches
|
||||
And GET /v1/article/{id} sits behind the jwtauth Verifier and Authenticator group, and requires a valid jwt cookie
|
||||
|
||||
Scenario Outline: The article repository reports a missing article as a domain error
|
||||
Given a repository backed by an in-memory SQLite database containing an article titled "Backyard Renovation Update" with id 1
|
||||
When <method> is called with <input>
|
||||
Then the result is the error article.ErrArticleNotFound
|
||||
And errors.Is(err, gorm.ErrRecordNotFound) is false
|
||||
|
||||
Examples:
|
||||
| method | input |
|
||||
| Get | id 9 |
|
||||
| GetByName | "Unknown Title" |
|
||||
|
||||
Scenario Outline: The user repository reports a missing user as a domain error
|
||||
Given a repository backed by an in-memory SQLite database containing a user with id 1, username "alice" and email "alice@example.com"
|
||||
When <method> is called with <input>
|
||||
Then the result is the error user.ErrUserNotFound
|
||||
And errors.Is(err, gorm.ErrRecordNotFound) is false
|
||||
|
||||
Examples:
|
||||
| method | input |
|
||||
| Get | id 9 |
|
||||
| GetByUsername | "bob" |
|
||||
| GetByEmail | "bob@example.com" |
|
||||
|
||||
Scenario: Fetching a nonexistent article answers 404, not 500
|
||||
Given a valid jwt cookie for a user with id 1
|
||||
And the article repository has no article with id 9999
|
||||
When the client sends GET /v1/article/9999 with that cookie
|
||||
Then the response status is 404
|
||||
And the response body is the text "Article not found"
|
||||
|
||||
Scenario: Fetching an offline article still answers 404 with the same message
|
||||
Given a valid jwt cookie for a user with id 1
|
||||
And the article repository contains an article with id 2, is_online false
|
||||
When the client sends GET /v1/article/2 with that cookie
|
||||
Then the response status is 404
|
||||
And the response body is the text "Article not found"
|
||||
|
||||
Scenario: Fetching an online article still answers 200
|
||||
Given a valid jwt cookie for a user with id 1
|
||||
And the article repository contains an article with id 1, is_online true
|
||||
When the client sends GET /v1/article/1 with that cookie
|
||||
Then the response status is 200
|
||||
And the response body is the article's JSON representation
|
||||
|
||||
Scenario: The article route still requires authentication before existence is even checked
|
||||
Given no jwt cookie is sent
|
||||
And the article repository has no article with id 9999
|
||||
When the client sends GET /v1/article/9999 without a cookie
|
||||
Then the response status is 401
|
||||
|
||||
Scenario Outline: Login never reveals whether the username exists
|
||||
Given a user repository containing a user "alice" with password "hunter2example"
|
||||
When the client sends POST /v1/auth/login with username "<username>" and password "<password>"
|
||||
Then the response status is 403
|
||||
And the response body is the text apperr.LogsErrorMessage
|
||||
And no jwt cookie is set
|
||||
|
||||
Examples:
|
||||
| username | password | case |
|
||||
| alice | wrongpassword12 | existing user, bad pass |
|
||||
| bob | hunter2example | unknown username |
|
||||
Reference in new issue
Block a user