Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,102 @@
## ADDED Requirements
### Requirement: Layer 0 dep-graph isolation
The `@suaveplan/testing-integration-mysql` 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-mysql...` is run
- **THEN** the only `@suaveplan/*` package in the runtime closure is `@suaveplan/testing-integration`
### Requirement: Image-pinning policy
The default image MUST be `mysql:8.4`. The `constants/index.ts` file MUST carry a `# TODO: replace with sha256:<digest>` comment until the digest is recorded.
#### Scenario: Pinned tag
- **WHEN** the constants file is read
- **THEN** the image string equals `mysql:8.4` AND a sha256 TODO line is present
### Requirement: Env-bridge passthrough
The fixture MUST consult `MYSQL_URL`, `MYSQL_DATABASE`, `MYSQL_USER`, `MYSQL_PASSWORD`, and `MYSQL_ROOT_PASSWORD`. When all five are present and non-empty, `start()` MUST skip container creation and return a handle whose config points at the live MySQL.
#### Scenario: Live MySQL present
- **WHEN** all five env vars are set
- **THEN** `start()` returns without invoking `containerFactory` AND the returned config's `url` equals `MYSQL_URL`
#### Scenario: Partial env triggers container
- **WHEN** `MYSQL_URL` is set but `MYSQL_ROOT_PASSWORD` is empty
- **THEN** `start()` falls back to container mode
### Requirement: Healthcheck
The fixture MUST run `mysqladmin ping -h localhost -p$MYSQL_ROOT_PASSWORD` in-container via the injectable `execFn` and treat exit code `0` with stdout containing `mysqld is alive` as ready. The default `healthTimeoutMs` MUST be `90000` (initial DB init can be slow on cold image pulls). Callers MAY override.
#### Scenario: Healthcheck succeeds
- **WHEN** in-container `mysqladmin ping` returns exit code 0 with `mysqld is alive`
- **THEN** `start()` resolves
#### Scenario: Healthcheck times out
- **WHEN** the ping never succeeds within `healthTimeoutMs`
- **THEN** `start()` rejects with code `INTEGRATION.MYSQL.HEALTHCHECK_TIMEOUT`
### Requirement: Charset and collation overrides
The fixture MUST default to `charset: 'utf8mb4'` and `collation: 'utf8mb4_0900_ai_ci'` and MUST pass `--character-set-server=<charset>` and `--collation-server=<collation>` to `mysqld` when overrides are supplied via config.
#### Scenario: UTF-8mb4 default
- **WHEN** the fixture is started with no charset override
- **THEN** `SHOW VARIABLES LIKE 'character_set_server'` returns `utf8mb4`
#### Scenario: Charset override applied
- **WHEN** the fixture is started with `charset: 'utf8'`
- **THEN** `SHOW VARIABLES LIKE 'character_set_server'` returns `utf8`
### Requirement: Config shape
The exported `MySqlConfig` interface MUST include `database`, `user`, `password`, `rootPassword`, optional `charset?: string`, optional `collation?: string`, and the resolved `url`. A sibling `mysql-fixture.schemas.ts` MUST export a Zod `MySqlConfigSchema` that validates the same shape.
#### Scenario: Schema parity
- **WHEN** `MySqlConfigSchema.safeParse` is run against a `MySqlConfig` value
- **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\.MYSQL\.[A-Z_]+$`.
#### Scenario: Coded error
- **WHEN** any fixture method throws
- **THEN** `code` starts with `INTEGRATION.MYSQL.`
### Requirement: Injectable fakes
The fixture constructor MUST accept `containerFactory?: () => GenericContainer` and `execFn?: (cmd: string[]) => Promise<{ stdout: string; stderr: string; exitCode: number }>`. Unit tests MUST drive 100% Istanbul branch coverage without Docker.
#### Scenario: Fake injection
- **WHEN** the fixture is constructed with both fakes
- **THEN** real Docker is never invoked during the test
### Requirement: Plugin scenarios
The fixture MUST support, end-to-end against a real container, the following flows in its smoke test:
#### Scenario: Transaction round-trip
- **WHEN** a transaction inserts rows and commits
- **THEN** the rows are visible to a subsequent connection AND a rolled-back transaction's rows are not visible
#### Scenario: DDL post-start
- **WHEN** `CREATE TABLE`, `ALTER TABLE ADD COLUMN`, and `DROP TABLE` statements run after `start()` resolves
- **THEN** each statement succeeds AND `INFORMATION_SCHEMA.TABLES` reflects the change