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

218 lines
7.1 KiB
PHP

<?php
namespace Tests\Unit\Services;
use App\Services\ModuleSettingsService;
use App\Services\NotificationChannelService;
use App\Services\PluginSettingsService;
use App\Services\SettingsService;
use Mockery;
use Tests\TestCase;
/**
* NotificationChannelService 단위 테스트
*
* 확장(core/module/plugin) 단위 채널 전역 활성 여부 조회를 검증합니다.
*/
class NotificationChannelServiceTest extends TestCase
{
private NotificationChannelService $service;
protected function setUp(): void
{
parent::setUp();
$this->service = new NotificationChannelService;
}
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
/**
* 코어 설정에서 채널이 활성화된 경우 true를 반환한다.
*/
public function test_core_channel_enabled_when_is_active_true(): void
{
$this->mockCoreSettings([
['id' => 'mail', 'is_active' => true],
['id' => 'database', 'is_active' => true],
]);
$this->assertTrue(
$this->service->isChannelEnabledForExtension('core', 'core', 'mail')
);
}
/**
* 코어 설정에서 채널이 비활성화된 경우 false를 반환한다.
*/
public function test_core_channel_disabled_when_is_active_false(): void
{
$this->mockCoreSettings([
['id' => 'mail', 'is_active' => false],
['id' => 'database', 'is_active' => true],
]);
$this->assertFalse(
$this->service->isChannelEnabledForExtension('core', 'core', 'mail')
);
$this->assertTrue(
$this->service->isChannelEnabledForExtension('core', 'core', 'database')
);
}
/**
* 설정에 엔트리가 없으면 기본 활성(true) — 하위호환 + 신규 플러그인 채널 대응.
*/
public function test_core_channel_defaults_to_enabled_when_entry_missing(): void
{
$this->mockCoreSettings([
['id' => 'mail', 'is_active' => true],
]);
// slack은 설정에 없음 → 기본 true
$this->assertTrue(
$this->service->isChannelEnabledForExtension('core', 'core', 'slack')
);
}
/**
* notifications.channels 키 자체가 없으면(빈 배열) 모든 채널 활성.
*/
public function test_core_channel_defaults_to_enabled_when_settings_empty(): void
{
$this->mockCoreSettings([]);
$this->assertTrue(
$this->service->isChannelEnabledForExtension('core', 'core', 'mail')
);
}
/**
* 모듈 경로: ModuleSettingsService를 통해 조회한다.
*/
public function test_module_channel_resolved_via_module_settings(): void
{
$moduleSettings = Mockery::mock(ModuleSettingsService::class);
$moduleSettings->shouldReceive('get')
->with('sirsoft-ecommerce', 'notifications.channels', [])
->andReturn([
['id' => 'mail', 'is_active' => false],
['id' => 'database', 'is_active' => true],
]);
$this->app->instance(ModuleSettingsService::class, $moduleSettings);
$this->assertFalse(
$this->service->isChannelEnabledForExtension('module', 'sirsoft-ecommerce', 'mail')
);
$this->assertTrue(
$this->service->isChannelEnabledForExtension('module', 'sirsoft-ecommerce', 'database')
);
}
/**
* 플러그인 경로: PluginSettingsService를 통해 조회한다.
*/
public function test_plugin_channel_resolved_via_plugin_settings(): void
{
$pluginSettings = Mockery::mock(PluginSettingsService::class);
$pluginSettings->shouldReceive('get')
->with('sirsoft-slack', 'notifications.channels', [])
->andReturn([
['id' => 'slack', 'is_active' => true],
]);
$this->app->instance(PluginSettingsService::class, $pluginSettings);
$this->assertTrue(
$this->service->isChannelEnabledForExtension('plugin', 'sirsoft-slack', 'slack')
);
}
/**
* 모듈 식별자가 비어 있으면 기본 활성 반환.
*/
public function test_module_without_identifier_returns_default_enabled(): void
{
$this->assertTrue(
$this->service->isChannelEnabledForExtension('module', null, 'mail')
);
$this->assertTrue(
$this->service->isChannelEnabledForExtension('module', '', 'mail')
);
}
/**
* 동일 조합 반복 호출 시 캐시를 사용한다 (SettingsService 1회만 호출).
*/
public function test_memoizes_channel_enabled_lookup(): void
{
$settingsService = Mockery::mock(SettingsService::class);
$settingsService->shouldReceive('getSetting')
->once() // 캐시 검증
->with('notifications.channels', [])
->andReturn([
['id' => 'mail', 'is_active' => false],
]);
$this->app->instance(SettingsService::class, $settingsService);
$this->service->isChannelEnabledForExtension('core', 'core', 'mail');
$this->service->isChannelEnabledForExtension('core', 'core', 'mail');
$this->service->isChannelEnabledForExtension('core', 'core', 'mail');
$this->assertFalse(
$this->service->isChannelEnabledForExtension('core', 'core', 'mail')
);
}
/**
* clearChannelEnabledCache() 호출 시 캐시가 초기화된다.
*/
public function test_clear_channel_enabled_cache(): void
{
$settingsService = Mockery::mock(SettingsService::class);
$settingsService->shouldReceive('getSetting')
->twice()
->with('notifications.channels', [])
->andReturn([['id' => 'mail', 'is_active' => true]]);
$this->app->instance(SettingsService::class, $settingsService);
$this->service->isChannelEnabledForExtension('core', 'core', 'mail');
$this->service->clearChannelEnabledCache();
$this->service->isChannelEnabledForExtension('core', 'core', 'mail');
// 2회 호출 검증은 Mockery가 처리
$this->assertTrue(true);
}
/**
* 설정 조회 중 예외 발생 시 기본 활성(true) 반환.
*/
public function test_returns_default_enabled_on_settings_service_exception(): void
{
$settingsService = Mockery::mock(SettingsService::class);
$settingsService->shouldReceive('getSetting')
->andThrow(new \RuntimeException('DB unavailable'));
$this->app->instance(SettingsService::class, $settingsService);
$this->assertTrue(
$this->service->isChannelEnabledForExtension('core', 'core', 'mail')
);
}
/**
* 코어 SettingsService 응답을 mocking 하는 헬퍼.
*
* @param array $channels
*/
private function mockCoreSettings(array $channels): void
{
$settingsService = Mockery::mock(SettingsService::class);
$settingsService->shouldReceive('getSetting')
->with('notifications.channels', [])
->andReturn($channels);
$this->app->instance(SettingsService::class, $settingsService);
}
}