diff --git a/core/Command/Background/Queue/Delete.php b/core/Command/Background/Queue/Delete.php new file mode 100644 index 000000000000..89a80493a774 --- /dev/null +++ b/core/Command/Background/Queue/Delete.php @@ -0,0 +1,65 @@ + + * + * @copyright Copyright (c) 2018, ownCloud GmbH + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OC\Core\Command\Background\Queue; + +use OCP\BackgroundJob\IJobList; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class Delete extends Command { + + /** @var \OCP\BackgroundJob\IJobList */ + private $jobList; + + public function __construct(IJobList $jobList) { + $this->jobList = $jobList; + parent::__construct(); + } + + protected function configure() { + $this + ->setName('background:queue:delete') + ->setDescription('Delete a job from the queue') + ->addArgument('id', InputArgument::REQUIRED, 'id of the job to be deleted'); + } + + /** + * @param InputInterface $input + * @param OutputInterface $output + * @return int + */ + protected function execute(InputInterface $input, OutputInterface $output) { + $id = $input->getArgument('id'); + + $job = $this->jobList->getById($id); + if ($job === null) { + $output->writeln("Job with id <$id> is not known."); + return 1; + } + + $this->jobList->removeById($id); + $output->writeln('Job has been deleted.'); + return 0; + } +} diff --git a/core/Command/Background/Queue/Status.php b/core/Command/Background/Queue/Status.php new file mode 100644 index 000000000000..1a2f7f572b05 --- /dev/null +++ b/core/Command/Background/Queue/Status.php @@ -0,0 +1,60 @@ + + * + * @copyright Copyright (c) 2018, ownCloud GmbH + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OC\Core\Command\Background\Queue; + +use OCP\BackgroundJob\IJob; +use OCP\BackgroundJob\IJobList; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Helper\Table; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class Status extends Command { + + /** @var \OCP\BackgroundJob\IJobList */ + private $jobList; + + public function __construct(IJobList $jobList) { + $this->jobList = $jobList; + parent::__construct(); + } + + protected function configure() { + $this + ->setName('background:queue:status') + ->setDescription('List queue status'); + } + + /** + * @param InputInterface $input + * @param OutputInterface $output + * @return void + */ + protected function execute(InputInterface $input, OutputInterface $output) { + $t = new Table($output); + $t->setHeaders(['Id', 'Job', 'Last run', 'Job Arguments']); + $this->jobList->listJobs(function (IJob $job) use ($t) { + $t->addRow([$job->getId(), \get_class($job), \date('c', $job->getLastRun()), $job->getArgument()]); + }); + $t->render(); + } +} diff --git a/core/register_command.php b/core/register_command.php index 7a40e12b89aa..d13bf529bbde 100644 --- a/core/register_command.php +++ b/core/register_command.php @@ -72,6 +72,8 @@ $application->add(new OC\Core\Command\Background\Cron(\OC::$server->getConfig())); $application->add(new OC\Core\Command\Background\WebCron(\OC::$server->getConfig())); $application->add(new OC\Core\Command\Background\Ajax(\OC::$server->getConfig())); + $application->add(new OC\Core\Command\Background\Queue\Status(\OC::$server->getJobList())); + $application->add(new OC\Core\Command\Background\Queue\Delete(\OC::$server->getJobList())); $application->add(new OC\Core\Command\Config\App\DeleteConfig(\OC::$server->getConfig())); $application->add(new OC\Core\Command\Config\App\GetConfig(\OC::$server->getConfig())); diff --git a/db_structure.xml b/db_structure.xml index e65060897583..f6f07ae002b3 100644 --- a/db_structure.xml +++ b/db_structure.xml @@ -724,7 +724,6 @@ false - last_checked diff --git a/lib/private/BackgroundJob/JobList.php b/lib/private/BackgroundJob/JobList.php index 23f7bbe14e85..1a57d4b07282 100644 --- a/lib/private/BackgroundJob/JobList.php +++ b/lib/private/BackgroundJob/JobList.php @@ -108,7 +108,7 @@ public function remove($job, $argument = null) { /** * @param int $id */ - protected function removeById($id) { + public function removeById($id) { $query = $this->connection->getQueryBuilder(); $query->delete('jobs') ->where($query->expr()->eq('id', $query->createNamedParameter($id, IQueryBuilder::PARAM_INT))); @@ -305,9 +305,7 @@ public function getLastJob() { } /** - * set the lastRun of $job to now - * - * @param IJob $job + * @inheritdoc */ public function setLastRun($job) { $query = $this->connection->getQueryBuilder(); @@ -324,4 +322,24 @@ public function setExecutionTime($job, $timeTaken) { ->where($query->expr()->eq('id', $query->createNamedParameter($job->getId(), IQueryBuilder::PARAM_INT))); $query->execute(); } + + /** + * @inheritdoc + */ + public function listJobs(\Closure $callback) { + $query = $this->connection->getQueryBuilder(); + $query->select('*') + ->from('jobs'); + $result = $query->execute(); + + while ($row = $result->fetch()) { + $job = $this->buildJob($row); + if ($job) { + if ($callback($job) === false) { + break; + } + } + } + $result->closeCursor(); + } } diff --git a/lib/public/BackgroundJob/IJobList.php b/lib/public/BackgroundJob/IJobList.php index 0120fb0ecbc7..7cf6431b5832 100644 --- a/lib/public/BackgroundJob/IJobList.php +++ b/lib/public/BackgroundJob/IJobList.php @@ -127,4 +127,19 @@ public function setLastRun($job); * @since 10.0.0 */ public function setExecutionTime($job, $timeTaken); + + /** + * iterate over all jobs in the queue + * + * @return void + * @since 10.0.9 + */ + public function listJobs(\Closure $callback); + + /** + * remove a specific job by id + * @return void + * @since 10.0.9 + */ + public function removeById($id); } diff --git a/tests/Core/Command/Background/Queue/DeleteTest.php b/tests/Core/Command/Background/Queue/DeleteTest.php new file mode 100644 index 000000000000..40c18ccdd6b4 --- /dev/null +++ b/tests/Core/Command/Background/Queue/DeleteTest.php @@ -0,0 +1,72 @@ + + * + * @copyright Copyright (c) 2017, ownCloud GmbH + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace Tests\Core\Command\Background\Queue; + +use OC\Core\Command\Background\Queue\Delete; +use OCP\BackgroundJob\IJobList; +use Symfony\Component\Console\Tester\CommandTester; +use Test\TestCase; + +/** + * Class DeleteTest + * + * @group DB + */ +class DeleteTest extends TestCase { + + /** @var CommandTester */ + private $commandTester; + /** @var IJobList */ + private $jobList; + + public function setUp() { + parent::setUp(); + + $this->jobList = $this->createMock(IJobList::class); + $this->jobList->expects($this->any())->method('getById') + ->willReturnCallback(function ($id) { + return ($id !== '666') ? true : null; + }); + + $command = new Delete($this->jobList); + $this->commandTester = new CommandTester($command); + } + + /** + * @dataProvider providesJobIds + * @param $jobId + * @param $expectedOutput + */ + public function testCommandInput($jobId, $expectedOutput) { + $input = ['id' => $jobId]; + $this->commandTester->execute($input); + $output = $this->commandTester->getDisplay(); + $this->assertContains($expectedOutput, $output); + } + + public function providesJobIds() { + return [ + ['666', 'Job with id <666> is not known.'], + ['1', 'Job has been deleted.'], + ]; + } +} diff --git a/tests/Core/Command/Background/Queue/StatusTest.php b/tests/Core/Command/Background/Queue/StatusTest.php new file mode 100644 index 000000000000..19015c041197 --- /dev/null +++ b/tests/Core/Command/Background/Queue/StatusTest.php @@ -0,0 +1,72 @@ + + * + * @copyright Copyright (c) 2017, ownCloud GmbH + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace Tests\Core\Command\Background\Queue; + +use OC\BackgroundJob\Legacy\RegularJob; +use OC\Core\Command\Background\Queue\Status; +use OCP\BackgroundJob\IJobList; +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Tester\CommandTester; +use Test\TestCase; + +/** + * Class StatusTest + * + * @group DB + */ +class StatusTest extends TestCase { + + /** @var CommandTester */ + private $commandTester; + /** @var IJobList */ + private $jobList; + + public function setUp() { + parent::setUp(); + + $this->jobList = $this->createMock(IJobList::class); + $this->jobList->expects($this->any())->method('listJobs') + ->willReturnCallback(function (\Closure $callBack) { + $job = new RegularJob(); + $job->setId(666); + $callBack($job); + }); + + $command = new Status($this->jobList); + $command->setApplication(new Application()); + $this->commandTester = new CommandTester($command); + } + + public function testCommandInput() { + $this->commandTester->execute([]); + $output = $this->commandTester->getDisplay(); + $expected = <<assertContains($expected, $output); + } +}