diff --git a/core/Command/Maintenance/Mode.php b/core/Command/Maintenance/Mode.php index 30d72da358..db4c9dc8c0 100644 --- a/core/Command/Maintenance/Mode.php +++ b/core/Command/Maintenance/Mode.php @@ -59,14 +59,23 @@ class Mode extends Command { } protected function execute(InputInterface $input, OutputInterface $output) { + $maintenanceMode = $this->config->getSystemValue('maintenance', false); if ($input->getOption('on')) { - $this->config->setSystemValue('maintenance', true); - $output->writeln('Maintenance mode enabled'); + if ($maintenanceMode === false) { + $this->config->setSystemValue('maintenance', true); + $output->writeln('Maintenance mode enabled'); + } else { + $output->writeln('Maintenance mode already enabled'); + } } elseif ($input->getOption('off')) { - $this->config->setSystemValue('maintenance', false); - $output->writeln('Maintenance mode disabled'); + if ($maintenanceMode === true) { + $this->config->setSystemValue('maintenance', false); + $output->writeln('Maintenance mode disabled'); + } else { + $output->writeln('Maintenance mode already disabled'); + } } else { - if ($this->config->getSystemValue('maintenance', false)) { + if ($maintenanceMode) { $output->writeln('Maintenance mode is currently enabled'); } else { $output->writeln('Maintenance mode is currently disabled'); diff --git a/lib/private/Console/Application.php b/lib/private/Console/Application.php index c85b67217b..1de5fbd6ca 100644 --- a/lib/private/Console/Application.php +++ b/lib/private/Console/Application.php @@ -39,6 +39,7 @@ use OCP\IRequest; use Symfony\Component\Console\Application as SymfonyApplication; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; @@ -69,10 +70,13 @@ class Application { /** * @param InputInterface $input - * @param OutputInterface $output + * @param ConsoleOutputInterface $output * @throws \Exception */ - public function loadCommands(InputInterface $input, OutputInterface $output) { + public function loadCommands( + InputInterface $input, + ConsoleOutputInterface $output + ) { // $application is required to be defined in the register_command scripts $application = $this->application; $inputDefinition = $application->getDefinition(); @@ -99,10 +103,7 @@ class Application { if (\OCP\Util::needUpgrade()) { throw new NeedsUpdateException(); } elseif ($this->config->getSystemValue('maintenance', false)) { - if ($input->getArgument('command') !== '_completion') { - $errOutput = $output->getErrorOutput(); - $errOutput->writeln('Nextcloud is in maintenance mode - no apps have been loaded' . PHP_EOL); - } + $this->writeMaintenanceModeInfo($input, $output); } else { OC_App::loadApps(); foreach (\OC::$server->getAppManager()->getInstalledApps() as $app) { @@ -150,6 +151,28 @@ class Application { } } + /** + * Write a maintenance mode info. + * The commands "_completion" and "maintenance:mode" are excluded. + * + * @param InputInterface $input The input implementation for reading inputs. + * @param ConsoleOutputInterface $output The output implementation + * for writing outputs. + * @return void + */ + private function writeMaintenanceModeInfo( + InputInterface $input, ConsoleOutputInterface $output + ) { + if ($input->getArgument('command') !== '_completion' + && $input->getArgument('command') !== 'maintenance:mode') { + $errOutput = $output->getErrorOutput(); + $errOutput->writeln( + 'Nextcloud is in maintenance mode - ' . + 'no apps have been loaded' . PHP_EOL + ); + } + } + /** * Sets whether to automatically exit after a command execution or not. * diff --git a/tests/Core/Command/Maintenance/ModeTest.php b/tests/Core/Command/Maintenance/ModeTest.php new file mode 100644 index 0000000000..da5e95998e --- /dev/null +++ b/tests/Core/Command/Maintenance/ModeTest.php @@ -0,0 +1,147 @@ +config = $this->getMockBuilder(IConfig::class) + ->getMock(); + $this->mode = new Mode($this->config); + $this->input = $this->getMockBuilder(InputInterface::class) + ->getMock(); + $this->output = $this->getMockBuilder(OutputInterface::class) + ->getMock(); + } + + /** + * Provides test data for the execute test. + * + * @return array + */ + public function getExecuteTestData(): array { + return [ + 'off -> on' => [ + 'on', // command option + false, // current maintenance mode state + true, // expected maintenance mode state, null for no change + 'Maintenance mode enabled', // expected output + ], + 'on -> off' => [ + 'off', + true, + false, + 'Maintenance mode disabled', + ], + 'on -> on' => [ + 'on', + true, + null, + 'Maintenance mode already enabled', + ], + 'off -> off' => [ + 'off', + false, + null, + 'Maintenance mode already disabled', + ], + 'no option, maintenance enabled' => [ + '', + true, + null, + 'Maintenance mode is currently enabled', + ], + 'no option, maintenance disabled' => [ + '', + false, + null, + 'Maintenance mode is currently disabled', + ], + ]; + } + + /** + * Asserts that execute works as expected. + * + * @dataProvider getExecuteTestData + * @param string $option The command option. + * @param bool $currentMaintenanceState The current maintenance state. + * @param null|bool $expectedMaintenanceState + * The expected maintenance state. Null for no change. + * @param string $expectedOutput The expected command output. + * @throws \Exception + */ + public function testExecute( + string $option, + bool $currentMaintenanceState, + $expectedMaintenanceState, + string $expectedOutput + ) { + $this->config->expects($this->any()) + ->method('getSystemValue') + ->willReturn($currentMaintenanceState); + + if ($expectedMaintenanceState !== null) { + $this->config->expects($this->once()) + ->method('setSystemValue') + ->with('maintenance', $expectedMaintenanceState); + } + + $this->input->expects($this->any()) + ->method('getOption') + ->willReturnCallback(function ($callOption) use ($option) { + return $callOption === $option; + }); + + $this->output->expects($this->once()) + ->method('writeln') + ->with($expectedOutput); + + $this->mode->run($this->input, $this->output); + } +}