* Add TUS protocol integration tests
This commit adds integration tests for the TUS (resumable upload) protocol
in preparation for implementing TUS support in the filer.
Test coverage includes:
- OPTIONS handler for capability discovery
- Basic single-request upload
- Chunked/resumable uploads
- HEAD requests for offset tracking
- DELETE for upload cancellation
- Error handling (invalid offsets, missing uploads)
- Creation-with-upload extension
- Resume after interruption simulation
Tests are skipped in short mode and require a running SeaweedFS cluster.
* Add TUS session storage types and utilities
Implements TUS upload session management:
- TusSession struct for tracking upload state
- Session creation with directory-based storage
- Session persistence using filer entries
- Session retrieval and offset updates
- Session deletion with chunk cleanup
- Upload completion with chunk assembly into final file
Session data is stored in /.uploads.tus/{upload-id}/ directory,
following the pattern used by S3 multipart uploads.
* Add TUS HTTP handlers
Implements TUS protocol HTTP handlers:
- tusHandler: Main entry point routing requests
- tusOptionsHandler: Capability discovery (OPTIONS)
- tusCreateHandler: Create new upload (POST)
- tusHeadHandler: Get upload offset (HEAD)
- tusPatchHandler: Upload data at offset (PATCH)
- tusDeleteHandler: Cancel upload (DELETE)
- tusWriteData: Upload data to volume servers
Features:
- Supports creation-with-upload extension
- Validates TUS protocol headers
- Offset conflict detection
- Automatic upload completion when size is reached
- Metadata parsing from Upload-Metadata header
* Wire up TUS protocol routes in filer server
Add TUS handler route (/.tus/) to the filer HTTP server.
The TUS route is registered before the catch-all route to ensure
proper routing of TUS protocol requests.
TUS protocol is now accessible at:
- OPTIONS /.tus/ - Capability discovery
- POST /.tus/{path} - Create upload
- HEAD /.tus/.uploads/{id} - Get offset
- PATCH /.tus/.uploads/{id} - Upload data
- DELETE /.tus/.uploads/{id} - Cancel upload
* Improve TUS integration test setup
Add comprehensive Makefile for TUS tests with targets:
- test-with-server: Run tests with automatic server management
- test-basic/chunked/resume/errors: Specific test categories
- manual-start/stop: For development testing
- debug-logs/status: For debugging
- ci-test: For CI/CD pipelines
Update README.md with:
- Detailed TUS protocol documentation
- All endpoint descriptions with headers
- Usage examples with curl commands
- Architecture diagram
- Comparison with S3 multipart uploads
Follows the pattern established by other tests in test/ folder.
* Fix TUS integration tests and creation-with-upload
- Fix test URLs to use full URLs instead of relative paths
- Fix creation-with-upload to refresh session before completing
- Fix Makefile to properly handle test cleanup
- Add FullURL helper function to TestCluster
* Add TUS protocol tests to GitHub Actions CI
- Add tus-tests.yml workflow that runs on PRs and pushes
- Runs when TUS-related files are modified
- Automatic server management for integration testing
- Upload logs on failure for debugging
* Make TUS base path configurable via CLI
- Add -tus.path CLI flag to filer command
- TUS is disabled by default (empty path)
- Example: -tus.path=/.tus to enable at /.tus endpoint
- Update test Makefile to use -tus.path flag
- Update README with TUS enabling instructions
* Rename -tus.path to -tusBasePath with default .tus
- Rename CLI flag from -tus.path to -tusBasePath
- Default to .tus (TUS enabled by default)
- Add -filer.tusBasePath option to weed server command
- Properly handle path prefix (prepend / if missing)
* Address code review comments
- Sort chunks by offset before assembling final file
- Use chunk.Offset directly instead of recalculating
- Return error on invalid file ID instead of skipping
- Require Content-Length header for PATCH requests
- Use fs.option.Cipher for encryption setting
- Detect MIME type from data using http.DetectContentType
- Fix concurrency group for push events in workflow
- Use os.Interrupt instead of Kill for graceful shutdown in tests
* fmt
* Address remaining code review comments
- Fix potential open redirect vulnerability by sanitizing uploadLocation path
- Add language specifier to README code block
- Handle os.Create errors in test setup
- Use waitForHTTPServer instead of time.Sleep for master/volume readiness
- Improve test reliability and debugging
* Address critical and high-priority review comments
- Add per-session locking to prevent race conditions in updateTusSessionOffset
- Stream data directly to volume server instead of buffering entire chunk
- Only buffer 512 bytes for MIME type detection, then stream remaining data
- Clean up session locks when session is deleted
* Fix race condition to work across multiple filer instances
- Store each chunk as a separate file entry instead of updating session JSON
- Chunk file names encode offset, size, and fileId for atomic storage
- getTusSession loads chunks from directory listing (atomic read)
- Eliminates read-modify-write race condition across multiple filers
- Remove in-memory mutex that only worked for single filer instance
* Address code review comments: fix variable shadowing, sniff size, and test stability
- Rename path variable to reqPath to avoid shadowing path package
- Make sniff buffer size respect contentLength (read at most contentLength bytes)
- Handle Content-Length < 0 in creation-with-upload (return error for chunked encoding)
- Fix test cluster: use temp directory for filer store, add startup delay
* Fix test stability: increase cluster stabilization delay to 5 seconds
The tests were intermittently failing because the volume server needed more
time to create volumes and register with the master. Increasing the delay
from 2 to 5 seconds fixes the flaky test behavior.
* Address PR review comments for TUS protocol support
- Fix strconv.Atoi error handling in test file (lines 386, 747)
- Fix lossy fileId encoding: use base64 instead of underscore replacement
- Add pagination support for ListDirectoryEntries in getTusSession
- Batch delete chunks instead of one-by-one in deleteTusSession
* Address additional PR review comments for TUS protocol
- Fix UploadAt timestamp: use entry.Crtime instead of time.Now()
- Remove redundant JSON content in chunk entry (metadata in filename)
- Refactor tusWriteData to stream in 4MB chunks to avoid OOM on large uploads
- Pass filer.Entry to parseTusChunkPath to preserve actual upload time
* Address more PR review comments for TUS protocol
- Normalize TUS path once in filer_server.go, store in option.TusPath
- Remove redundant path normalization from TUS handlers
- Remove goto statement in tusCreateHandler, simplify control flow
* Remove unnecessary mutexes in tusWriteData
The upload loop is sequential, so uploadErrLock and chunksLock are not needed.
* Rename updateTusSessionOffset to saveTusChunk
Remove unused newOffset parameter and rename function to better reflect its purpose.
* Improve TUS upload performance and add path validation
- Reuse operation.Uploader across sub-chunks for better connection reuse
- Guard against TusPath='/' to prevent hijacking all filer routes
* Address PR review comments for TUS protocol
- Fix critical chunk filename parsing: use strings.Cut instead of SplitN
to correctly handle base64-encoded fileIds that may contain underscores
- Rename tusPath to tusBasePath for naming consistency across codebase
- Add background garbage collection for expired TUS sessions (runs hourly)
- Improve error messages with %w wrapping for better debuggability
* Address additional TUS PR review comments
- Fix tusBasePath default to use leading slash (/.tus) for consistency
- Add chunk contiguity validation in completeTusUpload to detect gaps/overlaps
- Fix offset calculation to find maximum contiguous range from 0, not just last chunk
- Return 413 Request Entity Too Large instead of silently truncating content
- Document tusChunkSize rationale (4MB balances memory vs request overhead)
- Fix Makefile xargs portability by removing GNU-specific -r flag
- Add explicit -tusBasePath flag to integration test for robustness
- Fix README example to use /.uploads/tus path format
* Revert log_buffer changes (moved to separate PR)
* Minor style fixes from PR review
- Simplify tusBasePath flag description to use example format
- Add 'TUS upload' prefix to session not found error message
- Remove duplicate tusChunkSize comment
- Capitalize warning message for consistency
- Add grep filter to Makefile xargs for better empty input handling
242 lines
6.8 KiB
Markdown
242 lines
6.8 KiB
Markdown
# TUS Protocol Integration Tests
|
|
|
|
This directory contains integration tests for the TUS (resumable upload) protocol support in SeaweedFS Filer.
|
|
|
|
## Overview
|
|
|
|
TUS is an open protocol for resumable file uploads over HTTP. It allows clients to upload files in chunks and resume uploads after network failures or interruptions.
|
|
|
|
### Why TUS?
|
|
|
|
- **Resumable uploads**: Resume interrupted uploads without re-sending data
|
|
- **Chunked uploads**: Upload large files in smaller pieces
|
|
- **Simple protocol**: Standard HTTP methods with custom headers
|
|
- **Wide client support**: Libraries available for JavaScript, Python, Go, and more
|
|
|
|
## TUS Protocol Endpoints
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| `OPTIONS` | `/.tus/` | Server capability discovery |
|
|
| `POST` | `/.tus/{path}` | Create new upload session |
|
|
| `HEAD` | `/.tus/.uploads/{id}` | Get current upload offset |
|
|
| `PATCH` | `/.tus/.uploads/{id}` | Upload data at offset |
|
|
| `DELETE` | `/.tus/.uploads/{id}` | Cancel upload |
|
|
|
|
### TUS Headers
|
|
|
|
**Request Headers:**
|
|
- `Tus-Resumable: 1.0.0` - Protocol version (required)
|
|
- `Upload-Length` - Total file size in bytes (required on POST)
|
|
- `Upload-Offset` - Current byte offset (required on PATCH)
|
|
- `Upload-Metadata` - Base64-encoded key-value pairs (optional)
|
|
- `Content-Type: application/offset+octet-stream` (required on PATCH)
|
|
|
|
**Response Headers:**
|
|
- `Tus-Resumable` - Protocol version
|
|
- `Tus-Version` - Supported versions
|
|
- `Tus-Extension` - Supported extensions
|
|
- `Tus-Max-Size` - Maximum upload size
|
|
- `Upload-Offset` - Current byte offset
|
|
- `Location` - Upload URL (on POST)
|
|
|
|
## Enabling TUS
|
|
|
|
TUS protocol support is enabled by default at `/.tus` path. You can customize the path using the `-tusBasePath` flag:
|
|
|
|
```bash
|
|
# Start filer with default TUS path (/.tus)
|
|
weed filer -master=localhost:9333
|
|
|
|
# Use a custom path (leading slash added automatically if missing)
|
|
weed filer -master=localhost:9333 -tusBasePath=/.uploads/tus
|
|
|
|
# Disable TUS by setting empty path
|
|
weed filer -master=localhost:9333 -tusBasePath=
|
|
```
|
|
|
|
## Test Structure
|
|
|
|
### Integration Tests
|
|
|
|
The tests cover:
|
|
|
|
1. **Basic Functionality**
|
|
- `TestTusOptionsHandler` - Capability discovery
|
|
- `TestTusBasicUpload` - Simple complete upload
|
|
- `TestTusCreationWithUpload` - Creation-with-upload extension
|
|
|
|
2. **Chunked Uploads**
|
|
- `TestTusChunkedUpload` - Upload in multiple chunks
|
|
|
|
3. **Resumable Uploads**
|
|
- `TestTusHeadRequest` - Offset tracking
|
|
- `TestTusResumeAfterInterruption` - Resume after failure
|
|
|
|
4. **Error Handling**
|
|
- `TestTusInvalidOffset` - Offset mismatch (409 Conflict)
|
|
- `TestTusUploadNotFound` - Missing upload (404 Not Found)
|
|
- `TestTusDeleteUpload` - Upload cancellation
|
|
|
|
## Running Tests
|
|
|
|
### Prerequisites
|
|
|
|
1. **Build SeaweedFS**:
|
|
```bash
|
|
make build-weed
|
|
# or
|
|
cd ../../weed && go build -o weed
|
|
```
|
|
|
|
### Using Makefile
|
|
|
|
```bash
|
|
# Show available targets
|
|
make help
|
|
|
|
# Run all tests with automatic server management
|
|
make test-with-server
|
|
|
|
# Run all tests (requires running server)
|
|
make test
|
|
|
|
# Run specific test categories
|
|
make test-basic # Basic upload tests
|
|
make test-chunked # Chunked upload tests
|
|
make test-resume # Resume/HEAD tests
|
|
make test-errors # Error handling tests
|
|
|
|
# Manual testing
|
|
make manual-start # Start SeaweedFS for manual testing
|
|
make manual-stop # Stop and cleanup
|
|
```
|
|
|
|
### Using Go Test Directly
|
|
|
|
```bash
|
|
# Run all TUS tests
|
|
go test -v ./test/tus/...
|
|
|
|
# Run specific test
|
|
go test -v ./test/tus -run TestTusBasicUpload
|
|
|
|
# Skip integration tests (short mode)
|
|
go test -v -short ./test/tus/...
|
|
```
|
|
|
|
### Debug
|
|
|
|
```bash
|
|
# View server logs
|
|
make debug-logs
|
|
|
|
# Check process and port status
|
|
make debug-status
|
|
```
|
|
|
|
## Test Environment
|
|
|
|
Each test run:
|
|
1. Starts a SeaweedFS cluster (master, volume, filer)
|
|
2. Creates uploads using TUS protocol
|
|
3. Verifies files are stored correctly
|
|
4. Cleans up test data
|
|
|
|
### Default Ports
|
|
|
|
| Service | Port |
|
|
|---------|------|
|
|
| Master | 19333 |
|
|
| Volume | 18080 |
|
|
| Filer | 18888 |
|
|
|
|
### Configuration
|
|
|
|
Override defaults via environment or Makefile variables:
|
|
```bash
|
|
FILER_PORT=8889 MASTER_PORT=9334 make test
|
|
```
|
|
|
|
## Example Usage
|
|
|
|
### Create Upload
|
|
|
|
```bash
|
|
curl -X POST http://localhost:18888/.tus/mydir/file.txt \
|
|
-H "Tus-Resumable: 1.0.0" \
|
|
-H "Upload-Length: 1000" \
|
|
-H "Upload-Metadata: filename dGVzdC50eHQ="
|
|
```
|
|
|
|
### Upload Data
|
|
|
|
```bash
|
|
curl -X PATCH http://localhost:18888/.tus/.uploads/{upload-id} \
|
|
-H "Tus-Resumable: 1.0.0" \
|
|
-H "Upload-Offset: 0" \
|
|
-H "Content-Type: application/offset+octet-stream" \
|
|
--data-binary @file.txt
|
|
```
|
|
|
|
### Check Offset
|
|
|
|
```bash
|
|
curl -I http://localhost:18888/.tus/.uploads/{upload-id} \
|
|
-H "Tus-Resumable: 1.0.0"
|
|
```
|
|
|
|
### Cancel Upload
|
|
|
|
```bash
|
|
curl -X DELETE http://localhost:18888/.tus/.uploads/{upload-id} \
|
|
-H "Tus-Resumable: 1.0.0"
|
|
```
|
|
|
|
## TUS Extensions Supported
|
|
|
|
- **creation**: Create new uploads with POST
|
|
- **creation-with-upload**: Send data in creation request
|
|
- **termination**: Cancel uploads with DELETE
|
|
|
|
## Architecture
|
|
|
|
```text
|
|
Client Filer Volume Servers
|
|
| | |
|
|
|-- POST /.tus/path/file.mp4 ->| |
|
|
| |-- Create session dir ------->|
|
|
|<-- 201 Location: /.../{id} --| |
|
|
| | |
|
|
|-- PATCH /.tus/.uploads/{id} >| |
|
|
| Upload-Offset: 0 |-- Assign volume ------------>|
|
|
| [chunk data] |-- Upload chunk ------------->|
|
|
|<-- 204 Upload-Offset: N -----| |
|
|
| | |
|
|
| (network failure) | |
|
|
| | |
|
|
|-- HEAD /.tus/.uploads/{id} ->| |
|
|
|<-- Upload-Offset: N ---------| |
|
|
| | |
|
|
|-- PATCH (resume) ----------->|-- Upload remaining -------->|
|
|
|<-- 204 (complete) -----------|-- Assemble final file ----->|
|
|
```
|
|
|
|
## Comparison with S3 Multipart
|
|
|
|
| Feature | TUS | S3 Multipart |
|
|
|---------|-----|--------------|
|
|
| Protocol | Custom HTTP headers | S3 API |
|
|
| Session Init | POST with Upload-Length | CreateMultipartUpload |
|
|
| Upload Data | PATCH with offset | UploadPart with partNumber |
|
|
| Resume | HEAD to get offset | ListParts |
|
|
| Complete | Automatic at final offset | CompleteMultipartUpload |
|
|
| Ordering | Sequential (offset-based) | Parallel (part numbers) |
|
|
|
|
## Related Resources
|
|
|
|
- [TUS Protocol Specification](https://tus.io/protocols/resumable-upload)
|
|
- [tus-js-client](https://github.com/tus/tus-js-client) - JavaScript client
|
|
- [go-tus](https://github.com/eventials/go-tus) - Go client
|
|
- [SeaweedFS S3 API](../../weed/s3api) - Alternative multipart upload
|