From a64abd151ddbd7dfb010a3b5e051d2f52f1f90e8 Mon Sep 17 00:00:00 2001 From: boite Date: Thu, 2 Jun 2016 15:32:10 +0100 Subject: [PATCH 1/4] Add Normaliser for apache conf names. --- src/Util/Normaliser.php | 22 ++++++++++++++++++++ test/Util/NormaliserTest.php | 39 ++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 src/Util/Normaliser.php create mode 100644 test/Util/NormaliserTest.php diff --git a/src/Util/Normaliser.php b/src/Util/Normaliser.php new file mode 100644 index 0000000..27e6c40 --- /dev/null +++ b/src/Util/Normaliser.php @@ -0,0 +1,22 @@ +norm = new Normaliser; + } + + public function testNormaliseConfNameStripsExtension() + { + $this->assertSame( + 'foo_module', + $this->norm->normaliseConfName('foo_module.conf') + ); + $this->assertSame( + 'foo_module', + $this->norm->normaliseConfName('foo_module') + ); + } + + public function testNormaliseConfFilenameAddsExtension() + { + $this->assertSame( + 'foo_module.conf', + $this->norm->normaliseConfFilename('foo_module') + ); + $this->assertSame( + 'foo_module.conf', + $this->norm->normaliseConfFilename('foo_module.conf') + ); + } +} From 81f89bdbb16e85df4cf0cdcaae83adec26b60897 Mon Sep 17 00:00:00 2001 From: boite Date: Thu, 2 Jun 2016 15:34:36 +0100 Subject: [PATCH 2/4] Add dismod and enmod commands. --- src/Command/AbstractApacheCommand.php | 133 ++++++++ src/Command/ApacheModuleDisableCommand.php | 87 ++++++ src/Command/ApacheModuleEnableCommand.php | 87 ++++++ src/DroidPlugin.php | 14 + .../ApacheModuleDisableCommandTest.php | 279 +++++++++++++++++ .../Command/ApacheModuleEnableCommandTest.php | 283 ++++++++++++++++++ test/DroidPluginTest.php | 2 + 7 files changed, 885 insertions(+) create mode 100644 src/Command/AbstractApacheCommand.php create mode 100644 src/Command/ApacheModuleDisableCommand.php create mode 100644 src/Command/ApacheModuleEnableCommand.php create mode 100644 test/Command/ApacheModuleDisableCommandTest.php create mode 100644 test/Command/ApacheModuleEnableCommandTest.php diff --git a/src/Command/AbstractApacheCommand.php b/src/Command/AbstractApacheCommand.php new file mode 100644 index 0000000..fe93a0a --- /dev/null +++ b/src/Command/AbstractApacheCommand.php @@ -0,0 +1,133 @@ +processBuilder = $processBuilder; + $this->normaliser = $normaliser; + $this->confDir = $configDirectory; + return parent::__construct($name); + } + + abstract protected function getEnabledDir(); + abstract protected function getAvailableDir(); + + protected function getConfName($argument) + { + return $this->normaliser->normaliseConfName($argument); + } + + protected function getConfFilename($argument) + { + return $this->normaliser->normaliseConfFilename($argument); + } + + protected function available($confFilename) + { + $p = $this->getProcess( + array( + 'stat', + '-c', + '%F', + $this->getTargetPath($confFilename) + ) + ); + if (!$p->run() + && preg_match('/^regular(?: empty)? file/', $p->getOutput()) + ) { + return true; + } + return false; + } + + protected function enabled($confFilename) + { + $p = $this->getProcess( + array( + 'stat', + '-c', + '%F', + $this->getLinkPath($confFilename) + ) + ); + if (!$p->run() + && substr($p->getOutput(), 0, 13) === 'symbolic link' + ) { + return true; + } + return false; + } + + protected function enable($confFilename) + { + $p = $this->getProcess( + array( + 'ln', + '-s', + $this->getTargetPath($confFilename), + $this->getLinkPath($confFilename), + ) + ); + return $p->run() === 0; + } + + protected function disable($confFilename) + { + $p = $this->getProcess( + array( + 'unlink', + $this->getLinkPath($confFilename), + ) + ); + return $p->run() === 0; + } + + private function getLinkPath($confFilename) + { + return implode( + DIRECTORY_SEPARATOR, + array( + $this->confDir, + $this->getEnabledDir(), + $confFilename, + ) + ); + } + + private function getTargetPath($confFilename) + { + return implode( + DIRECTORY_SEPARATOR, + array( + $this->confDir, + $this->getAvailableDir(), + $confFilename, + ) + ); + } + + private function getProcess($arguments) + { + return $this + ->processBuilder + ->setArguments($arguments) + ->getProcess() + ; + } +} diff --git a/src/Command/ApacheModuleDisableCommand.php b/src/Command/ApacheModuleDisableCommand.php new file mode 100644 index 0000000..90ca0ea --- /dev/null +++ b/src/Command/ApacheModuleDisableCommand.php @@ -0,0 +1,87 @@ +setName('apache:dismod') + ->setDescription('Disable Apache modules.') + ->addArgument( + 'module-name', + InputArgument::REQUIRED, + 'Disable the named module.' + ) + ; + $this->configureCheckMode(); + } + + public function execute(InputInterface $input, OutputInterface $output) + { + $this->activateCheckMode($input); + + $confname = $this->getConfName($input->getArgument('module-name')); + $confFilename = $this->getConfFilename($input->getArgument('module-name')); + + if (! $this->available($confFilename)) { + throw new RuntimeException( + sprintf('I am not aware of a module named "%s".', $confname) + ); + } + + if (! $this->enabled($confFilename)) { + $output->writeLn( + sprintf( + 'The module "%s" is already disabled. Nothing to do.', + $confname + ) + ); + $this->reportChange($output); + return 0; + } + + $this->markChange(); + + if (! $this->checkMode() && ! $this->disable($confFilename)) { + throw new RuntimeException( + sprintf('I cannot disable module "%s".', $confname) + ); + } + + $output->writeLn( + sprintf( + 'I %s "%s".', + $this->checkMode() ? 'would disable' : 'have disabled', + $confname + ) + ); + + $this->reportChange($output); + return 0; + } + + protected function getAvailableDir() + { + return $this->availableDir; + } + + protected function getEnabledDir() + { + return $this->enabledDir; + } +} diff --git a/src/Command/ApacheModuleEnableCommand.php b/src/Command/ApacheModuleEnableCommand.php new file mode 100644 index 0000000..e60d1ad --- /dev/null +++ b/src/Command/ApacheModuleEnableCommand.php @@ -0,0 +1,87 @@ +setName('apache:enmod') + ->setDescription('Enable Apache modules.') + ->addArgument( + 'module-name', + InputArgument::REQUIRED, + 'Enable the named module.' + ) + ; + $this->configureCheckMode(); + } + + public function execute(InputInterface $input, OutputInterface $output) + { + $this->activateCheckMode($input); + + $confname = $this->getConfName($input->getArgument('module-name')); + $confFilename = $this->getConfFilename($input->getArgument('module-name')); + + if (! $this->available($confFilename)) { + throw new RuntimeException( + sprintf('I am not aware of a module named "%s".', $confname) + ); + } + + if ($this->enabled($confFilename)) { + $output->writeLn( + sprintf( + 'The module "%s" is already enabled. Nothing to do.', + $confname + ) + ); + $this->reportChange($output); + return 0; + } + + $this->markChange(); + + if (! $this->checkMode() && ! $this->enable($confFilename)) { + throw new RuntimeException( + sprintf('I cannot enable module "%s".', $confname) + ); + } + + $output->writeLn( + sprintf( + 'I %s "%s".', + $this->checkMode() ? 'would enable' : 'have enabled', + $confname + ) + ); + + $this->reportChange($output); + return 0; + } + + protected function getAvailableDir() + { + return $this->availableDir; + } + + protected function getEnabledDir() + { + return $this->enabledDir; + } +} diff --git a/src/DroidPlugin.php b/src/DroidPlugin.php index 050671a..17634c2 100644 --- a/src/DroidPlugin.php +++ b/src/DroidPlugin.php @@ -2,6 +2,12 @@ namespace Droid\Plugin\Apache; +use Symfony\Component\Process\ProcessBuilder; + +use Droid\Plugin\Apache\Command\ApacheModuleDisableCommand; +use Droid\Plugin\Apache\Command\ApacheModuleEnableCommand; +use Droid\Plugin\Apache\Util\Normaliser; + class DroidPlugin { public function __construct($droid) @@ -12,6 +18,14 @@ public function __construct($droid) public function getCommands() { return array( + new ApacheModuleDisableCommand( + new ProcessBuilder, + new Normaliser + ), + new ApacheModuleEnableCommand( + new ProcessBuilder, + new Normaliser + ), ); } } diff --git a/test/Command/ApacheModuleDisableCommandTest.php b/test/Command/ApacheModuleDisableCommandTest.php new file mode 100644 index 0000000..256a85e --- /dev/null +++ b/test/Command/ApacheModuleDisableCommandTest.php @@ -0,0 +1,279 @@ +process = $this + ->getMockBuilder(Process::class) + ->disableOriginalConstructor() + ->setMethods(array('run', 'getOutput', 'getExitCode')) + ->getMock() + ; + $this->processBuilder = $this + ->getMockBuilder(ProcessBuilder::class) + ->setMethods(array('setArguments', 'getProcess')) + ->getMock() + ; + $this + ->processBuilder + ->method('setArguments') + ->willReturnSelf() + ; + $this + ->processBuilder + ->method('getProcess') + ->willReturn($this->process) + ; + + $command = new ApacheModuleDisableCommand( + $this->processBuilder, + new Normaliser + ); + + $this->app = new Application; + $this->app->add($command); + + $this->tester = new CommandTester($command); + } + + /** + * @expectedException RuntimeException + * @expectedExceptionMessage I am not aware of a module named "not_a_module" + */ + public function testApacheModDisableThrowsRuntimeExceptionWithUnknownModule() + { + $this + ->processBuilder + ->expects($this->once()) + ->method('setArguments') + ->with( + array( + 'stat', + '-c', + '%F', + '/etc/apache2/mods-available/not_a_module.conf', + ) + ) + ; + $this + ->process + ->expects($this->once()) + ->method('run') + ->willReturn(1) + ; + + $this->tester->execute(array( + 'command' => $this->app->find('apache:dismod')->getName(), + 'module-name' => 'not_a_module', + )); + } + + public function testApacheModDisableExitsWhenModuleIsAlreadyDisabled() + { + $this + ->processBuilder + ->expects($this->exactly(2)) + ->method('setArguments') + ->withConsecutive( + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/mods-available/a_module.conf', + )), + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/mods-enabled/a_module.conf', + )) + ) + ; + $this + ->process + ->expects($this->exactly(2)) + ->method('run') + ->willReturnOnConsecutiveCalls(0, 1) + ; + $this + ->process + ->expects($this->once()) + ->method('getOutput') + ->willReturn('regular file') + ; + + $this->tester->execute(array( + 'command' => $this->app->find('apache:dismod')->getName(), + 'module-name' => 'a_module', + )); + + + $this->assertRegExp( + '/^The module "a_module" is already disabled\. Nothing to do/', + $this->tester->getDisplay() + ); + } + + /** + * @expectedException RuntimeException + * @expectedExceptionMessage I cannot disable module "a_module" + */ + public function testApacheModDisableThrowsRuntimeExceptionWhenFailsToDisable() + { + $this + ->processBuilder + ->expects($this->exactly(3)) + ->method('setArguments') + ->withConsecutive( + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/mods-available/a_module.conf', + )), + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/mods-enabled/a_module.conf', + )), + array(array( + 'unlink', + '/etc/apache2/mods-enabled/a_module.conf', + )) + ) + ; + $this + ->process + ->expects($this->exactly(3)) + ->method('run') + ->willReturnOnConsecutiveCalls(0, 0, 1) + ; + $this + ->process + ->expects($this->exactly(2)) + ->method('getOutput') + ->willReturnOnConsecutiveCalls('regular file', 'symbolic link') + ; + + $this->tester->execute(array( + 'command' => $this->app->find('apache:dismod')->getName(), + 'module-name' => 'a_module', + )); + } + + public function testApacheModDisableWillDisableEnabledModule() + { + $this + ->processBuilder + ->expects($this->exactly(3)) + ->method('setArguments') + ->withConsecutive( + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/mods-available/a_module.conf', + )), + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/mods-enabled/a_module.conf', + )), + array(array( + 'unlink', + '/etc/apache2/mods-enabled/a_module.conf', + )) + ) + ; + $this + ->process + ->expects($this->exactly(3)) + ->method('run') + ->willReturnOnConsecutiveCalls(0, 0, 0) + ; + $this + ->process + ->expects($this->exactly(2)) + ->method('getOutput') + ->willReturnOnConsecutiveCalls('regular file', 'symbolic link') + ; + + $this->tester->execute(array( + 'command' => $this->app->find('apache:dismod')->getName(), + 'module-name' => 'a_module', + )); + + + $this->assertRegExp( + '/^I have disabled "a_module"/', + $this->tester->getDisplay() + ); + } + + public function testApacheModDisableWillReportOnlyInCheckMode() + { + $this + ->processBuilder + ->expects($this->exactly(2)) + ->method('setArguments') + ->withConsecutive( + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/mods-available/a_module.conf' + )), + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/mods-enabled/a_module.conf' + )) + ) + ; + $this + ->process + ->expects($this->exactly(2)) + ->method('run') + ->willReturnOnConsecutiveCalls(0, 0) + ; + $this + ->process + ->expects($this->exactly(2)) + ->method('getOutput') + ->willReturnOnConsecutiveCalls('regular file', 'symbolic link') + ; + + $this->tester->execute(array( + 'command' => $this->app->find('apache:dismod')->getName(), + 'module-name' => 'a_module', + '--check' => true, + )); + + + $this->assertRegExp( + '/^I would disable "a_module"/', + $this->tester->getDisplay() + ); + } +} diff --git a/test/Command/ApacheModuleEnableCommandTest.php b/test/Command/ApacheModuleEnableCommandTest.php new file mode 100644 index 0000000..5f5b574 --- /dev/null +++ b/test/Command/ApacheModuleEnableCommandTest.php @@ -0,0 +1,283 @@ +process = $this + ->getMockBuilder(Process::class) + ->disableOriginalConstructor() + ->setMethods(array('run', 'getOutput', 'getExitCode')) + ->getMock() + ; + $this->processBuilder = $this + ->getMockBuilder(ProcessBuilder::class) + ->setMethods(array('setArguments', 'getProcess')) + ->getMock() + ; + $this + ->processBuilder + ->method('setArguments') + ->willReturnSelf() + ; + $this + ->processBuilder + ->method('getProcess') + ->willReturn($this->process) + ; + + $command = new ApacheModuleEnableCommand( + $this->processBuilder, + new Normaliser + ); + + $this->app = new Application; + $this->app->add($command); + + $this->tester = new CommandTester($command); + } + + /** + * @expectedException RuntimeException + * @expectedExceptionMessage I am not aware of a module named "not_a_module" + */ + public function testApacheModEnableThrowsRuntimeExceptionWithUnknownModule() + { + $this + ->processBuilder + ->expects($this->once()) + ->method('setArguments') + ->with( + array( + 'stat', + '-c', + '%F', + '/etc/apache2/mods-available/not_a_module.conf' + ) + ) + ; + $this + ->process + ->expects($this->once()) + ->method('run') + ->willReturn(1) + ; + + $this->tester->execute(array( + 'command' => $this->app->find('apache:enmod')->getName(), + 'module-name' => 'not_a_module', + )); + } + + public function testApacheModEnableExitsWhenModuleIsAlreadyEnabled() + { + $this + ->processBuilder + ->expects($this->exactly(2)) + ->method('setArguments') + ->withConsecutive( + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/mods-available/a_module.conf', + )), + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/mods-enabled/a_module.conf', + )) + ) + ; + $this + ->process + ->expects($this->exactly(2)) + ->method('run') + ->willReturnOnConsecutiveCalls(0, 0) + ; + $this + ->process + ->expects($this->exactly(2)) + ->method('getOutput') + ->willReturnOnConsecutiveCalls('regular file', 'symbolic link') + ; + + $this->tester->execute(array( + 'command' => $this->app->find('apache:enmod')->getName(), + 'module-name' => 'a_module', + )); + + + $this->assertRegExp( + '/^The module "a_module" is already enabled\. Nothing to do/', + $this->tester->getDisplay() + ); + } + + /** + * @expectedException RuntimeException + * @expectedExceptionMessage I cannot enable module "a_module" + */ + public function testApacheModEnableThrowsRuntimeExceptionWhenFailsToEnable() + { + $this + ->processBuilder + ->expects($this->exactly(3)) + ->method('setArguments') + ->withConsecutive( + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/mods-available/a_module.conf', + )), + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/mods-enabled/a_module.conf', + )), + array(array( + 'ln', + '-s', + '/etc/apache2/mods-available/a_module.conf', + '/etc/apache2/mods-enabled/a_module.conf', + )) + ) + ; + $this + ->process + ->expects($this->exactly(3)) + ->method('run') + ->willReturnOnConsecutiveCalls(0, 1, 1) + ; + $this + ->process + ->expects($this->once()) + ->method('getOutput') + ->willReturn('regular file') + ; + + $this->tester->execute(array( + 'command' => $this->app->find('apache:enmod')->getName(), + 'module-name' => 'a_module', + )); + } + + public function testApacheModEnableWillEnableDisabledModule() + { + $this + ->processBuilder + ->expects($this->exactly(3)) + ->method('setArguments') + ->withConsecutive( + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/mods-available/a_module.conf', + )), + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/mods-enabled/a_module.conf', + )), + array(array( + 'ln', + '-s', + '/etc/apache2/mods-available/a_module.conf', + '/etc/apache2/mods-enabled/a_module.conf', + )) + ) + ; + $this + ->process + ->expects($this->exactly(3)) + ->method('run') + ->willReturnOnConsecutiveCalls(0, 1, 0) + ; + $this + ->process + ->expects($this->once()) + ->method('getOutput') + ->willReturn('regular file') + ; + + $this->tester->execute(array( + 'command' => $this->app->find('apache:enmod')->getName(), + 'module-name' => 'a_module', + )); + + + $this->assertRegExp( + '/^I have enabled "a_module"/', + $this->tester->getDisplay() + ); + } + + public function testApacheModEnableWillReportOnlyInCheckMode() + { + $this + ->processBuilder + ->expects($this->exactly(2)) + ->method('setArguments') + ->withConsecutive( + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/mods-available/a_module.conf', + )), + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/mods-enabled/a_module.conf', + )) + ) + ; + $this + ->process + ->expects($this->exactly(2)) + ->method('run') + ->willReturnOnConsecutiveCalls(0, 1) + ; + $this + ->process + ->expects($this->once()) + ->method('getOutput') + ->willReturn('regular file') + ; + + $this->tester->execute(array( + 'command' => $this->app->find('apache:enmod')->getName(), + 'module-name' => 'a_module', + '--check' => true, + )); + + + $this->assertRegExp( + '/^I would enable "a_module"/', + $this->tester->getDisplay() + ); + } +} diff --git a/test/DroidPluginTest.php b/test/DroidPluginTest.php index 1d778ae..5b43581 100644 --- a/test/DroidPluginTest.php +++ b/test/DroidPluginTest.php @@ -17,6 +17,8 @@ public function testGetCommandsReturnsAllCommands() { $this->assertSame( array( + 'Droid\Plugin\Apache\Command\ApacheModuleDisableCommand', + 'Droid\Plugin\Apache\Command\ApacheModuleEnableCommand', ), array_map( function ($x) { From 09b59a35b8cb00d2950424ea6effef93aabb4120 Mon Sep 17 00:00:00 2001 From: boite Date: Thu, 2 Jun 2016 16:09:34 +0100 Subject: [PATCH 3/4] Add dissite and ensite commands. --- src/Command/ApacheSiteDisableCommand.php | 87 ++++++ src/Command/ApacheSiteEnableCommand.php | 87 ++++++ src/DroidPlugin.php | 10 + test/Command/ApacheSiteDisableCommandTest.php | 279 +++++++++++++++++ test/Command/ApacheSiteEnableCommandTest.php | 283 ++++++++++++++++++ test/DroidPluginTest.php | 2 + 6 files changed, 748 insertions(+) create mode 100644 src/Command/ApacheSiteDisableCommand.php create mode 100644 src/Command/ApacheSiteEnableCommand.php create mode 100644 test/Command/ApacheSiteDisableCommandTest.php create mode 100644 test/Command/ApacheSiteEnableCommandTest.php diff --git a/src/Command/ApacheSiteDisableCommand.php b/src/Command/ApacheSiteDisableCommand.php new file mode 100644 index 0000000..55d5867 --- /dev/null +++ b/src/Command/ApacheSiteDisableCommand.php @@ -0,0 +1,87 @@ +setName('apache:dissite') + ->setDescription('Disable Apache sites.') + ->addArgument( + 'site-name', + InputArgument::REQUIRED, + 'Disable the named site.' + ) + ; + $this->configureCheckMode(); + } + + public function execute(InputInterface $input, OutputInterface $output) + { + $this->activateCheckMode($input); + + $confname = $this->getConfName($input->getArgument('site-name')); + $confFilename = $this->getConfFilename($input->getArgument('site-name')); + + if (! $this->available($confFilename)) { + throw new RuntimeException( + sprintf('I am not aware of a site named "%s".', $confname) + ); + } + + if (! $this->enabled($confFilename)) { + $output->writeLn( + sprintf( + 'The site "%s" is already disabled. Nothing to do.', + $confname + ) + ); + $this->reportChange($output); + return 0; + } + + $this->markChange(); + + if (! $this->checkMode() && ! $this->disable($confFilename)) { + throw new RuntimeException( + sprintf('I cannot disable site "%s".', $confname) + ); + } + + $output->writeLn( + sprintf( + 'I %s "%s".', + $this->checkMode() ? 'would disable' : 'have disabled', + $confname + ) + ); + + $this->reportChange($output); + return 0; + } + + protected function getAvailableDir() + { + return $this->availableDir; + } + + protected function getEnabledDir() + { + return $this->enabledDir; + } +} diff --git a/src/Command/ApacheSiteEnableCommand.php b/src/Command/ApacheSiteEnableCommand.php new file mode 100644 index 0000000..ed3ff7b --- /dev/null +++ b/src/Command/ApacheSiteEnableCommand.php @@ -0,0 +1,87 @@ +setName('apache:ensite') + ->setDescription('Enable Apache sites.') + ->addArgument( + 'site-name', + InputArgument::REQUIRED, + 'Enable the named site.' + ) + ; + $this->configureCheckMode(); + } + + public function execute(InputInterface $input, OutputInterface $output) + { + $this->activateCheckMode($input); + + $confname = $this->getConfName($input->getArgument('site-name')); + $confFilename = $this->getConfFilename($input->getArgument('site-name')); + + if (! $this->available($confFilename)) { + throw new RuntimeException( + sprintf('I am not aware of a site named "%s".', $confname) + ); + } + + if ($this->enabled($confFilename)) { + $output->writeLn( + sprintf( + 'The site "%s" is already enabled. Nothing to do.', + $confname + ) + ); + $this->reportChange($output); + return 0; + } + + $this->markChange(); + + if (! $this->checkMode() && ! $this->enable($confFilename)) { + throw new RuntimeException( + sprintf('I cannot enable site "%s".', $confname) + ); + } + + $output->writeLn( + sprintf( + 'I %s "%s".', + $this->checkMode() ? 'would enable' : 'have enabled', + $confname + ) + ); + + $this->reportChange($output); + return 0; + } + + protected function getAvailableDir() + { + return $this->availableDir; + } + + protected function getEnabledDir() + { + return $this->enabledDir; + } +} diff --git a/src/DroidPlugin.php b/src/DroidPlugin.php index 17634c2..029b0f0 100644 --- a/src/DroidPlugin.php +++ b/src/DroidPlugin.php @@ -6,6 +6,8 @@ use Droid\Plugin\Apache\Command\ApacheModuleDisableCommand; use Droid\Plugin\Apache\Command\ApacheModuleEnableCommand; +use Droid\Plugin\Apache\Command\ApacheSiteDisableCommand; +use Droid\Plugin\Apache\Command\ApacheSiteEnableCommand; use Droid\Plugin\Apache\Util\Normaliser; class DroidPlugin @@ -26,6 +28,14 @@ public function getCommands() new ProcessBuilder, new Normaliser ), + new ApacheSiteDisableCommand( + new ProcessBuilder, + new Normaliser + ), + new ApacheSiteEnableCommand( + new ProcessBuilder, + new Normaliser + ), ); } } diff --git a/test/Command/ApacheSiteDisableCommandTest.php b/test/Command/ApacheSiteDisableCommandTest.php new file mode 100644 index 0000000..72293cf --- /dev/null +++ b/test/Command/ApacheSiteDisableCommandTest.php @@ -0,0 +1,279 @@ +process = $this + ->getMockBuilder(Process::class) + ->disableOriginalConstructor() + ->setMethods(array('run', 'getOutput', 'getExitCode')) + ->getMock() + ; + $this->processBuilder = $this + ->getMockBuilder(ProcessBuilder::class) + ->setMethods(array('setArguments', 'getProcess')) + ->getMock() + ; + $this + ->processBuilder + ->method('setArguments') + ->willReturnSelf() + ; + $this + ->processBuilder + ->method('getProcess') + ->willReturn($this->process) + ; + + $command = new ApacheSiteDisableCommand( + $this->processBuilder, + new Normaliser + ); + + $this->app = new Application; + $this->app->add($command); + + $this->tester = new CommandTester($command); + } + + /** + * @expectedException RuntimeException + * @expectedExceptionMessage I am not aware of a site named "not_a_site" + */ + public function testApacheSiteDisableThrowsRuntimeExceptionWithUnknownSite() + { + $this + ->processBuilder + ->expects($this->once()) + ->method('setArguments') + ->with( + array( + 'stat', + '-c', + '%F', + '/etc/apache2/sites-available/not_a_site.conf', + ) + ) + ; + $this + ->process + ->expects($this->once()) + ->method('run') + ->willReturn(1) + ; + + $this->tester->execute(array( + 'command' => $this->app->find('apache:dissite')->getName(), + 'site-name' => 'not_a_site', + )); + } + + public function testApacheSiteDisableExitsWhenSiteIsAlreadyDisabled() + { + $this + ->processBuilder + ->expects($this->exactly(2)) + ->method('setArguments') + ->withConsecutive( + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/sites-available/a_site.conf', + )), + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/sites-enabled/a_site.conf', + )) + ) + ; + $this + ->process + ->expects($this->exactly(2)) + ->method('run') + ->willReturnOnConsecutiveCalls(0, 1) + ; + $this + ->process + ->expects($this->once()) + ->method('getOutput') + ->willReturn('regular file') + ; + + $this->tester->execute(array( + 'command' => $this->app->find('apache:dissite')->getName(), + 'site-name' => 'a_site', + )); + + + $this->assertRegExp( + '/^The site "a_site" is already disabled\. Nothing to do/', + $this->tester->getDisplay() + ); + } + + /** + * @expectedException RuntimeException + * @expectedExceptionMessage I cannot disable site "a_site" + */ + public function testApacheSiteDisableThrowsRuntimeExceptionWhenFailsToDisable() + { + $this + ->processBuilder + ->expects($this->exactly(3)) + ->method('setArguments') + ->withConsecutive( + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/sites-available/a_site.conf', + )), + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/sites-enabled/a_site.conf', + )), + array(array( + 'unlink', + '/etc/apache2/sites-enabled/a_site.conf', + )) + ) + ; + $this + ->process + ->expects($this->exactly(3)) + ->method('run') + ->willReturnOnConsecutiveCalls(0, 0, 1) + ; + $this + ->process + ->expects($this->exactly(2)) + ->method('getOutput') + ->willReturnOnConsecutiveCalls('regular file', 'symbolic link') + ; + + $this->tester->execute(array( + 'command' => $this->app->find('apache:dissite')->getName(), + 'site-name' => 'a_site', + )); + } + + public function testApacheSiteDisableWillDisableEnabledSite() + { + $this + ->processBuilder + ->expects($this->exactly(3)) + ->method('setArguments') + ->withConsecutive( + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/sites-available/a_site.conf', + )), + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/sites-enabled/a_site.conf', + )), + array(array( + 'unlink', + '/etc/apache2/sites-enabled/a_site.conf', + )) + ) + ; + $this + ->process + ->expects($this->exactly(3)) + ->method('run') + ->willReturnOnConsecutiveCalls(0, 0, 0) + ; + $this + ->process + ->expects($this->exactly(2)) + ->method('getOutput') + ->willReturnOnConsecutiveCalls('regular file', 'symbolic link') + ; + + $this->tester->execute(array( + 'command' => $this->app->find('apache:dissite')->getName(), + 'site-name' => 'a_site', + )); + + + $this->assertRegExp( + '/^I have disabled "a_site"/', + $this->tester->getDisplay() + ); + } + + public function testApacheSiteDisableWillReportOnlyInCheckMode() + { + $this + ->processBuilder + ->expects($this->exactly(2)) + ->method('setArguments') + ->withConsecutive( + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/sites-available/a_site.conf' + )), + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/sites-enabled/a_site.conf' + )) + ) + ; + $this + ->process + ->expects($this->exactly(2)) + ->method('run') + ->willReturnOnConsecutiveCalls(0, 0) + ; + $this + ->process + ->expects($this->exactly(2)) + ->method('getOutput') + ->willReturnOnConsecutiveCalls('regular file', 'symbolic link') + ; + + $this->tester->execute(array( + 'command' => $this->app->find('apache:dissite')->getName(), + 'site-name' => 'a_site', + '--check' => true, + )); + + + $this->assertRegExp( + '/^I would disable "a_site"/', + $this->tester->getDisplay() + ); + } +} diff --git a/test/Command/ApacheSiteEnableCommandTest.php b/test/Command/ApacheSiteEnableCommandTest.php new file mode 100644 index 0000000..62b4dff --- /dev/null +++ b/test/Command/ApacheSiteEnableCommandTest.php @@ -0,0 +1,283 @@ +process = $this + ->getMockBuilder(Process::class) + ->disableOriginalConstructor() + ->setMethods(array('run', 'getOutput', 'getExitCode')) + ->getMock() + ; + $this->processBuilder = $this + ->getMockBuilder(ProcessBuilder::class) + ->setMethods(array('setArguments', 'getProcess')) + ->getMock() + ; + $this + ->processBuilder + ->method('setArguments') + ->willReturnSelf() + ; + $this + ->processBuilder + ->method('getProcess') + ->willReturn($this->process) + ; + + $command = new ApacheSiteEnableCommand( + $this->processBuilder, + new Normaliser + ); + + $this->app = new Application; + $this->app->add($command); + + $this->tester = new CommandTester($command); + } + + /** + * @expectedException RuntimeException + * @expectedExceptionMessage I am not aware of a site named "not_a_site" + */ + public function testApacheSiteEnableThrowsRuntimeExceptionWithUnknownSite() + { + $this + ->processBuilder + ->expects($this->once()) + ->method('setArguments') + ->with( + array( + 'stat', + '-c', + '%F', + '/etc/apache2/sites-available/not_a_site.conf' + ) + ) + ; + $this + ->process + ->expects($this->once()) + ->method('run') + ->willReturn(1) + ; + + $this->tester->execute(array( + 'command' => $this->app->find('apache:ensite')->getName(), + 'site-name' => 'not_a_site', + )); + } + + public function testApacheSiteEnableExitsWhenSiteIsAlreadyEnabled() + { + $this + ->processBuilder + ->expects($this->exactly(2)) + ->method('setArguments') + ->withConsecutive( + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/sites-available/a_site.conf', + )), + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/sites-enabled/a_site.conf', + )) + ) + ; + $this + ->process + ->expects($this->exactly(2)) + ->method('run') + ->willReturnOnConsecutiveCalls(0, 0) + ; + $this + ->process + ->expects($this->exactly(2)) + ->method('getOutput') + ->willReturnOnConsecutiveCalls('regular file', 'symbolic link') + ; + + $this->tester->execute(array( + 'command' => $this->app->find('apache:ensite')->getName(), + 'site-name' => 'a_site', + )); + + + $this->assertRegExp( + '/^The site "a_site" is already enabled\. Nothing to do/', + $this->tester->getDisplay() + ); + } + + /** + * @expectedException RuntimeException + * @expectedExceptionMessage I cannot enable site "a_site" + */ + public function testApacheSiteEnableThrowsRuntimeExceptionWhenFailsToEnable() + { + $this + ->processBuilder + ->expects($this->exactly(3)) + ->method('setArguments') + ->withConsecutive( + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/sites-available/a_site.conf', + )), + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/sites-enabled/a_site.conf', + )), + array(array( + 'ln', + '-s', + '/etc/apache2/sites-available/a_site.conf', + '/etc/apache2/sites-enabled/a_site.conf', + )) + ) + ; + $this + ->process + ->expects($this->exactly(3)) + ->method('run') + ->willReturnOnConsecutiveCalls(0, 1, 1) + ; + $this + ->process + ->expects($this->once()) + ->method('getOutput') + ->willReturn('regular file') + ; + + $this->tester->execute(array( + 'command' => $this->app->find('apache:ensite')->getName(), + 'site-name' => 'a_site', + )); + } + + public function testApacheSiteEnableWillEnableDisabledSite() + { + $this + ->processBuilder + ->expects($this->exactly(3)) + ->method('setArguments') + ->withConsecutive( + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/sites-available/a_site.conf', + )), + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/sites-enabled/a_site.conf', + )), + array(array( + 'ln', + '-s', + '/etc/apache2/sites-available/a_site.conf', + '/etc/apache2/sites-enabled/a_site.conf', + )) + ) + ; + $this + ->process + ->expects($this->exactly(3)) + ->method('run') + ->willReturnOnConsecutiveCalls(0, 1, 0) + ; + $this + ->process + ->expects($this->once()) + ->method('getOutput') + ->willReturn('regular file') + ; + + $this->tester->execute(array( + 'command' => $this->app->find('apache:ensite')->getName(), + 'site-name' => 'a_site', + )); + + + $this->assertRegExp( + '/^I have enabled "a_site"/', + $this->tester->getDisplay() + ); + } + + public function testApacheSiteEnableWillReportOnlyInCheckMode() + { + $this + ->processBuilder + ->expects($this->exactly(2)) + ->method('setArguments') + ->withConsecutive( + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/sites-available/a_site.conf', + )), + array(array( + 'stat', + '-c', + '%F', + '/etc/apache2/sites-enabled/a_site.conf', + )) + ) + ; + $this + ->process + ->expects($this->exactly(2)) + ->method('run') + ->willReturnOnConsecutiveCalls(0, 1) + ; + $this + ->process + ->expects($this->once()) + ->method('getOutput') + ->willReturn('regular file') + ; + + $this->tester->execute(array( + 'command' => $this->app->find('apache:ensite')->getName(), + 'site-name' => 'a_site', + '--check' => true, + )); + + + $this->assertRegExp( + '/^I would enable "a_site"/', + $this->tester->getDisplay() + ); + } +} diff --git a/test/DroidPluginTest.php b/test/DroidPluginTest.php index 5b43581..f059a63 100644 --- a/test/DroidPluginTest.php +++ b/test/DroidPluginTest.php @@ -19,6 +19,8 @@ public function testGetCommandsReturnsAllCommands() array( 'Droid\Plugin\Apache\Command\ApacheModuleDisableCommand', 'Droid\Plugin\Apache\Command\ApacheModuleEnableCommand', + 'Droid\Plugin\Apache\Command\ApacheSiteDisableCommand', + 'Droid\Plugin\Apache\Command\ApacheSiteEnableCommand', ), array_map( function ($x) { From 7d4f1565832b207e1ec7a5547e981ec1e9a14b11 Mon Sep 17 00:00:00 2001 From: boite Date: Mon, 13 Jun 2016 21:45:51 +0100 Subject: [PATCH 4/4] Add bin/droid-apache. --- bin/droid-apache | 30 ++++++++++++++++++++++++++++++ composer.json | 3 +++ 2 files changed, 33 insertions(+) create mode 100755 bin/droid-apache diff --git a/bin/droid-apache b/bin/droid-apache new file mode 100755 index 0000000..59c8be7 --- /dev/null +++ b/bin/droid-apache @@ -0,0 +1,30 @@ +#!/usr/bin/env php +setCatchExceptions(true); +$registry = new DroidPlugin($application); +foreach ($registry->getCommands() as $command) { + $application->add($command); +} +$application->run(); diff --git a/composer.json b/composer.json index 2367172..fa4a30e 100644 --- a/composer.json +++ b/composer.json @@ -26,5 +26,8 @@ "Droid\\Plugin\\Apache\\": "src/" } }, + "bin": [ + "bin/droid-apache" + ], "license": "MIT" }