60663a461c
A user could select another local file with the same name as one that already exists in completed storage. The upload would be allowed to start and only hit an existing-file conflict late in the flow, which made the UI look like the file was uploadable. Reject duplicate sanitized names during upload creation so no staging record or chunk transfer starts for a file that cannot be completed. Keep the completion path non-replacing as a second guard by promoting through a no-overwrite file creation path, with a hard-link fast path and copy fallback for custom temp locations. The browser now treats the server's duplicate-name conflict as a terminal row: it disables the action, marks the item visually, and tells the user to rename the file if they want to upload that copy. Test Plan: - just check Refs: none
69 lines
2.9 KiB
Markdown
69 lines
2.9 KiB
Markdown
# Test Scenarios
|
|
|
|
Keep this file as the reusable verification checklist while implementing
|
|
`PLAN.md`.
|
|
|
|
## Automated
|
|
|
|
- `just check`
|
|
- Runs formatting, all Rust tests, and clippy.
|
|
- Current coverage:
|
|
- `GET /` serves the static browser page.
|
|
- `GET /healthz` reports `ok`.
|
|
- `POST /api/uploads` creates `meta.json`, a temp upload file, and a
|
|
completion-marker directory.
|
|
- `POST /api/uploads` rejects an empty file name.
|
|
- `POST /api/uploads` rejects a name that already exists in completed
|
|
storage before staging begins.
|
|
- `PUT /api/uploads/:id/chunks/:index` writes validated chunks into the
|
|
temp upload file and records completion markers.
|
|
- `PUT /api/uploads/:id/chunks/:index` rejects wrong-size chunks.
|
|
- `PUT /api/uploads/:id/chunks/:index` rejects out-of-range indexes.
|
|
- `PUT /api/uploads/:id/chunks/:index` accepts duplicate chunks.
|
|
- `GET /api/uploads/:id` reports completed chunks from disk markers.
|
|
- `POST /api/uploads/:id/complete` promotes the verified temp upload file
|
|
and removes staging data.
|
|
- Parallel upload requests for separate files complete without crossing
|
|
bytes between temp upload files.
|
|
- `POST /api/uploads/:id/complete` rejects incomplete uploads.
|
|
- `POST /api/uploads/:id/complete` refuses to replace a completed file that
|
|
appears after the upload was created.
|
|
- `POST /api/uploads/:id/complete` rejects tampered temp upload files.
|
|
- `static/app.js` passes `node --check`.
|
|
- `just nginx-smoke`
|
|
- Runs upl behind nginx in Docker.
|
|
- Uploads a 17 MiB file through nginx.
|
|
- Restarts the Rust backend mid-upload, resumes through nginx, completes, and
|
|
compares SHA-256 hashes.
|
|
- Serves the completed file through nginx's final-upload alias.
|
|
|
|
## Manual
|
|
|
|
These scenarios come from `PLAN.md` and remain useful for real browser and
|
|
deployment retests.
|
|
|
|
- Upload a small file in one pass.
|
|
- Upload a file larger than one chunk.
|
|
- Select multiple files and confirm several upload rows advance at the same
|
|
time.
|
|
- Kill the browser tab mid-upload and resume.
|
|
- Restart the Rust server mid-upload and resume.
|
|
- Interrupt the network and resume.
|
|
- Pause from the browser controls and resume.
|
|
- Reload the page and resume from the pending upload list.
|
|
- In a browser with the File System Access API, resume without reselecting the
|
|
file after granting read permission.
|
|
- In a browser without the File System Access API, resume after reselecting the
|
|
same file.
|
|
- Retry a duplicate chunk and confirm it is accepted idempotently.
|
|
- Attempt an invalid chunk index and confirm it is rejected.
|
|
- Attempt a wrong-size non-final chunk and confirm it is rejected.
|
|
- Install `deploy/nginx/upl.conf.example` on the deployment host, add the real
|
|
TLS certificate and access-control settings, and repeat the resume scenarios
|
|
through the public nginx URL.
|
|
- Complete an upload and compare the final file with the source file:
|
|
|
|
```sh
|
|
sha256sum source-file data/complete/uploaded-file
|
|
```
|