4.3 KiB
ADDED Requirements
Requirement: Garage v2 image policy
The @suaveplan/testing-integration-garage-s3 plugin SHALL pin to dxflrs/garage:v2.0.0 (name + minor version). A follow-up operational change tracked at docs/superpowers/specs/2026-04-25-test-suite-audit.md §5 will pin to sha256:<digest>.
Scenario: Image tag pinned
- WHEN the container factory is invoked without injection
- THEN the resulting container uses image
dxflrs/garage:v2.0.0
Requirement: Dual-port exposure
The fixture SHALL expose two TCP ports from the container: the S3 API port on container port 3900 and the admin port on container port 3902. Both MUST be mapped to host ports and recorded in config.s3Endpoint and config.adminEndpoint.
Scenario: Both endpoints recorded
- WHEN the container has started
- THEN
config.s3Endpointandconfig.adminEndpointare populated with reachable host URLs
Requirement: Env-bridge contract
The plugin SHALL declare and forward exactly four environment variables: GARAGE_S3_ENDPOINT, GARAGE_S3_ACCESS_KEY_ID, GARAGE_S3_SECRET_ACCESS_KEY, GARAGE_S3_BUCKET. When ALL four are set on the parent process at construction time, the fixture MUST enter env-bridge passthrough mode.
Scenario: env() returns the full four-key set
- WHEN the fixture has started
- THEN
fixture.env()returns a record with exactly the four declared keys
Requirement: Seven-step initialisation sequence
In container mode start() SHALL execute the following sequence against the admin port, in order, before declaring the fixture healthy:
status— read cluster status to discover the node idlayout assign— assign capacity to the discovered nodelayout apply— commit the layout versionbucket create— create the configured bucketkey create— create an access/secret key pairbucket allow— grant the key full permissions on the bucketkey info— read back the key to confirm and capture the secret
Any step failure MUST abort the sequence and reject start() with a coded error naming the failing step.
Scenario: Successful seven-step init
- WHEN
start()is invoked against a fresh container - THEN all seven admin operations execute in the order above before
start()resolves
Scenario: Layout-apply failure aborts
- WHEN the third step (
layout apply) fails - THEN
start()rejects withcode === "INTEGRATION.GARAGE_S3.LAYOUT_APPLY_FAILED"AND steps 4–7 are not attempted
Requirement: Healthcheck contract — admin port
isHealthy() SHALL probe the admin port (3902) with an HTTP request and resolve true only when the admin endpoint responds. The S3 port (3900) alone is NOT sufficient evidence of health.
Scenario: Admin port is the source of truth
- WHEN the S3 port is open but the admin port has not yet started
- THEN
isHealthy()resolvesfalse
Requirement: Configurable timeouts
The fixture options SHALL accept healthIntervalMs?: number and healthTimeoutMs?: number overrides forwarded to HealthPoller. Defaults follow HealthPoller's defaults (500 ms / 120 s).
Scenario: Override applied
- WHEN the fixture is constructed with
{ healthTimeoutMs: 30000 } - THEN
HealthPollerrejects after 30 s when the container never becomes healthy
Requirement: Injectable factories
The fixture constructor SHALL accept optional containerFactory, execFn, and fetchFn parameters for the container, admin-CLI exec, and admin-port HTTP calls respectively. Defaults invoke testcontainers, the container's exec API, and the global fetch.
Scenario: Injected execFn drives the seven-step sequence
- WHEN
execFnis replaced with a stub that records every command - THEN the recorded commands match the seven-step order
Requirement: Error-code prefix
Errors thrown from the plugin SHALL carry codes matching ^INTEGRATION\.GARAGE_S3\.[A-Z_]+$. At minimum the package SHALL define: START_FAILED, STOP_FAILED, STATUS_FAILED, LAYOUT_ASSIGN_FAILED, LAYOUT_APPLY_FAILED, BUCKET_CREATE_FAILED, KEY_CREATE_FAILED, BUCKET_ALLOW_FAILED, KEY_INFO_FAILED.
Scenario: Each step has its own coded error
- WHEN
bucket createfails - THEN the rejection's
code === "INTEGRATION.GARAGE_S3.BUCKET_CREATE_FAILED"ANDcontext.step === "bucket-create"