여러 화면에서 조건부(FormRequest) 검증이 우회되거나 과도하게 제한되던 결함을 한 계열로 묶어 수정한다. - 검증 규칙 확장 필터 이름 10개를 나머지 92개와 동일 규칙으로 통일 - 설명 길이를 바이트가 아닌 글자 수로 계산(한글 오검출 해소) - 비활성 언어팩 번역 보존한 채 수정 허용 - 알림 템플릿 제목 nullable 존중, 미지원 발송 수단 저장 차단 - 일정/실행 이력 목록 조회 검증 정합 - 게시판 첨부 미사용 시 빈 확장자 통과, new_display_hours/최소 길이 0 허용, 일괄 적용 override_values 범위 검증(SSoT) - 이커머스 클레임 사유 조회 검증, 용어 정정 - 원문 i18n 키 노출 다수 해소, 저장/삭제 실패 시 사유 화면 노출 - 아이콘 크기/다크모드 대비 회귀 수정 번들 확장(모듈3·플러그인6·템플릿2·언어팩5) 버전 new-bump 및 CHANGELOG 반영, ja 언어팩 동기.
157 lines
5.0 KiB
PHP
157 lines
5.0 KiB
PHP
<?php
|
|
|
|
namespace Tests\Unit\Services;
|
|
|
|
use App\Enums\ScheduleType;
|
|
use App\Extension\HookManager;
|
|
use App\Models\Schedule;
|
|
use App\Models\ScheduleHistory;
|
|
use App\Services\ScheduleService;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Pagination\LengthAwarePaginator;
|
|
use Tests\TestCase;
|
|
|
|
/**
|
|
* ScheduleService 삭제 테스트
|
|
*
|
|
* 스케줄 삭제 시 관계 레코드 명시적 삭제 및 훅 실행을 검증합니다.
|
|
*/
|
|
class ScheduleServiceTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
private ScheduleService $scheduleService;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
$this->scheduleService = app(ScheduleService::class);
|
|
HookManager::resetAll();
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
HookManager::resetAll();
|
|
parent::tearDown();
|
|
}
|
|
|
|
// ========================================================================
|
|
// getPaginatedSchedules() / getHistory() - 반환 타입 해석 검증
|
|
// ========================================================================
|
|
|
|
/**
|
|
* 스케줄이 존재할 때 목록 조회가 TypeError 없이 페이지네이터를 반환하는지 확인
|
|
*
|
|
* 회귀 배경: LengthAwarePaginator 를 import 하지 않아 반환 타입이
|
|
* App\Services\LengthAwarePaginator 로 해석되어 목록 API 가 500 을 반환했다.
|
|
*/
|
|
public function test_get_paginated_schedules_returns_paginator(): void
|
|
{
|
|
Schedule::create([
|
|
'name' => '목록 조회 테스트 스케줄',
|
|
'type' => ScheduleType::Artisan,
|
|
'command' => 'inspire',
|
|
'expression' => '* * * * *',
|
|
'is_active' => true,
|
|
]);
|
|
|
|
$result = $this->scheduleService->getPaginatedSchedules([]);
|
|
|
|
$this->assertInstanceOf(LengthAwarePaginator::class, $result);
|
|
$this->assertSame(1, $result->total());
|
|
}
|
|
|
|
/**
|
|
* 실행 이력이 존재할 때 이력 조회가 TypeError 없이 페이지네이터를 반환하는지 확인
|
|
*/
|
|
public function test_get_history_returns_paginator(): void
|
|
{
|
|
$schedule = Schedule::create([
|
|
'name' => '이력 조회 테스트 스케줄',
|
|
'type' => ScheduleType::Artisan,
|
|
'command' => 'inspire',
|
|
'expression' => '* * * * *',
|
|
'is_active' => true,
|
|
]);
|
|
|
|
ScheduleHistory::create([
|
|
'schedule_id' => $schedule->id,
|
|
'started_at' => now(),
|
|
'finished_at' => now(),
|
|
'result_status' => 'success',
|
|
]);
|
|
|
|
$result = $this->scheduleService->getHistory($schedule->id, []);
|
|
|
|
$this->assertInstanceOf(LengthAwarePaginator::class, $result);
|
|
$this->assertSame(1, $result->total());
|
|
}
|
|
|
|
// ========================================================================
|
|
// delete() - 관계 레코드 명시적 삭제 검증
|
|
// ========================================================================
|
|
|
|
/**
|
|
* 스케줄 삭제 시 실행 이력이 삭제되는지 확인
|
|
*/
|
|
public function test_delete_schedule_deletes_histories(): void
|
|
{
|
|
$schedule = Schedule::create([
|
|
'name' => '테스트 스케줄',
|
|
'type' => ScheduleType::Artisan,
|
|
'command' => 'inspire',
|
|
'expression' => '* * * * *',
|
|
'is_active' => true,
|
|
]);
|
|
|
|
ScheduleHistory::create([
|
|
'schedule_id' => $schedule->id,
|
|
'started_at' => now(),
|
|
'finished_at' => now(),
|
|
'result_status' => 'success',
|
|
]);
|
|
|
|
$this->assertDatabaseHas('schedule_histories', ['schedule_id' => $schedule->id]);
|
|
|
|
$this->scheduleService->delete($schedule);
|
|
|
|
$this->assertDatabaseMissing('schedule_histories', ['schedule_id' => $schedule->id]);
|
|
}
|
|
|
|
// ========================================================================
|
|
// delete() - 훅 실행 검증
|
|
// ========================================================================
|
|
|
|
/**
|
|
* 스케줄 삭제 시 before_delete/after_delete 훅이 호출되는지 확인
|
|
*/
|
|
public function test_delete_schedule_fires_hooks(): void
|
|
{
|
|
$schedule = Schedule::create([
|
|
'name' => '훅 테스트 스케줄',
|
|
'type' => ScheduleType::Artisan,
|
|
'command' => 'inspire',
|
|
'expression' => '* * * * *',
|
|
'is_active' => true,
|
|
]);
|
|
|
|
$beforeCalled = false;
|
|
$afterCalled = false;
|
|
|
|
HookManager::addAction('core.schedule.before_delete', function ($s) use (&$beforeCalled, $schedule) {
|
|
$beforeCalled = true;
|
|
$this->assertEquals($schedule->id, $s->id);
|
|
});
|
|
|
|
HookManager::addAction('core.schedule.after_delete', function ($scheduleId) use (&$afterCalled, $schedule) {
|
|
$afterCalled = true;
|
|
$this->assertEquals($schedule->id, $scheduleId);
|
|
});
|
|
|
|
$this->scheduleService->delete($schedule);
|
|
|
|
$this->assertTrue($beforeCalled);
|
|
$this->assertTrue($afterCalled);
|
|
}
|
|
}
|