# MySQL Testing

## Purpose

提供 MySQL 数据库专项测试能力，验证迁移正确性、外键约束、并发写入等数据库特定行为。

## Requirements

### Requirement: MySQL 测试环境可启动

系统 SHALL 提供 Docker Compose 配置以启动 MySQL 8.0 测试环境。

#### Scenario: 启动 MySQL 测试容器
- **WHEN** 执行 `make test-mysql-up`
- **THEN** 启动 MySQL 8.0 容器，端口 13306
- **AND** 创建数据库 `nex_test`
- **AND** 容器数据存储在内存盘（tmpfs）

#### Scenario: 销毁 MySQL 测试容器
- **WHEN** 执行 `make test-mysql-down`
- **THEN** 停止并删除容器
- **AND** 所有数据被销毁

### Requirement: MySQL 测试可通过 build tag 控制

MySQL 测试 SHALL 使用 `// +build mysql` build tag，默认不运行。

#### Scenario: 默认测试不包含 MySQL 测试
- **WHEN** 执行 `go test ./...`
- **THEN** 不运行 `tests/mysql/` 下的测试

#### Scenario: 启用 MySQL 测试
- **WHEN** 执行 `go test -tags=mysql ./tests/mysql/...`
- **THEN** 运行所有 MySQL 测试

### Requirement: MySQL 迁移正确执行

MySQL 测试 SHALL 验证迁移脚本在 MySQL 环境下正确执行。

#### Scenario: 迁移创建所有表
- **WHEN** 运行 MySQL 迁移
- **THEN** 创建 `providers`、`models`、`usage_stats` 表
- **AND** 字段类型符合 MySQL 迁移文件定义（VARCHAR、DATETIME(3)、BOOLEAN 等）
- **AND** 索引 `idx_models_provider_id`、`idx_models_model_name`、`idx_usage_stats_provider_model_date` 创建成功

#### Scenario: 迁移可重复执行
- **WHEN** 在已迁移的数据库上再次运行迁移
- **THEN** 不报错，数据库状态不变

### Requirement: MySQL 外键约束生效

MySQL 测试 SHALL 验证外键约束行为符合预期。

#### Scenario: 外键约束阻止无效引用
- **WHEN** 创建 model 时 `provider_id` 不存在
- **THEN** 操作失败，返回外键约束错误

#### Scenario: 级联删除生效
- **WHEN** 删除 provider
- **THEN** 该 provider 的所有 models 被级联删除

### Requirement: MySQL UNIQUE 约束生效

MySQL 测试 SHALL 验证 UNIQUE 约束行为符合预期。

#### Scenario: models 表 UNIQUE 约束
- **WHEN** 尝试创建相同 `(provider_id, model_name)` 组合的 model
- **THEN** 操作失败，返回唯一约束错误

#### Scenario: usage_stats 表 UNIQUE 约束
- **WHEN** 尝试创建相同 `(provider_id, model_name, date)` 组合的 usage_stats
- **THEN** 操作失败，返回唯一约束错误

### Requirement: MySQL 并发写入正确

MySQL 测试 SHALL 验证并发写入不丢失数据。

#### Scenario: 并发记录 usage_stats
- **WHEN** 10 个 goroutine 并发调用 `statsRepo.Record(providerID, modelName)`
- **THEN** 最终 `request_count` 等于 10
- **AND** 无数据丢失或重复

#### Scenario: 并发创建相同 provider
- **WHEN** 10 个 goroutine 并发创建相同 ID 的 provider
- **THEN** 仅 1 个成功，其他 9 个失败

#### Scenario: 并发创建相同 model
- **WHEN** 10 个 goroutine 并发创建相同 `(provider_id, model_name)` 的 model
- **THEN** 仅 1 个成功，其他 9 个失败

### Requirement: MySQL 测试命令完整

Makefile SHALL 提供完整的 MySQL 测试命令。

#### Scenario: 完整测试流程
- **WHEN** 执行 `make test-mysql`
- **THEN** 启动 Docker MySQL
- **AND** 等待 MySQL 就绪
- **AND** 运行所有 MySQL 测试
- **AND** 销毁容器

#### Scenario: 快速测试（容器已运行）
- **WHEN** 执行 `make test-mysql-quick`
- **THEN** 直接运行测试，不管理容器生命周期
