You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
wx.sstbc.com/tests/Feature/VerifyQccEnterprisePackInfo...

149 lines
7.2 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
namespace Tests\Feature;
use App\Exceptions\YuanhePackInfoException;
use App\Repositories\YuanheRepository;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Mockery;
use Tests\TestCase;
class VerifyQccEnterprisePackInfoTest extends TestCase
{
protected function setUp(): void
{
parent::setUp();
config(['database.default' => 'sqlite', 'database.connections.sqlite.database' => ':memory:', 'audit.enabled' => false]);
DB::purge('sqlite');
Schema::create('companies', function (Blueprint $t) {
$t->id(); $t->string('company_name'); $t->string('credit_code')->nullable(); $t->timestamps(); $t->softDeletes();
});
Schema::create('company_qcc_accounts', function (Blueprint $t) {
$t->id(); $t->unsignedBigInteger('company_id'); $t->string('status'); $t->timestamps();
$t->dateTime('first_success_at')->nullable(); $t->string('first_success_source')->nullable();
$t->string('first_success_ref')->nullable(); $t->text('unknown_note')->nullable();
});
}
protected function tearDown(): void
{
DB::disconnect('sqlite');
parent::tearDown();
}
private function company(string $status): void
{
DB::table('companies')->insert(['id' => 333, 'company_name' => '测试企业', 'credit_code' => 'test-credit']);
DB::table('company_qcc_accounts')->insert([
'company_id' => 333, 'status' => $status, 'first_success_ref' => 'original-ref',
'updated_at' => '2026-01-01 00:00:00', 'unknown_note' => '原有诊断备注',
]);
}
/** @dataProvider responseCases */
public function test_response_and_timeout_without_database_writes(string $status, array $response, array $options, int $timeout, int $exit): void
{
$this->company($status);
$before = DB::table('company_qcc_accounts')->get()->toJson();
$companies = DB::table('companies')->get()->toJson();
$mock = Mockery::mock(YuanheRepository::class);
$mock->shouldReceive('enterprisePackInfo')->once()
->with(['creditCode' => 'test-credit', 'enterpriseName' => '测试企业'], $timeout)->andReturn($response);
$this->app->instance(YuanheRepository::class, $mock);
$this->assertSame($exit, Artisan::call('qcc:verify-pack-info', ['company_id' => 333] + $options));
$this->assertSame($response, json_decode(Artisan::output(), true));
$this->assertSame($before, DB::table('company_qcc_accounts')->get()->toJson());
$this->assertSame($companies, DB::table('companies')->get()->toJson());
}
public static function responseCases(): array
{
return [
['selected', ['code' => 200, 'data' => ['news' => [['Title' => '<info>标题</info>']]]], [], 60, 0],
['occupied', ['code' => '200', 'data' => []], ['--timeout' => '120', '--raw' => true], 120, 0],
['unknown', ['code' => 200, 'data' => ['news' => []]], [], 60, 0],
['unknown', ['code' => 500], ['--timeout' => '120'], 120, 1],
['selected', ['code' => 0], [], 60, 1],
['occupied', ['code' => 500, 'msg' => '失败'], [], 60, 1],
['selected', ['data' => []], [], 60, 1],
];
}
/** @dataProvider exceptionCases */
public function test_exception_leaves_account_unchanged(string $status, ?string $raw): void
{
$this->company($status);
$before = DB::table('company_qcc_accounts')->get()->toJson();
$mock = Mockery::mock(YuanheRepository::class);
$mock->shouldReceive('enterprisePackInfo')->once()->andThrow(new YuanhePackInfoException('请求超时', null, null, $raw));
$this->app->instance(YuanheRepository::class, $mock);
$this->assertSame(1, Artisan::call('qcc:verify-pack-info', ['company_id' => 333]));
$this->assertSame(($raw ?? '请求超时').PHP_EOL, Artisan::output());
$this->assertSame($before, DB::table('company_qcc_accounts')->get()->toJson());
}
public static function exceptionCases(): array
{
return [['selected', null], ['selected', '<html>Bad Gateway</html>'], ['unknown', null], ['unknown', '<html>Bad Gateway</html>']];
}
/** @dataProvider rejectedCases */
public function test_invalid_input_does_not_call_api(string $status, array $options): void
{
$this->company($status);
$mock = Mockery::mock(YuanheRepository::class);
$mock->shouldNotReceive('enterprisePackInfo');
$this->app->instance(YuanheRepository::class, $mock);
$this->assertSame(1, Artisan::call('qcc:verify-pack-info', ['company_id' => 333] + $options));
$this->assertSame($status, DB::table('company_qcc_accounts')->value('status'));
}
public static function rejectedCases(): array
{
return [
['none', []], ['non_occupying', []], ['selected', ['--timeout' => '0']],
['selected', ['--timeout' => '-1']], ['selected', ['--timeout' => '1.5']],
['selected', ['--timeout' => 'abc']],
];
}
/** @dataProvider requestCases */
public function test_request_details_are_from_actual_call_even_on_failure(?string $failure): void
{
$this->company('unknown');
$before = DB::table('company_qcc_accounts')->get()->toJson();
$request = [
'method' => 'POST', 'url' => 'https://example.test/gateway/openapi/businessCollege/enterprise/packInfo',
'headers' => ['Content-Type' => 'application/json', 'customerId' => 'test-customer', 'timestamp' => '1234567890000', 'token' => 'test-signature'],
'json' => ['creditCode' => 'test-credit', 'enterpriseName' => '测试企业'],
];
$mock = Mockery::mock(YuanheRepository::class);
$mock->authKey = 'secret-not-for-output';
$mock->shouldReceive('enterprisePackInfo')->once()->with($request['json'], 120)
->andReturnUsing(function () use ($mock, $request, $failure) {
$mock->lastRequest = $request;
if ($failure !== null) {
throw new YuanhePackInfoException('请求超时', null, null, $failure === 'timeout' ? null : $failure);
}
return ['code' => 200];
});
$this->app->instance(YuanheRepository::class, $mock);
$exit = Artisan::call('qcc:verify-pack-info', ['company_id' => 333, '--timeout' => '120', '--raw' => true, '--request' => true]);
$this->assertSame($failure === null ? 0 : 1, $exit);
$expected = "请求信息(不含 authKey):\n".json_encode($request, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)."\n返回结果:\n";
$expected .= $failure === null ? json_encode(['code' => 200], JSON_PRETTY_PRINT) : ($failure === 'timeout' ? '请求超时' : $failure);
$this->assertSame($expected.PHP_EOL, Artisan::output());
$this->assertStringNotContainsString('secret-not-for-output', Artisan::output());
$this->assertSame($before, DB::table('company_qcc_accounts')->get()->toJson());
}
public static function requestCases(): array
{
return [[null], ['timeout'], ['<html>504 Gateway Time-out</html>']];
}
}