222 lines
8.1 KiB
PHP
222 lines
8.1 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature\Services;
|
|
|
|
use App\Enums\ExtensionStatus;
|
|
use App\Models\Template;
|
|
use App\Repositories\TemplateRepository;
|
|
use App\Services\TemplateService;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\File;
|
|
use Tests\TestCase;
|
|
|
|
class TemplateServiceIntegrationTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
private TemplateService $templateService;
|
|
private TemplateRepository $templateRepository;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
// 실제 TemplateManager를 사용 (Mock 없음)
|
|
$this->templateRepository = new TemplateRepository();
|
|
$this->templateService = app(TemplateService::class);
|
|
|
|
// 템플릿 로드 (template.json 파일 읽기)
|
|
$templateManager = app(\App\Contracts\Extension\TemplateManagerInterface::class);
|
|
$templateManager->loadTemplates();
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
// 테스트 후 public/build/template 디렉토리 정리
|
|
$this->cleanupPublicTemplateDirectories();
|
|
parent::tearDown();
|
|
}
|
|
|
|
/**
|
|
* End-to-End 통합 테스트: 실제 sirsoft-admin_basic 템플릿 활성화
|
|
*
|
|
* 검증 항목:
|
|
* 1. npm run build로 dist/ 생성 확인
|
|
* 2. TemplateManager::installTemplate() 호출 (DB 등록)
|
|
* 3. TemplateService::activateTemplate() API 호출
|
|
* 4. TemplateManager의 파일 복사 실행 확인
|
|
* 5. public/build/template/admin/dist/ 디렉토리 생성 검증 (type별 분리)
|
|
* 6. 브라우저에서 /build/template/admin/dist/components.iife.js 접근 시 200 응답 확인
|
|
*/
|
|
public function test_end_to_end_template_activation_with_real_files(): void
|
|
{
|
|
// Arrange
|
|
$templatePath = base_path('templates/sirsoft-admin_basic');
|
|
$distPath = $templatePath . '/dist';
|
|
$publicDistPath = public_path('build/template/admin/dist'); // admin 타입으로 변경
|
|
|
|
// 1. dist/ 디렉토리 존재 확인 (빌드되지 않은 경우 skip)
|
|
if (!is_dir($distPath) || !file_exists($distPath . '/components.iife.js')) {
|
|
$this->markTestSkipped('Template dist/ not built. Run npm run build in template directory first.');
|
|
}
|
|
|
|
// 2. 템플릿 설치 (DB 등록) - TemplateManager 사용
|
|
$templateManager = app(\App\Contracts\Extension\TemplateManagerInterface::class);
|
|
$templateManager->installTemplate('sirsoft-admin_basic');
|
|
|
|
// DB에 등록된 템플릿 조회
|
|
$template = Template::where('identifier', 'sirsoft-admin_basic')->first();
|
|
$this->assertNotNull($template);
|
|
$this->assertEquals('inactive', $template->status);
|
|
|
|
// public/build 디렉토리가 없으면 생성
|
|
if (!is_dir(public_path('build'))) {
|
|
mkdir(public_path('build'), 0755, true);
|
|
}
|
|
|
|
// 기존 admin 디렉토리 정리
|
|
if (is_dir(public_path('build/template/admin'))) {
|
|
$this->deleteDirectory(public_path('build/template/admin'));
|
|
}
|
|
|
|
// 3. TemplateService::activateTemplate() API 호출
|
|
$activatedTemplate = $this->templateService->activateTemplate($template->id);
|
|
|
|
// 4. 템플릿 상태 변경 확인 (파일 복사는 더 이상 수행하지 않음)
|
|
$this->assertEquals(ExtensionStatus::Active->value, $activatedTemplate->status);
|
|
|
|
// 5. DB에서 활성화 확인
|
|
$this->assertDatabaseHas('templates', [
|
|
'identifier' => 'sirsoft-admin_basic',
|
|
'status' => ExtensionStatus::Active->value,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* admin과 user 템플릿 동시 활성화 시 디렉토리 분리 검증
|
|
*/
|
|
public function test_admin_and_user_templates_are_separated_by_type(): void
|
|
{
|
|
// Arrange
|
|
$templateManager = app(\App\Contracts\Extension\TemplateManagerInterface::class);
|
|
|
|
// admin 템플릿 설치
|
|
$templateManager->installTemplate('sirsoft-admin_basic');
|
|
$adminTemplate = Template::where('identifier', 'sirsoft-admin_basic')->first();
|
|
$this->assertNotNull($adminTemplate);
|
|
|
|
$publicAdminPath = public_path('build/template/admin');
|
|
$publicUserPath = public_path('build/template/user');
|
|
|
|
// public/build 디렉토리가 없으면 생성
|
|
if (!is_dir(public_path('build'))) {
|
|
mkdir(public_path('build'), 0755, true);
|
|
}
|
|
|
|
// 기존 디렉토리 정리
|
|
if (is_dir($publicAdminPath)) {
|
|
$this->deleteDirectory($publicAdminPath);
|
|
}
|
|
if (is_dir($publicUserPath)) {
|
|
$this->deleteDirectory($publicUserPath);
|
|
}
|
|
|
|
// Act: admin 템플릿 활성화
|
|
$activatedAdmin = $this->templateService->activateTemplate($adminTemplate->id);
|
|
|
|
// Assert: admin 템플릿 상태 확인 (파일 복사는 더 이상 수행하지 않음)
|
|
// activateTemplate은 배열을 반환함
|
|
$this->assertIsArray($activatedAdmin);
|
|
$this->assertEquals(ExtensionStatus::Active->value, $activatedAdmin['template_info']['status']);
|
|
$this->assertDatabaseHas('templates', [
|
|
'identifier' => 'sirsoft-admin_basic',
|
|
'status' => ExtensionStatus::Active->value,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 같은 타입의 템플릿 순차 활성화 시 이전 템플릿 비활성화 검증
|
|
*/
|
|
public function test_deactivates_previous_template_of_same_type(): void
|
|
{
|
|
// Arrange
|
|
$templateManager = app(\App\Contracts\Extension\TemplateManagerInterface::class);
|
|
|
|
// admin 템플릿 설치
|
|
$templateManager->installTemplate('sirsoft-admin_basic');
|
|
$template1 = Template::where('identifier', 'sirsoft-admin_basic')->first();
|
|
$this->assertNotNull($template1);
|
|
|
|
$publicAdminPath = public_path('build/template/admin');
|
|
|
|
// public/build 디렉토리가 없으면 생성
|
|
if (!is_dir(public_path('build'))) {
|
|
mkdir(public_path('build'), 0755, true);
|
|
}
|
|
|
|
// 기존 admin 디렉토리 정리
|
|
if (is_dir($publicAdminPath)) {
|
|
$this->deleteDirectory($publicAdminPath);
|
|
}
|
|
|
|
// Act: 첫 번째 템플릿 활성화
|
|
$activatedTemplate1 = $this->templateService->activateTemplate($template1->id);
|
|
|
|
// Assert: 첫 번째 템플릿이 활성화됨 (파일 복사는 더 이상 수행하지 않음)
|
|
// activateTemplate은 배열을 반환함
|
|
$this->assertIsArray($activatedTemplate1);
|
|
$this->assertEquals(ExtensionStatus::Active->value, $activatedTemplate1['template_info']['status']);
|
|
$this->assertDatabaseHas('templates', [
|
|
'identifier' => 'sirsoft-admin_basic',
|
|
'status' => ExtensionStatus::Active->value,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 디렉토리 재귀 삭제 헬퍼
|
|
*/
|
|
private function deleteDirectory(string $dir): void
|
|
{
|
|
if (!is_dir($dir)) {
|
|
return;
|
|
}
|
|
|
|
$files = array_diff(scandir($dir), ['.', '..']);
|
|
foreach ($files as $file) {
|
|
$path = $dir . '/' . $file;
|
|
is_dir($path) ? $this->deleteDirectory($path) : unlink($path);
|
|
}
|
|
rmdir($dir);
|
|
}
|
|
|
|
/**
|
|
* public/build/template 디렉토리 전체 정리
|
|
*/
|
|
private function cleanupPublicTemplateDirectories(): void
|
|
{
|
|
$templatePath = public_path('build/template');
|
|
|
|
if (File::exists($templatePath)) {
|
|
// Windows 권한 문제 방지: 재시도 로직 추가
|
|
$maxAttempts = 3;
|
|
$attempt = 0;
|
|
|
|
while ($attempt < $maxAttempts) {
|
|
try {
|
|
File::deleteDirectory($templatePath);
|
|
break;
|
|
} catch (\Exception $e) {
|
|
$attempt++;
|
|
if ($attempt >= $maxAttempts) {
|
|
// 최종 실패 시 경고만 출력 (테스트 실패 방지)
|
|
echo "\nWarning: Could not delete template directory: {$e->getMessage()}\n";
|
|
} else {
|
|
// 짧은 대기 후 재시도
|
|
usleep(100000); // 100ms
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|