Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ Latest
------

### Changes
* [#20](https://github.com/cleverage/cache-process-bundle/issues/20) Add missing tests: GetTask and SetTask (options validation at initialization, context, missing adapter, stored `null`, overwriting), custom tasks extending AbstractCacheTask, Adapter, bundle and DI extension.
* [#25](https://github.com/cleverage/cache-process-bundle/issues/25) Give the ids of both services in the error on duplicate adapter codes: the adapters are registered by a compiler pass of the bundle, `AdapterRegistry::addAdapter()` gets an optional `$serviceId` argument. Update documentation, add tests.

### Fixes
Expand Down
93 changes: 93 additions & 0 deletions tests/Adapter/AdapterTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?php

declare(strict_types=1);

/*
* This file is part of the CleverAge/CacheProcessBundle package.
*
* Copyright (c) Clever-Age
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace CleverAge\CacheProcessBundle\Tests\Adapter;

use CleverAge\CacheProcessBundle\Adapter\Adapter;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Cache\Adapter\ArrayAdapter;

#[CoversClass(Adapter::class)]
class AdapterTest extends TestCase
{
private ArrayAdapter $pool;

private Adapter $adapter;

protected function setUp(): void
{
$this->pool = new ArrayAdapter();
$this->adapter = new Adapter($this->pool, 'memory');
}

public function testGetCode(): void
{
self::assertSame('memory', $this->adapter->getCode());
}

public function testSaveAndGetItem(): void
{
self::assertFalse($this->adapter->getItem('key1')->isHit());

self::assertTrue($this->adapter->save($this->adapter->getItem('key1')->set('value1')));

self::assertTrue($this->adapter->hasItem('key1'));
self::assertSame('value1', $this->adapter->getItem('key1')->get());
// Stored in the decorated pool
self::assertSame('value1', $this->pool->getItem('key1')->get());
}

public function testGetItems(): void
{
$this->pool->save($this->pool->getItem('key1')->set('value1'));

$values = [];
foreach ($this->adapter->getItems(['key1', 'key2']) as $key => $item) {
$values[$key] = $item->get();
}

self::assertSame(['key1' => 'value1', 'key2' => null], $values);
}

public function testSaveDeferredAndCommit(): void
{
self::assertTrue($this->adapter->saveDeferred($this->adapter->getItem('key1')->set('value1')));
self::assertTrue($this->adapter->commit());

self::assertSame('value1', $this->pool->getItem('key1')->get());
}

public function testDeleteItems(): void
{
foreach (['key1', 'key2', 'key3'] as $key) {
$this->pool->save($this->pool->getItem($key)->set($key));
}

self::assertTrue($this->adapter->deleteItem('key1'));
self::assertTrue($this->adapter->deleteItems(['key2']));

self::assertFalse($this->pool->hasItem('key1'));
self::assertFalse($this->pool->hasItem('key2'));
self::assertTrue($this->pool->hasItem('key3'));
}

public function testClear(): void
{
$this->pool->save($this->pool->getItem('key1')->set('value1'));

self::assertTrue($this->adapter->clear());

self::assertFalse($this->pool->hasItem('key1'));
}
}
44 changes: 44 additions & 0 deletions tests/CleverAgeCacheProcessBundleTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

/*
* This file is part of the CleverAge/CacheProcessBundle package.
*
* Copyright (c) Clever-Age
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace CleverAge\CacheProcessBundle\Tests;

use CleverAge\CacheProcessBundle\CleverAgeCacheProcessBundle;
use CleverAge\CacheProcessBundle\DependencyInjection\Compiler\RegisterAdaptersPass;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\ContainerBuilder;

#[CoversClass(CleverAgeCacheProcessBundle::class)]
class CleverAgeCacheProcessBundleTest extends TestCase
{
public function testPathIsTheBundleRoot(): void
{
$path = (new CleverAgeCacheProcessBundle())->getPath();

self::assertSame(\dirname(__DIR__), $path);
self::assertDirectoryExists($path.'/config/services');
}

public function testAdaptersPassIsRegistered(): void
{
$container = new ContainerBuilder();
(new CleverAgeCacheProcessBundle())->build($container);

$passes = array_filter(
$container->getCompilerPassConfig()->getBeforeOptimizationPasses(),
static fn (object $pass): bool => $pass instanceof RegisterAdaptersPass
);
self::assertCount(1, $passes);
}
}
68 changes: 68 additions & 0 deletions tests/DependencyInjection/CleverAgeCacheProcessExtensionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

declare(strict_types=1);

/*
* This file is part of the CleverAge/CacheProcessBundle package.
*
* Copyright (c) Clever-Age
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace CleverAge\CacheProcessBundle\Tests\DependencyInjection;

use CleverAge\CacheProcessBundle\DependencyInjection\CleverAgeCacheProcessExtension;
use CleverAge\CacheProcessBundle\Registry\AdapterRegistry;
use CleverAge\CacheProcessBundle\Task\GetTask;
use CleverAge\CacheProcessBundle\Task\SetTask;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

#[CoversClass(CleverAgeCacheProcessExtension::class)]
class CleverAgeCacheProcessExtensionTest extends TestCase
{
public function testRegistryIsRegistered(): void
{
$container = new ContainerBuilder();
(new CleverAgeCacheProcessExtension())->load([], $container);

$definition = $container->getDefinition('cleverage_cache_process.registry.adapter');
self::assertSame(AdapterRegistry::class, $definition->getClass());
self::assertTrue($definition->isShared());
}

/**
* @return iterable<string, array{string, class-string}>
*/
public static function provideTasks(): iterable
{
yield 'get' => ['cleverage_cache_process.task.get', GetTask::class];
yield 'set' => ['cleverage_cache_process.task.set', SetTask::class];
}

/**
* @param class-string $class
*/
#[DataProvider('provideTasks')]
public function testTaskIsRegistered(string $id, string $class): void
{
$container = new ContainerBuilder();
(new CleverAgeCacheProcessExtension())->load([], $container);

$definition = $container->getDefinition($id);
self::assertSame($class, $definition->getClass());
// Tasks are stateful: each process execution must get its own instance
self::assertFalse($definition->isShared());
self::assertEquals([new Reference('cleverage_cache_process.registry.adapter')], $definition->getArguments());

// Referenced as '@<class>' in process configurations
$alias = $container->getAlias($class);
self::assertSame($id, (string) $alias);
self::assertTrue($alias->isPublic());
}
}
96 changes: 96 additions & 0 deletions tests/Task/AbstractCacheTaskTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php

declare(strict_types=1);

/*
* This file is part of the CleverAge/CacheProcessBundle package.
*
* Copyright (c) Clever-Age
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace CleverAge\CacheProcessBundle\Tests\Task;

use CleverAge\CacheProcessBundle\Registry\AdapterRegistry;
use CleverAge\CacheProcessBundle\Task\AbstractCacheTask;
use CleverAge\ProcessBundle\Configuration\ProcessConfiguration;
use CleverAge\ProcessBundle\Configuration\TaskConfiguration;
use CleverAge\ProcessBundle\Context\ContextualOptionResolver;
use CleverAge\ProcessBundle\Model\ProcessHistory;
use CleverAge\ProcessBundle\Model\ProcessState;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\TestCase;
use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
use Symfony\Component\OptionsResolver\OptionsResolver;

/**
* Custom cache tasks extending AbstractCacheTask get their own options from the input.
*/
#[CoversClass(AbstractCacheTask::class)]
class AbstractCacheTaskTest extends TestCase
{
public function testCustomOptionFromInput(): void
{
[$task, $state] = $this->createTask(['adapter' => 'memory', 'key' => 'key1']);

// Resolved options: the order of the keys is not relevant
self::assertEquals(
['adapter' => 'memory', 'key' => 'key2', 'ttl' => 60],
$this->execute($task, $state, ['key' => 'key2', 'ttl' => 60, 'sku' => 'ignored'])
);
self::assertEquals(['adapter' => 'memory', 'key' => 'key1', 'ttl' => null], $this->execute($task, $state, null));
}

public function testCustomOptionFromInputIsValidated(): void
{
[$task, $state] = $this->createTask(['adapter' => 'memory', 'key' => 'key1']);

$this->expectException(InvalidOptionsException::class);
$this->expectExceptionMessage('The option "ttl" with value "60" is expected to be of type "int" or "null", but is of type "string".');
$this->execute($task, $state, ['ttl' => '60']);
}

/**
* @param array<string, mixed> $options
*
* @return array{AbstractCacheTask, ProcessState}
*/
private function createTask(array $options): array
{
$processConfiguration = new ProcessConfiguration('test', []);
$state = new ProcessState($processConfiguration, new ProcessHistory($processConfiguration));
$state->setContextualOptionResolver(new ContextualOptionResolver());
$state->setContext([]);
$state->setTaskConfiguration(new TaskConfiguration('custom', AbstractCacheTask::class, $options));

$task = new class(new AdapterRegistry()) extends AbstractCacheTask {
public function execute(ProcessState $state): void
{
$state->setOutput($this->getMergedOptions($state));
}

#[\Override]
protected function configureOptions(OptionsResolver $resolver): void
{
parent::configureOptions($resolver);

$resolver->setDefault('ttl', null);
$resolver->setAllowedTypes('ttl', ['int', 'null']);
}
};
$task->initialize($state);

return [$task, $state];
}

private function execute(AbstractCacheTask $task, ProcessState $state, mixed $input): mixed
{
$state->reset(false);
$state->setInput($input);
$task->execute($state);

return $state->getOutput();
}
}
Loading
Loading