Files
bililive-go/playwright.ffmpeg.config.ts
kira1928andClaude Fable 5 d5d8b797e4 fix: 处理第三轮 code review 意见(并发安全、路径语义一致性、后处理等待)
Gemini 高危:
- FFmpegAsyncInit 增加 ffmpegInitRunning CAS 守卫,并发调用(如 e2e
  多次 reinit)时只有第一个生效,避免并发 tool.Install()
- setFFmpegStatus 用 ffmpegStatusMu 串行化存储、变化通知与回调执行,
  保证订阅者看到的状态顺序与实际更新顺序一致
- ./ffmpeg 兜底改为 LookPath 任何失败都尝试:Unix 下当前目录不在 PATH,
  返回 ErrNotFound 而非 ErrDot,原来只处理 ErrDot 在 Unix 上不生效;
  该逻辑收敛到 utils.LookupSystemFFmpeg 供状态检测与实际查找共用

Gemini 中危:
- tool.Install() 前检查 ctx.Err(),程序退出中不再发起耗时下载

Codex P2:
- 配置了无效 ffmpeg_path 时不再走 remotetools 下载(下载了实际录制也
  不会用),直接置 not_found 并提示修正配置,状态与实际查找语义一致;
  e2e 相应改为 ffmpeg_path 留空 + BILILIVE_IGNORE_SYSTEM_FFMPEG=1
  环境变量屏蔽系统 FFmpeg(CI 预装 ffmpeg,无法用真实 PATH 模拟)
- 等待逻辑上移为 tools.WaitFFmpegAsyncInitDone 供多处复用:ffmpeg
  parser、pipeline 后处理阶段(convert_mp4 / burn_subtitles /
  custom_command)及 recorder 的 legacy custom commandline 在获取
  FFmpeg 路径前等待后台初始化结束,短直播后处理不再因下载未完成而失败

Copilot:
- WaitForToolsInit 轮询改用 time.NewTicker 复用计时器
- FFmpegBanner 初始状态查询失败时打印 console.warn,不再静默吞掉
- mock server 检查 w.Write 错误,客户端断开后立即停止发送

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 15:16:30 +09:00

121 lines
4.2 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* playwright.ffmpeg.config.ts
*
* FFmpeg 异步下载流程 e2e 测试专用配置。
*
* 与普通 playwright.config.ts 的区别:
* - bgo 运行在 8085 端口(避免端口冲突)
* - bgo 配置 ffmpeg_path 指向不存在路径,强制走 remotetools 下载流程
* - 通过 REMOTETOOLS_CONFIG 环境变量将 remotetools 重定向到本地 mock server
* - 额外启动 ffmpeg-mock-server 在 8890 端口,提供可控的 FFmpeg 下载
* - 只运行 ffmpeg-download.spec.ts(状态注入测试在普通配置中运行)
*/
import { defineConfig, devices } from '@playwright/test';
import * as fs from 'fs';
import * as path from 'path';
const configTemplate = path.join(
__dirname,
'tests/e2e/fixtures/ffmpeg-test-config.template.yml',
);
const configRuntime = path.join(__dirname, 'test-output/ffmpeg-test-config.yml');
const toolsConfigPath = path.join(
__dirname,
'tests/e2e/fixtures/test-tools-config.json',
).replace(/\\/g, '/');
// 以下带副作用的准备工作只能在 Playwright 主进程执行一次。
// worker 进程也会重新加载本配置文件(此时 TEST_WORKER_INDEX 已设置),
// 若在 worker 中再次执行 rmSync,会把 bgo 正在下载写入的工具目录删掉,导致下载报错。
if (!process.env.TEST_WORKER_INDEX) {
// 确保 test-output 目录存在并准备配置文件
fs.mkdirSync(path.dirname(configRuntime), { recursive: true });
fs.copyFileSync(configTemplate, configRuntime);
// 清空 FFmpeg e2e 测试专用的 appdata 目录,避免上次测试缓存的 fake-ffmpeg 影响结果
const ffmpegAppData = path.join(__dirname, 'test-output/.appdata-ffmpeg-e2e/external_tools');
try {
fs.rmSync(ffmpegAppData, { recursive: true, force: true });
} catch (_) {
// 目录不存在时忽略
}
}
// 构建启动 bgo 的命令。
// REMOTETOOLS_CONFIG:将 remotetools 下载源重定向到本地 mock server;
// BILILIVE_IGNORE_SYSTEM_FFMPEG:跳过系统 PATH 中的 FFmpeg 查找(CI 机器预装了 ffmpeg),
// 强制走 remotetools 下载流程。
function makeBgoCommand(): string {
const configArg = `test-output/ffmpeg-test-config.yml`;
if (process.platform === 'win32') {
// PowerShell 语法设置环境变量
return (
`powershell -Command "$env:REMOTETOOLS_CONFIG='${toolsConfigPath}'; ` +
`$env:BILILIVE_IGNORE_SYSTEM_FFMPEG='1'; ` +
`go run -tags dev ./src/cmd/bililive --config ${configArg}"`
);
}
// bash/sh 语法
return (
`REMOTETOOLS_CONFIG='${toolsConfigPath}' BILILIVE_IGNORE_SYSTEM_FFMPEG=1 ` +
`go run -tags dev ./src/cmd/bililive --config ${configArg}`
);
}
export default defineConfig({
// 只运行 FFmpeg 下载流程专用的测试文件
testDir: './tests/e2e',
testMatch: ['**/ffmpeg-download.spec.ts'],
outputDir: 'test-results-ffmpeg',
timeout: 120 * 1000, // 下载测试需要更长超时
expect: { timeout: 10 * 1000 },
fullyParallel: false,
forbidOnly: !!process.env.CI,
retries: 0,
workers: 1,
reporter: [
['list'],
['html', { outputFolder: 'playwright-report-ffmpeg', open: 'never' }],
],
use: {
baseURL: 'http://127.0.0.1:8085',
screenshot: 'only-on-failure',
trace: { mode: 'on', sources: true, snapshots: true, screenshots: true },
video: 'retain-on-failure',
viewport: { width: 1280, height: 720 },
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],
webServer: [
// ffmpeg-mock-server — 提供可控的 FFmpeg zip 下载
// 初始限速 1KB/s:必须在 bgo 启动前生效,否则 bgo 的 FFmpegAsyncInit 可能在
// 测试用例执行前就完成不限速下载,导致 downloading 状态断言失败
{
command: 'go run ./test/ffmpeg-mock-server -port 8890 -speed 1024',
url: 'http://127.0.0.1:8890/health',
reuseExistingServer: false,
timeout: 120 * 1000, // 等待 fake-ffmpeg 编译完成
stdout: 'pipe',
stderr: 'pipe',
},
// bgo — 无可用 FFmpeg,remotetools 指向 mock server
{
command: makeBgoCommand(),
url: 'http://127.0.0.1:8085/api/info',
reuseExistingServer: false,
timeout: 60 * 1000,
stdout: 'pipe',
stderr: 'pipe',
},
],
});