Files

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.