Skip to content

Commit

Permalink
Add Console Command to Load Elasticsearch fixtures (#23)
Browse files Browse the repository at this point in the history
* Add Console Command to Load Elasticsearch fixtures

* Update paramters.yml

* Improve console commands description

* Remove DoctrineCacheBundle because its not used

* Remove deprecations and get rid of getNameByAlias method in commands

* Introduce withHeader and withServerParameter in RequestBuilder
  • Loading branch information
joaoalves-kununu authored Apr 23, 2021
1 parent 08fee40 commit de008dc
Show file tree
Hide file tree
Showing 32 changed files with 844 additions and 504 deletions.
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,34 @@ final class IntegrationTest extends FixturesAwareTestCase
}
```

#### Command to load Elasticsearch fixtures

This bundles can automatically create a command to load Elasticsearch fixtures.

```
php bin/console kununu_testing:load_fixtures:elastic_search:MY_INDEX_ALIAS [--append]
```

There is the need to define the files with the fixtures in the configuration of the bundle

```
# kununu_testing.yaml
kununu_testing:
elastic_search:
my_index_alias:
load_command_fixtures_classes_namespace:
- 'Kununu\TestingBundle\Tests\App\Fixtures\ElasticSearch\ElasticSearchFixture2' # FQDN for a fixtures class
```

Then the fixtures can be loaded running:

```
php bin/console kununu_testing:load_fixtures:elastic_search:my_index_alias --append
```

If `--append` option is not used, then the Elasticsearch index will be truncated. A prompt appears to confirm index truncation.

## Initializable Fixtures

Since this bundle is using the [KununuDataFixtures](https://github.com/kununu/data-fixtures) package, it also has support for initializable features, allowing you to inject arguments into your feature classes (see documentation at the KununuDataFixtures package).
Expand Down
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
"symfony/http-kernel": "^4.3"
},
"require-dev": {
"ext-json": "*",
"doctrine/doctrine-bundle": "^1.10 || ^2.0",
"elasticsearch/elasticsearch": "~7.0",
"kununu/scripts": "^1.1",
"matthiasnoback/symfony-dependency-injection-test": "^4.0",
"phpunit/phpunit": "^8.1",
"symfony/browser-kit": "^4.3"
"symfony/browser-kit": "^4.3",
"symfony/phpunit-bridge": "^5.2"
},
"suggest": {
"ext-pdo_sqlite": "To run Integration Tests.",
Expand Down
4 changes: 4 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
</whitelist>
</filter>

<listeners>
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener"/>
</listeners>

<logging>
<log type="coverage-clover" target="tests/.results/tests-clover.xml"/>
<log type="junit" target="tests/.results/tests-junit.xml"/>
Expand Down
12 changes: 12 additions & 0 deletions src/Command/LoadConnectionFixturesCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);

namespace Kununu\TestingBundle\Command;

final class LoadConnectionFixturesCommand extends LoadFixturesCommand
{
protected static function getFixtureType(): string
{
return 'connections';
}
}
12 changes: 12 additions & 0 deletions src/Command/LoadElasticsearchFixturesCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);

namespace Kununu\TestingBundle\Command;

final class LoadElasticsearchFixturesCommand extends LoadFixturesCommand
{
protected static function getFixtureType(): string
{
return 'elastic_search';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,47 +10,60 @@
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

final class LoadDatabaseFixturesCommand extends Command
abstract class LoadFixturesCommand extends Command
{
private $connectionName;
private $alias;
private $orchestrator;
private $fixturesClassNames;

public function __construct(string $connectionName, Orchestrator $orchestrator, array $fixturesClassNames)
public function __construct(string $alias, Orchestrator $orchestrator, array $fixturesClassNames)
{
parent::__construct(sprintf('kununu_testing:load_fixtures:connections:%s', $connectionName));
$this->alias = $alias;

parent::__construct(sprintf('kununu_testing:load_fixtures:%s:%s', static::getFixtureType(), $alias));

$this->connectionName = $connectionName;
$this->orchestrator = $orchestrator;
$this->fixturesClassNames = $fixturesClassNames;
}

protected function configure(): void
abstract protected static function getFixtureType(): string;

final protected function configure(): void
{
parent::configure();

$this
->setDescription('Load Database Fixtures')
->addOption('append', null, InputOption::VALUE_NONE, 'Append the data fixtures instead of deleting all data from the database first.');
->setDescription(sprintf('Load "%s" default fixtures for alias "%s"', static::getFixtureType(), $this->alias))
->addOption('append', null, InputOption::VALUE_NONE, 'Append the fixtures instead of purging the storage');
}

protected function execute(InputInterface $input, OutputInterface $output): void
final protected function execute(InputInterface $input, OutputInterface $output): int
{
$fixtureType = static::getFixtureType();

$appendOption = $input->getOption('append');

$ui = new SymfonyStyle($input, $output);

if (!$appendOption &&
!$ui->confirm(
sprintf('Careful, database "%s" will be purged. Do you want to continue?', $this->connectionName),
sprintf('Careful, Fixture type "%s" named "%s" will be purged. Do you want to continue?', $fixtureType, $this->alias),
!$input->isInteractive()
)
) {
return;
return 0;
}

$this->orchestrator->execute($this->fixturesClassNames, $appendOption);

$output->writeln(sprintf('Fixtures loaded with success for connection "%s"', $this->connectionName));
$output->writeln(
sprintf(
'Fixtures loaded with success for Fixture type "%s" named "%s"',
$fixtureType,
$this->alias
)
);

return 0;
}
}
1 change: 0 additions & 1 deletion src/DependencyInjection/Compiler/CachePoolCompilerPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ private function buildCachePoolOrchestrator(ContainerBuilder $container, string
Orchestrator::class,
[
new Reference($executorId),
new Reference($purgerId),
new Reference($loaderId),
]
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,21 @@
use Kununu\DataFixtures\Executor\ConnectionExecutor;
use Kununu\DataFixtures\Loader\ConnectionFixturesLoader;
use Kununu\DataFixtures\Purger\ConnectionPurger;
use Kununu\TestingBundle\Command\LoadDatabaseFixturesCommand;
use Kununu\TestingBundle\Command\LoadConnectionFixturesCommand;
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 DoctrineCompilerPass implements CompilerPassInterface
final class ConnectionCompilerPass implements CompilerPassInterface
{
use LoadFixturesCommandsTrait;

private const EXCLUDED_TABLES_CONFIG = 'excluded_tables';
private const LOAD_COMMAND_FIXTURES_CLASSES_NAMESPACE_CONFIG = 'load_command_fixtures_classes_namespace';

private const ORCHESTRATOR_SERVICE_PREFIX = 'kununu_testing.orchestrator.connections';

private const LOAD_FIXTURES_COMMAND_SERVICE_PREFIX = 'kununu_testing.command.load_fixtures.connections';
private const LOAD_FIXTURES_COMMAND_PREFIX = 'kununu_testing:load_fixtures:connections';

public function process(ContainerBuilder $container): void
{
if (!$container->hasParameter('doctrine.connections')) {
Expand All @@ -40,20 +38,40 @@ public function process(ContainerBuilder $container): void
continue;
}

$connConfigs = $container->getParameter($connConfigsParameterName);

$orchestratorId = $this->buildConnectionOrchestrator($container, $connName, $connConfigs, $connId);
$this->buildConnectionLoadFixturesCommand($container, $connName, $connConfigs, $orchestratorId);
$this->buildContainerDefinitions(
$container,
$connId,
$connName,
$container->getParameter($connConfigsParameterName)
);
}
}

private function buildContainerDefinitions(
ContainerBuilder $container,
string $connId,
string $connName,
array $connConfig
): void {
$orchestratorId = $this->buildConnectionOrchestrator($container, $connId, $connName, $connConfig);

$this->buildLoadFixturesCommand(
$container,
'connections',
$orchestratorId,
LoadConnectionFixturesCommand::class,
$connName,
$connConfig[self::LOAD_COMMAND_FIXTURES_CLASSES_NAMESPACE_CONFIG] ?? []
);
}

private function buildConnectionOrchestrator(
ContainerBuilder $container,
string $id,
string $connName,
array $connConfigs,
string $id
array $connConfig
): string {
$excludedTables = empty($connConfigs[self::EXCLUDED_TABLES_CONFIG]) ? [] : $connConfigs[self::EXCLUDED_TABLES_CONFIG];
$excludedTables = $connConfig[self::EXCLUDED_TABLES_CONFIG] ?? [];

/** @var Connection $connection */
$connection = new Reference($id);
Expand All @@ -77,7 +95,6 @@ private function buildConnectionOrchestrator(
Orchestrator::class,
[
new Reference($executorId),
new Reference($purgerId),
new Reference($loaderId),
]
);
Expand All @@ -89,38 +106,4 @@ private function buildConnectionOrchestrator(

return $orchestratorId;
}

private function buildConnectionLoadFixturesCommand(
ContainerBuilder $container,
string $connName,
array $connConfigs,
string $orchestratorId
): void {
// Connection does not have fixtures configured for LoadDatabaseFixturesCommand
if (!isset($connConfigs[self::LOAD_COMMAND_FIXTURES_CLASSES_NAMESPACE_CONFIG]) ||
empty($connConfigs[self::LOAD_COMMAND_FIXTURES_CLASSES_NAMESPACE_CONFIG])
) {
return;
}

$connectionLoadFixturesDefinition = new Definition(
LoadDatabaseFixturesCommand::class,
[
$connName,
new Reference($orchestratorId),
$connConfigs[self::LOAD_COMMAND_FIXTURES_CLASSES_NAMESPACE_CONFIG],
]
);
$connectionLoadFixturesDefinition->setPublic(true);
$connectionLoadFixturesDefinition->setTags(
['console.command' => [
['command' => sprintf('%s:%s', self::LOAD_FIXTURES_COMMAND_PREFIX, $connName)], ],
]
);

$container->setDefinition(
sprintf('%s.%s', self::LOAD_FIXTURES_COMMAND_SERVICE_PREFIX, $connName),
$connectionLoadFixturesDefinition
);
}
}
32 changes: 28 additions & 4 deletions src/DependencyInjection/Compiler/ElasticSearchCompilerPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Kununu\DataFixtures\Executor\ElasticSearchExecutor;
use Kununu\DataFixtures\Loader\ElasticSearchFixturesLoader;
use Kununu\DataFixtures\Purger\ElasticSearchPurger;
use Kununu\TestingBundle\Command\LoadElasticsearchFixturesCommand;
use Kununu\TestingBundle\Service\Orchestrator;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
Expand All @@ -15,7 +16,10 @@

final class ElasticSearchCompilerPass implements CompilerPassInterface
{
use LoadFixturesCommandsTrait;

private const SERVICE_PREFIX = 'kununu_testing.orchestrator.elastic_search';
private const LOAD_COMMAND_FIXTURES_CLASSES_NAMESPACE_CONFIG = 'load_command_fixtures_classes_namespace';

public function process(ContainerBuilder $container): void
{
Expand All @@ -26,12 +30,29 @@ public function process(ContainerBuilder $container): void
$indexes = $container->getParameter('kununu_testing.elastic_search');

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

private function buildElasticSearchOrchestrator(ContainerBuilder $container, string $alias, string $indexName, string $id): void
private function buildContainerDefinitions(ContainerBuilder $containerBuilder, string $alias, array $config): void
{
$orchestratorId = $this->buildElasticSearchOrchestrator($containerBuilder, $alias, $config);

$this->buildLoadFixturesCommand(
$containerBuilder,
'elastic_search',
$orchestratorId,
LoadElasticsearchFixturesCommand::class,
$alias,
$config[self::LOAD_COMMAND_FIXTURES_CLASSES_NAMESPACE_CONFIG] ?? []
);
}

private function buildElasticSearchOrchestrator(ContainerBuilder $container, string $alias, array $config): string
{
$indexName = $config['index_name'];
$id = $config['service'];

/** @var Client $client */
$client = new Reference($id);

Expand All @@ -54,12 +75,15 @@ private function buildElasticSearchOrchestrator(ContainerBuilder $container, str
Orchestrator::class,
[
new Reference($executorId),
new Reference($purgerId),
new Reference($loaderId),
]
);
$connectionOrchestratorDefinition->setPublic(true);

$container->setDefinition(sprintf('%s.%s', self::SERVICE_PREFIX, $alias), $connectionOrchestratorDefinition);
$orchestratorId = sprintf('%s.%s', self::SERVICE_PREFIX, $alias);

$container->setDefinition($orchestratorId, $connectionOrchestratorDefinition);

return $orchestratorId;
}
}
Loading

0 comments on commit de008dc

Please sign in to comment.