6.0 KiB
ADDED Requirements
Requirement: Layer 0 dep-graph isolation
The @suaveplan/testing-integration-minio package's dependencies MUST be exactly @suaveplan/testing-integration (workspace:^) and testcontainers (catalog:integration). No other @suaveplan/* runtime dep is permitted. devDependencies MAY include @suaveplan/testing for the package's own tests.
Scenario: Runtime closure clean
- WHEN
bunx turbo ls --filter=@suaveplan/testing-integration-minio...is run - THEN the only
@suaveplan/*package in the runtime closure is@suaveplan/testing-integration
Requirement: Coexistence with Garage S3 fixture
The MinIO fixture MUST exist alongside @suaveplan/testing-integration-garage-s3 rather than replacing it. The two fixtures expose deliberately different surfaces: Garage masks several AWS-S3 quirks (admin-port health, layout-assignment init), while MinIO mirrors AWS-S3 surface much more closely. Tests that need AWS-API parity MUST target the MinIO fixture; tests covering the Garage init dance MUST target the Garage fixture.
Scenario: Both fixtures coexist
- WHEN a test environment registers both
MinioFixtureandGarageS3Fixture - THEN both fixtures start in parallel with no shared port or env-var conflicts
Requirement: Image-pinning policy
The default image MUST be a pinned minio/minio:RELEASE.<date> tag (latest stable RELEASE at implementation time). The constants/index.ts file MUST carry a # TODO: replace with sha256:<digest> comment until the digest is recorded.
Scenario: Pinned RELEASE tag
- WHEN the constants file is read
- THEN the image string starts with
minio/minio:RELEASE.AND a sha256 TODO line is present
Requirement: Env-bridge passthrough
The fixture MUST consult MINIO_S3_ENDPOINT, MINIO_S3_ACCESS_KEY_ID, MINIO_S3_SECRET_ACCESS_KEY, MINIO_S3_REGION, and MINIO_S3_BUCKET. When the first four are present and non-empty, start() MUST skip container creation and return a handle whose config points at the live MinIO. MINIO_S3_BUCKET is optional in passthrough mode.
Scenario: Live MinIO present
- WHEN the four required env vars are set
- THEN
start()returns without invokingcontainerFactoryAND the returned config'sendpointequalsMINIO_S3_ENDPOINT
Scenario: Partial env triggers container
- WHEN
MINIO_S3_ENDPOINTis set butMINIO_S3_SECRET_ACCESS_KEYis empty - THEN
start()falls back to container mode
Requirement: Healthcheck
The fixture MUST poll HTTP GET <endpoint>/minio/health/live and treat a 200 response as ready. The default healthTimeoutMs MUST be 60000. Callers MAY override.
Scenario: Healthcheck succeeds
- WHEN
/minio/health/livereturns 200 - THEN
start()resolves
Scenario: Healthcheck times out
- WHEN the endpoint never returns 200 within
healthTimeoutMs - THEN
start()rejects with codeINTEGRATION.MINIO.HEALTHCHECK_TIMEOUT
Requirement: Random keys per run
In container mode, when accessKeyId/secretAccessKey are not supplied, the fixture MUST generate cryptographically random keys for each run (≥ 20 chars, alphanumeric) and pass them as MINIO_ROOT_USER / MINIO_ROOT_PASSWORD env vars to the container.
Scenario: Random keys
- WHEN the fixture starts twice without explicit keys
- THEN the two runs use different
accessKeyIdvalues
Requirement: Bucket pre-seeding
When bucket is supplied, the fixture MUST create the bucket via the MinIO admin API after the healthcheck passes, using the injectable fetchFn. The fixture MUST NOT resolve start() until the bucket exists (verified via HEAD <endpoint>/<bucket> returning 200).
Scenario: Bucket created
- WHEN
start({ bucket: 'app-uploads' })resolves - THEN
HEAD /app-uploadsreturns 200 against the returned endpoint
Requirement: Config shape
The exported MinioConfig interface MUST include accessKeyId, secretAccessKey, region, optional bucket?: string, optional console?: boolean, and the resolved endpoint. A sibling minio-fixture.schemas.ts MUST export a Zod MinioConfigSchema that validates the same shape.
Scenario: Schema parity
- WHEN
MinioConfigSchema.safeParseruns against aMinioConfigvalue - THEN valid configs parse OK AND missing required fields fail with
ZodError
Requirement: Error-code prefix
All errors thrown from the fixture MUST carry a code matching ^INTEGRATION\.MINIO\.[A-Z_]+$.
Scenario: Coded error
- WHEN any fixture method throws
- THEN
codestarts withINTEGRATION.MINIO.
Requirement: Injectable fakes
The fixture constructor MUST accept containerFactory?: () => GenericContainer and fetchFn?: typeof fetch. Unit tests MUST drive 100% Istanbul branch coverage without Docker or network.
Scenario: Fake injection
- WHEN the fixture is constructed with both fakes
- THEN real Docker / real
fetchare never called during the test
Requirement: Plugin scenarios — AWS-S3 parity
The fixture MUST support, end-to-end against a real container with an AWS S3 SDK client (@aws-sdk/client-s3), the following flows in its smoke test:
Scenario: PutObject and GetObject round-trip
- WHEN an SDK client puts an object then gets it back
- THEN the retrieved body bytes equal the put body bytes AND the
ETagheader is present
Scenario: Presigned GET URL works
- WHEN a presigned GET URL is created via
@aws-sdk/s3-request-presignerand fetched directly with no SDK signing - THEN the response is
200with the object body
Scenario: Multipart upload works
- WHEN an object larger than the part-size threshold (≥ 5 MB) is uploaded via
CreateMultipartUpload+UploadPart+CompleteMultipartUpload - THEN the assembled object's body equals the concatenated source AND
HeadObjectreports the full content length
Scenario: Bucket policy attach
- WHEN a
PutBucketPolicyrequest attaches a public-read policy - THEN
GetBucketPolicyreturns the same JSON document