313 lines
11 KiB
PHP
313 lines
11 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Unit\Infra\Cache;
|
|
|
|
use Domain\Models\Entities\Brand;
|
|
use Domain\Models\ValueObjects\Brand\ArcadiaId;
|
|
use Domain\Models\ValueObjects\Brand\BrandCode;
|
|
use Domain\Models\ValueObjects\Brand\BrandId;
|
|
use Domain\Models\ValueObjects\Brand\BrandName;
|
|
use Infra\Cache\BrandCache;
|
|
use Mockery;
|
|
use Psr\SimpleCache\CacheInterface;
|
|
use Ramsey\Uuid\Uuid;
|
|
|
|
covers(BrandCache::class);
|
|
|
|
describe('BrandCache Unit Tests', function (): void {
|
|
it('returns brand from cache when found by id', function (): void {
|
|
// GIVEN
|
|
$uuid = Uuid::uuid7()->toString();
|
|
$brandId = new BrandId(Uuid::fromString($uuid));
|
|
|
|
$cacheData = [
|
|
'id' => $uuid,
|
|
'name' => 'Le Gaulois',
|
|
'code' => 'LGL01',
|
|
'arcadiaId' => '1',
|
|
];
|
|
|
|
/** @var CacheInterface&Mockery\MockInterface $cacheMock */
|
|
$cacheMock = Mockery::mock(CacheInterface::class);
|
|
$cacheMock->shouldReceive('get')
|
|
->once()
|
|
->with("brand:id:{$uuid}")
|
|
->andReturn($cacheData);
|
|
|
|
/** @var \Psr\Log\LoggerInterface&Mockery\MockInterface $loggerMock */
|
|
$loggerMock = Mockery::mock(\Psr\Log\LoggerInterface::class);
|
|
$loggerMock->shouldReceive('warning')->zeroOrMoreTimes();
|
|
$brandCache = new BrandCache($cacheMock, $loggerMock);
|
|
|
|
// WHEN
|
|
$result = $brandCache->getById($brandId);
|
|
|
|
// THEN
|
|
assert($result !== null);
|
|
expect($result)->not->toBeNull()
|
|
->and($result->id()->value)->toBe($brandId->value)
|
|
->and($result->name->value)->toBe('Le Gaulois')
|
|
->and($result->code->value)->toBe('LGL01')
|
|
->and($result->arcadiaId->value)->toBe('1');
|
|
});
|
|
|
|
it('returns brand from cache when found by code', function (): void {
|
|
// GIVEN
|
|
$uuid = Uuid::uuid7()->toString();
|
|
$brandCode = new BrandCode('LGL01');
|
|
|
|
$cacheData = [
|
|
'id' => $uuid,
|
|
'name' => 'Le Gaulois',
|
|
'code' => 'LGL01',
|
|
'arcadiaId' => '1',
|
|
];
|
|
|
|
/** @var CacheInterface&Mockery\MockInterface $cacheMock */
|
|
$cacheMock = Mockery::mock(CacheInterface::class);
|
|
$cacheMock->shouldReceive('get')
|
|
->once()
|
|
->with('brand:code:LGL01')
|
|
->andReturn($cacheData);
|
|
|
|
/** @var \Psr\Log\LoggerInterface&Mockery\MockInterface $loggerMock */
|
|
$loggerMock = Mockery::mock(\Psr\Log\LoggerInterface::class);
|
|
$loggerMock->shouldReceive('warning')->zeroOrMoreTimes();
|
|
$brandCache = new BrandCache($cacheMock, $loggerMock);
|
|
|
|
// WHEN
|
|
$result = $brandCache->getByCode($brandCode);
|
|
|
|
// THEN
|
|
assert($result !== null);
|
|
expect($result)->not->toBeNull()
|
|
->and($result->code->value)->toBe('LGL01')
|
|
->and($result->name->value)->toBe('Le Gaulois');
|
|
});
|
|
|
|
it('returns brand from cache when found by arcadia id', function (): void {
|
|
// GIVEN
|
|
$uuid = Uuid::uuid7()->toString();
|
|
$arcadiaId = new ArcadiaId('10');
|
|
|
|
$cacheData = [
|
|
'id' => $uuid,
|
|
'name' => 'Maître CoQ',
|
|
'code' => 'MCQ01',
|
|
'arcadiaId' => '10',
|
|
];
|
|
|
|
/** @var CacheInterface&Mockery\MockInterface $cacheMock */
|
|
$cacheMock = Mockery::mock(CacheInterface::class);
|
|
$cacheMock->shouldReceive('get')
|
|
->once()
|
|
->with('brand:arcadia:10')
|
|
->andReturn($cacheData);
|
|
|
|
/** @var \Psr\Log\LoggerInterface&Mockery\MockInterface $loggerMock */
|
|
$loggerMock = Mockery::mock(\Psr\Log\LoggerInterface::class);
|
|
$loggerMock->shouldReceive('warning')->zeroOrMoreTimes();
|
|
$brandCache = new BrandCache($cacheMock, $loggerMock);
|
|
|
|
// WHEN
|
|
$result = $brandCache->getByArcadiaId($arcadiaId);
|
|
|
|
// THEN
|
|
assert($result !== null);
|
|
expect($result)->not->toBeNull()
|
|
->and($result->arcadiaId->value)->toBe('10')
|
|
->and($result->name->value)->toBe('Maître CoQ');
|
|
});
|
|
|
|
it('returns null and recovers gracefully when cache data is corrupted', function (): void {
|
|
// GIVEN
|
|
$brandId = new BrandId(Uuid::uuid7());
|
|
|
|
/** @var CacheInterface&Mockery\MockInterface $cacheMock */
|
|
$cacheMock = Mockery::mock(CacheInterface::class);
|
|
$cacheMock->shouldReceive('get')
|
|
->once()
|
|
->with("brand:id:{$brandId->value}")
|
|
->andReturn('corrupted_string');
|
|
|
|
/** @var \Psr\Log\LoggerInterface&Mockery\MockInterface $loggerMock */
|
|
$loggerMock = Mockery::mock(\Psr\Log\LoggerInterface::class);
|
|
$loggerMock->shouldReceive('warning')->zeroOrMoreTimes();
|
|
$brandCache = new BrandCache($cacheMock, $loggerMock);
|
|
|
|
// WHEN
|
|
$result = $brandCache->getById($brandId);
|
|
|
|
// THEN
|
|
expect($result)->toBeNull();
|
|
});
|
|
|
|
it('stores brand in cache across all key variations', function (): void {
|
|
// GIVEN
|
|
$uuid = Uuid::uuid7()->toString();
|
|
$brand = Brand::hydrate(
|
|
id: new BrandId(Uuid::fromString($uuid)),
|
|
name: new BrandName('Doux'),
|
|
code: new BrandCode('DOX01'),
|
|
arcadiaId: new ArcadiaId('20'),
|
|
);
|
|
|
|
$expectedData = [
|
|
'id' => $uuid,
|
|
'name' => 'Doux',
|
|
'code' => 'DOX01',
|
|
'arcadiaId' => '20',
|
|
];
|
|
|
|
/** @var CacheInterface&Mockery\MockInterface $cacheMock */
|
|
$cacheMock = Mockery::mock(CacheInterface::class);
|
|
$cacheMock->shouldReceive('set')
|
|
->once()
|
|
->with("brand:id:{$uuid}", $expectedData, 86400);
|
|
$cacheMock->shouldReceive('set')
|
|
->once()
|
|
->with('brand:code:DOX01', $expectedData, 86400);
|
|
$cacheMock->shouldReceive('set')
|
|
->once()
|
|
->with('brand:arcadia:20', $expectedData, 86400);
|
|
|
|
/** @var \Psr\Log\LoggerInterface&Mockery\MockInterface $loggerMock */
|
|
$loggerMock = Mockery::mock(\Psr\Log\LoggerInterface::class);
|
|
$loggerMock->shouldReceive('warning')->zeroOrMoreTimes();
|
|
$brandCache = new BrandCache($cacheMock, $loggerMock);
|
|
|
|
// WHEN
|
|
$brandCache->put($brand);
|
|
|
|
// THEN
|
|
expect(true)->toBeTrue();
|
|
});
|
|
|
|
it('invalidates specific brand keys and collection key', function (): void {
|
|
// GIVEN
|
|
$uuid = Uuid::uuid7()->toString();
|
|
$brand = Brand::hydrate(
|
|
id: new BrandId(Uuid::fromString($uuid)),
|
|
name: new BrandName('Père Dodu'),
|
|
code: new BrandCode('PRD01'),
|
|
arcadiaId: new ArcadiaId('30'),
|
|
);
|
|
|
|
/** @var CacheInterface&Mockery\MockInterface $cacheMock */
|
|
$cacheMock = Mockery::mock(CacheInterface::class);
|
|
$cacheMock->shouldReceive('delete')
|
|
->once()
|
|
->with('brand:all');
|
|
$cacheMock->shouldReceive('delete')
|
|
->once()
|
|
->with("brand:id:{$uuid}");
|
|
$cacheMock->shouldReceive('delete')
|
|
->once()
|
|
->with('brand:code:PRD01');
|
|
$cacheMock->shouldReceive('delete')
|
|
->once()
|
|
->with('brand:arcadia:30');
|
|
|
|
/** @var \Psr\Log\LoggerInterface&Mockery\MockInterface $loggerMock */
|
|
$loggerMock = Mockery::mock(\Psr\Log\LoggerInterface::class);
|
|
$loggerMock->shouldReceive('warning')->zeroOrMoreTimes();
|
|
$brandCache = new BrandCache($cacheMock, $loggerMock);
|
|
|
|
// WHEN
|
|
$brandCache->invalidate($brand);
|
|
|
|
// THEN
|
|
expect(true)->toBeTrue();
|
|
});
|
|
|
|
it('resets all brand caches when reset is called', function (): void {
|
|
// GIVEN
|
|
$uuid = Uuid::uuid7()->toString();
|
|
$cacheData = [
|
|
[
|
|
'id' => $uuid,
|
|
'name' => 'Brand 1',
|
|
'code' => 'BRD01',
|
|
'arcadiaId' => '1',
|
|
],
|
|
];
|
|
|
|
/** @var CacheInterface&Mockery\MockInterface $cacheMock */
|
|
$cacheMock = Mockery::mock(CacheInterface::class);
|
|
$cacheMock->shouldReceive('get')
|
|
->once()
|
|
->with('brand:all')
|
|
->andReturn($cacheData);
|
|
|
|
$cacheMock->shouldReceive('delete')
|
|
->once()
|
|
->with('brand:all');
|
|
$cacheMock->shouldReceive('delete')
|
|
->once()
|
|
->with("brand:id:{$uuid}");
|
|
$cacheMock->shouldReceive('delete')
|
|
->once()
|
|
->with('brand:code:BRD01');
|
|
$cacheMock->shouldReceive('delete')
|
|
->once()
|
|
->with('brand:arcadia:1');
|
|
|
|
/** @var \Psr\Log\LoggerInterface&Mockery\MockInterface $loggerMock */
|
|
$loggerMock = Mockery::mock(\Psr\Log\LoggerInterface::class);
|
|
$loggerMock->shouldReceive('warning')->zeroOrMoreTimes();
|
|
$brandCache = new BrandCache($cacheMock, $loggerMock);
|
|
|
|
// WHEN
|
|
$brandCache->reset();
|
|
|
|
// THEN
|
|
expect(true)->toBeTrue();
|
|
});
|
|
it('returns null and logs warning when getById throws exception', function (): void {
|
|
// GIVEN
|
|
$brandId = new BrandId(Uuid::uuid7());
|
|
/** @var CacheInterface&\Mockery\MockInterface $cacheMock */
|
|
$cacheMock = Mockery::mock(CacheInterface::class);
|
|
$cacheMock->shouldReceive('get')->andThrow(new \RuntimeException('Redis error'));
|
|
|
|
/** @var \Psr\Log\LoggerInterface&\Mockery\MockInterface $loggerMock */
|
|
$loggerMock = Mockery::mock(\Psr\Log\LoggerInterface::class);
|
|
$loggerMock->shouldReceive('warning')->once();
|
|
|
|
$brandCache = new BrandCache($cacheMock, $loggerMock);
|
|
|
|
// WHEN
|
|
$result = $brandCache->getById($brandId);
|
|
|
|
// THEN
|
|
expect($result)->toBeNull();
|
|
});
|
|
|
|
it('logs warning and does not throw when put throws exception', function (): void {
|
|
// GIVEN
|
|
$brand = Brand::hydrate(
|
|
id: new BrandId(Uuid::uuid7()),
|
|
name: new BrandName('Ghost'),
|
|
code: new BrandCode('GHO01'),
|
|
arcadiaId: new ArcadiaId('999'),
|
|
);
|
|
/** @var CacheInterface&\Mockery\MockInterface $cacheMock */
|
|
$cacheMock = Mockery::mock(CacheInterface::class);
|
|
$cacheMock->shouldReceive('set')->andThrow(new \RuntimeException('Redis error'));
|
|
|
|
/** @var \Psr\Log\LoggerInterface&\Mockery\MockInterface $loggerMock */
|
|
$loggerMock = Mockery::mock(\Psr\Log\LoggerInterface::class);
|
|
$loggerMock->shouldReceive('warning')->once();
|
|
|
|
$brandCache = new BrandCache($cacheMock, $loggerMock);
|
|
|
|
// WHEN
|
|
$brandCache->put($brand);
|
|
|
|
// THEN
|
|
// No exception is thrown
|
|
expect(true)->toBeTrue();
|
|
});
|
|
});
|