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

4 days ago
<?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',
4 days ago
'updated_at' => '2026-01-01 00:00:00', 'unknown_note' => '原有诊断备注',
4 days ago
]);
}
/** @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],
4 days ago
['unknown', ['code' => 200, 'data' => ['news' => []]], [], 60, 0],
['unknown', ['code' => 500], ['--timeout' => '120'], 120, 1],
4 days ago
['selected', ['code' => 0], [], 60, 1],
['occupied', ['code' => 500, 'msg' => '失败'], [], 60, 1],
['selected', ['data' => []], [], 60, 1],
];
}
/** @dataProvider exceptionCases */
4 days ago
public function test_exception_leaves_account_unchanged(string $status, ?string $raw): void
4 days ago
{
4 days ago
$this->company($status);
4 days ago
$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
{
4 days ago
return [['selected', null], ['selected', '<html>Bad Gateway</html>'], ['unknown', null], ['unknown', '<html>Bad Gateway</html>']];
4 days ago
}
/** @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 [
4 days ago
['none', []], ['non_occupying', []], ['selected', ['--timeout' => '0']],
4 days ago
['selected', ['--timeout' => '-1']], ['selected', ['--timeout' => '1.5']],
['selected', ['--timeout' => 'abc']],
];
}
4 days ago
/** @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>']];
}
4 days ago
}