test(mcp): MCP 端点、CSRF 豁免与回归全量测试

This commit is contained in:
augushong
2026-08-16 23:33:39 +08:00
parent adc10d1157
commit bba7dec278
4 changed files with 891 additions and 0 deletions

51
tests/router.php Normal file
View File

@@ -0,0 +1,51 @@
<?php
/**
* MCP e2e 专用 HTTP 入口php -S 路由脚本,仅测试使用,绝不能被生产引用).
*
* 用法(容器内,由 tests/McpEndpointTest::setUpBeforeClass 自动拉起):
* PHP_CLI_SERVER_WORKERS=4 php -S 127.0.0.1:8127 -t public tests/router.php
*
* 文件名必须是 router.php关键约束
* php -S + 路由脚本时 $_SERVER['SCRIPT_FILENAME'] 指向本文件,
* think-multi-app 的 MultiApp::getScriptName() 用它的文件名做「入口绑定应用」
* 判定——白名单仅 ['index','router','think'] 豁免;叫别的名字(如 e2e_server
* 会被当成应用名绑定pathinfo 首段不再做应用识别,/admin/* 全部 404。
*
* 为什么不用容器 nginx127.0.0.1:8000
* nginx/fpm 栈读 .env 指向开发库ulthon而 e2e 断言要求 fixture 自包含
* 且严格落在测试库ulthon_testulthon-testing 技能铁律 + 任务 MUST NOT
* 事务内的 fixture 对独立 HTTP 连接永远不可见,因此 e2e 只能:
* a) 把 fixture 提交进开发库(违反测试库/开发库分离,禁止);或
* b) 起一个与 PHPUnit 同样做 config 级测试库覆盖的独立 HTTP 服务(本方案)。
* 本入口与 tests/bootstrap.php 共享同一套覆盖逻辑require 复用,防漂移),
* 走完整 HTTP 内核(多应用路由 / 中间件 / Session是真实 HTTP 栈 e2e。
*
* 测试专用请求头(生产代码零改动的注入点):
* X-E2E-Mcp-Disabled: 1 -> config mcp.enable=false覆盖 403 分支;
* mcp.enable 在控制器内经 config() 读取e2e 期望它默认 true
* 又不能从 PHPUnit 进程改另一个进程的 Config故由本入口代劳
*
* 自请求并发说明tools/call 分发会从本服务回环 POST /admin/*McpDispatchBase
* php -S 默认单 worker 会死锁,必须 PHP_CLI_SERVER_WORKERS>1LinuxPHP>=7.4)。
*/
declare(strict_types=1);
// 复用 PHPUnit 引导autoload + App 初始化 + config 级覆盖到测试库 + 非 test 库护栏。
// bootstrap.php 是无 PHPUnit 依赖的纯脚本(抛 RuntimeException 拒绝非测试库),
// 这里 require 后 $app 即已就绪的容器实例。
require __DIR__ . '/bootstrap.php';
// 403 分支模拟(仅测试头,见文件头注释)
if (($_SERVER['HTTP_X_E2E_MCP_DISABLED'] ?? '') === '1') {
\think\facade\Config::set(['enable' => false], 'mcp');
}
// 标准 HTTP 内核(与 public/index.php 同构initialize 幂等config 覆盖不会被冲掉)
$http = $app->http;
$response = $http->run();
$response->send();
$http->end($response);