feat: optional S3-compatible storage for uploaded images, instead of the local upload directory
This commit is contained in:
1 parent
d752a61e52
commit
eb9bfabed5
23 files changed
+1962
-7
No files matched your search
@@ -0,0 +1,26 @@
|
||||
# QA: S3 image storage
|
||||
|
||||
All tests live in test/ (package test). No cloud account, no real SMTP, no real SQLite file. Test names carry "S3Storage".
|
||||
|
||||
Settled decisions: boot backfill gets a log line only, wired in the composition root, with no cap and no use case change. No ETag is emitted; the staticimages handler is unchanged and conditional requests are validated by Last-Modified only.
|
||||
|
||||
## Automated
|
||||
1. Config validation: table test over STORAGE_DRIVER and S3_* lookup functions (the MissingEnvVarError pattern, a `StorageRequiredEnvVars(driver)` helper like `DatabaseRequiredEnvVars`). Covers the validation table, UPLOAD_DIR ignored, unknown driver error.
|
||||
2. Registry: storage.Open with "local" returns local storage, "s3" returns the S3 storage after HEAD bucket, anything else returns the "unsupported storage driver" error.
|
||||
3. Fake S3: an httptest.Server on 127.0.0.1 only (never bind :port) implementing HEAD bucket, PUT, GET with Range, HEAD and DELETE object, with injectable statuses and recorded keys, headers and bodies.
|
||||
4. Adapter tests against the fake: the Put, Open (found, 404, 500) and Delete scenarios, HEAD bucket 404/403/500, prefix handling, ModTime and Size from metadata, Content as io.ReadSeeker (seek then read issues a ranged GET), secret absent from error text.
|
||||
5. Handler tests: staticimages.NewHandler over OpenMediaUseCase over the S3 storage on the fake server, mounted on a fresh chi.NewRouter() at /static/uploadedImages/*. Cover GET, HEAD, 304 via If-Modified-Since, 206, 416, SVG CSP, 404, 500, traversal.
|
||||
6. Handler regression: a storage fake returning a non-seekable Blob. GET and HEAD behave exactly as today.
|
||||
7. Backfill log: the boot log line for the number of images read, captured with a log writer, containing no credential.
|
||||
8. Local regression: all existing image tests pass unchanged.
|
||||
9. Gates: `task test` and `task lint:go` pass. `task mutate` is not part of this slice, but the new storage package becomes a target if the mutation scope is widened. The 404 to ErrBlobNotFound and idempotent-Delete branches need killing tests.
|
||||
|
||||
## Optional integration (task test:s3)
|
||||
Start a SeaweedFS container with Docker, create a bucket, set RENEWCMS_TEST_S3_ENDPOINT and run the adapter tests against it. Skip with a message when Docker is unavailable. Not part of `task test`.
|
||||
|
||||
## Manual
|
||||
- Run docker-compose.s3.yml, upload an image in the SPA, confirm the object is in the bucket and /static/uploadedImages/<name> serves it, including after the container is recreated.
|
||||
- Real AWS S3, R2, B2 or Scaleway smoke test, and an instance-role credential check.
|
||||
- Start with a wrong bucket and confirm a clear, secret-free startup error.
|
||||
- Sync an old UPLOAD_DIR with `aws s3 sync` or `mc mirror` and confirm old images load.
|
||||
- Confirm docs describe: variables (configuration.md, .env.example, docker.env.example, Docker docs), UPLOAD_DIR ignored with s3, manual migration, update backups covering the DB only and not the bucket, and the updated architecture.md "Storage and database seams" section.
|
||||
Reference in new issue
Block a user