Add the background job list to the public server containertags/v7.0.0alpha2
@@ -97,7 +97,7 @@ try { | |||
touch(TemporaryCronClass::$lockfile); | |||
// Work | |||
$jobList = new \OC\BackgroundJob\JobList(); | |||
$jobList = \OC::$server->getJobList(); | |||
$jobs = $jobList->getAll(); | |||
foreach ($jobs as $job) { | |||
$job->execute($jobList, $logger); | |||
@@ -109,7 +109,7 @@ try { | |||
OC_JSON::error(array('data' => array('message' => 'Backgroundjobs are using system cron!'))); | |||
} else { | |||
// Work and success :-) | |||
$jobList = new \OC\BackgroundJob\JobList(); | |||
$jobList = \OC::$server->getJobList(); | |||
$job = $jobList->getNext(); | |||
$job->execute($jobList, $logger); | |||
$jobList->setLastJob($job); |
@@ -8,7 +8,9 @@ | |||
namespace OC\BackgroundJob; | |||
abstract class Job { | |||
use OCP\BackgroundJob\IJob; | |||
abstract class Job implements IJob { | |||
/** | |||
* @var int $id | |||
*/ |
@@ -1,6 +1,6 @@ | |||
<?php | |||
/** | |||
* Copyright (c) 2013 Robin Appelman <icewind@owncloud.com> | |||
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com> | |||
* This file is licensed under the Affero General Public License version 3 or | |||
* later. | |||
* See the COPYING-README file. | |||
@@ -8,14 +8,28 @@ | |||
namespace OC\BackgroundJob; | |||
/** | |||
* Class QueuedJob | |||
* | |||
* create a background job that is to be executed once | |||
* | |||
* @package OC\BackgroundJob | |||
*/ | |||
class JobList { | |||
use OCP\BackgroundJob\IJobList; | |||
class JobList implements IJobList { | |||
/** | |||
* @var \OCP\IDBConnection | |||
*/ | |||
private $conn; | |||
/** | |||
* @var \OCP\IConfig $config | |||
*/ | |||
private $config; | |||
/** | |||
* @param \OCP\IDBConnection $conn | |||
* @param \OCP\IConfig $config | |||
*/ | |||
public function __construct($conn, $config) { | |||
$this->conn = $conn; | |||
$this->config = $config; | |||
} | |||
/** | |||
* @param Job|string $job | |||
* @param mixed $argument | |||
@@ -28,7 +42,7 @@ class JobList { | |||
$class = $job; | |||
} | |||
$argument = json_encode($argument); | |||
$query = \OC_DB::prepare('INSERT INTO `*PREFIX*jobs`(`class`, `argument`, `last_run`) VALUES(?, ?, 0)'); | |||
$query = $this->conn->prepare('INSERT INTO `*PREFIX*jobs`(`class`, `argument`, `last_run`) VALUES(?, ?, 0)'); | |||
$query->execute(array($class, $argument)); | |||
} | |||
} | |||
@@ -45,10 +59,10 @@ class JobList { | |||
} | |||
if (!is_null($argument)) { | |||
$argument = json_encode($argument); | |||
$query = \OC_DB::prepare('DELETE FROM `*PREFIX*jobs` WHERE `class` = ? AND `argument` = ?'); | |||
$query = $this->conn->prepare('DELETE FROM `*PREFIX*jobs` WHERE `class` = ? AND `argument` = ?'); | |||
$query->execute(array($class, $argument)); | |||
} else { | |||
$query = \OC_DB::prepare('DELETE FROM `*PREFIX*jobs` WHERE `class` = ?'); | |||
$query = $this->conn->prepare('DELETE FROM `*PREFIX*jobs` WHERE `class` = ?'); | |||
$query->execute(array($class)); | |||
} | |||
} | |||
@@ -67,9 +81,9 @@ class JobList { | |||
$class = $job; | |||
} | |||
$argument = json_encode($argument); | |||
$query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*jobs` WHERE `class` = ? AND `argument` = ?'); | |||
$result = $query->execute(array($class, $argument)); | |||
return (bool)$result->fetchRow(); | |||
$query = $this->conn->prepare('SELECT `id` FROM `*PREFIX*jobs` WHERE `class` = ? AND `argument` = ?'); | |||
$query->execute(array($class, $argument)); | |||
return (bool)$query->fetch(); | |||
} | |||
/** | |||
@@ -78,10 +92,10 @@ class JobList { | |||
* @return Job[] | |||
*/ | |||
public function getAll() { | |||
$query = \OC_DB::prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs`'); | |||
$result = $query->execute(); | |||
$query = $this->conn->prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs`'); | |||
$query->execute(); | |||
$jobs = array(); | |||
while ($row = $result->fetchRow()) { | |||
while ($row = $query->fetch()) { | |||
$jobs[] = $this->buildJob($row); | |||
} | |||
return $jobs; | |||
@@ -94,15 +108,15 @@ class JobList { | |||
*/ | |||
public function getNext() { | |||
$lastId = $this->getLastJob(); | |||
$query = \OC_DB::prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs` WHERE `id` > ? ORDER BY `id` ASC', 1); | |||
$result = $query->execute(array($lastId)); | |||
if ($row = $result->fetchRow()) { | |||
$query = $this->conn->prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs` WHERE `id` > ? ORDER BY `id` ASC', 1); | |||
$query->execute(array($lastId)); | |||
if ($row = $query->fetch()) { | |||
return $this->buildJob($row); | |||
} else { | |||
//begin at the start of the queue | |||
$query = \OC_DB::prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs` ORDER BY `id` ASC', 1); | |||
$result = $query->execute(); | |||
if ($row = $result->fetchRow()) { | |||
$query = $this->conn->prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs` ORDER BY `id` ASC', 1); | |||
$query->execute(); | |||
if ($row = $query->fetch()) { | |||
return $this->buildJob($row); | |||
} else { | |||
return null; //empty job list | |||
@@ -115,9 +129,9 @@ class JobList { | |||
* @return Job | |||
*/ | |||
public function getById($id) { | |||
$query = \OC_DB::prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs` WHERE `id` = ?'); | |||
$result = $query->execute(array($id)); | |||
if ($row = $result->fetchRow()) { | |||
$query = $this->conn->prepare('SELECT `id`, `class`, `last_run`, `argument` FROM `*PREFIX*jobs` WHERE `id` = ?'); | |||
$query->execute(array($id)); | |||
if ($row = $query->fetch()) { | |||
return $this->buildJob($row); | |||
} else { | |||
return null; | |||
@@ -148,7 +162,7 @@ class JobList { | |||
* @param Job $job | |||
*/ | |||
public function setLastJob($job) { | |||
\OC_Appconfig::setValue('backgroundjob', 'lastjob', $job->getId()); | |||
$this->config->setAppValue('backgroundjob', 'lastjob', $job->getId()); | |||
} | |||
/** | |||
@@ -157,7 +171,7 @@ class JobList { | |||
* @return int | |||
*/ | |||
public function getLastJob() { | |||
return \OC_Appconfig::getValue('backgroundjob', 'lastjob', 0); | |||
return $this->config->getAppValue('backgroundjob', 'lastjob', 0); | |||
} | |||
/** | |||
@@ -166,7 +180,7 @@ class JobList { | |||
* @param Job $job | |||
*/ | |||
public function setLastRun($job) { | |||
$query = \OC_DB::prepare('UPDATE `*PREFIX*jobs` SET `last_run` = ? WHERE `id` = ?'); | |||
$query = $this->conn->prepare('UPDATE `*PREFIX*jobs` SET `last_run` = ? WHERE `id` = ?'); | |||
$query->execute(array(time(), $job->getId())); | |||
} | |||
} |
@@ -151,6 +151,13 @@ class Server extends SimpleContainer implements IServerContainer { | |||
$this->registerService('AvatarManager', function($c) { | |||
return new AvatarManager(); | |||
}); | |||
$this->registerService('JobList', function ($c) { | |||
/** | |||
* @var Server $c | |||
*/ | |||
$config = $c->getConfig(); | |||
return new \OC\BackgroundJob\JobList($c->getDatabaseConnection(), $config); | |||
}); | |||
} | |||
/** | |||
@@ -348,4 +355,13 @@ class Server extends SimpleContainer implements IServerContainer { | |||
function getActivityManager() { | |||
return $this->query('ActivityManager'); | |||
} | |||
/** | |||
* Returns an job list for controlling background jobs | |||
* | |||
* @return \OCP\BackgroundJob\IJobList | |||
*/ | |||
function getJobList(){ | |||
return $this->query('JobList'); | |||
} | |||
} |
@@ -33,7 +33,7 @@ use \OC\BackgroundJob\JobList; | |||
/** | |||
* This class provides functions to register backgroundjobs in ownCloud | |||
* | |||
* To create a new backgroundjob create a new class that inharits from either \OC\BackgroundJob\Job, | |||
* To create a new backgroundjob create a new class that inherits from either \OC\BackgroundJob\Job, | |||
* \OC\BackgroundJob\QueuedJob or \OC\BackgroundJob\TimedJob and register it using | |||
* \OCP\BackgroundJob->registerJob($job, $argument), $argument will be passed to the run() function | |||
* of the job when the job is executed. | |||
@@ -73,7 +73,7 @@ class BackgroundJob { | |||
* @param mixed $argument | |||
*/ | |||
public static function registerJob($job, $argument = null) { | |||
$jobList = new JobList(); | |||
$jobList = \OC::$server->getJobList(); | |||
$jobList->add($job, $argument); | |||
} | |||
@@ -99,7 +99,7 @@ class BackgroundJob { | |||
* key is string "$klass-$method", value is array( $klass, $method ) | |||
*/ | |||
static public function allRegularTasks() { | |||
$jobList = new JobList(); | |||
$jobList = \OC::$server->getJobList(); | |||
$allJobs = $jobList->getAll(); | |||
$regularJobs = array(); | |||
foreach ($allJobs as $job) { | |||
@@ -118,7 +118,7 @@ class BackgroundJob { | |||
* @return associative array | |||
*/ | |||
public static function findQueuedTask($id) { | |||
$jobList = new JobList(); | |||
$jobList = \OC::$server->getJobList(); | |||
return $jobList->getById($id); | |||
} | |||
@@ -128,7 +128,7 @@ class BackgroundJob { | |||
* @return array with associative arrays | |||
*/ | |||
public static function allQueuedTasks() { | |||
$jobList = new JobList(); | |||
$jobList = \OC::$server->getJobList(); | |||
$allJobs = $jobList->getAll(); | |||
$queuedJobs = array(); | |||
foreach ($allJobs as $job) { | |||
@@ -148,7 +148,7 @@ class BackgroundJob { | |||
* @return array with associative arrays | |||
*/ | |||
public static function queuedTaskWhereAppIs($app) { | |||
$jobList = new JobList(); | |||
$jobList = \OC::$server->getJobList(); | |||
$allJobs = $jobList->getAll(); | |||
$queuedJobs = array(); | |||
foreach ($allJobs as $job) { | |||
@@ -186,7 +186,7 @@ class BackgroundJob { | |||
* Deletes a report | |||
*/ | |||
public static function deleteQueuedTask($id) { | |||
$jobList = new JobList(); | |||
$jobList = \OC::$server->getJobList(); | |||
$job = $jobList->getById($id); | |||
if ($job) { | |||
$jobList->remove($job); |
@@ -0,0 +1,42 @@ | |||
<?php | |||
/** | |||
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com> | |||
* This file is licensed under the Affero General Public License version 3 or | |||
* later. | |||
* See the COPYING-README file. | |||
*/ | |||
namespace OCP\BackgroundJob; | |||
interface IJob { | |||
/** | |||
* Run the background job with the registered argument | |||
* | |||
* @param \OCP\BackgroundJob\IJobList $jobList The job list that manages the state of this job | |||
* @param \OC\Log $logger | |||
*/ | |||
public function execute($jobList, $logger = null); | |||
/** | |||
* Get the id of the background job | |||
* This id is determined by the job list when a job is added to the list | |||
* | |||
* @return int | |||
*/ | |||
public function getId(); | |||
/** | |||
* Get the last time this job was run as unix timestamp | |||
* | |||
* @return int | |||
*/ | |||
public function getLastRun(); | |||
/** | |||
* Get the argument associated with the background job | |||
* This is the argument that will be passed to the background job | |||
* | |||
* @return mixed | |||
*/ | |||
public function getArgument(); | |||
} |
@@ -0,0 +1,77 @@ | |||
<?php | |||
/** | |||
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com> | |||
* This file is licensed under the Affero General Public License version 3 or | |||
* later. | |||
* See the COPYING-README file. | |||
*/ | |||
namespace OCP\BackgroundJob; | |||
interface IJobList { | |||
/** | |||
* Add a job to the list | |||
* | |||
* @param \OCP\BackgroundJob\IJob |string $job | |||
* @param mixed $argument The argument to be passed to $job->run() when the job is exectured | |||
*/ | |||
public function add($job, $argument = null); | |||
/** | |||
* Remove a job from the list | |||
* | |||
* @param \OCP\BackgroundJob\IJob|string $job | |||
* @param mixed $argument | |||
*/ | |||
public function remove($job, $argument = null); | |||
/** | |||
* check if a job is in the list | |||
* | |||
* @param $job | |||
* @param mixed $argument | |||
* @return bool | |||
*/ | |||
public function has($job, $argument); | |||
/** | |||
* get all jobs in the list | |||
* | |||
* @return \OCP\BackgroundJob\IJob[] | |||
*/ | |||
public function getAll(); | |||
/** | |||
* get the next job in the list | |||
* | |||
* @return \OCP\BackgroundJob\IJob | |||
*/ | |||
public function getNext(); | |||
/** | |||
* @param int $id | |||
* @return \OCP\BackgroundJob\IJob | |||
*/ | |||
public function getById($id); | |||
/** | |||
* set the job that was last ran to the current time | |||
* | |||
* @param \OCP\BackgroundJob\IJob $job | |||
*/ | |||
public function setLastJob($job); | |||
/** | |||
* get the id of the last ran job | |||
* | |||
* @return int | |||
*/ | |||
public function getLastJob(); | |||
/** | |||
* set the lastRun of $job to now | |||
* | |||
* @param \OCP\BackgroundJob\IJob $job | |||
*/ | |||
public function setLastRun($job); | |||
} |
@@ -183,4 +183,11 @@ interface IServerContainer { | |||
*/ | |||
function getAvatarManager(); | |||
/** | |||
* Returns an job list for controlling background jobs | |||
* | |||
* @return \OCP\BackgroundJob\IJobList | |||
*/ | |||
function getJobList(); | |||
} |
@@ -21,6 +21,8 @@ class DummyJobList extends \OC\BackgroundJob\JobList { | |||
private $last = 0; | |||
public function __construct(){} | |||
/** | |||
* @param \OC\BackgroundJob\Job|string $job | |||
* @param mixed $argument |
@@ -8,31 +8,6 @@ | |||
namespace Test\BackgroundJob; | |||
class TestJob extends \OC\BackgroundJob\Job { | |||
private $testCase; | |||
/** | |||
* @var callable $callback | |||
*/ | |||
private $callback; | |||
/** | |||
* @param Job $testCase | |||
* @param callable $callback | |||
*/ | |||
public function __construct($testCase, $callback) { | |||
$this->testCase = $testCase; | |||
$this->callback = $callback; | |||
} | |||
public function run($argument) { | |||
$this->testCase->markRun(); | |||
$callback = $this->callback; | |||
$callback($argument); | |||
} | |||
} | |||
class Job extends \PHPUnit_Framework_TestCase { | |||
private $run = false; | |||
@@ -0,0 +1,203 @@ | |||
<?php | |||
/** | |||
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com> | |||
* This file is licensed under the Affero General Public License version 3 or | |||
* later. | |||
* See the COPYING-README file. | |||
*/ | |||
namespace Test\BackgroundJob; | |||
class JobList extends \PHPUnit_Framework_TestCase { | |||
/** | |||
* @var \OC\BackgroundJob\JobList | |||
*/ | |||
protected $instance; | |||
/** | |||
* @var \OCP\IConfig | \PHPUnit_Framework_MockObject_MockObject $config | |||
*/ | |||
protected $config; | |||
public function setUp() { | |||
$conn = \OC::$server->getDatabaseConnection(); | |||
$this->config = $this->getMock('\OCP\IConfig'); | |||
$this->instance = new \OC\BackgroundJob\JobList($conn, $this->config); | |||
} | |||
public function argumentProvider() { | |||
return array( | |||
array(null), | |||
array(false), | |||
array('foobar'), | |||
array(12), | |||
array(array( | |||
'asd' => 5, | |||
'foo' => 'bar' | |||
)) | |||
); | |||
} | |||
/** | |||
* @dataProvider argumentProvider | |||
* @param $argument | |||
*/ | |||
public function testAddRemove($argument) { | |||
$existingJobs = $this->instance->getAll(); | |||
$job = new TestJob(); | |||
$this->instance->add($job, $argument); | |||
$jobs = $this->instance->getAll(); | |||
$this->assertCount(count($existingJobs) + 1, $jobs); | |||
$addedJob = $jobs[count($jobs) - 1]; | |||
$this->assertInstanceOf('\Test\BackgroundJob\TestJob', $addedJob); | |||
$this->assertEquals($argument, $addedJob->getArgument()); | |||
$this->instance->remove($job, $argument); | |||
$jobs = $this->instance->getAll(); | |||
$this->assertEquals($existingJobs, $jobs); | |||
} | |||
/** | |||
* @dataProvider argumentProvider | |||
* @param $argument | |||
*/ | |||
public function testRemoveDifferentArgument($argument) { | |||
$existingJobs = $this->instance->getAll(); | |||
$job = new TestJob(); | |||
$this->instance->add($job, $argument); | |||
$jobs = $this->instance->getAll(); | |||
$this->instance->remove($job, 10); | |||
$jobs2 = $this->instance->getAll(); | |||
$this->assertEquals($jobs, $jobs2); | |||
$this->instance->remove($job, $argument); | |||
$jobs = $this->instance->getAll(); | |||
$this->assertEquals($existingJobs, $jobs); | |||
} | |||
/** | |||
* @dataProvider argumentProvider | |||
* @param $argument | |||
*/ | |||
public function testHas($argument) { | |||
$job = new TestJob(); | |||
$this->assertFalse($this->instance->has($job, $argument)); | |||
$this->instance->add($job, $argument); | |||
$this->assertTrue($this->instance->has($job, $argument)); | |||
$this->instance->remove($job, $argument); | |||
$this->assertFalse($this->instance->has($job, $argument)); | |||
} | |||
/** | |||
* @dataProvider argumentProvider | |||
* @param $argument | |||
*/ | |||
public function testHasDifferentArgument($argument) { | |||
$job = new TestJob(); | |||
$this->instance->add($job, $argument); | |||
$this->assertFalse($this->instance->has($job, 10)); | |||
$this->instance->remove($job, $argument); | |||
} | |||
public function testGetLastJob() { | |||
$this->config->expects($this->once()) | |||
->method('getAppValue') | |||
->with('backgroundjob', 'lastjob', 0) | |||
->will($this->returnValue(15)); | |||
$this->assertEquals(15, $this->instance->getLastJob()); | |||
} | |||
public function testGetNext() { | |||
$job = new TestJob(); | |||
$this->instance->add($job, 1); | |||
$this->instance->add($job, 2); | |||
$jobs = $this->instance->getAll(); | |||
$savedJob1 = $jobs[count($jobs) - 2]; | |||
$savedJob2 = $jobs[count($jobs) - 1]; | |||
$this->config->expects($this->once()) | |||
->method('getAppValue') | |||
->with('backgroundjob', 'lastjob', 0) | |||
->will($this->returnValue($savedJob1->getId())); | |||
$nextJob = $this->instance->getNext(); | |||
$this->assertEquals($savedJob2, $nextJob); | |||
$this->instance->remove($job, 1); | |||
$this->instance->remove($job, 2); | |||
} | |||
public function testGetNextWrapAround() { | |||
$job = new TestJob(); | |||
$this->instance->add($job, 1); | |||
$this->instance->add($job, 2); | |||
$jobs = $this->instance->getAll(); | |||
$savedJob2 = $jobs[count($jobs) - 1]; | |||
$this->config->expects($this->once()) | |||
->method('getAppValue') | |||
->with('backgroundjob', 'lastjob', 0) | |||
->will($this->returnValue($savedJob2->getId())); | |||
$nextJob = $this->instance->getNext(); | |||
$this->assertEquals($jobs[0], $nextJob); | |||
$this->instance->remove($job, 1); | |||
$this->instance->remove($job, 2); | |||
} | |||
/** | |||
* @dataProvider argumentProvider | |||
* @param $argument | |||
*/ | |||
public function testGetById($argument) { | |||
$job = new TestJob(); | |||
$this->instance->add($job, $argument); | |||
$jobs = $this->instance->getAll(); | |||
$addedJob = $jobs[count($jobs) - 1]; | |||
$this->assertEquals($addedJob, $this->instance->getById($addedJob->getId())); | |||
$this->instance->remove($job, $argument); | |||
} | |||
public function testSetLastRun() { | |||
$job = new TestJob(); | |||
$this->instance->add($job); | |||
$jobs = $this->instance->getAll(); | |||
$addedJob = $jobs[count($jobs) - 1]; | |||
$timeStart = time(); | |||
$this->instance->setLastRun($addedJob); | |||
$timeEnd = time(); | |||
$addedJob = $this->instance->getById($addedJob->getId()); | |||
$this->assertGreaterThanOrEqual($timeStart, $addedJob->getLastRun()); | |||
$this->assertLessThanOrEqual($timeEnd, $addedJob->getLastRun()); | |||
$this->instance->remove($job); | |||
} | |||
} |
@@ -0,0 +1,34 @@ | |||
<?php | |||
/** | |||
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com> | |||
* This file is licensed under the Affero General Public License version 3 or | |||
* later. | |||
* See the COPYING-README file. | |||
*/ | |||
namespace Test\BackgroundJob; | |||
class TestJob extends \OC\BackgroundJob\Job { | |||
private $testCase; | |||
/** | |||
* @var callable $callback | |||
*/ | |||
private $callback; | |||
/** | |||
* @param Job $testCase | |||
* @param callable $callback | |||
*/ | |||
public function __construct($testCase = null, $callback = null) { | |||
$this->testCase = $testCase; | |||
$this->callback = $callback; | |||
} | |||
public function run($argument) { | |||
$this->testCase->markRun(); | |||
$callback = $this->callback; | |||
$callback($argument); | |||
} | |||
} |