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:
@@ -0,0 +1,43 @@
|
||||
# @suaveplan/testing-integration-redis - Redis 7 testcontainers fixture for @suaveplan/testing-integration
|
||||
|
||||
## Summary
|
||||
|
||||
Redis 7 testcontainers fixture for `@suaveplan/testing-integration`.
|
||||
|
||||
Implements `ServiceFixture<RedisConfig>` — manages a Redis container lifecycle with env-bridge passthrough and TCP PING health checks. Returns a plain config; consumers bring their own Redis client.
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
## Documentation tree
|
||||
|
||||
- [fixture](./src/fixture/redis-fixture.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [redis-fixture](./src/fixture/redis-fixture.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
<!-- end:auto-docs --> - [redis-fixture](./src/fixture/redis-fixture.md) — <!-- begin:auto-docs --> _(no submodules)_- [redis-fixture](./src/fixture/redis-fixture.md) — <!-- begin:auto-docs --> _(no submodules)_- [redis-fixture](./src/fixture/redis-fixture.md) — <!-- begin:auto-docs --> _(no submodules)_- [redis-fixture](./src/fixture/redis-fixture.md) — <!-- begin:auto-docs --> _(no submodules)_
|
||||
## Install
|
||||
|
||||
```bash
|
||||
bun add -D @suaveplan/testing-integration-redis
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```typescript
|
||||
import { RedisFixture } from "@suaveplan/testing-integration-redis";
|
||||
|
||||
const fixture = new RedisFixture();
|
||||
const config = await fixture.start();
|
||||
// config.url, config.host, config.port
|
||||
await fixture.stop();
|
||||
```
|
||||
|
||||
## Env-bridge passthrough
|
||||
|
||||
Set the env var to skip container startup:
|
||||
|
||||
```text
|
||||
REDIS_URL=redis://localhost:6379
|
||||
```
|
||||
|
||||
## Docs
|
||||
|
||||
- [RedisFixture](src/fixture/redis-fixture.md)
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
# RedisFixture
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
`RedisFixture` is an integration test fixture that manages the full lifecycle of a Redis 7 container using testcontainers. It implements the `ServiceFixture<RedisConfig>` interface from `@suaveplan/testing-integration`, enabling consistent startup, health checking via TCP PING, and teardown as part of a `TestEnvironment` or standalone usage.
|
||||
|
||||
The fixture intentionally keeps `ioredis` and other Redis clients out of its dependencies — it returns a plain `RedisConfig` object with `url`, `host`, and `port`. Consumers bring their own Redis client library, keeping the fixture lightweight and framework-agnostic.
|
||||
|
||||
## Features
|
||||
|
||||
- **Env-bridge passthrough**: when `REDIS_URL` is set and non-empty, container startup is bypassed and the URL is parsed into a `RedisConfig` directly.
|
||||
- **TCP PING health check**: connects to Redis via `node:net`, sends `PING\r\n`, and verifies the response starts with `+PONG`. No Redis client dependency required.
|
||||
- **Injectable TCP ping function**: the `tcpPingFn` option allows unit tests to substitute the health check without a real network connection.
|
||||
- **Injectable container factory**: the `containerFactory` option allows unit tests to swap in a fake container without starting Docker.
|
||||
- **URL parsing for passthrough**: `new URL(url)` extracts `hostname` and `port` from the `REDIS_URL` env var, ensuring `RedisConfig.host` and `RedisConfig.port` are always consistent with `RedisConfig.url`.
|
||||
- **Idempotent stop**: calling `stop()` on an already-stopped or passthrough fixture is safe and does not throw.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```typescript
|
||||
import { RedisFixture } from "@suaveplan/testing-integration-redis";
|
||||
|
||||
const fixture = new RedisFixture();
|
||||
const config = await fixture.start();
|
||||
|
||||
// config.url → "redis://localhost:<randomPort>"
|
||||
// config.host → "localhost"
|
||||
// config.port → random ephemeral port
|
||||
|
||||
// Use with ioredis:
|
||||
// const redis = new Redis(config.url);
|
||||
|
||||
await fixture.stop();
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```typescript
|
||||
import { RedisFixture } from "@suaveplan/testing-integration-redis";
|
||||
import { createClient } from "redis";
|
||||
|
||||
const fixture = new RedisFixture({
|
||||
image: "redis:7-alpine",
|
||||
tcpPingFn: async (port, host) => {
|
||||
// Custom health check — connect and verify
|
||||
const client = createClient({ socket: { host, port } });
|
||||
try {
|
||||
await client.connect();
|
||||
const pong = await client.ping();
|
||||
return pong === "PONG";
|
||||
} catch {
|
||||
return false;
|
||||
} finally {
|
||||
await client.disconnect();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const config = await fixture.start();
|
||||
const client = createClient({ url: config.url });
|
||||
await client.connect();
|
||||
await client.set("key", "value");
|
||||
await client.disconnect();
|
||||
await fixture.stop();
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `class RedisFixture`
|
||||
|
||||
Implements `ServiceFixture<RedisConfig>`.
|
||||
|
||||
#### `constructor(options?: RedisFixtureOptions)`
|
||||
|
||||
Creates a new fixture instance. All options are optional.
|
||||
|
||||
#### `name: string`
|
||||
|
||||
Always `"redis"`. Used by `TestEnvironment` as the registry key.
|
||||
|
||||
#### `start(): Promise<RedisConfig>`
|
||||
|
||||
Starts the service. Returns the runtime configuration. In passthrough mode (when `REDIS_URL` env var is set), returns immediately with parsed config. Otherwise starts a testcontainers container.
|
||||
|
||||
#### `stop(): Promise<void>`
|
||||
|
||||
Stops the container. No-op in passthrough mode or when not started.
|
||||
|
||||
#### `healthCheck(): Promise<boolean>`
|
||||
|
||||
Returns `true` when a TCP PING to `localhost:<mappedPort>` returns `+PONG`. Returns `false` if no container is active or the TCP connection fails.
|
||||
|
||||
### `interface RedisConfig`
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `url` | `string` | Full Redis URL: `redis://localhost:<port>` |
|
||||
| `host` | `string` | Hostname parsed from the URL |
|
||||
| `port` | `number` | Port number parsed from the URL |
|
||||
|
||||
### `interface RedisFixtureOptions`
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `image?` | `string` | Docker image override. Defaults to `redis:7-alpine`. |
|
||||
| `containerFactory?` | `(image: string) => GenericContainer` | Injectable factory for unit testing. |
|
||||
| `tcpPingFn?` | `(port: number, host: string) => Promise<boolean>` | Injectable TCP ping for health check unit testing. |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- **Why TCP PING over Redis client**: including `ioredis` or `redis` in this fixture's dependencies would force consumers to use a specific client version. The TCP PING is protocol-level and works with any Redis server, requiring only Node.js's built-in `node:net` module.
|
||||
- **Dynamic import of testcontainers**: the `GenericContainer` import is deferred to `start()` time so unit tests that provide a `containerFactory` do not trigger testcontainers initialization.
|
||||
- **URL parsing for passthrough**: `new URL(url)` provides consistent host/port extraction. If the URL omits a port, the fixture defaults to `REDIS_CONTAINER_PORT` (6379).
|
||||
- **Socket timeout**: the built-in `defaultTcpPing` uses a 2-second socket timeout to prevent health check hangs during container startup race conditions.
|
||||
Reference in New Issue
Block a user