6.0 KiB
QA procedure: media_library
Package: test (black-box). New file test/media_library_http_test.go. Fake type names must be unique in the package.
Setup shared by every case
-
Call
validator.InitValidator()once. -
Rewrite
mockImageRepo(test/image_test.go) to the newimage.Repository: Create (stores the metadata from the ImageInput and derives a/static/uploadedImages/<n>.<ext>path), Get, Delete (records calls, honoursfailDeleteFor), List(query), FindByHash, Rename, ListByHash groups, Counts. Add fields for seedingFilename,Size,ContentType,Width,Height,SHA256,UploadedByID,CreatedAt. -
Extend
mockArticleRepo(test/article_test.go) withFindByBodyContaining(filename)(substring overBody) and a per-id failure switch forUpdateBody. RemoveAddImageand the articleImagesfield from the fake and from every test that uses them. -
Use the existing user fake so
uploaded_byresolves: user 1 display name "Inès Duarte", user 2 username "marta" with empty display name. -
Wire the real use cases over the fakes: create, list, rename, delete, merge and usage media use cases,
NewCreateImageUseCase(imageRepo),NewGetUserUseCase(userRepo). Buildmedia.NewHandler(...)(api/handlers/media) andimage.NewHandler(...)for the alias. -
Build
jwtauth.New("HS256", []byte("test-secret"), nil). Mount on a freshchi.NewRouter()mirroringapi/router.go:jwtauth.Verifierat the top, then in the media groupAuthenticator,RequireCurrentToken(getUser),RequireVerifiedUser(getUser), with the six routes under/v1/media. -
Mint cookies via
token.Encode(map[string]any{"user_id": uint32(n), ...})as in the other HTTP tests. Build a stale-token cookie with atoken_versionlower than the user's, and use an unverified user for the 403 case. -
Build multipart bodies with
mime/multipart.Writer, usingCreatePartwith an explicit partContent-Typeheader. Generate real bytes in the test:- PNG (3x2) with
image/png; - JPEG (3x2) with
image/jpeg; - a tiny valid WEBP fixture (1x1) as a byte constant;
- SVG
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10"/>.
Compute expected sha256 in the test with
crypto/sha256. For size limits, pad valid PNG bytes to 10485760 and 10485761 bytes. - PNG (3x2) with
-
Seed the Listing background exactly as in the feature (5 images, 3 articles, 2 users), with
created_atstrictly increasing by id.
HTTP checks
- Auth table: each method+path from the outline with no cookie -> 401, stale cookie -> 401 with
apperr.UnauthorizedErrorMessage, unverified cookie -> 403 withapperr.VerificationRequiredErrorMessage. Assert no fake method beyond the middleware's user lookup was called. - List: decode
{items, next_cursor, counts}. Assert each row of the sort, filter,qandhashtables, the combined query, the paging walk (limit 2 across three pages ending innext_cursor == null), the empty library (itemsis[]in the raw JSON, notnull), SVGwidth/heightare JSONnull(assert on the raw body), andcountsis unchanged byq/filter. Assert every 400 query row, body equalsapperr.MediaQueryErrorMessage + "\n". - Upload: for each allowed type assert 201, the item fields,
sha256equals the test's own hash,uploaded_by, the url regex, and one repo entry withUploadedByID == 1. Upload identical bytes twice: both 201, second hasduplicate: true, listcounts.duplicates == 1. Assert filename rules (no extension gets.png, path stripped). Assert 413/415/400 statuses and bodies, thatCreateis never called on rejection, boundary 10485760 vs 10485761, a missingfilepart -> 400, and an armedCreatefailure -> 500"Internal server error\n". - Rename: assert 200 with the new filename, the same
url, the article body unchanged, and every invalid row -> 400 with"Enter a filename.\n"for the filename rows; 404 for 9999; 400 withapperr.IdUint32ErrorMessageforabc. Assert the repository filename is unchanged after each 400. - Delete: in-use image -> 204 with an empty body, article bodies byte-identical,
deleteCalls == [1]; 404, 400, 500 rows. The "file already gone" case is a persistence behaviour and is a manual item. - Usage: assert the exact JSON arrays (raw body compared as JSON), the empty
[], the absolute-url article, 404 and 400. - Merge: assert 200
{articles_updated, merged}, resulting bodies (both occurrences replaced), unchanged bodies for the other articles, and only image 2 left. Assert the 409 rows and 404 row, with no body change and noDeletecalls (deleteCallsempty). Assert every 400 row withapperr.MediaMergeRequestErrorMessage. Assert the two failure rows:UpdateBodyfailing for article 2 leaves article 1 restored and noDeletecall;Deletefailing for image 3 leaves bodies switched and returns 500. - Unit-level asserts (same file, no HTTP) with
errors.Ison the sentinelsErrImageUnreadable,ErrMergeCopyMissing,ErrMergeHashMismatch,ErrInvalidFilename. - Layering guard:
go list -depsor a grep-style test thatapi/handlers/mediaimports nopersistence,mailer,modelsorgormpackage.
Manual verification (not exercised by task test)
- Real upload, rename, delete, merge against a scratch SQLite file and
UPLOAD_DIRviatask dev: the files land on disk,urlloads through/static/uploadedImages/, deleting an in-use image leaves the article body text untouched, and a merge removes the copy files. - Delete when the file was already removed from
UPLOAD_DIRstill answers 204. - Startup backfill: copy an old database (rows with only
path), boot, and check that filename, size, content_type, width, height and sha256 are filled; check idempotency on a second boot; check that a row whose file is missing does not stop the boot; check that thearticle_imagestable andarticle_idcolumn are still present and not written. UploadedByID0 rows display an emptyuploaded_by.- WEBP dimensions with a real WEBP file (the fixture is minimal).
- No SMTP involvement. No real rate limit (out of scope for this slice).