171 lines
6.0 KiB
PHP
171 lines
6.0 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace App\Tests\Command;
|
||
|
|
|
||
|
|
use App\Command\BackupCommand;
|
||
|
|
use App\Entity\Backup;
|
||
|
|
use App\Service\Mailer\Mailer;
|
||
|
|
use App\Service\System\DatabaseDumper;
|
||
|
|
use App\Service\System\ZipArchiver;
|
||
|
|
use Doctrine\ORM\EntityManagerInterface;
|
||
|
|
use Doctrine\ORM\Query;
|
||
|
|
use PHPUnit\Framework\MockObject\MockObject;
|
||
|
|
use PHPUnit\Framework\TestCase;
|
||
|
|
use Symfony\Component\Console\Application;
|
||
|
|
use Symfony\Component\Console\Tester\CommandTester;
|
||
|
|
use Symfony\Component\HttpKernel\KernelInterface;
|
||
|
|
|
||
|
|
class BackupCommandTest extends TestCase
|
||
|
|
{
|
||
|
|
private MockObject&KernelInterface $kernel;
|
||
|
|
private MockObject&EntityManagerInterface $entityManager;
|
||
|
|
private MockObject&Mailer $mailer;
|
||
|
|
private MockObject&DatabaseDumper $databaseDumper;
|
||
|
|
private MockObject&ZipArchiver $zipArchiver;
|
||
|
|
|
||
|
|
protected function setUp(): void
|
||
|
|
{
|
||
|
|
$this->kernel = $this->createMock(KernelInterface::class);
|
||
|
|
$this->entityManager = $this->createMock(EntityManagerInterface::class);
|
||
|
|
$this->mailer = $this->createMock(Mailer::class);
|
||
|
|
$this->databaseDumper = $this->createMock(DatabaseDumper::class);
|
||
|
|
$this->zipArchiver = $this->createMock(ZipArchiver::class);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testExecuteSuccess()
|
||
|
|
{
|
||
|
|
// 1. Setup Data
|
||
|
|
$projectDir = sys_get_temp_dir() . '/backup_test_' . uniqid();
|
||
|
|
mkdir($projectDir . '/sauvegarde', 0777, true);
|
||
|
|
|
||
|
|
$this->kernel->method('getProjectDir')->willReturn($projectDir);
|
||
|
|
|
||
|
|
// 2. Expectations
|
||
|
|
|
||
|
|
// EntityManager
|
||
|
|
$this->entityManager->expects($this->once())->method('persist')->with($this->isInstanceOf(Backup::class));
|
||
|
|
$this->entityManager->expects($this->atLeast(2))->method('flush'); // Once at start, once at end
|
||
|
|
|
||
|
|
// Cleanup expectations
|
||
|
|
// Mocking Query class which might be final. If so, we'll see an error.
|
||
|
|
// But commonly in Doctrine mocks, we have to deal with this.
|
||
|
|
$query = $this->createMock(Query::class);
|
||
|
|
$query->method('setParameter')->willReturnSelf();
|
||
|
|
$query->method('execute');
|
||
|
|
$this->entityManager->method('createQuery')->willReturn($query);
|
||
|
|
|
||
|
|
// Database Dumper
|
||
|
|
$this->databaseDumper->expects($this->once())
|
||
|
|
->method('dump')
|
||
|
|
->with($this->anything(), $this->stringEndsWith('temp_db.sql'));
|
||
|
|
|
||
|
|
// Zip Archiver
|
||
|
|
$this->zipArchiver->expects($this->once())
|
||
|
|
->method('createArchive')
|
||
|
|
->willReturnCallback(function($zipPath, $sqlPath, $dirs) {
|
||
|
|
// Create a dummy zip file so filesize() works
|
||
|
|
touch($zipPath);
|
||
|
|
});
|
||
|
|
|
||
|
|
// Mailer
|
||
|
|
$this->mailer->expects($this->once())
|
||
|
|
->method('send')
|
||
|
|
->with(
|
||
|
|
'notification@siteconseil.fr',
|
||
|
|
'Intranet Ludievent',
|
||
|
|
$this->stringContains('✅ Sauvegarde'),
|
||
|
|
'mails/backup_notification.twig',
|
||
|
|
$this->callback(function($context) {
|
||
|
|
return isset($context['backup']) && $context['backup']->getStatus() === 'SUCCESS';
|
||
|
|
})
|
||
|
|
);
|
||
|
|
|
||
|
|
// 3. Execution
|
||
|
|
$command = new BackupCommand(
|
||
|
|
$this->kernel,
|
||
|
|
$this->entityManager,
|
||
|
|
$this->mailer,
|
||
|
|
$this->databaseDumper,
|
||
|
|
$this->zipArchiver
|
||
|
|
);
|
||
|
|
|
||
|
|
$application = new Application();
|
||
|
|
$application->add($command);
|
||
|
|
$commandTester = new CommandTester($application->find('app:backup'));
|
||
|
|
|
||
|
|
$commandTester->execute([]);
|
||
|
|
|
||
|
|
// 4. Assertions
|
||
|
|
$output = $commandTester->getDisplay();
|
||
|
|
$this->assertStringContainsString('Sauvegarde réussie', $output);
|
||
|
|
|
||
|
|
// Cleanup
|
||
|
|
$this->removeDirectory($projectDir);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testExecuteFailure()
|
||
|
|
{
|
||
|
|
// 1. Setup Data
|
||
|
|
$projectDir = sys_get_temp_dir() . '/backup_test_fail_' . uniqid();
|
||
|
|
mkdir($projectDir . '/sauvegarde', 0777, true);
|
||
|
|
|
||
|
|
$this->kernel->method('getProjectDir')->willReturn($projectDir);
|
||
|
|
|
||
|
|
// 2. Expectations - Fail at Dump
|
||
|
|
$this->databaseDumper->expects($this->once())
|
||
|
|
->method('dump')
|
||
|
|
->willThrowException(new \Exception("Simulated Dump Error"));
|
||
|
|
|
||
|
|
// Mailer - Should send Error notification
|
||
|
|
$this->mailer->expects($this->once())
|
||
|
|
->method('send')
|
||
|
|
->with(
|
||
|
|
'notification@siteconseil.fr',
|
||
|
|
'Intranet Ludievent',
|
||
|
|
$this->stringContains('❌ Sauvegarde'),
|
||
|
|
'mails/backup_notification.twig',
|
||
|
|
$this->callback(function($context) {
|
||
|
|
return isset($context['backup'])
|
||
|
|
&& $context['backup']->getStatus() === 'ERROR'
|
||
|
|
&& $context['backup']->getErrorMessage() === 'Simulated Dump Error';
|
||
|
|
})
|
||
|
|
);
|
||
|
|
|
||
|
|
// Cleanup expectations
|
||
|
|
$query = $this->createMock(Query::class);
|
||
|
|
$query->method('setParameter')->willReturnSelf();
|
||
|
|
$query->method('execute');
|
||
|
|
$this->entityManager->method('createQuery')->willReturn($query);
|
||
|
|
|
||
|
|
// 3. Execution
|
||
|
|
$command = new BackupCommand(
|
||
|
|
$this->kernel,
|
||
|
|
$this->entityManager,
|
||
|
|
$this->mailer,
|
||
|
|
$this->databaseDumper,
|
||
|
|
$this->zipArchiver
|
||
|
|
);
|
||
|
|
|
||
|
|
$application = new Application();
|
||
|
|
$application->add($command);
|
||
|
|
$commandTester = new CommandTester($application->find('app:backup'));
|
||
|
|
|
||
|
|
$commandTester->execute([]);
|
||
|
|
|
||
|
|
// 4. Assertions
|
||
|
|
$output = $commandTester->getDisplay();
|
||
|
|
$this->assertStringContainsString('Échec : Simulated Dump Error', $output);
|
||
|
|
|
||
|
|
// Cleanup
|
||
|
|
$this->removeDirectory($projectDir);
|
||
|
|
}
|
||
|
|
|
||
|
|
private function removeDirectory($dir) {
|
||
|
|
if (!is_dir($dir)) return;
|
||
|
|
$files = array_diff(scandir($dir), array('.','..'));
|
||
|
|
foreach ($files as $file) {
|
||
|
|
(is_dir("$dir/$file")) ? $this->removeDirectory("$dir/$file") : unlink("$dir/$file");
|
||
|
|
}
|
||
|
|
rmdir($dir);
|
||
|
|
}
|
||
|
|
}
|