3.4 KiB
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.