Files
Gnuboard7/tests/Unit/Extension/NotificationSyncHelperTest.php
2026-04-20 20:37:49 +09:00

233 lines
8.2 KiB
PHP

<?php
namespace Tests\Unit\Extension;
use App\Extension\Helpers\NotificationSyncHelper;
use App\Models\NotificationDefinition;
use App\Models\NotificationTemplate;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
/**
* NotificationSyncHelper 의 cleanupStale* 회귀 방지 테스트.
*
* 정책:
* - seeder 에 없는 (extension_type + extension_identifier + type) 조합의 definition 삭제
* - definition 삭제 시 FK cascade 로 연관 template 도 자동 정리
* - definition 은 유지되지만 channel 이 재구성된 경우: 제거된 channel 의 template 삭제
* - user_overrides 무관 삭제
*/
class NotificationSyncHelperTest extends TestCase
{
use RefreshDatabase;
private NotificationSyncHelper $helper;
protected function setUp(): void
{
parent::setUp();
$this->helper = app(NotificationSyncHelper::class);
}
public function test_cleanupStaleDefinitions_deletes_definitions_not_in_seeder_scope(): void
{
NotificationDefinition::create([
'type' => 'in-seeder',
'hook_prefix' => 'core.auth',
'extension_type' => 'core',
'extension_identifier' => 'core',
'name' => ['ko' => '유지'],
'description' => ['ko' => '유지'],
'channels' => ['mail'],
'hooks' => [],
'variables' => [],
'is_active' => true,
'is_default' => true,
]);
NotificationDefinition::create([
'type' => 'not-in-seeder',
'hook_prefix' => 'core.auth',
'extension_type' => 'core',
'extension_identifier' => 'core',
'name' => ['ko' => '삭제'],
'description' => ['ko' => '삭제'],
'channels' => ['mail'],
'hooks' => [],
'variables' => [],
'is_active' => true,
'is_default' => true,
]);
$deleted = $this->helper->cleanupStaleDefinitions(
'core',
'core',
['in-seeder'],
);
$this->assertSame(1, $deleted);
$this->assertDatabaseHas('notification_definitions', ['type' => 'in-seeder']);
$this->assertDatabaseMissing('notification_definitions', ['type' => 'not-in-seeder']);
}
public function test_cleanupStaleDefinitions_deletes_even_with_user_overrides(): void
{
NotificationDefinition::create([
'type' => 'stale-with-overrides',
'hook_prefix' => 'core.auth',
'extension_type' => 'core',
'extension_identifier' => 'core',
'name' => ['ko' => '유저 수정 있음'],
'description' => ['ko' => '삭제 대상'],
'channels' => ['mail'],
'hooks' => [],
'variables' => [],
'is_active' => true,
'is_default' => true,
'user_overrides' => ['name'],
]);
$deleted = $this->helper->cleanupStaleDefinitions('core', 'core', []);
$this->assertSame(1, $deleted);
$this->assertDatabaseMissing('notification_definitions', ['type' => 'stale-with-overrides']);
}
public function test_cleanupStaleDefinitions_scope_isolation_protects_other_extensions(): void
{
NotificationDefinition::create([
'type' => 'core-type',
'hook_prefix' => 'core.auth',
'extension_type' => 'core',
'extension_identifier' => 'core',
'name' => ['ko' => 'core'],
'description' => ['ko' => 'core'],
'channels' => ['mail'],
'hooks' => [],
'variables' => [],
'is_active' => true,
'is_default' => true,
]);
NotificationDefinition::create([
'type' => 'module-type',
'hook_prefix' => 'core.auth',
'extension_type' => 'module',
'extension_identifier' => 'sirsoft-board',
'name' => ['ko' => 'module'],
'description' => ['ko' => 'module'],
'channels' => ['mail'],
'hooks' => [],
'variables' => [],
'is_active' => true,
'is_default' => true,
]);
$deleted = $this->helper->cleanupStaleDefinitions('core', 'core', []);
$this->assertSame(1, $deleted, '코어 scope 만 삭제, 모듈 scope 는 보호');
$this->assertDatabaseMissing('notification_definitions', ['type' => 'core-type']);
$this->assertDatabaseHas('notification_definitions', ['type' => 'module-type']);
}
public function test_cleanupStaleTemplates_deletes_by_channel_diff(): void
{
$def = NotificationDefinition::create([
'type' => 'with-templates',
'hook_prefix' => 'core.auth',
'extension_type' => 'core',
'extension_identifier' => 'core',
'name' => ['ko' => '정의'],
'description' => ['ko' => '정의'],
'channels' => ['mail', 'database'],
'hooks' => [],
'variables' => [],
'is_active' => true,
'is_default' => true,
]);
NotificationTemplate::create([
'definition_id' => $def->id,
'channel' => 'mail',
'subject' => ['ko' => '유지'],
'body' => ['ko' => '유지'],
'is_active' => true,
'is_default' => true,
]);
NotificationTemplate::create([
'definition_id' => $def->id,
'channel' => 'fcm',
'subject' => ['ko' => '삭제'],
'body' => ['ko' => '삭제'],
'is_active' => true,
'is_default' => true,
]);
$deleted = $this->helper->cleanupStaleTemplates($def->id, ['mail']);
$this->assertSame(1, $deleted);
$this->assertDatabaseHas('notification_templates', ['definition_id' => $def->id, 'channel' => 'mail']);
$this->assertDatabaseMissing('notification_templates', ['definition_id' => $def->id, 'channel' => 'fcm']);
}
public function test_cleanupStaleTemplates_deletes_even_with_user_overrides(): void
{
$def = NotificationDefinition::create([
'type' => 'tpl-overrides-test',
'hook_prefix' => 'core.auth',
'extension_type' => 'core',
'extension_identifier' => 'core',
'name' => ['ko' => '정의'],
'description' => ['ko' => '정의'],
'channels' => ['mail'],
'hooks' => [],
'variables' => [],
'is_active' => true,
'is_default' => true,
]);
NotificationTemplate::create([
'definition_id' => $def->id,
'channel' => 'fcm',
'subject' => ['ko' => '유저 수정 있음'],
'body' => ['ko' => '삭제 대상'],
'is_active' => true,
'is_default' => true,
'user_overrides' => ['subject', 'body'],
]);
$deleted = $this->helper->cleanupStaleTemplates($def->id, ['mail']);
$this->assertSame(1, $deleted);
$this->assertDatabaseMissing('notification_templates', ['definition_id' => $def->id, 'channel' => 'fcm']);
}
public function test_definition_delete_cascades_to_templates(): void
{
$def = NotificationDefinition::create([
'type' => 'cascade-test',
'hook_prefix' => 'core.auth',
'extension_type' => 'core',
'extension_identifier' => 'core',
'name' => ['ko' => 'cascade'],
'description' => ['ko' => 'cascade'],
'channels' => ['mail'],
'hooks' => [],
'variables' => [],
'is_active' => true,
'is_default' => true,
]);
$tpl = NotificationTemplate::create([
'definition_id' => $def->id,
'channel' => 'mail',
'subject' => ['ko' => 'cascade'],
'body' => ['ko' => 'cascade'],
'is_active' => true,
'is_default' => true,
]);
$this->helper->cleanupStaleDefinitions('core', 'core', []);
$this->assertDatabaseMissing('notification_definitions', ['id' => $def->id]);
$this->assertDatabaseMissing('notification_templates', ['id' => $tpl->id]);
}
}