water_mini_http_test.php 5.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. <?php
  2. /** Live routing checks. Temporary unbound mini identity is removed in finally; no business writes. */
  3. require dirname(__DIR__) . '/vendor/autoload.php';
  4. \Dotenv\Dotenv::createUnsafeMutable(dirname(__DIR__))->load();
  5. \support\App::loadAllConfig(['route']);
  6. date_default_timezone_set('Asia/Shanghai');
  7. use app\miniapi\service\AuthService;
  8. use app\miniapi\model\MiniUser;
  9. use app\miniapi\model\MiniSession;
  10. $checks = 0;
  11. function verify(bool $condition, string $label): void
  12. {
  13. global $checks;
  14. $checks++;
  15. if (!$condition) {
  16. throw new RuntimeException($label);
  17. }
  18. }
  19. function requestApi(string $method, string $path, int $status, int $code, ?string $token = null, string $payload = '{}'): array
  20. {
  21. $headers = ['Content-Type: application/json'];
  22. if ($token !== null) {
  23. $headers[] = 'Authorization: Bearer ' . $token;
  24. }
  25. $curl = curl_init('http://127.0.0.1:8787' . $path);
  26. curl_setopt_array($curl, [CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 10, CURLOPT_CUSTOMREQUEST => $method, CURLOPT_HTTPHEADER => $headers]);
  27. if ($method === 'POST') {
  28. curl_setopt($curl, CURLOPT_POSTFIELDS, $payload);
  29. }
  30. $raw = curl_exec($curl);
  31. $actual = curl_getinfo($curl, CURLINFO_HTTP_CODE);
  32. curl_close($curl);
  33. $data = json_decode((string) $raw, true);
  34. verify($actual === $status && ($data['code'] ?? null) === $code, "$method $path expected $status/$code got $actual/" . ($data['code'] ?? 'invalid JSON'));
  35. verify(isset($data['request_id']) && array_key_exists('data', $data), "$path response envelope");
  36. return $data['data'] ?? [];
  37. }
  38. $base = '/api/mini/v1';
  39. $configuration = requestApi('GET', $base . '/config', 200, 0);
  40. verify(!$configuration['capabilities']['payment'], 'payments not fabricated');
  41. $catalog = requestApi('GET', $base . '/packages?page_size=1', 200, 0);
  42. verify(isset($catalog['items'], $catalog['total']), 'live catalog list');
  43. if ($catalog['items']) {
  44. requestApi('GET', $base . '/packages/' . $catalog['items'][0]['id'], 200, 0);
  45. }
  46. requestApi('POST', $base . '/auth/wechat', 400, 40001, null, '[');
  47. requestApi('POST', $base . '/auth/wechat', 422, 42201, null, '{"code":"unused","user_id":1}');
  48. if (!$configuration['capabilities']['wechat_login']) {
  49. requestApi('POST', $base . '/auth/wechat', 503, 50301, null, '{"code":"unused"}');
  50. }
  51. $getPaths = ['/me', '/addresses', '/enterprises/1/address', '/enterprises/1/home', '/enterprises/1/rights', '/enterprises/1/ledger', '/enterprises/1/orders', '/enterprises/1/devices', '/enterprises/1/rewards', '/enterprises/1/devices/1', '/enterprises/1/deliveries/1', '/enterprises/1/checkouts/1', '/drivers/1/dashboard', '/drivers/1/tasks', '/drivers/1/routes', '/drivers/1/tasks/1', '/drivers/1/tasks/1/device-check?sn=test', '/photos/1?scope=enterprise&resource_id=1', '/agents/1/dashboard', '/agents/1/customers', '/agents/1/orders', '/agents/1/commissions'];
  52. $postPaths = ['/auth/logout', '/enterprises/1/address', '/enterprises/1/deliveries', '/enterprises/1/deliveries/1/cancel', '/enterprises/1/checkout/quote', '/enterprises/1/checkouts', '/enterprises/1/checkouts/1/cancel', '/enterprises/1/checkouts/1/pay', '/drivers/1/tasks/1/start', '/drivers/1/tasks/1/checkin', '/drivers/1/tasks/1/draft', '/drivers/1/tasks/1/complete', '/drivers/1/tasks/1/exception', '/drivers/1/tasks/1/photos', '/agents/1/withdrawals'];
  53. foreach ($getPaths as $path) {
  54. requestApi('GET', $base . $path, 401, 40101);
  55. }
  56. foreach ($postPaths as $path) {
  57. requestApi('POST', $base . $path, 401, 40101);
  58. }
  59. $session = (new AuthService())->issue(['appid' => 'http-test-' . bin2hex(random_bytes(8)), 'openid' => 'unbound']);
  60. try {
  61. $token = $session['access_token'];
  62. $profile = requestApi('GET', $base . '/me', 200, 0, $token);
  63. verify($profile['identities'] === [], 'HTTP login alone grants no role');
  64. $addresses = requestApi('GET', $base . '/addresses', 200, 0, $token);
  65. verify($addresses['items'] === [], 'HTTP unbound user has no enterprise');
  66. foreach (['/enterprises/1/home', '/enterprises/1/address', '/drivers/1/tasks/1', '/agents/1/dashboard'] as $path) {
  67. requestApi('GET', $base . $path, 403, 40301, $token);
  68. }
  69. requestApi('POST', $base . '/enterprises/1/checkouts', 403, 40301, $token, '{"items":[{"package_id":1,"quantity":1}]}');
  70. requestApi('POST', $base . '/auth/logout', 200, 0, $token);
  71. requestApi('GET', $base . '/me', 401, 40101, $token);
  72. foreach (['/miniapi/enterprise/addresses', '/miniapi/photo/photo', '/miniapi/driver/taskCommand'] as $path) {
  73. $curl = curl_init('http://127.0.0.1:8787' . $path);
  74. curl_setopt_array($curl, [CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 10]);
  75. curl_exec($curl);
  76. verify(curl_getinfo($curl, CURLINFO_HTTP_CODE) !== 200, 'implicit route disabled: ' . $path);
  77. curl_close($curl);
  78. }
  79. } finally {
  80. MiniSession::query()->where('user_id', $session['user_id'])->delete();
  81. MiniUser::query()->where('id', $session['user_id'])->delete();
  82. }
  83. verify(!MiniUser::query()->where('id', $session['user_id'])->exists(), 'HTTP test user cleaned up');
  84. echo "PASS: $checks live mini HTTP checks; temporary identity removed.\n";