mirror of
https://github.com/rustfs/rustfs.git
synced 2026-07-26 08:18:18 +00:00
3779e674a8
Follow-ups to the compatibility harness rework: - Weekly full sweep now runs as a matrix over both topologies: single node and the 4-node distributed cluster. Manual dispatch keeps the test-mode input. - New mint workflow (weekly + dispatch) runs MinIO Mint against RustFS: functional suites of real client SDKs and tools (awscli, mc, aws-sdk-*, minio-*, s3cmd, ...), catching client-specific signing and streaming edge cases that boto3-only ceph/s3-tests cannot. Report-only for test failures with a per-suite summary table; fails only when mint produces no results. - New scripts/s3-tests/api_coverage.py quantifies API surface coverage by diffing the s3s S3 trait (at the Cargo.toml pinned revision) against the methods overridden in impl S3 for FS, distinguishing NotImplemented defaults from delegating defaults (e.g. post_object). Current state: 76/101 operations covered (75 overridden, 1 delegated). Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
489 lines
16 KiB
Markdown
489 lines
16 KiB
Markdown
# S3 Compatibility Tests
|
|
|
|
This directory contains scripts for running S3 compatibility tests against RustFS.
|
|
|
|
## Quick Start
|
|
|
|
Run the local S3 compatibility test script:
|
|
|
|
```bash
|
|
./scripts/s3-tests/run.sh
|
|
```
|
|
|
|
The script will automatically:
|
|
|
|
1. **Check prerequisites**: Verify port availability (unless in existing mode)
|
|
2. **Build/Start RustFS**:
|
|
- Build mode (default): Compile with `cargo build --release` (skips if binary is recent < 30 min)
|
|
- Binary mode: Use specified or default binary path
|
|
- Docker mode: Build Docker image and start container
|
|
- Existing mode: Skip startup, connect to running service
|
|
3. **Wait for readiness**: Multi-step health check (process/container → port → log → S3 API)
|
|
4. **Prepare environment**:
|
|
- Generate s3tests configuration from template
|
|
- Provision alt user via admin API
|
|
- Fetch s3-tests at the pinned revision (`S3TESTS_REV`)
|
|
- Install missing dependencies (awscurl, tox, gettext)
|
|
5. **Run tests**: Execute ceph s3-tests via tox with configured filters
|
|
6. **Collect results**: Save logs and test results in `artifacts/s3tests-${TEST_MODE}/`
|
|
|
|
## Deployment Modes
|
|
|
|
The script supports four deployment modes, controlled via the `DEPLOY_MODE` environment variable:
|
|
|
|
### 1. Build Mode (Default)
|
|
|
|
Compile with `cargo build --release` and run:
|
|
|
|
```bash
|
|
DEPLOY_MODE=build ./scripts/s3-tests/run.sh
|
|
# Or simply (build is the default)
|
|
./scripts/s3-tests/run.sh
|
|
|
|
# Force rebuild even if binary exists and is recent
|
|
./scripts/s3-tests/run.sh --no-cache
|
|
```
|
|
|
|
**Behavior**:
|
|
- Automatically compiles RustFS binary if it doesn't exist
|
|
- If binary exists and was compiled less than **30 minutes** ago, compilation is skipped (unless `--no-cache` is specified)
|
|
- Automatically starts the service after compilation
|
|
- Automatically fetches s3-tests at the pinned revision if missing
|
|
- Automatically installs missing dependencies (awscurl, tox, gettext)
|
|
- **Automatic Cleanup**: Process is automatically stopped when script exits
|
|
|
|
### 2. Binary File Mode
|
|
|
|
Use pre-compiled binary file:
|
|
|
|
```bash
|
|
# Use default path (./target/release/rustfs)
|
|
DEPLOY_MODE=binary ./scripts/s3-tests/run.sh
|
|
|
|
# Specify custom binary path
|
|
DEPLOY_MODE=binary RUSTFS_BINARY=./target/release/rustfs ./scripts/s3-tests/run.sh
|
|
```
|
|
|
|
**Behavior**:
|
|
- Uses existing binary file (must exist, script will not compile)
|
|
- Automatically starts the service using the specified binary
|
|
- Automatically fetches s3-tests at the pinned revision if missing
|
|
- Automatically installs missing dependencies (awscurl, tox, gettext)
|
|
- **Automatic Cleanup**: Process is automatically stopped when script exits
|
|
|
|
### 3. Docker Mode
|
|
|
|
Build Docker image and run in container:
|
|
|
|
```bash
|
|
DEPLOY_MODE=docker ./scripts/s3-tests/run.sh
|
|
```
|
|
|
|
**Behavior**:
|
|
- Automatically builds Docker image using `Dockerfile.source`
|
|
- Creates Docker network (`rustfs-net`) if it doesn't exist
|
|
- Automatically fetches s3-tests at the pinned revision if missing
|
|
- Automatically installs missing dependencies (awscurl, tox, gettext)
|
|
- **Automatic Cleanup**: Container and network are automatically removed when script exits
|
|
|
|
### 4. Existing Service Mode
|
|
|
|
Connect to an already running RustFS service:
|
|
|
|
```bash
|
|
DEPLOY_MODE=existing S3_HOST=127.0.0.1 S3_PORT=9000 ./scripts/s3-tests/run.sh
|
|
|
|
# Connect to remote service
|
|
DEPLOY_MODE=existing S3_HOST=192.168.1.100 S3_PORT=9000 ./scripts/s3-tests/run.sh
|
|
```
|
|
|
|
**Behavior**:
|
|
- Skips service startup and port availability checks
|
|
- Connects directly to the specified service endpoint
|
|
- Automatically fetches s3-tests at the pinned revision if missing
|
|
- Automatically installs missing dependencies (awscurl, tox, gettext)
|
|
- **Note**: The service must already have the alt user (`rustfsalt`) provisioned, or the script will provision it automatically
|
|
|
|
**Automatic Cleanup**: The script uses trap handlers to automatically clean up resources when it exits (success or failure):
|
|
- Stops RustFS process (build/binary mode)
|
|
- Stops and removes Docker container (docker mode)
|
|
- Removes Docker network (docker mode)
|
|
|
|
## Configuration Options
|
|
|
|
### Command Line Options
|
|
|
|
- `-h, --help`: Show help message
|
|
- `--no-cache`: Force rebuild even if binary exists and is recent (for build mode)
|
|
|
|
### Deployment Configuration
|
|
|
|
- `DEPLOY_MODE`: Deployment mode, options:
|
|
- `build`: Compile with `cargo build --release` and run (default)
|
|
- `binary`: Use pre-compiled binary file
|
|
- `docker`: Build Docker image and run in container
|
|
- `existing`: Use already running service
|
|
- `RUSTFS_BINARY`: Path to binary file (for binary mode, default: `./target/release/rustfs`)
|
|
- `DATA_ROOT`: Root directory for test data storage (default: `target`)
|
|
- Final path: `${DATA_ROOT}/test-data/${CONTAINER_NAME}`
|
|
- Example: `DATA_ROOT=/tmp` stores data in `/tmp/test-data/rustfs-single/`
|
|
|
|
### Service Configuration
|
|
|
|
- `S3_ACCESS_KEY`: Main user access key (default: `rustfsadmin`)
|
|
- `S3_SECRET_KEY`: Main user secret key (default: `rustfsadmin`)
|
|
- `S3_ALT_ACCESS_KEY`: Alt user access key (default: `rustfsalt`)
|
|
- `S3_ALT_SECRET_KEY`: Alt user secret key (default: `rustfsalt`)
|
|
- `S3_REGION`: S3 region (default: `us-east-1`)
|
|
- `S3_HOST`: S3 service host (default: `127.0.0.1`)
|
|
- `S3_PORT`: S3 service port (default: `9000`)
|
|
|
|
### Test Parameters
|
|
|
|
- `TEST_MODE`: Test mode (default: `single`)
|
|
- `TEST_SCOPE`: Test scope (default: `implemented`)
|
|
- `implemented`: run only the `implemented_tests.txt` whitelist (the PR gate)
|
|
- `all`: run the entire upstream suite (used by the weekly full sweep)
|
|
- `MAXFAIL`: Stop after N failures, `0` = never stop (default: `1`)
|
|
- `XDIST`: Enable parallel execution with N workers (default: `0`, disabled)
|
|
- `S3TESTS_REPO`: s3-tests repository URL (default: `https://github.com/ceph/s3-tests.git`)
|
|
- `S3TESTS_REV`: Pinned s3-tests commit for reproducible runs
|
|
- Bump deliberately: upstream changes can rename tests or change assertions,
|
|
so a bump usually requires reclassifying the test list files
|
|
- `MARKEXPR`: pytest marker expression for filtering tests
|
|
- Default: no marker filtering; file-based test lists control the selected tests
|
|
- Can be customized to test specific marker groups
|
|
- `TESTEXPR`: optional pytest `-k` expression for custom runs
|
|
- Default: exact pytest node ids loaded from `implemented_tests.txt`
|
|
- Setting `TESTEXPR` overrides the implemented test list
|
|
|
|
### Configuration Files
|
|
|
|
- `S3TESTS_CONF_TEMPLATE`: Path to s3tests config template (default: `.github/s3tests/s3tests.conf`)
|
|
- Relative to project root
|
|
- Uses `envsubst` to substitute variables (e.g., `${S3_HOST}`)
|
|
- `S3TESTS_CONF`: Path to generated s3tests config (default: `s3tests.conf`)
|
|
- Relative to project root
|
|
- This file is generated from the template before running tests
|
|
|
|
## Examples
|
|
|
|
### Build Mode (Default)
|
|
|
|
```bash
|
|
# Basic usage - compiles and runs automatically
|
|
# Skips compilation if binary exists and is less than 30 minutes old
|
|
./scripts/s3-tests/run.sh
|
|
|
|
# Force rebuild (skip cache check, always compile)
|
|
./scripts/s3-tests/run.sh --no-cache
|
|
|
|
# Run all tests, stop after 50 failures
|
|
MAXFAIL=50 ./scripts/s3-tests/run.sh
|
|
|
|
# Enable parallel execution (4 worker processes)
|
|
# Automatically installs pytest-xdist if needed
|
|
XDIST=4 ./scripts/s3-tests/run.sh
|
|
|
|
# Use custom data storage location
|
|
# Data will be stored in /tmp/test-data/rustfs-single/
|
|
DATA_ROOT=/tmp ./scripts/s3-tests/run.sh
|
|
|
|
# Run specific test markers (e.g., test multipart uploads only)
|
|
MARKEXPR="multipart" ./scripts/s3-tests/run.sh
|
|
```
|
|
|
|
### Binary File Mode
|
|
|
|
```bash
|
|
# First compile the binary
|
|
cargo build --release
|
|
|
|
# Run with default path
|
|
DEPLOY_MODE=binary ./scripts/s3-tests/run.sh
|
|
|
|
# Specify custom path
|
|
DEPLOY_MODE=binary RUSTFS_BINARY=/path/to/rustfs ./scripts/s3-tests/run.sh
|
|
|
|
# Use binary with parallel tests
|
|
DEPLOY_MODE=binary XDIST=4 ./scripts/s3-tests/run.sh
|
|
```
|
|
|
|
### Docker Mode
|
|
|
|
```bash
|
|
# Build Docker image and run in container
|
|
DEPLOY_MODE=docker ./scripts/s3-tests/run.sh
|
|
|
|
# Run with parallel tests
|
|
DEPLOY_MODE=docker XDIST=4 ./scripts/s3-tests/run.sh
|
|
```
|
|
|
|
### Existing Service Mode
|
|
|
|
```bash
|
|
# Connect to locally running service (default: 127.0.0.1:9000)
|
|
DEPLOY_MODE=existing ./scripts/s3-tests/run.sh
|
|
|
|
# Connect to remote service
|
|
DEPLOY_MODE=existing S3_HOST=192.168.1.100 S3_PORT=9000 ./scripts/s3-tests/run.sh
|
|
|
|
# Test specific features (custom marker expression)
|
|
DEPLOY_MODE=existing MARKEXPR="not lifecycle and not versioning" ./scripts/s3-tests/run.sh
|
|
|
|
# Use custom credentials
|
|
DEPLOY_MODE=existing \
|
|
S3_ACCESS_KEY=myaccesskey \
|
|
S3_SECRET_KEY=mysecretkey \
|
|
./scripts/s3-tests/run.sh
|
|
```
|
|
|
|
### Custom Configuration Files
|
|
|
|
```bash
|
|
# Use custom config template and output path
|
|
S3TESTS_CONF_TEMPLATE=my-configs/s3tests.conf.template \
|
|
S3TESTS_CONF=my-s3tests.conf \
|
|
./scripts/s3-tests/run.sh
|
|
```
|
|
|
|
## Test Results
|
|
|
|
Test results are saved in the `artifacts/s3tests-${TEST_MODE}/` directory (default: `artifacts/s3tests-single/`):
|
|
|
|
- `junit.xml`: Test results in JUnit format (compatible with CI/CD systems)
|
|
- `pytest.log`: Detailed pytest logs with full test output
|
|
- `compat-report.md`: Classification report generated by `report_compat.py` —
|
|
regressions against `implemented_tests.txt`, promotion candidates (tests
|
|
that pass but are still listed as unimplemented/excluded), and tests missing
|
|
from every list
|
|
- `rustfs-${TEST_MODE}/rustfs.log`: RustFS service logs
|
|
- `rustfs-${TEST_MODE}/inspect.json`: Service metadata (PID, binary path, mode, etc.)
|
|
|
|
View results:
|
|
|
|
```bash
|
|
# Check test summary
|
|
cat artifacts/s3tests-single/junit.xml | grep -E "testsuite|testcase"
|
|
|
|
# View test logs
|
|
less artifacts/s3tests-single/pytest.log
|
|
|
|
# View service logs
|
|
less artifacts/s3tests-single/rustfs-single/rustfs.log
|
|
```
|
|
|
|
## Prerequisites
|
|
|
|
### Required System Dependencies
|
|
|
|
The following dependencies must be installed manually on your system:
|
|
|
|
#### All Deployment Modes
|
|
|
|
- **Python 3**: Required for running s3-tests
|
|
- Check: `python3 --version`
|
|
- Install:
|
|
- macOS: Usually pre-installed, or `brew install python3`
|
|
- Linux: `apt-get install python3` or `yum install python3`
|
|
|
|
- **Git**: Required for cloning s3-tests repository
|
|
- Check: `git --version`
|
|
- Install:
|
|
- macOS: Usually pre-installed, or `brew install git`
|
|
- Linux: `apt-get install git` or `yum install git`
|
|
|
|
- **Port checking tools**: One of the following for port availability checks
|
|
- `nc` (netcat): `apt-get install netcat` or `brew install netcat`
|
|
- OR `timeout` command: Usually pre-installed on Linux
|
|
- OR bash built-in TCP redirection support
|
|
|
|
#### Docker Mode Only
|
|
|
|
- **Docker**: Required only when using `DEPLOY_MODE=docker`
|
|
- Check: `docker --version`
|
|
- Install: [Docker Installation Guide](https://docs.docker.com/get-docker/)
|
|
|
|
#### Build Mode Only
|
|
|
|
- **Rust toolchain**: Required when using `DEPLOY_MODE=build` (default)
|
|
- Check: `rustc --version` and `cargo --version`
|
|
- Install: [Rust Installation Guide](https://www.rust-lang.org/tools/install)
|
|
|
|
### Auto-installed Dependencies
|
|
|
|
The script will automatically install the following dependencies if missing (no manual action required):
|
|
|
|
- **awscurl**: For S3 API calls and user provisioning
|
|
- Installed via: `python3 -m pip install --user --upgrade pip awscurl`
|
|
- Location: `$HOME/.local/bin/awscurl`
|
|
|
|
- **tox**: For running s3-tests in isolated Python environment
|
|
- Installed via: `python3 -m pip install --user --upgrade pip tox`
|
|
- Location: `$HOME/.local/bin/tox`
|
|
|
|
- **gettext-base**: For `envsubst` command (config file generation)
|
|
- macOS: Automatically installs via `brew install gettext`
|
|
- Linux: Automatically installs via `sudo apt-get install gettext-base`
|
|
- **Note**: macOS installation may require manual intervention if brew fails
|
|
|
|
- **s3-tests repository**: Automatically fetched if not present
|
|
- Source: `https://github.com/ceph/s3-tests.git`, pinned to the commit in
|
|
`S3TESTS_REV` (see run.sh) for reproducible runs
|
|
- Location: `${PROJECT_ROOT}/s3-tests`
|
|
|
|
**Note**: The script adds `$HOME/.local/bin` to `PATH` automatically, so auto-installed Python tools are accessible.
|
|
|
|
### Proxy Configuration
|
|
|
|
The script automatically disables proxy for localhost requests to avoid interference. All proxy environment variables (`http_proxy`, `https_proxy`, `HTTP_PROXY`, `HTTPS_PROXY`) are unset at script startup. The `NO_PROXY` variable is set to `127.0.0.1,localhost,::1`.
|
|
|
|
## Cleanup
|
|
|
|
The test script automatically cleans up processes and containers when it exits. However, if you need to manually clean up:
|
|
|
|
### Using the Cleanup Script
|
|
|
|
A dedicated cleanup script is available to clean up test resources:
|
|
|
|
```bash
|
|
# Report port 9000 usage and clean the test data directory
|
|
./scripts/s3-tests/cleanup.sh
|
|
|
|
# Use custom port
|
|
S3_PORT=9001 ./scripts/s3-tests/cleanup.sh
|
|
```
|
|
|
|
The cleanup script will:
|
|
- Report any process using the specified port (default: 9000)
|
|
- Clean test data directory at `target/test-data/rustfs-single/`
|
|
- Leave unrelated processes running
|
|
|
|
### Manual Cleanup
|
|
|
|
If the cleanup script doesn't work or you need more control:
|
|
|
|
```bash
|
|
# Kill process on port 9000
|
|
lsof -ti:9000 | xargs kill -9
|
|
|
|
# Or use netstat/ss
|
|
kill -9 $(netstat -tuln | grep :9000 | awk '{print $7}' | cut -d'/' -f1)
|
|
|
|
# Remove test data
|
|
rm -rf target/test-data/rustfs-single/
|
|
|
|
# Stop Docker container (if using docker mode)
|
|
docker rm -f rustfs-single
|
|
|
|
# Remove Docker network (if using docker mode)
|
|
docker network rm rustfs-net
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Port Already in Use
|
|
|
|
If port 9000 is already in use, change the port:
|
|
|
|
```bash
|
|
S3_PORT=9001 ./scripts/s3-tests/run.sh
|
|
```
|
|
|
|
**Note**: The script automatically checks if the port is available before starting (except in `existing` mode). If the port is in use, the script will exit with an error message.
|
|
|
|
### Container Start Failure
|
|
|
|
Check Docker logs:
|
|
|
|
```bash
|
|
docker logs rustfs-single
|
|
```
|
|
|
|
### Binary Not Found
|
|
|
|
For binary mode, ensure the binary is compiled:
|
|
|
|
```bash
|
|
cargo build --release
|
|
```
|
|
|
|
Or specify the correct path:
|
|
|
|
```bash
|
|
DEPLOY_MODE=binary RUSTFS_BINARY=/path/to/rustfs ./scripts/s3-tests/run.sh
|
|
```
|
|
|
|
### Test Timeout
|
|
|
|
Increase wait time or check service status:
|
|
|
|
```bash
|
|
curl http://127.0.0.1:9000/health
|
|
```
|
|
|
|
### Existing Service Not Accessible
|
|
|
|
For existing mode, ensure the service is running and accessible:
|
|
|
|
```bash
|
|
# Check if service is reachable
|
|
curl http://192.168.1.100:9000/health
|
|
|
|
# Verify S3 API is responding
|
|
awscurl --service s3 --region us-east-1 \
|
|
--access_key rustfsadmin \
|
|
--secret_key rustfsadmin \
|
|
-X GET "http://192.168.1.100:9000/"
|
|
```
|
|
|
|
## Workflow Integration
|
|
|
|
This script is the single source of truth for running ceph s3-tests against
|
|
RustFS. Two GitHub Actions workflows delegate to it:
|
|
|
|
- **PR gate** (`.github/workflows/ci.yml`, job `s3-implemented-tests`): runs
|
|
the `implemented_tests.txt` whitelist against a single-node debug binary on
|
|
every pull request (`DEPLOY_MODE=binary`, `MAXFAIL=0`, `XDIST=4`). Any
|
|
failure blocks the PR.
|
|
- **Full sweep** (`.github/workflows/e2e-s3tests.yml`): weekly scheduled (and
|
|
manually dispatchable) run of the ENTIRE upstream suite (`TEST_SCOPE=all`)
|
|
against a Docker deployment — single node or a real 4-node distributed
|
|
cluster behind HAProxy. The sweep fails only on regressions in the
|
|
implemented whitelist; everything else is reported by `report_compat.py`
|
|
as promotion candidates or unclassified tests.
|
|
|
|
Keeping both workflows on this script means local runs, the PR gate, and the
|
|
scheduled sweep always execute tests the same way (same pinned s3-tests
|
|
revision, same config template, same user provisioning).
|
|
|
|
A third workflow, **mint** (`.github/workflows/mint.yml`), complements ceph
|
|
s3-tests with MinIO Mint: the functional suites of many real client SDKs and
|
|
tools (awscli, mc, aws-sdk-java/go/php/ruby, minio-go/java/js/py, s3cmd, ...).
|
|
It runs weekly, is report-only for test failures, and publishes a per-suite
|
|
pass/fail table in the job summary.
|
|
|
|
## Companion Tools
|
|
|
|
- `report_compat.py` — diffs a junit.xml result against the classification
|
|
lists; run automatically at the end of `run.sh`, and used by the weekly
|
|
sweep to gate on whitelist regressions only (`--fail-on-regression`).
|
|
- `api_coverage.py` — quantifies S3 API surface coverage by comparing the
|
|
s3s `S3` trait (at the revision pinned in Cargo.toml) against the methods
|
|
RustFS overrides in `impl S3 for FS`:
|
|
|
|
```bash
|
|
python3 scripts/s3-tests/api_coverage.py # summary + missing ops
|
|
python3 scripts/s3-tests/api_coverage.py --output api-coverage.md
|
|
```
|
|
|
|
- `compare_dual_targets.py` — sends one signed S3 request to two endpoints
|
|
(e.g. RustFS and MinIO) and diffs status, headers, and body; useful when
|
|
triaging a behavioral difference found by the suites above.
|
|
|
|
## See Also
|
|
|
|
- [GitHub Actions Workflow](../../.github/workflows/e2e-s3tests.yml)
|
|
- [S3 Tests Configuration](../../.github/s3tests/s3tests.conf)
|
|
- [Ceph S3 Tests Repository](https://github.com/ceph/s3-tests)
|