100 lines
3.4 KiB
Markdown
100 lines
3.4 KiB
Markdown
# Assignment 4: Testing the Snippet Sharing API
|
|
|
|
## How to Run Tests
|
|
|
|
### Unit tests (no database)
|
|
|
|
go test ./internal/auth/...
|
|
go test ./internal/middleware/...
|
|
go test ./internal/handler/...
|
|
|
|
### Store tests (require PostgreSQL)
|
|
|
|
Store tests truncate tables. The database name MUST end with `_test`.
|
|
`TestMain` refuses to run otherwise.
|
|
|
|
export DB_HOST=localhost
|
|
export DB_PORT=5432
|
|
export DB_USER=postgres
|
|
export DB_PASSWORD=postgres
|
|
export DB_NAME=snippet_test
|
|
go test ./internal/store/...
|
|
|
|
### E2E tests (require a running server)
|
|
|
|
Start the server in one terminal:
|
|
|
|
go run ./cmd/server
|
|
|
|
Then run the e2e suite in another terminal:
|
|
|
|
API_BASE_URL=http://localhost:8080 go test ./e2e/...
|
|
|
|
### Full suite
|
|
|
|
go vet ./...
|
|
go test -race -shuffle=on -count=2 ./...
|
|
|
|
---
|
|
|
|
## Bugs My Tests Found
|
|
|
|
The following defects were found in Assignment 3 code while writing tests for
|
|
Assignment 4, and were fixed.
|
|
|
|
### 1. `POST /register` returned 400 for duplicate username (should be 409)
|
|
Found by `TestRegister/duplicate_username_->_409` and `TestE2E_RegisterDuplicate`.
|
|
Fix: `UserStore.Create` translates PostgreSQL SQLSTATE 23505 to `store.ErrDuplicate`; handler returns `409`.
|
|
|
|
### 2. `POST /logout` returned 200 with JSON body (should be 204 empty)
|
|
Found by `TestLogout` and `TestE2E_LogoutInvalidatesToken`.
|
|
Fix: Handler writes `204 No Content` with empty body.
|
|
|
|
### 3. `POST /logout` did not verify token exists
|
|
Found by `TestLogout/unknown_token_->_401`.
|
|
Fix: Handler calls `SessionStore.Get` first; unknown token → `401`.
|
|
|
|
### 4. `GET /snippets` returned every user's snippets (mutant M5)
|
|
Found by `TestListSnippets` and `TestE2E_DataIsolation`.
|
|
Fix: Added `ListByOwner(ctx, ownerID)` and handler passes caller's id.
|
|
|
|
### 5. `DELETE /snippets/{id}` had no ownership check (mutant M1)
|
|
Found by `TestDeleteSnippet/non-owner_->_403`.
|
|
Fix: Handler fetches snippet first, compares `UserID`, returns `403`.
|
|
|
|
### 6. `DELETE /snippets/{id}` returned 204 for nonexistent id (mutant M2)
|
|
Found by `TestDeleteSnippet/nonexistent_id_->_404`.
|
|
Fix: Store checks `RowsAffected`, returns `ErrNotFound`, handler maps to `404`.
|
|
|
|
### 7. Error responses used `http.Error` (text/plain, not JSON) (mutant M8)
|
|
Found by `TestRequireAuth` and `TestE2E_ContentTypeAndSchema`.
|
|
Fix: Added JSON error helpers setting `Content-Type: application/json`.
|
|
|
|
### 8. `GET /snippets/{id}` required auth (should be public) (mutant M10)
|
|
Found by `TestGetSnippet` and `TestE2E_PublicRead`.
|
|
Fix: Removed middleware wrapper in `main.go`.
|
|
|
|
### 9. Empty snippet list serialized as `null` (should be `[]`) (mutant M7)
|
|
Found by `TestListSnippets/no_snippets_->_body_is_literally_[]`.
|
|
Fix: Store and handler build non-nil slices.
|
|
|
|
### 10. Snippet responses could include `user_id` (mutant M9)
|
|
Found by `TestE2E_ContentTypeAndSchema`.
|
|
Fix: Introduced `snippetResponse` DTO with only `id`, `title`, `content`.
|
|
|
|
### 11. Malformed JSON returned 500 instead of 400
|
|
Found by `TestE2E_BadInput`.
|
|
Fix: All decoders return `400` on JSON decode error.
|
|
|
|
### 12. Login failures distinguishable (user enumeration)
|
|
Found by `TestE2E_LoginFailuresIndistinguishable`.
|
|
Fix: Same `401` body for wrong-password and unknown-user.
|
|
|
|
---
|
|
|
|
## Refactor Summary
|
|
|
|
Handlers and middleware now depend on interfaces defined in their own packages
|
|
(`UserStore`, `SessionStore`, `SnippetStore`, `SessionLookup`). Concrete types
|
|
in `internal/store` satisfy these interfaces without any import cycle. Public
|
|
API behavior is unchanged. |