# 测试插件

测试插件是 Monibuca v5 的综合测试框架，为各种流媒体协议和媒体处理场景提供自动化测试能力。它使开发者能够通过可配置的测试用例来验证流媒体功能、性能和可靠性。

## 概述

测试插件作为 Monibuca 流媒体能力的质量保证工具，提供：

- **自动化测试用例**：为常见流媒体工作流预配置测试场景
- **多协议支持**：支持 RTMP、RTSP、SRT、WebRTC、HLS、MP4、FLV 和 PS 协议的测试
- **压力测试**：通过可配置的并发推拉流操作进行性能测试
- **实时监控**：通过服务器发送事件（SSE）提供实时状态更新
- **灵活的任务系统**：可扩展的任务框架，支持自定义测试场景

## 架构设计

### 核心组件

1. **TestPlugin**：主插件控制器，管理测试用例和压力测试
2. **TestCase**：具有可配置任务和参数的单个测试场景
3. **TestTaskFactory**：用于创建不同类型测试任务的工厂模式
4. **任务类型**：针对不同操作的专业化任务（推流、拉流、截图、录制、读取）

### 任务系统设计

插件使用复杂的任务编排系统：

```go
type TestTaskConfig struct {
    Action     string        `json:"action"`     // 任务类型：push, pull, snapshot, write, read
    Delay      time.Duration `json:"delay"`      // 任务执行前的延迟
    Format     string        `json:"format"`     // 协议/格式：rtmp, rtsp, srt 等
    ServerAddr string        `json:"serverAddr"` // 目标服务器地址
    Input      string        `json:"input"`      // 输入源（文件、URL 等）
    StreamPath string        `json:"streamPath"` // 流标识符
}
```

### 任务类型详解

#### 1. 推流任务（`AcceptPushTask`）
- **目的**：模拟向服务器推送媒体流
- **实现**：使用 FFmpeg 从文件或实时源推送媒体
- **支持格式**：RTMP、RTSP、SRT、WebRTC、PS
- **设计巧思**：利用 FFmpeg 强大的流媒体能力，同时通过进程管理保持控制

#### 2. 截图任务（`SnapshotTask`）
- **目的**：从流中捕获帧以验证内容质量
- **实现**：两种模式：
  - 直接从流 URL 进行 FFmpeg 捕获
  - 内部流订阅与 AnnexB 格式处理
- **设计巧思**：双重方法允许测试外部可访问性和内部流处理

#### 3. 录制任务（`WriteRemoteTask`）
- **目的**：将流录制为各种格式
- **实现**：与 Monibuca 的录制插件集成
- **支持格式**：MP4、FLV、HLS、PS
- **设计巧思**：重用现有录制基础设施以确保一致性

#### 4. 读取任务（`ReadRemoteTask`）
- **目的**：从各种源拉取流
- **实现**：使用 Monibuca 的拉流插件
- **支持格式**：MP4、FLV、HLS、RTMP、RTSP、SRT、WebRTC、AnnexB
- **设计巧思**：为不同拉流器实现提供统一接口

## 关键设计模式

### 1. 工厂模式
`TestTaskFactory` 使用注册表模式动态创建任务：

```go
func (f *TestTaskFactory) Register(action string, taskCreator func(*TestCase, TestTaskConfig) task.ITask) {
    f.tasks[action] = taskCreator
}
```

这允许轻松扩展新任务类型而无需修改核心代码。

### 2. 基于反射的任务编排
测试用例执行使用 Go 的反射 API 进行动态任务调度：

```go
subTaskSelect := []reflect.SelectCase{
    {Dir: reflect.SelectRecv, Chan: reflect.ValueOf(time.After(ts.Timeout))},
    {Dir: reflect.SelectRecv, Chan: reflect.ValueOf(ts.Done())},
}
```

这实现了复杂的时间控制和并行任务执行。

### 3. 实时状态更新
插件实现服务器发送事件（SSE）进行实时监控：

```go
func (p *TestPlugin) GetTestCaseSSE(w http.ResponseWriter, r *http.Request) {
    util.NewSSE(w, r.Context(), func(sse *util.SSE) {
        // 实时状态广播
    })
}
```

### 4. 压力测试架构
压力测试系统维护活跃推拉流操作的集合：

```go
type TestPlugin struct {
    pushers util.Collection[string, *m7s.PushJob]
    pullers util.Collection[string, *m7s.PullJob]
}
```

这允许动态扩展和管理并发操作。

## 配置说明

### 测试用例配置

测试用例以 YAML 格式定义，结构如下：

```yaml
cases:
  test_name:
    description: "测试描述"
    videoCodec: "h264"
    audioCodec: "aac"
    videoOnly: false
    audioOnly: false
    timeout: "30s"
    tasks:
      - action: push
        format: rtmp
        delay: 0s
      - action: snapshot
        format: rtmp
        delay: 5s
```

### 预配置测试用例

插件包含全面的测试场景：

- **协议交叉测试**：RTMP↔RTSP、RTMP↔SRT、RTSP↔SRT
- **文件格式测试**：MP4、FLV、HLS 读取和录制
- **高级功能**：PS 封装、AnnexB 处理、WebRTC 测试

## API 接口

### REST API
- `GET /test/api/cases` - 列出测试用例
- `POST /test/api/cases/execute` - 执行测试用例
- `GET /test/api/stress/count` - 获取压力测试计数
- `POST /test/api/stress/push/{protocol}/{count}` - 开始推流压力测试
- `POST /test/api/stress/pull/{protocol}/{count}` - 开始拉流压力测试

### 服务器发送事件
- `GET /sse/cases` - 实时测试用例状态更新

### gRPC API
完整的 gRPC 服务定义在 `pb/test.proto` 中，包含相应的 HTTP 网关端点。

## 使用示例

### 基本测试执行
```bash
# 执行特定测试用例
curl -X POST http://localhost:8080/test/api/cases/execute \
  -H "Content-Type: application/json" \
  -d '{"names": ["rtmp2rtmp"]}'
```

### 压力测试
```bash
# 启动 10 个并发 RTMP 推流
curl -X POST http://localhost:8080/test/api/stress/push/rtmp/10 \
  -H "Content-Type: application/json" \
  -d '{
    "streamPath": "stress_test",
    "remoteURL": "rtmp://localhost/live/%d"
  }'
```

### 实时监控
```javascript
// 监控测试用例状态
const eventSource = new EventSource('/sse/cases');
eventSource.onmessage = function(event) {
    const testCases = JSON.parse(event.data);
    // 使用测试状态更新 UI
};
```

## 高级功能

### 1. 动态流路径生成
插件自动为并行测试执行生成唯一流路径：

```go
if taskConfig.StreamPath == "" {
    taskConfig.StreamPath = fmt.Sprintf("test/%d", ts.ID)
}
```

### 2. 智能输入处理
支持基于文件和基于 URL 的输入，具有自动路径解析：

```go
if taskConfig.Input != "" && !strings.Contains(taskConfig.Input, ".") {
    taskConfig.Input = fmt.Sprintf("%s/%d", taskConfig.Input, ts.ID)
}
```

### 3. 综合日志记录
每个测试用例维护带时间戳的详细日志：

```go
func (ts *TestCase) Write(buf []byte) (int, error) {
    ts.Logs += time.Now().Format("2006-01-02 15:04:05") + " " + string(buf) + "\n"
    return len(buf), nil
}
```

## 与 Monibuca 生态系统的集成

测试插件与 Monibuca 的插件架构无缝集成：

- **插件注册**：使用 `m7s.InstallPlugin` 进行自动发现
- **配置管理**：利用 Monibuca 的配置系统
- **任务框架**：基于 Monibuca 的任务管理系统构建
- **流管理**：与发布者/订阅者模型集成

## 性能考虑

### 内存管理
- 使用 `gomem.Memory` 进行高效的缓冲区管理
- 为临时文件和进程实现适当的清理
- 利用 Go 的垃圾收集器进行自动内存管理

### 并发性
- 使用 Monibuca 的 `Call` 方法进行线程安全操作
- 为压力测试进行高效的集合管理
- 非阻塞 SSE 实现

### 资源清理
- 任务完成时自动终止进程
- 录制测试后清理临时文件
- 网络操作的适当连接管理

## 可扩展性

插件设计便于扩展：

1. **新任务类型**：向工厂注册新的任务创建器
2. **自定义协议**：添加对新流媒体协议的支持
3. **高级指标**：扩展监控和报告功能
4. **集成测试**：创建复杂的多步骤测试场景

## 最佳实践

1. **测试隔离**：每个测试用例使用唯一的流路径运行
2. **超时管理**：为不同场景配置适当的超时
3. **资源监控**：在压力测试期间监控系统资源
4. **日志分析**：使用详细日志进行调试和性能分析
5. **增量测试**：在复杂场景之前从简单用例开始

## 故障排除

### 常见问题

1. **找不到 FFmpeg**：确保 FFmpeg 已安装并在 PATH 中
2. **端口冲突**：在压力测试中检查端口可用性
3. **文件权限**：确保录制测试的写入权限
4. **网络连接**：验证远程流测试的网络访问

### 调试模式
通过在 Monibuca 配置中设置适当的日志级别来启用详细日志记录。

## 设计巧思总结

### 1. 任务工厂模式
通过注册表模式实现任务的动态创建，使得添加新任务类型变得非常简单，无需修改核心代码。

### 2. 反射驱动的任务调度
使用 Go 的反射 API 实现复杂的任务编排，支持动态延迟和并行执行，提供了极大的灵活性。

### 3. 双重截图机制
截图任务支持两种模式：外部 FFmpeg 捕获和内部流订阅，既测试了外部可访问性，又验证了内部流处理能力。

### 4. 智能资源管理
通过 `util.Collection` 管理并发操作，支持动态扩展和收缩，实现了高效的压力测试。

### 5. 实时状态同步
使用 SSE 技术实现实时状态更新，为测试监控提供了良好的用户体验。

### 6. 流路径隔离
自动生成唯一的流路径，确保并行测试之间不会相互干扰，提高了测试的可靠性。

## 未来增强

- **可视化测试报告**：基于 HTML 的测试结果可视化
- **性能指标**：详细的性能分析和报告
- **CI/CD 集成**：在持续集成管道中的自动化测试
- **自定义断言**：用户定义的测试用例验证规则
- **分布式测试**：多节点测试能力

---

测试插件代表了流媒体测试的复杂方法，结合了灵活性、性能和易用性，以确保 Monibuca 流媒体能力的可靠性。通过其精心设计的架构和丰富的功能集，它为开发者提供了一个强大的工具来验证和优化流媒体系统。
