149 lines
5.4 KiB
PHP
149 lines
5.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Command;
|
|
|
|
use App\BusProNet\XmlLoader\TravelLoader;
|
|
use App\Command\BpnXmlSyncCommand;
|
|
use App\Service\TravelDataService;
|
|
use League\Flysystem\DirectoryListing;
|
|
use League\Flysystem\FilesystemOperator;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Psr\Log\LoggerInterface;
|
|
use Symfony\Component\Console\Command\Command;
|
|
use Symfony\Component\Console\Tester\CommandTester;
|
|
use Symfony\Contracts\Cache\CacheInterface;
|
|
|
|
class BpnXmlSyncCommandTest extends TestCase
|
|
{
|
|
private FilesystemOperator $xmlSource;
|
|
private FilesystemOperator $xmlExport;
|
|
private CacheInterface $cache;
|
|
private LoggerInterface $logger;
|
|
private TravelLoader $travelLoader;
|
|
private TravelDataService $travelDataService;
|
|
private BpnXmlSyncCommand $command;
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
// Release the filesystem lock held by LockableTrait so subsequent tests can acquire it.
|
|
$release = new \ReflectionMethod($this->command, 'release');
|
|
$release->setAccessible(true);
|
|
$release->invoke($this->command);
|
|
}
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->xmlSource = $this->createMock(FilesystemOperator::class);
|
|
$this->xmlExport = $this->createMock(FilesystemOperator::class);
|
|
$this->cache = $this->createMock(CacheInterface::class);
|
|
$this->logger = $this->createMock(LoggerInterface::class);
|
|
$this->travelLoader = $this->createMock(TravelLoader::class);
|
|
$this->travelDataService = $this->createMock(TravelDataService::class);
|
|
|
|
$this->command = new BpnXmlSyncCommand(
|
|
$this->xmlSource,
|
|
$this->xmlExport,
|
|
$this->cache,
|
|
$this->logger,
|
|
$this->travelLoader,
|
|
$this->travelDataService,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Remote newer than local → files downloaded → syncSnapshotsFromXml() called once.
|
|
*/
|
|
public function testSnapshotSyncIsTriggeredAfterSuccessfulFileDownload(): void
|
|
{
|
|
$this->xmlSource->method('read')
|
|
->willReturn("24.03.2026 12:00:00\nExport\n3 Dateien\n");
|
|
|
|
$this->xmlExport->method('fileExists')->willReturn(true);
|
|
$this->xmlExport->method('read')
|
|
->willReturn("24.03.2026 10:00:00\nExport\n3 Dateien\n");
|
|
|
|
// No remote files to copy (keeps syncFiles() trivial while still completing).
|
|
$this->xmlSource->method('listContents')
|
|
->willReturn(new DirectoryListing([]));
|
|
$this->xmlExport->method('listContents')
|
|
->willReturn(new DirectoryListing([]));
|
|
|
|
$fileMap = [
|
|
101 => ['hotels' => ['H1' => null, 'H2' => null]],
|
|
102 => ['hotels' => ['H3' => null]],
|
|
];
|
|
$this->travelLoader->expects($this->once())
|
|
->method('generateFilesMap')
|
|
->willReturn($fileMap);
|
|
|
|
$this->travelDataService->expects($this->once())
|
|
->method('syncSnapshotsFromXml')
|
|
->with($fileMap, $this->isInstanceOf(\Closure::class))
|
|
->willReturn(['processed' => 2, 'failed' => 0]);
|
|
|
|
$tester = new CommandTester($this->command);
|
|
$tester->execute([]);
|
|
|
|
$this->assertSame(Command::SUCCESS, $tester->getStatusCode());
|
|
$this->assertStringContainsString('snapshots: 2 processed, 0 failed', $tester->getDisplay());
|
|
}
|
|
|
|
/**
|
|
* Local already up to date → early return before snapshot code is reached.
|
|
*/
|
|
public function testSnapshotSyncIsSkippedWhenLocalDataIsUpToDate(): void
|
|
{
|
|
$sameTimestamp = "24.03.2026 10:00:00\nExport\n3 Dateien\n";
|
|
$this->xmlSource->method('read')->willReturn($sameTimestamp);
|
|
$this->xmlExport->method('fileExists')->willReturn(true);
|
|
$this->xmlExport->method('read')->willReturn($sameTimestamp);
|
|
|
|
$this->travelLoader->expects($this->never())->method('generateFilesMap');
|
|
$this->travelDataService->expects($this->never())->method('syncSnapshotsFromXml');
|
|
|
|
$tester = new CommandTester($this->command);
|
|
$tester->execute([]);
|
|
|
|
$this->assertSame(Command::SUCCESS, $tester->getStatusCode());
|
|
}
|
|
|
|
/**
|
|
* generateFilesMap() throws → warning logged, syncSnapshotsFromXml() never called,
|
|
* command still returns SUCCESS.
|
|
*/
|
|
public function testSnapshotSyncIsSkippedAndWarningLoggedWhenFileMapGenerationFails(): void
|
|
{
|
|
$this->xmlSource->method('read')
|
|
->willReturn("24.03.2026 12:00:00\nExport\n3 Dateien\n");
|
|
|
|
$this->xmlExport->method('fileExists')->willReturn(true);
|
|
$this->xmlExport->method('read')
|
|
->willReturn("24.03.2026 10:00:00\nExport\n3 Dateien\n");
|
|
|
|
$this->xmlSource->method('listContents')
|
|
->willReturn(new DirectoryListing([]));
|
|
$this->xmlExport->method('listContents')
|
|
->willReturn(new DirectoryListing([]));
|
|
|
|
$this->travelLoader->expects($this->once())
|
|
->method('generateFilesMap')
|
|
->willThrowException(new \RuntimeException('Storage unavailable'));
|
|
|
|
$this->logger->expects($this->atLeastOnce())
|
|
->method('warning')
|
|
->with(
|
|
$this->stringContains('snapshot refresh skipped'),
|
|
$this->anything(),
|
|
);
|
|
|
|
$this->travelDataService->expects($this->never())->method('syncSnapshotsFromXml');
|
|
|
|
$tester = new CommandTester($this->command);
|
|
$tester->execute([]);
|
|
|
|
$this->assertSame(Command::SUCCESS, $tester->getStatusCode());
|
|
}
|
|
}
|