From 47295bda29468213abfb8f096d54f230eb55bc29 Mon Sep 17 00:00:00 2001 From: Sebastian Almberg <83243306+Sebbeben@users.noreply.github.com> Date: Sun, 1 Feb 2026 19:28:15 +0100 Subject: [PATCH] Add unit tests for BackupManager and UpdateExecutor Tests cover: - BackupManager: backup directory, listing, details parsing - UpdateExecutor: lock/unlock, maintenance mode, validation, progress --- tests/Services/System/BackupManagerTest.php | 102 +++++++++++ tests/Services/System/UpdateExecutorTest.php | 173 +++++++++++++++++++ 2 files changed, 275 insertions(+) create mode 100644 tests/Services/System/BackupManagerTest.php create mode 100644 tests/Services/System/UpdateExecutorTest.php diff --git a/tests/Services/System/BackupManagerTest.php b/tests/Services/System/BackupManagerTest.php new file mode 100644 index 00000000..145b039d --- /dev/null +++ b/tests/Services/System/BackupManagerTest.php @@ -0,0 +1,102 @@ +. + */ + +declare(strict_types=1); + +namespace App\Tests\Services\System; + +use App\Services\System\BackupManager; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; + +class BackupManagerTest extends KernelTestCase +{ + private ?BackupManager $backupManager = null; + + protected function setUp(): void + { + self::bootKernel(); + $this->backupManager = self::getContainer()->get(BackupManager::class); + } + + public function testGetBackupDir(): void + { + $backupDir = $this->backupManager->getBackupDir(); + + // Should end with var/backups + $this->assertStringEndsWith('var/backups', $backupDir); + } + + public function testGetBackupsReturnsEmptyArrayWhenNoBackups(): void + { + // If there are no backups (or the directory doesn't exist), should return empty array + $backups = $this->backupManager->getBackups(); + + $this->assertIsArray($backups); + } + + public function testGetBackupDetailsReturnsNullForNonExistentFile(): void + { + $details = $this->backupManager->getBackupDetails('non-existent-backup.zip'); + + $this->assertNull($details); + } + + public function testGetBackupDetailsReturnsNullForNonZipFile(): void + { + $details = $this->backupManager->getBackupDetails('not-a-zip.txt'); + + $this->assertNull($details); + } + + /** + * Test that version parsing from filename works correctly. + * This tests the regex pattern used in getBackupDetails. + */ + public function testVersionParsingFromFilename(): void + { + // Test the regex pattern directly + $filename = 'pre-update-v2.5.1-to-v2.6.0-2024-01-30-185400.zip'; + $matches = []; + + $result = preg_match('/pre-update-v([\d.]+)-to-v?([\d.]+)-/', $filename, $matches); + + $this->assertEquals(1, $result); + $this->assertEquals('2.5.1', $matches[1]); + $this->assertEquals('2.6.0', $matches[2]); + } + + /** + * Test version parsing with different filename formats. + */ + public function testVersionParsingVariants(): void + { + // Without 'v' prefix on target version + $filename1 = 'pre-update-v1.0.0-to-2.0.0-2024-01-30-185400.zip'; + preg_match('/pre-update-v([\d.]+)-to-v?([\d.]+)-/', $filename1, $matches1); + $this->assertEquals('1.0.0', $matches1[1]); + $this->assertEquals('2.0.0', $matches1[2]); + + // With 'v' prefix on target version + $filename2 = 'pre-update-v1.0.0-to-v2.0.0-2024-01-30-185400.zip'; + preg_match('/pre-update-v([\d.]+)-to-v?([\d.]+)-/', $filename2, $matches2); + $this->assertEquals('1.0.0', $matches2[1]); + $this->assertEquals('2.0.0', $matches2[2]); + } +} diff --git a/tests/Services/System/UpdateExecutorTest.php b/tests/Services/System/UpdateExecutorTest.php new file mode 100644 index 00000000..9b832f6c --- /dev/null +++ b/tests/Services/System/UpdateExecutorTest.php @@ -0,0 +1,173 @@ +. + */ + +declare(strict_types=1); + +namespace App\Tests\Services\System; + +use App\Services\System\UpdateExecutor; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; + +class UpdateExecutorTest extends KernelTestCase +{ + private ?UpdateExecutor $updateExecutor = null; + + protected function setUp(): void + { + self::bootKernel(); + $this->updateExecutor = self::getContainer()->get(UpdateExecutor::class); + } + + public function testIsLockedReturnsFalseWhenNoLockFile(): void + { + // Initially there should be no lock + // Note: This test assumes no concurrent update is running + $isLocked = $this->updateExecutor->isLocked(); + + $this->assertIsBool($isLocked); + } + + public function testIsMaintenanceModeReturnsBool(): void + { + $isMaintenanceMode = $this->updateExecutor->isMaintenanceMode(); + + $this->assertIsBool($isMaintenanceMode); + } + + public function testGetLockInfoReturnsNullOrArray(): void + { + $lockInfo = $this->updateExecutor->getLockInfo(); + + // Should be null when not locked, or array when locked + $this->assertTrue($lockInfo === null || is_array($lockInfo)); + } + + public function testGetMaintenanceInfoReturnsNullOrArray(): void + { + $maintenanceInfo = $this->updateExecutor->getMaintenanceInfo(); + + // Should be null when not in maintenance, or array when in maintenance + $this->assertTrue($maintenanceInfo === null || is_array($maintenanceInfo)); + } + + public function testGetUpdateLogsReturnsArray(): void + { + $logs = $this->updateExecutor->getUpdateLogs(); + + $this->assertIsArray($logs); + } + + public function testGetBackupsReturnsArray(): void + { + $backups = $this->updateExecutor->getBackups(); + + $this->assertIsArray($backups); + } + + public function testValidateUpdatePreconditionsReturnsProperStructure(): void + { + $validation = $this->updateExecutor->validateUpdatePreconditions(); + + $this->assertIsArray($validation); + $this->assertArrayHasKey('valid', $validation); + $this->assertArrayHasKey('errors', $validation); + $this->assertIsBool($validation['valid']); + $this->assertIsArray($validation['errors']); + } + + public function testGetProgressFilePath(): void + { + $progressPath = $this->updateExecutor->getProgressFilePath(); + + $this->assertIsString($progressPath); + $this->assertStringEndsWith('var/update_progress.json', $progressPath); + } + + public function testGetProgressReturnsNullOrArray(): void + { + $progress = $this->updateExecutor->getProgress(); + + // Should be null when no progress file, or array when exists + $this->assertTrue($progress === null || is_array($progress)); + } + + public function testIsUpdateRunningReturnsBool(): void + { + $isRunning = $this->updateExecutor->isUpdateRunning(); + + $this->assertIsBool($isRunning); + } + + public function testAcquireAndReleaseLock(): void + { + // First, ensure no lock exists + if ($this->updateExecutor->isLocked()) { + $this->updateExecutor->releaseLock(); + } + + // Acquire lock + $acquired = $this->updateExecutor->acquireLock(); + $this->assertTrue($acquired); + + // Should be locked now + $this->assertTrue($this->updateExecutor->isLocked()); + + // Lock info should exist + $lockInfo = $this->updateExecutor->getLockInfo(); + $this->assertIsArray($lockInfo); + $this->assertArrayHasKey('started_at', $lockInfo); + + // Trying to acquire again should fail + $acquiredAgain = $this->updateExecutor->acquireLock(); + $this->assertFalse($acquiredAgain); + + // Release lock + $this->updateExecutor->releaseLock(); + + // Should no longer be locked + $this->assertFalse($this->updateExecutor->isLocked()); + } + + public function testEnableAndDisableMaintenanceMode(): void + { + // First, ensure maintenance mode is off + if ($this->updateExecutor->isMaintenanceMode()) { + $this->updateExecutor->disableMaintenanceMode(); + } + + // Enable maintenance mode + $this->updateExecutor->enableMaintenanceMode('Test maintenance'); + + // Should be in maintenance mode now + $this->assertTrue($this->updateExecutor->isMaintenanceMode()); + + // Maintenance info should exist + $maintenanceInfo = $this->updateExecutor->getMaintenanceInfo(); + $this->assertIsArray($maintenanceInfo); + $this->assertArrayHasKey('reason', $maintenanceInfo); + $this->assertEquals('Test maintenance', $maintenanceInfo['reason']); + + // Disable maintenance mode + $this->updateExecutor->disableMaintenanceMode(); + + // Should no longer be in maintenance mode + $this->assertFalse($this->updateExecutor->isMaintenanceMode()); + } +}