131 lines
4.6 KiB
PHP
131 lines
4.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Service\Upload;
|
|
|
|
use App\Entity\Upload;
|
|
use App\Service\Pdf\Sanitizer;
|
|
use App\Service\Upload\UploadHandler;
|
|
use Flagception\Manager\FeatureManagerInterface;
|
|
use Oneup\UploaderBundle\Uploader\Orphanage\OrphanageManager;
|
|
use PHPUnit\Framework\MockObject\MockObject;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Psr\Log\NullLogger;
|
|
use Symfony\Component\Filesystem\Filesystem;
|
|
use Symfony\Component\HttpFoundation\RequestStack;
|
|
|
|
/**
|
|
* The stand-in document fills a gap, it never covers a file that is there: environments other
|
|
* than prod run on anonymized copies of the production database but never carry over the uploaded
|
|
* files. A file that is present - one uploaded while testing - has to come back untouched, or the
|
|
* upload flow could not be exercised at all. That, and the fact that the feature is the only
|
|
* thing gating the fallback, is what is pinned here.
|
|
*/
|
|
class UploadHandlerTest extends TestCase
|
|
{
|
|
private const REPLACEMENT_FILE = 'assets/pdf/chicken.pdf';
|
|
private const UPLOAD_PATH = 'uploads/invoice/i/invoice-1.pdf';
|
|
|
|
private FeatureManagerInterface&MockObject $featureManager;
|
|
private Filesystem $filesystem;
|
|
private string $projectDir;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->featureManager = $this->createMock(FeatureManagerInterface::class);
|
|
$this->filesystem = new Filesystem();
|
|
$this->projectDir = sprintf('%s/upload-handler-%s', sys_get_temp_dir(), uniqid());
|
|
|
|
$this->filesystem->mkdir($this->projectDir.'/'.\dirname(self::REPLACEMENT_FILE));
|
|
$this->filesystem->dumpFile($this->projectDir.'/'.self::REPLACEMENT_FILE, '%PDF-1.4 stand-in');
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
$this->filesystem->remove($this->projectDir);
|
|
}
|
|
|
|
/**
|
|
* The point of the whole feature: a document uploaded while testing is served as it is.
|
|
*/
|
|
public function testAnExistingUploadIsServedEvenWhileTheFeatureIsOn(): void
|
|
{
|
|
$this->featureManager->method('isActive')->with('upload_replacement')->willReturn(true);
|
|
$this->filesystem->dumpFile($this->projectDir.'/'.self::UPLOAD_PATH, '%PDF-1.4 the real one');
|
|
|
|
$this->assertSame(
|
|
$this->projectDir.'/'.self::UPLOAD_PATH,
|
|
$this->handler()->getResolvedUploadFilepath($this->upload())
|
|
);
|
|
}
|
|
|
|
public function testAMissingUploadIsReplacedWhileTheFeatureIsOn(): void
|
|
{
|
|
$this->featureManager->method('isActive')->with('upload_replacement')->willReturn(true);
|
|
|
|
$this->assertSame(
|
|
$this->projectDir.'/'.self::REPLACEMENT_FILE,
|
|
$this->handler()->getResolvedUploadFilepath($this->upload())
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Without the feature a missing file stays missing - the callers turn that into their own
|
|
* error, e.g. the 404 of the download controller.
|
|
*/
|
|
public function testAMissingUploadIsLeftAloneWhileTheFeatureIsOff(): void
|
|
{
|
|
$this->featureManager->method('isActive')->with('upload_replacement')->willReturn(false);
|
|
|
|
$this->assertSame(
|
|
$this->projectDir.'/'.self::UPLOAD_PATH,
|
|
$this->handler()->getResolvedUploadFilepath($this->upload())
|
|
);
|
|
}
|
|
|
|
public function testAMissingStandInIsAMisconfigurationAndFails(): void
|
|
{
|
|
$this->featureManager->method('isActive')->with('upload_replacement')->willReturn(true);
|
|
|
|
$this->expectException(\RuntimeException::class);
|
|
$this->expectExceptionMessage($this->projectDir.'/assets/pdf/nope.pdf');
|
|
|
|
$this->handler('assets/pdf/nope.pdf')->getResolvedUploadFilepath($this->upload());
|
|
}
|
|
|
|
/**
|
|
* The real location is never substituted: it is what writes target.
|
|
*/
|
|
public function testTheUploadFilepathIgnoresTheFeature(): void
|
|
{
|
|
$this->featureManager->method('isActive')->with('upload_replacement')->willReturn(true);
|
|
|
|
$this->assertSame(
|
|
$this->projectDir.'/'.self::UPLOAD_PATH,
|
|
$this->handler()->getUploadFilepath($this->upload())
|
|
);
|
|
}
|
|
|
|
private function handler(string $replacementFile = self::REPLACEMENT_FILE): UploadHandler
|
|
{
|
|
return new UploadHandler(
|
|
$this->createStub(RequestStack::class),
|
|
$this->createStub(OrphanageManager::class),
|
|
$this->createStub(Sanitizer::class),
|
|
new NullLogger(),
|
|
$this->featureManager,
|
|
$this->projectDir,
|
|
$replacementFile,
|
|
);
|
|
}
|
|
|
|
private function upload(): Upload
|
|
{
|
|
return (new Upload())
|
|
->setType(Upload::TYPE_INVOICE)
|
|
->setFilename('invoice-1.pdf')
|
|
;
|
|
}
|
|
}
|