fix(tosspayments,pay_kginicis): 플러그인 설정 검증이 큐로 나가 무동작하던 문제 수정
설정 저장을 차단해야 할 검증 리스너가 core.plugin_settings.before_save 를 구독하면서 sync 를 선언하지 않았다. Action 훅의 기본값은 큐 디스패치이고 실환경 큐 드라이버는 database 이므로, ValidationException 이 워커 안에서 죽고 PluginSettingsService::save 는 doAction 직후 저장을 그대로 진행했다. 결과적으로 범위 밖 가상계좌 유효시간, 허용값 밖 에스크로 설정, 빈 CBT 라이브 필수값이 아무 저항 없이 저장됐다. 리스너 docblock 이 스스로 약속한 422 응답도 나가지 않았다. 두 리스너에 sync 를 선언해 저장 트랜잭션 안에서 동기 실행되도록 했다. 회귀 가드는 훅 디스패치 경로를 실제로 통과시킨다. phpunit.xml 이 큐 드라이버를 sync 로 강제해 큐 경로도 즉시 실행되므로, Queue::fake 로 운영과 같은 비동기 상황을 만들어야 결함이 드러난다 — 리스너 메서드를 직접 호출하는 기존 테스트는 이 결함을 구조적으로 잡지 못한다.
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
### Fixed
|
||||
|
||||
- 일본 편의점결제(CVS) 관련 안내 메시지가 번역되지 않고 내부 코드 그대로 표시되던 문제를 수정했습니다. 주문을 찾을 수 없거나 입금 통보 테스트·입금기한 만료 처리를 할 때 정상적인 한국어(영어) 안내가 표시됩니다.
|
||||
- 일본(CBT) 설정을 운영 모드로 전환할 때 상점 정보나 서명키가 비어 있어도 저장되던 문제를 수정했습니다. 필수값이 비었거나 샘플값이 그대로면 저장이 중단되고 안내 메시지가 표시됩니다.
|
||||
- 이 플러그인이 설치된 사이트에서 관리자 주문 목록의 '일부취소' 표시와 적립예정 포인트·마일리지 사용 금액, 주문상품의 추가옵션 요약이 보이지 않던 문제를 수정했습니다. 결제 정보 칸에 테스트결제 표시를 덧붙이는 과정에서 목록 표 구성 전체를 옛 버전으로 되돌려 놓고 있었습니다.
|
||||
- 관리자 결제수단 설정에서 가상계좌·계좌이체·휴대폰결제에 PG사를 지정할 수 없던 문제를 수정했습니다. 해당 결제수단의 PG사 목록이 항상 비어 있어 기본 PG사만 사용할 수 있었고, 결제수단별로 다른 PG사를 지정하는 설정이 화면에서 불가능했습니다.
|
||||
- 카드결제를 거치지 않은 주문(무통장입금 등)의 완료 화면에서도 영수증 조회를 시도해 불필요한 요청이 나가던 문제를 수정했습니다. 화면에는 영향이 없었으나 이제 카드결제 주문에서만 조회합니다. (#81 @jiwonpapa 님께서 제보해주셨습니다.)
|
||||
|
||||
@@ -38,19 +38,39 @@ class ValidateCbtSettingsListener implements HookListenerInterface
|
||||
|
||||
private const SAMPLE_VALUE_ERROR_FIELD = 'japan_contract_info';
|
||||
|
||||
/**
|
||||
* 구독할 훅 매핑 반환.
|
||||
*
|
||||
* @return array<string, array<string, mixed>>
|
||||
*/
|
||||
public static function getSubscribedHooks(): array
|
||||
{
|
||||
return [
|
||||
'core.plugin_settings.before_save' => [
|
||||
'method' => 'validateBeforeSave',
|
||||
'priority' => 10,
|
||||
// 저장을 차단하는 인라인 가드 — Action 훅 기본값(큐 디스패치)이면 ValidationException 이
|
||||
// 워커 안에서 죽고 PluginSettingsService::save() 가 저장을 그대로 진행한다.
|
||||
'sync' => true,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 기본 핸들러 (미사용).
|
||||
*
|
||||
* @param mixed ...$args
|
||||
*/
|
||||
public function handle(...$args): void {}
|
||||
|
||||
/**
|
||||
* 설정 저장 전 CBT(일본) 필수값 검증. 위반 시 ValidationException 으로 422 응답을 유도한다.
|
||||
*
|
||||
* @param string $identifier 저장 대상 플러그인 식별자
|
||||
* @param array<string, mixed> $settings 저장 요청 설정값
|
||||
*
|
||||
* @throws ValidationException 라이브 모드 필수값이 비었거나 샘플값이 그대로일 때
|
||||
*/
|
||||
public function validateBeforeSave(string $identifier, array $settings): void
|
||||
{
|
||||
if ($identifier !== self::PLUGIN_IDENTIFIER) {
|
||||
|
||||
+33
@@ -2,7 +2,10 @@
|
||||
|
||||
namespace Plugins\Sirsoft\PayKginicis\Tests\Unit\Listeners;
|
||||
|
||||
use App\Extension\HookListenerRegistrar;
|
||||
use App\Extension\HookManager;
|
||||
use App\Services\PluginSettingsService;
|
||||
use Illuminate\Support\Facades\Queue;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Plugins\Sirsoft\PayKginicis\Listeners\ValidateCbtSettingsListener;
|
||||
use Plugins\Sirsoft\PayKginicis\Plugin;
|
||||
@@ -100,6 +103,36 @@ class ValidateCbtSettingsListenerTest extends PluginTestCase
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 훅 디스패치 경로를 실제로 통과시켜 예외가 저장 호출자에게 전파되는지 검증한다.
|
||||
*
|
||||
* 리스너 메서드를 직접 호출하는 테스트는 이 결함을 잡지 못한다 — Action 훅의 기본값은
|
||||
* 큐 디스패치이고, 'sync' => true 가 없으면 ValidationException 이 워커 안에서 죽어
|
||||
* PluginSettingsService::save() 가 doAction 직후 저장을 그대로 진행한다.
|
||||
*
|
||||
* phpunit.xml 은 QUEUE_CONNECTION=sync 라 큐 경로도 즉시 실행되어 결함이 가려진다.
|
||||
* Queue::fake() 로 운영(database 드라이버)과 같은 비동기 상황을 만들어야 가드가 성립한다.
|
||||
*/
|
||||
public function test_validation_exception_propagates_through_the_hook_chain(): void
|
||||
{
|
||||
Queue::fake();
|
||||
|
||||
$this->mockCurrentSettings([]);
|
||||
|
||||
HookManager::clearAction('core.plugin_settings.before_save');
|
||||
HookListenerRegistrar::clear();
|
||||
HookListenerRegistrar::register(ValidateCbtSettingsListener::class, 'test');
|
||||
|
||||
$this->expectException(ValidationException::class);
|
||||
|
||||
HookManager::doAction('core.plugin_settings.before_save', 'sirsoft-pay_kginicis', [
|
||||
'japan_enabled' => true,
|
||||
'is_test_mode' => false,
|
||||
'live_japan_mid' => '',
|
||||
'live_japan_sign_key' => '',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_backend_settings_validation_messages_are_localized(): void
|
||||
{
|
||||
$this->mockCurrentSettings([]);
|
||||
|
||||
@@ -40,6 +40,9 @@ class ValidateTossSettingsListener implements HookListenerInterface
|
||||
'core.plugin_settings.before_save' => [
|
||||
'method' => 'validateBeforeSave',
|
||||
'priority' => 10,
|
||||
// 저장을 차단하는 인라인 가드 — Action 훅 기본값(큐 디스패치)이면 ValidationException 이
|
||||
// 워커 안에서 죽고 PluginSettingsService::save() 가 저장을 그대로 진행한다.
|
||||
'sync' => true,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
+30
@@ -4,6 +4,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace Plugins\Sirsoft\Tosspayments\Tests\Unit\Listeners;
|
||||
|
||||
use App\Extension\HookListenerRegistrar;
|
||||
use App\Extension\HookManager;
|
||||
use Illuminate\Support\Facades\Queue;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Plugins\Sirsoft\Tosspayments\Listeners\ValidateTossSettingsListener;
|
||||
use Plugins\Sirsoft\Tosspayments\Plugin;
|
||||
@@ -40,6 +43,33 @@ class ValidateTossSettingsListenerTest extends PluginTestCase
|
||||
$this->addToAssertionCount(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 훅 디스패치 경로를 실제로 통과시켜 예외가 저장 호출자에게 전파되는지 검증한다.
|
||||
*
|
||||
* 리스너 메서드를 직접 호출하는 테스트는 이 결함을 잡지 못한다 — Action 훅의 기본값은
|
||||
* 큐 디스패치이고, 'sync' => true 가 없으면 ValidationException 이 워커 안에서 죽어
|
||||
* PluginSettingsService::save() 가 doAction 직후 저장을 그대로 진행한다.
|
||||
*
|
||||
* phpunit.xml 은 QUEUE_CONNECTION=sync 라 큐 경로도 즉시 실행되어 결함이 가려진다.
|
||||
* Queue::fake() 로 운영(database 드라이버)과 같은 비동기 상황을 만들어야 가드가 성립한다.
|
||||
*/
|
||||
public function test_validation_exception_propagates_through_the_hook_chain(): void
|
||||
{
|
||||
Queue::fake();
|
||||
|
||||
HookManager::clearAction('core.plugin_settings.before_save');
|
||||
HookListenerRegistrar::clear();
|
||||
HookListenerRegistrar::register(ValidateTossSettingsListener::class, 'test');
|
||||
|
||||
$this->expectException(ValidationException::class);
|
||||
|
||||
HookManager::doAction(
|
||||
'core.plugin_settings.before_save',
|
||||
'sirsoft-tosspayments',
|
||||
['vbank_valid_hours' => 9999],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, array{int}>
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user