Move docs/ package mirror into document-navigator plugin

Relocate the ~6k-file docs tree from the repo root into
plugins/document-navigator/docs/ so the plugin is self-contained and
portable. docs/superpowers/ (specs and plans) stays at the repo root.

Moved via cp+rm rather than git mv because directory rename() fails with
EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the
identical-content files at commit time.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-30 01:10:00 +01:00
parent fe3fedf42e
commit 9bf56a806b
6022 changed files with 12437 additions and 0 deletions

View File

@@ -0,0 +1,126 @@
# GarageS3Fixture
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`GarageS3Fixture` is an integration test fixture that manages the full lifecycle of a Garage S3 v2.0.0 container using testcontainers. It implements the `ServiceFixture<GarageS3Config>` interface from `@suaveplan/testing-integration`, providing a complete S3-compatible object storage backend for integration tests.
Garage requires a 7-step initialization sequence after startup: node status, layout assignment, layout application, bucket creation, key creation, bucket permission grant, and key credential retrieval. This fixture automates the entire sequence.
## Features
- **Env-bridge passthrough**: when all four vars (`GARAGE_S3_ENDPOINT`, `GARAGE_S3_ADMIN_ENDPOINT`, `GARAGE_S3_ACCESS_KEY_ID`, `GARAGE_S3_SECRET_ACCESS_KEY`) are set and non-empty, returns them directly. Partial sets fall through to container mode.
- **7-step init sequence**: fully automated post-startup initialization including layout and bucket provisioning.
- **Admin-port health check**: polls `GET /health` on the admin port (3902) not the S3 port (3900), which does not expose a health endpoint.
- **Inline health polling**: `waitForHealth()` polls before running the init sequence, using configurable `healthTimeoutMs` and `healthPollIntervalMs` for fast test timeouts.
- **Injectable exec function**: the `execFn` option replaces `container.exec()` for unit tests covering all 7 init steps.
- **Injectable fetch**: the `fetchFn` option replaces `globalThis.fetch` in health checks.
- **Injectable container factory**: the `containerFactory` option allows unit tests to swap in a fake container without Docker.
- **Configurable bucket name**: the `bucket` option overrides the default `test-bucket`.
## Usage: Basic Example
```typescript
import { GarageS3Fixture } from "@suaveplan/testing-integration-garage-s3";
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
const fixture = new GarageS3Fixture({ bucket: "test-bucket" });
const config = await fixture.start();
const s3 = new S3Client({
endpoint: config.endpoint,
region: config.region,
credentials: {
accessKeyId: config.accessKeyId,
secretAccessKey: config.secretAccessKey,
},
forcePathStyle: true,
});
await s3.send(new PutObjectCommand({
Bucket: config.bucket,
Key: "hello.txt",
Body: "world",
}));
await fixture.stop();
```
## Usage: Advanced Example
```typescript
import { GarageS3Fixture } from "@suaveplan/testing-integration-garage-s3";
// Unit test using injected execFn and fetchFn
const fixture = new GarageS3Fixture({
containerFactory: fakeContainerFactory,
execFn: async (cmd) => {
if (cmd[1] === "status") return { stdout: "ID\tabc123\n", exitCode: 0 };
if (cmd[1] === "key" && cmd[2] === "info")
return { stdout: "Key ID: GK123\nSecret key: sk456\n", exitCode: 0 };
return { stdout: "", exitCode: 0 };
},
fetchFn: async () => ({ ok: true } as Response),
healthTimeoutMs: 100,
healthPollIntervalMs: 10,
});
const config = await fixture.start();
```
## API Reference
### `class GarageS3Fixture`
Implements `ServiceFixture<GarageS3Config>`.
#### `constructor(options?: GarageS3FixtureOptions)`
Creates a new fixture instance. All options are optional.
#### `name: string`
Always `"garage-s3"`. Used by `TestEnvironment` as the registry key.
#### `start(): Promise<GarageS3Config>`
Starts the service. In passthrough mode returns env var values immediately. Otherwise starts a container, waits for health, runs the 7-step init sequence, and returns the provisioned config.
#### `stop(): Promise<void>`
Stops the container. No-op in passthrough mode or when not started.
#### `healthCheck(): Promise<boolean>`
Fetches `GET http://localhost:<adminPort>/health` and returns `true` when the response is OK. Returns `false` if no container is active or the request fails.
### `interface GarageS3Config`
| Field | Type | Description |
|-------|------|-------------|
| `endpoint` | `string` | S3 API URL: `http://localhost:<port>` |
| `adminEndpoint` | `string` | Admin API URL: `http://localhost:<port>` |
| `region` | `string` | Always `"garage"` |
| `bucket` | `string` | Bucket name created during init |
| `accessKeyId` | `string` | S3 access key ID from `garage key info` |
| `secretAccessKey` | `string` | S3 secret access key from `garage key info` |
### `interface GarageS3FixtureOptions`
| Field | Type | Description |
|-------|------|-------------|
| `image?` | `string` | Docker image override. |
| `bucket?` | `string` | Bucket name override. Defaults to `"test-bucket"`. |
| `containerFactory?` | `(image: string) => GenericContainer` | Injectable factory for unit testing. |
| `execFn?` | `(cmd: string[]) => Promise<{ stdout: string; exitCode: number }>` | Injectable executor for init sequence unit testing. |
| `fetchFn?` | `typeof fetch` | Injectable fetch for health check unit testing. |
| `healthTimeoutMs?` | `number` | Health check timeout. Defaults to 120s. |
| `healthPollIntervalMs?` | `number` | Health check poll interval. Defaults to 1s. |
## Implementation Notes
- **Why admin port for health check**: the Garage S3 API port (3900) serves S3 protocol only and does not expose `/health`. Only the admin API port (3902) does.
- **Why inline health poll in `start()`**: the `ServiceFixture` contract requires `start()` to return only after the service is ready. The 7-step init sequence requires a live Garage instance.
- **testcontainers exec return shape**: `ExecResult.output` contains combined stdout+stderr in testcontainers v11. The `getExecFn()` wrapper maps `.output` to `.stdout` for consistency with the `execFn` interface.
- **Garage node ID format**: the `garage status` output contains a row per node. The node ID is the first whitespace-separated token on the first non-header data line.