CaiWuXiTong/tests/Feature/Console/PollEsignSignaturesTest.php

188 lines
7.1 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace Tests\Feature\Console;
use App\Models\Business\CourierAgreementSignature;
use App\Models\Business\CourierQuoteSignature;
use Illuminate\Support\Facades\Http;
use Tests\Feature\FeatureTestCase;
class PollEsignSignaturesTest extends FeatureTestCase
{
protected function setUp(): void
{
parent::setUp();
config([
'services.esign.environment' => 'production',
'services.esign.base_url' => 'https://openapi.esign.test',
'services.esign.app_id' => 'production-app-id',
'services.esign.app_secret' => 'production-app-secret',
'services.esign.notify_url' => null,
'services.esign.polling_enabled' => true,
]);
}
public function test_it_polls_only_due_non_terminal_flows_without_a_callback(): void
{
$quote = $this->quoteSignature([
'status' => CourierQuoteSignature::STATUS_SIGNING,
'esign_sign_flow_id' => 'quote-flow-due',
'last_synced_at' => now()->subMinutes(5),
]);
$this->quoteSignature([
'status' => CourierQuoteSignature::STATUS_ARCHIVED,
'esign_sign_flow_id' => 'quote-flow-archived',
'last_synced_at' => now()->subMinutes(5),
]);
$agreement = $this->agreementSignature([
'status' => CourierAgreementSignature::STATUS_UNKNOWN,
'esign_sign_flow_id' => 'agreement-flow-due',
'last_synced_at' => null,
]);
$this->agreementSignature([
'status' => CourierAgreementSignature::STATUS_SIGNING,
'esign_sign_flow_id' => 'agreement-flow-recent',
'last_synced_at' => now(),
]);
Http::fake([
'https://openapi.esign.test/v3/sign-flow/*/detail' => Http::response([
'code' => 0,
'data' => ['signFlowStatus' => 1],
]),
]);
$this->artisan('esign:poll-signatures', ['--limit' => 10, '--min-age' => 120])
->expectsOutputToContain('候选 2,成功 2,失败 0')
->assertSuccessful();
Http::assertSentCount(2);
$this->assertNotNull($quote->fresh()->last_synced_at);
$this->assertNotNull($agreement->fresh()->last_synced_at);
}
public function test_it_skips_polling_until_the_private_switch_is_enabled(): void
{
config(['services.esign.polling_enabled' => false]);
Http::preventStrayRequests();
$this->artisan('esign:poll-signatures')
->expectsOutputToContain('定时轮询未启用')
->assertSuccessful();
Http::assertNothingSent();
}
public function test_it_does_not_poll_flows_created_in_another_environment(): void
{
$this->quoteSignature([
'environment' => 'sandbox',
'esign_sign_flow_id' => 'sandbox-quote-flow',
'last_synced_at' => now()->subMinutes(5),
]);
$this->agreementSignature([
'environment' => 'sandbox',
'esign_sign_flow_id' => 'sandbox-agreement-flow',
'last_synced_at' => now()->subMinutes(5),
]);
Http::preventStrayRequests();
$this->artisan('esign:poll-signatures', ['--limit' => 10, '--min-age' => 0])
->expectsOutputToContain('候选 0,成功 0,失败 0')
->assertSuccessful();
Http::assertNothingSent();
}
public function test_it_limits_the_total_number_of_remote_queries_per_run(): void
{
$this->agreementSignature([
'esign_sign_flow_id' => 'agreement-flow-first',
'last_synced_at' => now()->subMinutes(10),
]);
$this->agreementSignature([
'esign_sign_flow_id' => 'agreement-flow-second',
'last_synced_at' => now()->subMinutes(5),
]);
Http::fake([
'https://openapi.esign.test/v3/sign-flow/*/detail' => Http::response([
'code' => 0,
'data' => ['signFlowStatus' => 1],
]),
]);
$this->artisan('esign:poll-signatures', ['--limit' => 1, '--min-age' => 0])
->expectsOutputToContain('候选 1,成功 1,失败 0')
->assertSuccessful();
Http::assertSentCount(1);
}
public function test_it_continues_after_one_remote_query_fails(): void
{
$failed = $this->agreementSignature([
'esign_sign_flow_id' => 'agreement-flow-failed',
'last_synced_at' => now()->subMinutes(10),
]);
$succeeded = $this->agreementSignature([
'esign_sign_flow_id' => 'agreement-flow-succeeded',
'last_synced_at' => now()->subMinutes(5),
]);
Http::fake(fn ($request) => str_contains($request->url(), 'agreement-flow-failed')
? Http::response(['code' => 500, 'message' => 'temporary failure'], 503)
: Http::response(['code' => 0, 'data' => ['signFlowStatus' => 1]]));
$this->artisan('esign:poll-signatures', ['--limit' => 10, '--min-age' => 0])
->expectsOutputToContain('候选 2,成功 1,失败 1')
->assertFailed();
Http::assertSentCount(2);
$this->assertNotNull($failed->fresh()->last_error);
$this->assertNotNull($succeeded->fresh()->last_synced_at);
}
private function quoteSignature(array $overrides = []): CourierQuoteSignature
{
return CourierQuoteSignature::create(array_merge([
'company_id' => $this->company->id,
'quote_version_id' => random_int(1000, 999999),
'provider' => 'esign',
'environment' => 'production',
'status' => CourierQuoteSignature::STATUS_SIGNING,
'organization_name' => '测试快递公司',
'source_pdf_path' => 'quotes/source.pdf',
'source_pdf_sha256' => str_repeat('a', 64),
'source_pdf_generated_at' => now(),
'created_by' => $this->user->id,
'updated_by' => $this->user->id,
], $overrides));
}
private function agreementSignature(array $overrides = []): CourierAgreementSignature
{
$sequence = CourierAgreementSignature::count() + 1;
return CourierAgreementSignature::create(array_merge([
'company_id' => $this->company->id,
'business_no' => 'ESIGN-POLL-' . $sequence,
'idempotency_key' => 'esign-poll-' . $sequence,
'document_type' => 'account-proof',
'template_code' => 'TPL-ACCOUNT-CERT-V2',
'template_version' => '2',
'source_file_name' => 'account-proof.doc',
'status' => CourierAgreementSignature::STATUS_SIGNING,
'courier_name' => '测试快递',
'company_full_name' => '测试公司',
'organization_name' => '测试快递公司',
'operator_account' => '13800138000',
'payload' => ['archive_mode' => 'auto'],
'environment' => 'production',
'source_pdf_path' => 'agreements/source.pdf',
'source_pdf_sha256' => str_repeat('b', 64),
'created_by' => $this->user->id,
'updated_by' => $this->user->id,
], $overrides));
}
}