3.5 KiB
Snippet Sharing API
A Go + PostgreSQL REST API for sharing code snippets (Assignment 3), with a full test suite (Assignment 4).
Name: Zagar Nashrullah NRP: 5803025048
Module: 5803025048/W04
Run the server
Set the database variables, then start the server. It listens on PORT (default 8080).
$env:DB_HOST="..."; $env:DB_PORT="..."
$env:DB_USER="..."; $env:DB_PASSWORD="..."; $env:DB_NAME="..."
go run ./cmd/server/main.go
PORT is the HTTP port of the API. DB_PORT is the PostgreSQL port.
Run the tests
Each layer has its own command:
go test ./internal/auth/... # unit tests
go test ./internal/middleware/... # unit tests, hand-written fake
go test ./internal/handler/... # unit tests, hand-written fakes
go test ./internal/store/... # integration tests, real PostgreSQL
go test ./e2e/... # black-box tests over HTTP
What each layer needs:
- auth, middleware, handler: nothing.
- store: the
DB_*variables, andDB_NAMEmust end in_test. - e2e: a running server. It uses
API_BASE_URL(defaulthttp://localhost:8080).
To run everything the way the grader does (start the server first, because ./... includes e2e):
go vet ./...
go test -race -shuffle=on -count=2 ./...
go test -coverpkg=./internal/... -coverprofile=cover.out ./internal/...
Warning: store tests wipe the database
The store tests TRUNCATE all tables at the start of every test. For safety, TestMain in internal/store refuses to run unless DB_NAME ends in _test (for example w04_5803025048_test). Never point them at a real database.
If the DB_* variables are missing or the database is unreachable, the tests fail. They never skip.
The e2e tests create their own unique usernames, so they work against a server that already has data.
Bugs My Tests Found
Defects in my Assignment 3 code that these tests exposed, and how I fixed them:
- Errors were not JSON. Every 400/401/403/404/409/500 used
http.Error, which sendstext/plain. Fix: a JSON error writer in the handlers and in the middleware. - A token without the
Bearerscheme was accepted. The middleware and logout used the whole header as the token. Fix: one strictmiddleware.BearerTokenhelper. A missing scheme,Basic ..., or an empty token now gives 401. - Logout returned 204 for tokens that did not exist. Fix: logout checks that the session exists and returns 401 otherwise.
- "Not found" leaked the database driver. Handlers compared against
pgx.ErrNoRows, andSnippetStore.Deletereturnednilfor an unknown id. Fix: addedstore.ErrNotFound, returned by every lookup.Deletereturns it when no row was affected. - Passwords longer than 72 bytes caused a 500 on
/register(bcrypt rejects them). Fix: they now return 400. - Username length was counted in bytes, not characters. Fix: it is now counted in runes.
GET /snippetscould returnnullfor an empty list. Fix: the handler always returns[], even if the store returns a nil slice.- Any login lookup error was reported as 401. Fix: a real database failure is now 500. Only "user not found" and "wrong password" give the (identical) 401.
Refactor for testability
No behavior change. Handlers depend on the UserStore, SessionStore and SnippetStore interfaces (package handler). The middleware depends on a small SessionLookup interface. The concrete types in internal/store satisfy them without importing handler or middleware.