Skip to content

Commit

Permalink
implemented configuration check command
Browse files Browse the repository at this point in the history
  • Loading branch information
wachterjohannes committed Jun 12, 2016
1 parent ac40512 commit 15c73ae
Show file tree
Hide file tree
Showing 6 changed files with 325 additions and 3 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ wget http://nanbando.github.io/core/nanbando.phar.pubkey
chmod +x nanbando.phar
mv nanbando.phar /usr/local/bin/nanbando
mv nanbando.phar.pubkey /usr/local/bin/nanbando.pubkey
nanbando check
```

After first installation you can update the application with a built-in command.
Expand Down
7 changes: 6 additions & 1 deletion docs/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ Configuration

The configuration is devided into two parts - global (optional) and project configuration.

.. warning::

After changing configuration please run command ``reconfigure`` to be sure that the configuration will be used for
recreating the symfony container.

Global Configuration
--------------------

Expand Down Expand Up @@ -37,7 +42,7 @@ For nanbando you have to define the local directory, where the backup command ca
remote filesystem-service which can be configured in the ``oneup_flysystem`` extension.

By default the ``local_directory`` will be set to ``%home%/nanbando`` and the ``remote_service`` will be ``null``. This
leads to local backups will work out of the box but all commands (``fetch``, ``push`) which needs the remote-storage
leads to local backups will work out of the box but all commands (``fetch``, ``push``) which needs the remote-storage
will be disabled.

Local Configuration
Expand Down
2 changes: 2 additions & 0 deletions docs/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@ After first installation you can update the application with a built-in command.
.. note::

The executable is signed with a OpenSSL private key. This ensures the origin of the build.

Check the configuration state of your application by using the command ``nanbando check``.
114 changes: 114 additions & 0 deletions src/Bundle/Command/CheckCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<?php

namespace Nanbando\Bundle\Command;

use Nanbando\Core\Plugin\PluginRegistry;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\OptionsResolver\Exception\InvalidArgumentException;
use Symfony\Component\OptionsResolver\OptionsResolver;

class CheckCommand extends ContainerAwareCommand
{
/**
* {@inheritdoc}
*/
protected function configure()
{
$this
->setName('check')
->setDescription('Checks configuration issues')
->setHelp(
<<<EOT
The <info>{$this->getName()}</info> command looks for configuration issues
EOT
);
}

/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);

$io->title('Configuration Check Report');

$io->writeln('Local directory: ' . $this->getContainer()->getParameter('nanbando.storage.local_directory'));

if (!$this->getContainer()->has('filesystem.remote')) {
$io->warning(
'No remote storage configuration found. This leads into disabled "fetch" and "push" commands.' .
'Please follow the documentation for global configuration.' . PHP_EOL . PHP_EOL .
'http://nanbando.readthedocs.io/en/latest/configuration.html#global-configuration'
);
} else {
$io->writeln('Remote Storage: YES');
}

$backups = $this->getContainer()->getParameter('nanbando.backup');
if (0 === count($backups)) {
$io->warning(
'No backup configuration found. Please follow the documentation for local configuration.' . PHP_EOL . PHP_EOL .
'http://nanbando.readthedocs.io/en/latest/configuration.html#local-configuration'
);
}

$this->checkBackups($io, $backups);

$io->writeln('');
}

/**
* Check backup-configuration.
*
* @param SymfonyStyle $io
* @param array $backups
*/
private function checkBackups(SymfonyStyle $io, array $backups)
{
/** @var PluginRegistry $plugins */
$plugins = $this->getContainer()->get('plugins');
foreach ($backups as $name => $backup) {
$this->checkBackup($plugins, $io, $name, $backup);
}
}

/**
* Check single backup-configuration.
*
* @param PluginRegistry $plugins
* @param SymfonyStyle $io
* @param string $name
* @param array $backup
*
* @return bool
*/
private function checkBackup(PluginRegistry $plugins, SymfonyStyle $io, $name, array $backup)
{
$io->section('Backup: ' . $name);
if (!$plugins->has($backup['plugin'])) {
$io->warning(sprintf('Plugin "%s" not found', $backup['plugin']));

return false;
}

$optionsResolver = new OptionsResolver();
$plugins->getPlugin($backup['plugin'])->configureOptionsResolver($optionsResolver);

try {
$optionsResolver->resolve($backup['parameter']);
} catch (InvalidArgumentException $e) {
$io->warning(sprintf('Parameter not valid' . PHP_EOL . PHP_EOL . 'Message: "%s"', $e->getMessage()));

return false;
}

$io->writeln('OK');

return true;
}
}
4 changes: 2 additions & 2 deletions src/Core/Storage/LocalStorage.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ public function remoteListing()
if (!$this->remoteFilesystem) {
throw new RemoteStorageNotConfiguredException();
}

return $this->listing($this->remoteFilesystem);
}

Expand Down Expand Up @@ -167,7 +167,7 @@ public function push($file)
if (!$this->remoteFilesystem) {
throw new RemoteStorageNotConfiguredException();
}

$path = sprintf('%s/%s.zip', $this->name, $file);

if (false === ($stream = $this->localFilesystem->readStream($path))) {
Expand Down
200 changes: 200 additions & 0 deletions tests/Unit/Bundle/Command/CheckCommandTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
<?php

namespace Nanbando\Unit\Bundle\Command;

use Nanbando\Bundle\Command\CheckCommand;
use Nanbando\Core\Plugin\PluginInterface;
use Nanbando\Core\Plugin\PluginRegistry;
use Prophecy\Argument;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class CheckCommandTest extends \PHPUnit_Framework_TestCase
{
/**
* @var ContainerInterface
*/
private $container;

/**
* @var PluginRegistry
*/
private $plugins;

protected function setUp()
{
$this->container = $this->prophesize(ContainerInterface::class);
$this->plugins = $this->prophesize(PluginRegistry::class);
}

private function getCommandTester($remote = false, $backup = [])
{
$this->container->getParameter('nanbando.storage.local_directory')->willReturn('/User/test/nanbando');
$this->container->getParameter('nanbando.backup')->willReturn($backup);
$this->container->has('filesystem.remote')->willReturn($remote);

$this->container->get('plugins')->willReturn($this->plugins->reveal());

$command = new CheckCommand();
$command->setContainer($this->container->reveal());

$application = new Application();
$application->add($command);

$command = $application->find('check');

return new CommandTester($command);
}

public function testExecute()
{
$commandTester = $this->getCommandTester();
$commandTester->execute([]);

$this->assertContains('Local directory: /User/test/nanbando', $commandTester->getDisplay());
$this->assertContains('No remote storage configuration found.', $commandTester->getDisplay());
$this->assertContains('No backup configuration found.', $commandTester->getDisplay());
}

public function testExecuteWithRemote()
{
$commandTester = $this->getCommandTester(true);
$commandTester->execute([]);

$this->assertContains('Local directory: /User/test/nanbando', $commandTester->getDisplay());
$this->assertContains('Remote Storage: YES', $commandTester->getDisplay());
}

public function testExecutePluginNotFound()
{
$this->plugins->has('my-plugin')->willReturn(false);

$commandTester = $this->getCommandTester(true, ['test' => ['plugin' => 'my-plugin']]);
$commandTester->execute([]);

$this->assertContains('Plugin "my-plugin" not found', $commandTester->getDisplay());
}

public function testExecutePluginNotFoundMultiple()
{
$plugin = $this->prophesize(PluginInterface::class);
$plugin->configureOptionsResolver(Argument::type(OptionsResolver::class))->shouldBeCalled();

$this->plugins->has('my-plugin-1')->willReturn(true);
$this->plugins->getPlugin('my-plugin-1')->willReturn($plugin->reveal());
$this->plugins->has('my-plugin-2')->willReturn(false);

$commandTester = $this->getCommandTester(
true,
[
'test-1' => ['plugin' => 'my-plugin-1', 'parameter' => []],
'test-2' => ['plugin' => 'my-plugin-2'],
]
);
$commandTester->execute([]);


$this->assertRegExp('/test-1[-\s]*OK/', $commandTester->getDisplay());
$this->assertRegExp('/test-2[-\s]*\[WARNING\] Plugin "my-plugin-2" not found/', $commandTester->getDisplay());
}

public function testExecuteParameterNotValid()
{
$plugin = $this->prophesize(PluginInterface::class);
$plugin->configureOptionsResolver(Argument::type(OptionsResolver::class))
->will(
function ($args) {
$args[0]->setRequired(['chmod', 'directory']);
}
);

$this->plugins->has('my-plugin')->willReturn(true);
$this->plugins->getPlugin('my-plugin')->willReturn($plugin->reveal());

$commandTester = $this->getCommandTester(
true,
['test' => ['plugin' => 'my-plugin', 'parameter' => ['directory' => '/test']]]
);
$commandTester->execute([]);

$this->assertContains('Parameter not valid', $commandTester->getDisplay());
}

public function testExecuteParameterNotValidMultiple()
{
$plugin = $this->prophesize(PluginInterface::class);
$plugin->configureOptionsResolver(Argument::type(OptionsResolver::class))
->will(
function ($args) {
$args[0]->setRequired(['chmod', 'directory']);
}
);

$this->plugins->has('my-plugin-1')->willReturn(true);
$this->plugins->has('my-plugin-2')->willReturn(true);
$this->plugins->getPlugin('my-plugin-1')->willReturn($plugin->reveal());
$this->plugins->getPlugin('my-plugin-2')->willReturn($plugin->reveal());

$commandTester = $this->getCommandTester(
true,
[
'test-1' => ['plugin' => 'my-plugin-1', 'parameter' => ['directory' => '/test']],
'test-2' => ['plugin' => 'my-plugin-2', 'parameter' => ['directory' => '/test', 'chmod' => 0777]],
]
);
$commandTester->execute([]);

$this->assertRegExp('/test-1[-\s]*\[WARNING\] Parameter not valid/', $commandTester->getDisplay());
$this->assertRegExp('/test-2[-\s]*OK/', $commandTester->getDisplay());
}

public function testExecuteOK()
{
$plugin = $this->prophesize(PluginInterface::class);
$plugin->configureOptionsResolver(Argument::type(OptionsResolver::class))
->will(
function ($args) {
$args[0]->setRequired(['chmod', 'directory']);
}
);

$this->plugins->has('my-plugin')->willReturn(true);
$this->plugins->getPlugin('my-plugin')->willReturn($plugin->reveal());

$commandTester = $this->getCommandTester(
true,
['test' => ['plugin' => 'my-plugin', 'parameter' => ['directory' => '/test', 'chmod' => 0777]]]
);
$commandTester->execute([]);

$this->assertContains('OK', $commandTester->getDisplay());
}

public function testExecuteOKMultiple()
{
$plugin = $this->prophesize(PluginInterface::class);
$plugin->configureOptionsResolver(Argument::type(OptionsResolver::class))
->will(
function ($args) {
$args[0]->setRequired(['chmod', 'directory']);
}
);

$this->plugins->has('my-plugin')->willReturn(true);
$this->plugins->getPlugin('my-plugin')->willReturn($plugin->reveal());

$commandTester = $this->getCommandTester(
true,
[
'test-1' => ['plugin' => 'my-plugin', 'parameter' => ['directory' => '/test', 'chmod' => 0777]],
'test-2' => ['plugin' => 'my-plugin', 'parameter' => ['directory' => '/test', 'chmod' => 0777]],
]
);
$commandTester->execute([]);

$this->assertRegExp('/test-1[-\s]*OK/', $commandTester->getDisplay());
$this->assertRegExp('/test-2[-\s]*OK/', $commandTester->getDisplay());
}
}

0 comments on commit 15c73ae

Please sign in to comment.