2
0

run.php 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. <?php
  2. /**
  3. * api-test 入口:装配配置 → 加载用例 → 运行 → 报告。
  4. *
  5. * 用法:
  6. * php run.php [--server=<alias|URL>] [--token=<bearer>] [--username=<u> --password=<p>] [--filter=<子串>] [--list]
  7. *
  8. * 例:
  9. * php run.php # 默认 local
  10. * php run.php --server=staging
  11. * php run.php --server=https://foo/api
  12. * php run.php --filter=search
  13. * php run.php --list # 列出可用服务器
  14. * php run.php --username=alice --password=secret # 调 /v3/sessions 换 token
  15. *
  16. * 退出码:0 全绿;1 有失败/错误;2 参数或加载错误。
  17. */
  18. error_reporting(E_ALL & ~E_DEPRECATED);
  19. $opts = [];
  20. foreach (array_slice($argv, 1) as $arg) {
  21. if (preg_match('/^--([^=]+)(?:=(.*))?$/', $arg, $m)) {
  22. $opts[$m[1]] = $m[2] ?? true;
  23. }
  24. }
  25. // --list:只打印服务器清单
  26. if (isset($opts['list'])) {
  27. $cfg = require __DIR__ . '/config.php';
  28. echo "可用服务器(--server=alias,默认 {$cfg['default_server']}):\n";
  29. foreach ($cfg['servers'] as $alias => $url) {
  30. printf(" %-8s %s\n", $alias, $url);
  31. }
  32. echo "\n也可直接 --server=<完整 base URL>。\n";
  33. exit(0);
  34. }
  35. // 解析服务器
  36. $config = require __DIR__ . '/config.php';
  37. $servers = $config['servers'];
  38. $serverArg = is_string($opts['server'] ?? null) ? $opts['server'] : null;
  39. $envBase = getenv('API_TEST_BASE') ?: null;
  40. if ($envBase !== null) {
  41. $config['base_url'] = rtrim($envBase, '/');
  42. } elseif ($serverArg !== null && isset($servers[$serverArg])) {
  43. $config['base_url'] = $servers[$serverArg];
  44. } elseif ($serverArg !== null && preg_match('#^https?://#', $serverArg)) {
  45. $config['base_url'] = rtrim($serverArg, '/');
  46. } elseif (isset($servers[$config['default_server']])) {
  47. $config['base_url'] = $servers[$config['default_server']];
  48. } else {
  49. // config.local.php 的 default_server 也可以直接写完整 base URL
  50. $config['base_url'] = rtrim($config['default_server'], '/');
  51. }
  52. // token 覆盖
  53. if (is_string($opts['token'] ?? null) && $opts['token'] !== '') {
  54. $config['token'] = $opts['token'];
  55. }
  56. // username/password 覆盖
  57. if (is_string($opts['username'] ?? null) && $opts['username'] !== '') {
  58. $config['username'] = $opts['username'];
  59. }
  60. if (is_string($opts['password'] ?? null) && $opts['password'] !== '') {
  61. $config['password'] = $opts['password'];
  62. }
  63. $GLOBALS['config'] = $config;
  64. $GLOBALS['fixtures'] = array_replace(require __DIR__ . '/fixtures.php', $config['fixtures']);
  65. require __DIR__ . '/src/bootstrap.php';
  66. // 没给 token 但给了账号密码 → 调 /v3/sessions 现换一个
  67. if (empty($config['token']) && $config['username'] && $config['password']) {
  68. try {
  69. $config['token'] = login($config['username'], $config['password']);
  70. $GLOBALS['config']['token'] = $config['token'];
  71. echo "已用 {$config['username']} 登录(/v3/sessions)换取 token\n\n";
  72. } catch (Fail $e) {
  73. echo "登录失败:{$e->getMessage()}(需登录的用例将 FAIL)\n\n";
  74. }
  75. }
  76. // 加载用例
  77. $caseFiles = glob(__DIR__ . '/cases/*.php') ?: [];
  78. sort($caseFiles);
  79. foreach ($caseFiles as $file) {
  80. require $file;
  81. }
  82. $tests = $GLOBALS['__tests'];
  83. $filter = is_string($opts['filter'] ?? null) ? $opts['filter'] : null;
  84. $pass = $fail = $skip = $error = 0;
  85. $start = microtime(true);
  86. printf("目标服务器: %s\n\n", $config['base_url']);
  87. foreach ($tests as [$name, $fn]) {
  88. if ($filter !== null && ! str_contains($name, $filter)) {
  89. continue;
  90. }
  91. try {
  92. $fn();
  93. $pass++;
  94. echo " ✅ PASS {$name}\n";
  95. } catch (Skip $e) {
  96. $skip++;
  97. echo " ⏭️ SKIP {$name} ({$e->getMessage()})\n";
  98. } catch (Fail $e) {
  99. $fail++;
  100. echo " ❌ FAIL {$name}\n {$e->getMessage()}\n";
  101. } catch (Throwable $e) {
  102. $error++;
  103. echo " 💥 ERROR {$name}\n " . get_class($e) . ': ' . $e->getMessage() . "\n";
  104. }
  105. }
  106. $total = $pass + $fail + $skip + $error;
  107. $elapsed = round(microtime(true) - $start, 2);
  108. printf("\n%d 用例:%d 通过 / %d 失败 / %d 跳过 / %d 错误(%.2fs)\n", $total, $pass, $fail, $skip, $error, $elapsed);
  109. exit($fail === 0 && $error === 0 ? 0 : 1);