Initial commit

This commit is contained in:
Chris Boulton 2010-04-18 23:58:43 +10:00
commit cb4205d508
37 changed files with 2808 additions and 0 deletions

View file

@ -0,0 +1,102 @@
<?php
require_once dirname(__FILE__) . '/bootstrap.php';
/**
* Resque_Job_Status tests.
*
* @package Resque/Tests
* @author Chris Boulton <chris.boulton@interspire.com>
* @copyright (c) 2010 Chris Boulton
* @license http://www.opensource.org/licenses/mit-license.php
*/
class Resque_Tests_JobStatusTest extends Resque_Tests_TestCase
{
public function setUp()
{
parent::setUp();
// Register a worker to test with
$this->worker = new Resque_Worker('jobs');
}
public function testJobStatusCanBeTracked()
{
$token = Resque::enqueue('jobs', 'Test_Job', null, true);
$status = new Resque_Job_Status($token);
$this->assertTrue($status->isTracking());
}
public function testJobStatusIsReturnedViaJobInstance()
{
$token = Resque::enqueue('jobs', 'Test_Job', null, true);
$job = Resque_Job::reserve('jobs');
$this->assertEquals(Resque_Job_Status::STATUS_WAITING, $job->getStatus());
}
public function testQueuedJobReturnsQueuedStatus()
{
$token = Resque::enqueue('jobs', 'Test_Job', null, true);
$status = new Resque_Job_Status($token);
$this->assertEquals(Resque_Job_Status::STATUS_WAITING, $status->get());
}
public function testRunningJobReturnsRunningStatus()
{
$token = Resque::enqueue('jobs', 'Failing_Job', null, true);
$job = $this->worker->reserve();
$this->worker->workingOn($job);
$status = new Resque_Job_Status($token);
$this->assertEquals(Resque_Job_Status::STATUS_RUNNING, $status->get());
}
public function testFailedJobReturnsFailedStatus()
{
$token = Resque::enqueue('jobs', 'Failing_Job', null, true);
$this->worker->work(0);
$status = new Resque_Job_Status($token);
$this->assertEquals(Resque_Job_Status::STATUS_FAILED, $status->get());
}
public function testCompletedJobReturnsCompletedStatus()
{
$token = Resque::enqueue('jobs', 'Test_Job', null, true);
$this->worker->work(0);
$status = new Resque_Job_Status($token);
$this->assertEquals(Resque_Job_Status::STATUS_COMPLETE, $status->get());
}
public function testStatusIsNotTrackedWhenToldNotTo()
{
$token = Resque::enqueue('jobs', 'Test_Job', null, false);
$status = new Resque_Job_Status($token);
$this->assertFalse($status->isTracking());
}
public function testStatusTrackingCanBeStopped()
{
Resque_Job_Status::create('test');
$status = new Resque_Job_Status('test');
$this->assertEquals(Resque_Job_Status::STATUS_WAITING, $status->get());
$status->stop();
$this->assertFalse($status->get());
}
public function testRecreatedJobWithTrackingStillTracksStatus()
{
$originalToken = Resque::enqueue('jobs', 'Test_Job', null, true);
$job = $this->worker->reserve();
// Mark this job as being worked on to ensure that the new status is still
// waiting.
$this->worker->workingOn($job);
// Now recreate it
$newToken = $job->recreate();
// Make sure we've got a new job returned
$this->assertNotEquals($originalToken, $newToken);
// Now check the status of the new job
$newJob = Resque_Job::reserve('jobs');
$this->assertEquals(Resque_Job_Status::STATUS_WAITING, $newJob->getStatus());
}
}

View file

@ -0,0 +1,140 @@
<?php
require_once dirname(__FILE__) . '/bootstrap.php';
/**
* Resque_Job tests.
*
* @package Resque/Tests
* @author Chris Boulton <chris.boulton@interspire.com>
* @copyright (c) 2010 Chris Boulton
* @license http://www.opensource.org/licenses/mit-license.php
*/
class Resque_Tests_JobTest extends Resque_Tests_TestCase
{
protected $worker;
public function setUp()
{
parent::setUp();
// Register a worker to test with
$this->worker = new Resque_Worker('jobs');
$this->worker->registerWorker();
}
public function tearDown()
{
$this->worker->unregisterWorker();
}
public function testJobCanBeQueued()
{
$this->assertTrue((bool)Resque::enqueue('jobs', 'Test_Job'));
}
public function testQeueuedJobCanBeReserved()
{
Resque::enqueue('jobs', 'Test_Job');
$job = Resque_Job::reserve('jobs');
if($job == false) {
$this->fail('Job could not be reserved.');
}
$this->assertEquals('jobs', $job->queue);
$this->assertEquals('Test_Job', $job->payload->class);
}
/**
* @expectedException InvalidArgumentException
*/
public function testArrayArgumentsCannotBePassedToJob()
{
Resque::enqueue('jobs', 'Test_Job', array(
'test'
));
}
public function testQueuedJobReturnsExactSamePassedInArguments()
{
$args = new stdClass;
$args->int = 123;
$args->numArray = array(
1,
2,
);
$args->assocArray = new stdClass;
$args->assocArray->key1 = 'value1';
$args->assocArray->key2 = 'value2';
Resque::enqueue('jobs', 'Test_Job', $args);
$job = Resque_Job::reserve('jobs');
$this->assertEquals($args, $job->payload->args);
}
public function testAfterJobIsReservedItIsRemoved()
{
Resque::enqueue('jobs', 'Test_Job');
Resque_Job::reserve('jobs');
$this->assertFalse(Resque_Job::reserve('jobs'));
}
public function testRecreatedJobMatchesExistingJob()
{
$args = new stdClass;
$args->int = 123;
$args->numArray = array(
1,
2,
);
$args->assocArray = new stdClass;
$args->assocArray->key1 = 'value1';
$args->assocArray->key2 = 'value2';
Resque::enqueue('jobs', 'Test_Job', $args);
$job = Resque_Job::reserve('jobs');
// Now recreate it
$job->recreate();
$newJob = Resque_Job::reserve('jobs');
$this->assertEquals($job->payload->class, $newJob->payload->class);
$this->assertEquals($job->payload->args, $newJob->payload->args);
}
public function testFailedJobExceptionsAreCaught()
{
$payload = new stdClass;
$payload->class = 'Failing_Job';
$payload->args = null;
$job = new Resque_Job('jobs', $payload);
$job->worker = $this->worker;
$this->worker->perform($job);
$this->assertEquals(1, Resque_Stat::get('failed'));
$this->assertEquals(1, Resque_Stat::get('failed:'.$this->worker));
}
/**
* @expectedException Resque_Exception
*/
public function testJobWithoutPerformMethodThrowsException()
{
Resque::enqueue('jobs', 'Test_Job_Without_Perform_Method');
$job = $this->worker->reserve();
$job->worker = $this->worker;
$job->perform();
}
/**
* @expectedException Resque_Exception
*/
public function testInvalidJobThrowsException()
{
Resque::enqueue('jobs', 'Invalid_Job');
$job = $this->worker->reserve();
$job->worker = $this->worker;
$job->perform();
}
}

View file

@ -0,0 +1,52 @@
<?php
require_once dirname(__FILE__) . '/bootstrap.php';
/**
* Resque_Stat tests.
*
* @package Resque/Tests
* @author Chris Boulton <chris.boulton@interspire.com>
* @copyright (c) 2010 Chris Boulton
* @license http://www.opensource.org/licenses/mit-license.php
*/
class Resque_Tests_StatTest extends Resque_Tests_TestCase
{
public function testStatCanBeIncremented()
{
Resque_Stat::incr('test_incr');
Resque_Stat::incr('test_incr');
$this->assertEquals(2, $this->redis->get('resque:stat:test_incr'));
}
public function testStatCanBeIncrementedByX()
{
Resque_Stat::incr('test_incrX', 10);
Resque_Stat::incr('test_incrX', 11);
$this->assertEquals(21, $this->redis->get('resque:stat:test_incrX'));
}
public function testStatCanBeDecremented()
{
Resque_Stat::incr('test_decr', 22);
Resque_Stat::decr('test_decr');
$this->assertEquals(21, $this->redis->get('resque:stat:test_decr'));
}
public function testStatCanBeDecrementedByX()
{
Resque_Stat::incr('test_decrX', 22);
Resque_Stat::decr('test_decrX', 11);
$this->assertEquals(11, $this->redis->get('resque:stat:test_decrX'));
}
public function testGetStatByName()
{
Resque_Stat::incr('test_get', 100);
$this->assertEquals(100, Resque_Stat::get('test_get'));
}
public function testGetUnknownStatReturns0()
{
$this->assertEquals(0, Resque_Stat::get('test_get_unknown'));
}
}

View file

@ -0,0 +1,24 @@
<?php
/**
* Resque test case class. Contains setup and teardown methods.
*
* @package Resque/Tests
* @author Chris Boulton <chris.boulton@interspire.com>
* @copyright (c) 2010 Chris Boulton
* @license http://www.opensource.org/licenses/mit-license.php
*/
class Resque_Tests_TestCase extends PHPUnit_Framework_TestCase
{
protected $resque;
protected $redis;
public function setUp()
{
$config = file_get_contents(REDIS_CONF);
preg_match('#^\s*port\s+([0-9]+)#m', $config, $matches);
$this->redis = new Redisent('localhost', $matches[1]);
// Flush redis
$this->redis->flushAll();
}
}

View file

@ -0,0 +1,251 @@
<?php
require_once dirname(__FILE__) . '/bootstrap.php';
/**
* Resque_Worker tests.
*
* @package Resque/Tests
* @author Chris Boulton <chris.boulton@interspire.com>
* @copyright (c) 2010 Chris Boulton
* @license http://www.opensource.org/licenses/mit-license.php
*/
class Resque_Tests_WorkerTest extends Resque_Tests_TestCase
{
public function testWorkerRegistersInList()
{
$worker = new Resque_Worker('*');
$worker->registerWorker();
// Make sure the worker is in the list
$this->assertTrue((bool)$this->redis->sismember('resque:workers', (string)$worker));
}
public function testGetAllWorkers()
{
$num = 3;
// Register a few workers
for($i = 0; $i < $num; ++$i) {
$worker = new Resque_Worker('queue_' . $i);
$worker->registerWorker();
}
// Now try to get them
$this->assertEquals($num, count(Resque_Worker::all()));
}
public function testGetWorkerById()
{
$worker = new Resque_Worker('*');
$worker->registerWorker();
$newWorker = Resque_Worker::find((string)$worker);
$this->assertEquals((string)$worker, (string)$newWorker);
}
public function testInvalidWorkerDoesNotExist()
{
$this->assertFalse(Resque_Worker::exists('blah'));
}
public function testWorkerCanUnregister()
{
$worker = new Resque_Worker('*');
$worker->registerWorker();
$worker->unregisterWorker();
$this->assertFalse(Resque_Worker::exists((string)$worker));
$this->assertEquals(array(), Resque_Worker::all());
$this->assertNull($this->redis->smembers('redis:workers'));
}
public function testPausedWorkerDoesNotPickUpJobs()
{
$worker = new Resque_Worker('*');
$worker->pauseProcessing();
Resque::enqueue('jobs', 'Test_Job');
$worker->work(0);
$worker->work(0);
$this->assertEquals(0, Resque_Stat::get('processed'));
}
public function testResumedWorkerPicksUpJobs()
{
$worker = new Resque_Worker('*');
$worker->pauseProcessing();
Resque::enqueue('jobs', 'Test_Job');
$worker->work(0);
$this->assertEquals(0, Resque_Stat::get('processed'));
$worker->unPauseProcessing();
$worker->work(0);
$this->assertEquals(1, Resque_Stat::get('processed'));
}
public function testWorkerCanWorkOverMultipleQueues()
{
$worker = new Resque_Worker(array(
'queue1',
'queue2'
));
$worker->registerWorker();
Resque::enqueue('queue1', 'Test_Job_1');
Resque::enqueue('queue2', 'Test_Job_2');
$job = $worker->reserve();
$this->assertEquals('queue1', $job->queue);
$job = $worker->reserve();
$this->assertEquals('queue2', $job->queue);
}
public function testWorkerWorksQueuesInSpecifiedOrder()
{
$worker = new Resque_Worker(array(
'high',
'medium',
'low'
));
$worker->registerWorker();
// Queue the jobs in a different order
Resque::enqueue('low', 'Test_Job_1');
Resque::enqueue('high', 'Test_Job_2');
Resque::enqueue('medium', 'Test_Job_3');
// Now check we get the jobs back in the right order
$job = $worker->reserve();
$this->assertEquals('high', $job->queue);
$job = $worker->reserve();
$this->assertEquals('medium', $job->queue);
$job = $worker->reserve();
$this->assertEquals('low', $job->queue);
}
public function testWildcardQueueWorkerWorksAllQueues()
{
$worker = new Resque_Worker('*');
$worker->registerWorker();
Resque::enqueue('queue1', 'Test_Job_1');
Resque::enqueue('queue2', 'Test_Job_2');
$job = $worker->reserve();
$this->assertEquals('queue1', $job->queue);
$job = $worker->reserve();
$this->assertEquals('queue2', $job->queue);
}
public function testWorkerDoesNotWorkOnUnknownQueues()
{
$worker = new Resque_Worker('queue1');
$worker->registerWorker();
Resque::enqueue('queue2', 'Test_Job');
$this->assertFalse($worker->reserve());
}
public function testWorkerClearsItsStatusWhenNotWorking()
{
Resque::enqueue('jobs', 'Test_Job');
$worker = new Resque_Worker('jobs');
$job = $worker->reserve();
$worker->workingOn($job);
$worker->doneWorking();
$this->assertEquals(new stdClass, $worker->job());
}
public function testWorkerRecordsWhatItIsWorkingOn()
{
$worker = new Resque_Worker('jobs');
$worker->registerWorker();
$payload = new stdClass;
$payload->class = 'Test_Job';
$job = new Resque_Job('jobs', $payload);
$worker->workingOn($job);
$job = $worker->job();
$this->assertEquals('jobs', $job->queue);
if(!isset($job->run_at)) {
$this->fail('Job does not have run_at time');
}
$this->assertEquals($payload, $job->payload);
}
public function testWorkerErasesItsStatsWhenShutdown()
{
Resque::enqueue('jobs', 'Test_Job');
Resque::enqueue('jobs', 'Invalid_Job');
$worker = new Resque_Worker('jobs');
$worker->work(0);
$worker->work(0);
$this->assertEquals(0, $worker->getStat('processed'));
$this->assertEquals(0, $worker->getStat('failed'));
}
public function testWorkerCleansUpDeadWorkersOnStartup()
{
// Register a good worker
$goodWorker = new Resque_Worker('jobs');
$goodWorker->registerWorker();
$workerId = explode(':', $goodWorker);
// Register some bad workers
$worker = new Resque_Worker('jobs');
$worker->setId($workerId[0].':1:jobs');
$worker->registerWorker();
$worker = new Resque_Worker(array('high', 'low'));
$worker->setId($workerId[0].':2:high,low');
$worker->registerWorker();
$this->assertEquals(3, count(Resque_Worker::all()));
$goodWorker->pruneDeadWorkers();
// There should only be $goodWorker left now
$this->assertEquals(1, count(Resque_Worker::all()));
}
public function testDeadWorkerCleanUpDoesNotCleanUnknownWorkers()
{
// Register a bad worker on this machine
$worker = new Resque_Worker('jobs');
$workerId = explode(':', $worker);
$worker->setId($workerId[0].':1:jobs');
$worker->registerWorker();
// Register some other false workers
$worker = new Resque_Worker('jobs');
$worker->setId('my.other.host:1:jobs');
$worker->registerWorker();
$this->assertEquals(2, count(Resque_Worker::all()));
$worker->pruneDeadWorkers();
// my.other.host should be left
$workers = Resque_Worker::all();
$this->assertEquals(1, count($workers));
$this->assertEquals((string)$worker, (string)$workers[0]);
}
public function testWorkerFailsUncompletedJobsOnExit()
{
$worker = new Resque_Worker('jobs');
$worker->registerWorker();
$payload = new stdClass;
$payload->class = 'Test_Job';
$job = new Resque_Job('jobs', $payload);
$worker->workingOn($job);
$worker->unregisterWorker();
$this->assertEquals(1, Resque_Stat::get('failed'));
}
}

View file

@ -0,0 +1,116 @@
<?php
/**
* Resque test bootstrap file - sets up a test environment.
*
* @package Resque/Tests
* @author Chris Boulton <chris.boulton@interspire.com>
* @copyright (c) 2010 Chris Boulton
* @license http://www.opensource.org/licenses/mit-license.php
*/
define('CWD', dirname(__FILE__));
define('RESQUE_LIB', CWD . '/../../../lib/');
define('TEST_MISC', realpath(CWD . '/../../misc/'));
define('REDIS_CONF', TEST_MISC . '/redis.conf');
// Change to the directory this file lives in. This is important, due to
// how we'll be running redis.
require_once CWD . '/TestCase.php';
// Include Resque
require_once RESQUE_LIB . 'Resque.php';
require_once RESQUE_LIB . 'Resque/Worker.php';
// Attempt to start our own redis instance for tesitng.
exec('which redis-server', $output, $returnVar);
if($returnVar != 0) {
echo "Cannot find redis-server in path. Please make sure redis is installed.\n";
exit(1);
}
exec('cd ' . TEST_MISC . '; redis-server ' . REDIS_CONF, $output, $returnVar);
if($returnVar != 0) {
echo "Cannot start redis-server.\n";
exit(1);
}
// Get redis port from conf
$config = file_get_contents(REDIS_CONF);
if(!preg_match('#^\s*port\s+([0-9]+)#m', $config, $matches)) {
echo "Could not determine redis port from redis.conf";
exit(1);
}
Resque::setBackend('localhost:' . $matches[1]);
// Shutdown
function killRedis()
{
$config = file_get_contents(REDIS_CONF);
if(!preg_match('#^\s*pidfile\s+([^\s]+)#m', $config, $matches)) {
return;
}
$pidFile = TEST_MISC . '/' . $matches[1];
$pid = trim(file_get_contents($pidFile));
posix_kill($pid, 9);
if(is_file($pidFile)) {
unlink($pidFile);
}
// Remove the redis database
if(!preg_match('#^\s*dir\s+([^\s]+)#m', $config, $matches)) {
return;
}
$dir = $matches[1];
if(!preg_match('#^\s*dbfilename\s+([^\s]+)#m', $config, $matches)) {
return;
}
$filename = TEST_MISC . '/' . $dir . '/' . $matches[1];
if(is_file($filename)) {
unlink($filename);
}
}
register_shutdown_function('killRedis');
if(function_exists('pcntl_signal')) {
// Override INT and TERM signals, so they do a clean shutdown and also
// clean up redis-server as well.
function sigint()
{
exit;
}
pcntl_signal(SIGINT, 'sigint');
pcntl_signal(SIGTERM, 'sigint');
}
class Test_Job
{
public function perform()
{
}
}
class Failing_Job_Exception extends Exception
{
}
class Failing_Job
{
public function perform()
{
throw new Failing_Job_Exception('Message!');
}
}
class Test_Job_Without_Perform_Method
{
}