S3 Configuration#
This guide covers how to configure S3-compatible object storage for integration testing with tomato.
Overview#
The s3 resource talks to any S3-compatible endpoint. In tests that usually means
MinIO or LocalStack, but the same
resource works against a real bucket if you point it at one.
Because it speaks the S3 protocol rather than a vendor API, one set of steps covers all three.
Container Setup#
MinIO#
MinIO needs an explicit server command — the image's default entrypoint only prints help.
containers:
minio:
image: minio/minio:latest
command: ["server", "/data"]
ports:
- "9000/tcp"
env:
MINIO_ROOT_USER: minioadmin
MINIO_ROOT_PASSWORD: minioadmin
wait_for:
type: port
target: "9000"
timeout: 30s
LocalStack#
containers:
localstack:
image: localstack/localstack:3
ports:
- "4566/tcp"
env:
SERVICES: s3
wait_for:
type: port
target: "4566"
timeout: 90s
Resource Configuration#
minio is accepted as an alias for type: s3.
The endpoint is derived from the container automatically. Tomato probes port 9000
(MinIO) and then 4566 (LocalStack), so neither image needs a port option.
Options#
| Option | Default | Description |
|---|---|---|
endpoint |
(from container) | Explicit endpoint, e.g. localhost:9000. Scheme is optional. |
port |
9000 then 4566 |
Container port to resolve the endpoint from. |
region |
us-east-1 |
AWS region. |
access_key |
minioadmin |
Access key ID. |
secret_key |
minioadmin |
Secret access key. |
use_ssl |
false |
Use https:// when building the endpoint. |
force_path_style |
true |
Path-style addressing. Required by MinIO and LocalStack. |
buckets |
(none) | Buckets created at startup, before any scenario runs. |
reset_strategy |
purge |
purge, delete, or none. See below. |
reset_buckets |
(all buckets) | Limit reset to these buckets. |
reset_exclude |
(none) | Buckets reset never touches. |
Connecting Without a Container#
Point the resource at an endpoint directly to test against something tomato does not manage:
resources:
files:
type: s3
options:
endpoint: "https://s3.eu-central-1.amazonaws.com"
region: eu-central-1
use_ssl: true
force_path_style: false
access_key: "${AWS_ACCESS_KEY_ID}"
secret_key: "${AWS_SECRET_ACCESS_KEY}"
reset_strategy: none
Reset deletes objects
Reset is destructive by design. Against a real account, set
reset_strategy: none or scope it with reset_buckets.
Reset Behaviour#
Following tomato's clean-state principle, every scenario starts with empty storage.
| Strategy | Behaviour |
|---|---|
purge (default) |
Deletes every object, keeps the buckets. |
delete |
Deletes the buckets entirely, then recreates those listed in buckets. |
none |
Leaves storage untouched. |
By default reset covers every bucket on the endpoint, not just the ones in
buckets. That way buckets your application creates at runtime are cleaned up too.
Narrow it with reset_buckets, or protect individual buckets with reset_exclude:
resources:
files:
type: s3
container: minio
options:
buckets: [uploads]
reset_exclude: [fixtures] # seeded once in a before_all hook
To keep storage across scenarios, either set reset_strategy: none or opt the
resource out of reset entirely:
Wiring Your Application#
Pass the endpoint to the application under test with container templates:
app:
command: go run ./cmd/server
port: 8080
env:
S3_ENDPOINT: "http://{{.minio.host}}:{{.minio.port.9000}}"
S3_ACCESS_KEY: minioadmin
S3_SECRET_KEY: minioadmin
S3_FORCE_PATH_STYLE: "true"
Object Paths#
Every object step takes a single bucket/key path. An s3:// prefix is stripped if present.
Writing to a bucket that does not exist creates it, so seeding steps do not need a
bucket ... exists line first.
Example#
Feature: Report export
Scenario: Exporting writes a report to S3
Given "db" table "orders" with values:
| id | total |
| 1 | 42.00 |
When "api" sends "POST" request to "/exports"
Then "api" response code should be "202"
And "files" object "reports/orders.csv" should exist within "10s"
And "files" object "reports/orders.csv" content should contain "42.00"
The within steps matter here: applications usually upload in the background, so a
plain should exist would race the write.
See Also#
- S3 Steps — the full step reference
- Configuration Reference