PaymentPayTimeoutTest.php 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. <?php
  2. namespace Tests\Integration;
  3. use App\Console\Commands\PaymentPayTimeout;
  4. use App\Models\PaymentOrder;
  5. use App\Services\PaymentOrderService;
  6. use Illuminate\Config\Repository;
  7. use Illuminate\Database\Capsule\Manager;
  8. use Illuminate\Database\Schema\Blueprint;
  9. use Illuminate\Foundation\Application;
  10. use Illuminate\Support\Facades\DB;
  11. use Illuminate\Support\Facades\Facade;
  12. use PHPUnit\Framework\TestCase;
  13. /** 在线充值超时:定时任务把处理中超过30分钟的订单标记为7超时,迟到的回调仍会处理。 */
  14. class PaymentPayTimeoutTest extends TestCase
  15. {
  16. protected function setUp(): void
  17. {
  18. parent::setUp();
  19. Facade::clearResolvedInstances();
  20. $app = new Application(dirname(__DIR__, 2));
  21. $app->instance('config', new Repository(['app' => ['timezone' => 'Asia/Shanghai'], 'admin_realtime' => ['enabled' => false]]));
  22. Facade::setFacadeApplication($app);
  23. $db = new Manager($app);
  24. $db->addConnection(['driver' => 'sqlite', 'database' => ':memory:', 'prefix' => 'bot_']);
  25. $db->setAsGlobal();
  26. $db->bootEloquent();
  27. $app->instance('db', $db->getDatabaseManager());
  28. $db->schema()->create('payment_orders', function (Blueprint $t) {
  29. $t->id(); $t->string('member_id'); $t->integer('type'); $t->integer('status'); $t->string('state')->nullable();
  30. $t->text('callback_data')->nullable(); $t->decimal('amount', 24, 10); $t->timestamps();
  31. });
  32. $old = date('Y-m-d H:i:s', strtotime('-2 hours'));
  33. $fresh = date('Y-m-d H:i:s', strtotime('-5 minutes'));
  34. foreach ([
  35. [1, 1, $old], // 1 → 超时
  36. [1, 1, $fresh], // 2 未到时限,仍处理中
  37. [1, 2, $old], // 3 已成功不动
  38. [3, 1, $old], // 4 人工充值不受影响
  39. ] as [$type, $status, $at]) {
  40. DB::table('payment_orders')->insert(['member_id' => 'm1', 'type' => $type, 'status' => $status,
  41. 'amount' => 10, 'created_at' => $at, 'updated_at' => $at]);
  42. }
  43. }
  44. protected function tearDown(): void
  45. {
  46. DB::disconnect();
  47. Facade::clearResolvedInstances();
  48. parent::tearDown();
  49. }
  50. public function test_command_marks_only_overdue_online_pay_orders_as_timeout(): void
  51. {
  52. (new PaymentPayTimeout())->handle();
  53. $this->assertSame([1 => 7, 2 => 1, 3 => 2, 4 => 1],
  54. DB::table('payment_orders')->orderBy('id')->pluck('status', 'id')->map(fn($s) => (int)$s)->all());
  55. }
  56. public function test_late_callback_is_still_applied_to_timeout_order(): void
  57. {
  58. (new PaymentPayTimeout())->handle();
  59. $apply = new \ReflectionMethod(PaymentOrderService::class, 'applyPayCallback');
  60. $processed = $apply->invoke(null, PaymentOrder::find(1), '10', '2', '3', '2', []);
  61. $this->assertTrue($processed);
  62. $this->assertSame(PaymentOrderService::STATUS_FAIL, (int)DB::table('payment_orders')->where('id', 1)->value('status'));
  63. }
  64. }