Skip to content

Commit

Permalink
Introduce Elasticsearch Fixtures (#6)
Browse files Browse the repository at this point in the history
* Introduce Elasticsearch Fixtures

* Update tests and readme

* Add final keyword

* Update composer

* Provide  to ElasticSearchExecutor & update tests

* Update readme

* Define data-fixtures package dependency version

* Address code review

* Apply Code Standards

* Format config

* Update parameters.yml
  • Loading branch information
joaoalves-kununu authored Aug 21, 2019
1 parent 0f2c3a3 commit 12f9ac6
Show file tree
Hide file tree
Showing 28 changed files with 673 additions and 121 deletions.
61 changes: 60 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,59 @@ final class IntegrationTest extends FixturesAwareTestCase
}
```

### Elasticsearch Fixtures

If you want to load Elasticsearch fixtures in your tests first you will need to configure the bundle:

```
kununu_testing:
elastic_search:
my_index_alias:
service: 'My\Elasticsearch\Client'
index_name: 'my_index_name'
```

In your tests you can extend the classes `FixturesAwareTestCase` or `WebTestCase` which expose the following method:

```
loadElasticSearchFixtures(string $alias, array $classNames = [], bool $append = false)
```

- `$alias` - Alias defined above
- `$classNames` - Array with classes names of fixtures to load
- `$append` - If `false` the cache pool will be purged before loading your fixtures

**Example**

```
use Kununu\TestingBundle\Test\FixturesAwareTestCase;
final class IntegrationTest extends FixturesAwareTestCase
{
public function testIntegration()
{
// Start with an empty index and loading data from Fixture1
$this->loadElasticSearchFixtures(
'my_index_alias',
[Fixture1::class]
);
// Start from a empty index
$this->loadElasticSearchFixtures(
'my_index_alias',
[]
);
// Do not purge index before loading fixtures
$this->loadElasticSearchFixtures(
'my_index_alias',
[Fixture1::class],
true
);
}
}
```

## Making a Request

The class `WebTestCase` exposes two methods that help you testing your controllers:
Expand Down Expand Up @@ -168,6 +221,11 @@ kununu_testing:
connection_name:
excluded_tables:
- table_to_exclude_from_purge
elastic_search:
my_index_alias: # Alias to be use to load fixtures for the configured index using the defined service
service: 'Kununu\TestingBundle\Tests\App\ElasticSearch' # Service Id of an instance of Elasticsearch\Client
index_name: 'my_index_name' # name of your index
```

## Tests
Expand All @@ -182,4 +240,5 @@ kununu test lib testing-bundle [--exclude-group integration]
vendor/phpunit/phpunit/phpunit tests [--exclude-group integration]
```

**If you want to run the integration tests you will need the extension `ext-pdo_sqlite`.**
**If you want to run the integration tests you will need the extension `ext-pdo_sqlite`.**
**If you want to run the integration tests you will need to have an Elasticsearch cluster running. To change the hosts of the cluster please go to `tests/App/config/packages/parameters.yml`.**
8 changes: 5 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"require": {
"php": "^7.2",
"symfony/framework-bundle": "^4.3",
"kununu/data-fixtures": "^2.0.0",
"kununu/data-fixtures": "^3.0",
"symfony/config": "^4.3",
"symfony/dependency-injection": "^4.3",
"symfony/http-kernel": "^4.3"
Expand All @@ -14,10 +14,12 @@
"phpunit/phpunit": "^8.1",
"matthiasnoback/symfony-dependency-injection-test": "^4.0",
"doctrine/doctrine-bundle": "^1.10",
"symfony/browser-kit": "^4.3"
"symfony/browser-kit": "^4.3",
"elasticsearch/elasticsearch": "~7.0"
},
"suggest": {
"ext-pdo_sqlite": "To run Integration Tests."
"ext-pdo_sqlite": "To run Integration Tests.",
"elasticsearch/elasticsearch": "To run Integration Tests."
},
"autoload": {
"psr-4": {
Expand Down
10 changes: 5 additions & 5 deletions src/DependencyInjection/Compiler/CachePoolCompilerPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ final class CachePoolCompilerPass implements CompilerPassInterface
{
private const SERVICE_PREFIX = 'kununu_testing.orchestrator.cache_pools';

public function process(ContainerBuilder $container)
public function process(ContainerBuilder $container): void
{
$cachePoolServices = $container->findTaggedServiceIds('cache.pool');

Expand All @@ -29,23 +29,23 @@ public function process(ContainerBuilder $container)
}
}

private function buildCachePoolOrchestrator(ContainerBuilder $container, string $id) : void
private function buildCachePoolOrchestrator(ContainerBuilder $container, string $id): void
{
/** @var CacheItemPoolInterface $cachePool */
$cachePool = new Reference($id);

// Purger Definition for the CachePool with provided $id
$purgerId = sprintf('%s.%s.purger',self::SERVICE_PREFIX, $id);
$purgerId = sprintf('%s.%s.purger', self::SERVICE_PREFIX, $id);
$purgerDefinition = new Definition(CachePoolPurger::class, [$cachePool]);
$container->setDefinition($purgerId, $purgerDefinition);

// Executor Definition for the CachePool with provided $id
$executorId = sprintf('%s.%s.executor',self::SERVICE_PREFIX, $id);
$executorId = sprintf('%s.%s.executor', self::SERVICE_PREFIX, $id);
$executorDefinition = new Definition(CachePoolExecutor::class, [$cachePool, new Reference($purgerId)]);
$container->setDefinition($executorId, $executorDefinition);

// Loader Definition for the CachePool with provided $id
$loaderId = sprintf('%s.%s.loader',self::SERVICE_PREFIX, $id);
$loaderId = sprintf('%s.%s.loader', self::SERVICE_PREFIX, $id);
$loaderDefinition = new Definition(CachePoolFixturesLoader::class);
$container->setDefinition($loaderId, $loaderDefinition);

Expand Down
10 changes: 5 additions & 5 deletions src/DependencyInjection/Compiler/DoctrineCompilerPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ final class DoctrineCompilerPass implements CompilerPassInterface
{
private const SERVICE_PREFIX = 'kununu_testing.orchestrator.connections';

public function process(ContainerBuilder $container)
public function process(ContainerBuilder $container): void
{
if (!$container->hasParameter('doctrine.connections')) {
return;
Expand All @@ -29,7 +29,7 @@ public function process(ContainerBuilder $container)
}
}

private function buildConnectionOrchestrator(ContainerBuilder $container, string $connName, string $id) : void
private function buildConnectionOrchestrator(ContainerBuilder $container, string $connName, string $id): void
{
$excludedTables = [];

Expand All @@ -44,17 +44,17 @@ private function buildConnectionOrchestrator(ContainerBuilder $container, string
$connection = new Reference($id);

// Purger Definition for the Connection with provided $id
$purgerId = sprintf('%s.%s.purger',self::SERVICE_PREFIX, $connName);
$purgerId = sprintf('%s.%s.purger', self::SERVICE_PREFIX, $connName);
$purgerDefinition = new Definition(ConnectionPurger::class, [$connection, $excludedTables]);
$container->setDefinition($purgerId, $purgerDefinition);

// Executor Definition for the Connection with provided $id
$executorId = sprintf('%s.%s.executor',self::SERVICE_PREFIX, $connName);
$executorId = sprintf('%s.%s.executor', self::SERVICE_PREFIX, $connName);
$executorDefinition = new Definition(ConnectionExecutor::class, [$connection, new Reference($purgerId)]);
$container->setDefinition($executorId, $executorDefinition);

// Loader Definition for the Connection with provided $id
$loaderId = sprintf('%s.%s.loader',self::SERVICE_PREFIX, $connName);
$loaderId = sprintf('%s.%s.loader', self::SERVICE_PREFIX, $connName);
$loaderDefinition = new Definition(ConnectionFixturesLoader::class);
$container->setDefinition($loaderId, $loaderDefinition);

Expand Down
64 changes: 64 additions & 0 deletions src/DependencyInjection/Compiler/ElasticSearchCompilerPass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php declare(strict_types=1);

namespace Kununu\TestingBundle\DependencyInjection\Compiler;

use Elasticsearch\Client;
use Kununu\DataFixtures\Executor\ElasticSearchExecutor;
use Kununu\DataFixtures\Loader\ElasticSearchFixturesLoader;
use Kununu\DataFixtures\Purger\ElasticSearchPurger;
use Kununu\TestingBundle\Service\Orchestrator;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;

final class ElasticSearchCompilerPass implements CompilerPassInterface
{
private const SERVICE_PREFIX = 'kununu_testing.orchestrator.elastic_search';

public function process(ContainerBuilder $container): void
{
if (!$container->hasParameter('kununu_testing.elastic_search')) {
return;
}

$indexes = $container->getParameter('kununu_testing.elastic_search');

foreach ($indexes as $alias => $config) {
$this->buildElasticSearchOrchestrator($container, $alias, $config['index_name'], $config['service']);
}
}

private function buildElasticSearchOrchestrator(ContainerBuilder $container, string $alias, string $indexName, string $id): void
{
/** @var Client $client */
$client = new Reference($id);

// Purger Definition
$purgerId = sprintf('%s.%s.purger', self::SERVICE_PREFIX, $alias);
$purgerDefinition = new Definition(ElasticSearchPurger::class, [$client, $indexName]);
$container->setDefinition($purgerId, $purgerDefinition);

// Executor Definition
$executorId = sprintf('%s.%s.executor', self::SERVICE_PREFIX, $alias);
$executorDefinition = new Definition(ElasticSearchExecutor::class, [$client, $indexName, new Reference($purgerId)]);
$container->setDefinition($executorId, $executorDefinition);

// Loader definition
$loaderId = sprintf('%s.%s.loader', self::SERVICE_PREFIX, $alias);
$loaderDefinition = new Definition(ElasticSearchFixturesLoader::class);
$container->setDefinition($loaderId, $loaderDefinition);

$connectionOrchestratorDefinition = new Definition(
Orchestrator::class,
[
new Reference($executorId),
new Reference($purgerId),
new Reference($loaderId),
]
);
$connectionOrchestratorDefinition->setPublic(true);

$container->setDefinition(sprintf('%s.%s', self::SERVICE_PREFIX, $alias), $connectionOrchestratorDefinition);
}
}
16 changes: 16 additions & 0 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,22 @@ public function getConfigTreeBuilder()
->end()
->end()
->end()
->arrayNode('elastic_search')
->requiresAtLeastOneElement()
->useAttributeAsKey('name')
->arrayPrototype()
->children()
->scalarNode('service')
->isRequired()
->cannotBeEmpty()
->end()
->scalarNode('index_name')
->isRequired()
->cannotBeEmpty()
->end()
->end()
->end()
->end()
->end()
;

Expand Down
6 changes: 5 additions & 1 deletion src/DependencyInjection/KununuTestingExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

final class KununuTestingExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
public function load(array $configs, ContainerBuilder $container): void
{
$configuration = new Configuration();

Expand All @@ -21,5 +21,9 @@ public function load(array $configs, ContainerBuilder $container)
);
}
}

if (!empty($config['elastic_search'])) {
$container->setParameter('kununu_testing.elastic_search', $config['elastic_search']);
}
}
}
4 changes: 3 additions & 1 deletion src/KununuTestingBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@

use Kununu\TestingBundle\DependencyInjection\Compiler\CachePoolCompilerPass;
use Kununu\TestingBundle\DependencyInjection\Compiler\DoctrineCompilerPass;
use Kununu\TestingBundle\DependencyInjection\Compiler\ElasticSearchCompilerPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;

final class KununuTestingBundle extends Bundle
{
public function build(ContainerBuilder $container)
public function build(ContainerBuilder $container): void
{
parent::build($container);

$container->addCompilerPass(new CachePoolCompilerPass());
$container->addCompilerPass(new DoctrineCompilerPass());
$container->addCompilerPass(new ElasticSearchCompilerPass());
}
}
2 changes: 1 addition & 1 deletion src/Service/Orchestrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public function __construct(ExecutorInterface $executor, PurgerInterface $purger
$this->loader = $loader;
}

public function execute(array $fixturesClassNames, bool $append) : void
public function execute(array $fixturesClassNames, bool $append): void
{
foreach ($fixturesClassNames as $className) {
$this->loader->loadFromClassName($className);
Expand Down
14 changes: 11 additions & 3 deletions src/Test/FixturesAwareTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,31 @@

abstract class FixturesAwareTestCase extends BaseWebTestCase
{
final protected function loadDbFixtures(string $connectionName, array $classNames = [], bool $append = false)
final protected function loadDbFixtures(string $connectionName, array $classNames = [], bool $append = false): void
{
/** @var Orchestrator $orchestrator */
$orchestrator = $this->getContainer()->get(sprintf('kununu_testing.orchestrator.connections.%s', $connectionName));

$orchestrator->execute($classNames, $append);
}

final protected function loadCachePoolFixtures(string $cachePoolServiceId, array $classNames = [], bool $append = false) : void
final protected function loadCachePoolFixtures(string $cachePoolServiceId, array $classNames = [], bool $append = false): void
{
/** @var Orchestrator $orchestrator */
$orchestrator = $this->getContainer()->get(sprintf('kununu_testing.orchestrator.cache_pools.%s', $cachePoolServiceId));

$orchestrator->execute($classNames, $append);
}

final protected function getContainer() : ContainerInterface
final protected function loadElasticSearchFixtures(string $alias, array $classNames = [], bool $append = false): void
{
/** @var Orchestrator $orchestrator */
$orchestrator = $this->getContainer()->get(sprintf('kununu_testing.orchestrator.elastic_search.%s', $alias));

$orchestrator->execute($classNames, $append);
}

final protected function getContainer(): ContainerInterface
{
if (!static::$kernel || !static::$container) {
static::createClient();
Expand Down
4 changes: 2 additions & 2 deletions src/Test/WebTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ final protected function doRequest(RequestBuilder $builder): Response
$response = $this->client->getResponse();

// Since there is no content, then there is also no content-type header.
if ($response->getStatusCode() !== Response::HTTP_NO_CONTENT) {
if (Response::HTTP_NO_CONTENT !== $response->getStatusCode()) {
$this->assertTrue(
$response->headers->contains(
'Content-type',
Expand All @@ -32,7 +32,7 @@ final protected function doRequest(RequestBuilder $builder): Response
return $response;
}

private function initClient() : void
private function initClient(): void
{
if (!$this->client) {
$this->client = static::createClient();
Expand Down
16 changes: 16 additions & 0 deletions tests/App/ElasticSearch/ClientFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php declare(strict_types=1);

namespace Kununu\TestingBundle\Tests\App\ElasticSearch;

use Elasticsearch\Client;
use Elasticsearch\ClientBuilder;

final class ClientFactory
{
public static function getInstance(array $hosts): Client
{
return ClientBuilder::create()
->setHosts($hosts)
->build();
}
}
Loading

0 comments on commit 12f9ac6

Please sign in to comment.