Commit b8402c95 authored by Benjamin Eberlei's avatar Benjamin Eberlei

Added Gearman Lock Test and Worker, verified lockings indeed works on MySQL, PostgreSQL and Oracle

parent f65a555d
<?php
namespace Doctrine\Tests\ORM\Functional\Locking;
use Doctrine\Tests\Models\CMS\CmsArticle,
Doctrine\Tests\Models\CMS\CmsUser,
Doctrine\ORM\LockMode,
Doctrine\ORM\EntityManager;
require_once __DIR__ . '/../../../TestInit.php';
class GearmanLockTest extends \Doctrine\Tests\OrmFunctionalTestCase
{
private $gearman = null;
private $maxRunTime = 0;
private $articleId;
protected function setUp()
{
if (!class_exists('GearmanClient', false)) {
$this->markTestSkipped('pecl/gearman is required for this test to run.');
}
$this->useModelSet('cms');
parent::setUp();
$this->tasks = array();
$this->gearman = new \GearmanClient();
$this->gearman->addServer();
$this->gearman->setCompleteCallback(array($this, "gearmanTaskCompleted"));
$article = new CmsArticle();
$article->text = "my article";
$article->topic = "Hello";
$this->_em->persist($article);
$this->_em->flush();
$this->articleId = $article->id;
}
public function gearmanTaskCompleted($task)
{
$this->maxRunTime = max($this->maxRunTime, $task->data());
}
public function testFindWithLock()
{
$this->asyncFindWithLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_WRITE);
$this->asyncFindWithLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_WRITE);
$this->assertLockWorked();
}
public function testFindWithWriteThenReadLock()
{
$this->asyncFindWithLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_WRITE);
$this->asyncFindWithLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_READ);
$this->assertLockWorked();
}
public function testFindWithReadThenWriteLock()
{
$this->asyncFindWithLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_READ);
$this->asyncFindWithLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_WRITE);
$this->assertLockWorked();
}
public function testFindWithOneLock()
{
$this->asyncFindWithLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_WRITE);
$this->asyncFindWithLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::NONE);
$this->assertLockDoesNotBlock();
}
public function testDqlWithLock()
{
$this->asyncDqlWithLock('SELECT a FROM Doctrine\Tests\Models\CMS\CmsArticle a', array(), LockMode::PESSIMISTIC_WRITE);
$this->asyncFindWithLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_WRITE);
$this->assertLockWorked();
}
public function testLock()
{
$this->asyncFindWithLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_WRITE);
$this->asyncLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_WRITE);
$this->assertLockWorked();
}
public function testLock2()
{
$this->asyncFindWithLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_WRITE);
$this->asyncLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_READ);
$this->assertLockWorked();
}
public function testLock3()
{
$this->asyncFindWithLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_READ);
$this->asyncLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_WRITE);
$this->assertLockWorked();
}
public function testLock4()
{
$this->asyncFindWithLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::NONE);
$this->asyncLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_WRITE);
$this->assertLockDoesNotBlock();
}
protected function assertLockDoesNotBlock()
{
$this->assertLockWorked($onlyForSeconds = 1);
}
protected function assertLockWorked($forTime = 2, $notLongerThan = null)
{
if ($notLongerThan === null) {
$notLongerThan = $forTime + 1;
}
$this->gearman->runTasks();
$this->assertTrue($this->maxRunTime > $forTime,
"Because of locking this tests should have run at least " . $forTime . " seconds, ".
"but only did for " . $this->maxRunTime . " seconds.");
$this->assertTrue($this->maxRunTime < $notLongerThan,
"The longest task should not run longer than " . $notLongerThan . " seconds, ".
"but did for " . $this->maxRunTime . " seconds."
);
}
protected function asyncFindWithLock($entityName, $entityId, $lockMode)
{
$this->startGearmanJob('findWithLock', array(
'entityName' => $entityName,
'entityId' => $entityId,
'lockMode' => $lockMode,
));
}
protected function asyncDqlWithLock($dql, $params, $lockMode)
{
$this->startGearmanJob('dqlWithLock', array(
'dql' => $dql,
'dqlParams' => $params,
'lockMode' => $lockMode,
));
}
protected function asyncLock($entityName, $entityId, $lockMode)
{
$this->startGearmanJob('lock', array(
'entityName' => $entityName,
'entityId' => $entityId,
'lockMode' => $lockMode,
));
}
protected function startGearmanJob($fn, $fixture)
{
$this->gearman->addTask($fn, serialize(array(
'conn' => $this->_em->getConnection()->getParams(),
'fixture' => $fixture
)));
$this->assertEquals(GEARMAN_SUCCESS, $this->gearman->returnCode());
}
}
\ No newline at end of file
<?php
namespace Doctrine\Tests\ORM\Functional\Locking;
require_once __DIR__ . "/../../../TestInit.php";
class LockAgentWorker
{
private $em;
static public function run()
{
$lockAgent = new LockAgentWorker();
$worker = new \GearmanWorker();
$worker->addServer();
$worker->addFunction("findWithLock", array($lockAgent, "findWithLock"));
$worker->addFunction("dqlWithLock", array($lockAgent, "dqlWithLock"));
$worker->addFunction('lock', array($lockAgent, 'lock'));
while($worker->work()) {
if ($worker->returnCode() != GEARMAN_SUCCESS) {
echo "return_code: " . $worker->returnCode() . "\n";
break;
}
}
}
protected function process($job, \Closure $do)
{
$fixture = $this->processWorkload($job);
$s = microtime(true);
$this->em->beginTransaction();
$do($fixture, $this->em);
sleep(1);
$this->em->rollback();
$this->em->clear();
$this->em->close();
$this->em->getConnection()->close();
return (microtime(true) - $s);
}
public function findWithLock($job)
{
return $this->process($job, function($fixture, $em) {
$entity = $em->find($fixture['entityName'], $fixture['entityId'], $fixture['lockMode']);
});
}
public function dqlWithLock($job)
{
return $this->process($job, function($fixture, $em) {
/* @var $query Doctrine\ORM\Query */
$query = $em->createQuery($fixture['dql']);
$query->setLockMode($fixture['lockMode']);
$query->setParameters($fixture['dqlParams']);
$result = $query->getResult();
});
}
public function lock($job)
{
return $this->process($job, function($fixture, $em) {
$entity = $em->find($fixture['entityName'], $fixture['entityId']);
$em->lock($entity, $fixture['lockMode']);
});
}
protected function processWorkload($job)
{
echo "Received job: " . $job->handle() . " for function " . $job->functionName() . "\n";
$workload = $job->workload();
$workload = unserialize($workload);
if (!isset($workload['conn']) || !is_array($workload['conn'])) {
throw new \InvalidArgumentException("Missing Database parameters");
}
$this->em = $this->createEntityManager($workload['conn']);
if (!isset($workload['fixture'])) {
throw new \InvalidArgumentException("Missing Fixture parameters");
}
return $workload['fixture'];
}
protected function createEntityManager($conn)
{
$config = new \Doctrine\ORM\Configuration();
$config->setProxyDir(__DIR__ . '/../../../Proxies');
$config->setProxyNamespace('MyProject\Proxies');
$config->setAutoGenerateProxyClasses(true);
$annotDriver = $config->newDefaultAnnotationDriver(array(__DIR__ . '/../../../Models/'));
$config->setMetadataDriverImpl($annotDriver);
$cache = new \Doctrine\Common\Cache\ArrayCache();
$config->setMetadataCacheImpl($cache);
$config->setQueryCacheImpl($cache);
$em = \Doctrine\ORM\EntityManager::create($conn, $config);
return $em;
}
}
LockAgentWorker::run();
\ No newline at end of file
# Running the Doctrine 2 Testsuite
## Setting up a PHPUnit Configuration XML
..
## Testing Lock-Support
The Lock support in Doctrine 2 is tested using Gearman, which allows to run concurrent tasks in parallel.
Install Gearman with PHP as follows:
1. Go to http://www.gearman.org and download the latest Gearman Server
2. Compile it and then call ldconfig
3. Start it up "gearmand -vvvv"
4. Install pecl/gearman by calling "gearman-beta"
You can then go into tests/ and start up two workers:
php Doctrine/Tests/ORM/Functional/Locking/LockAgentWorker.php
Then run the locking test-suite:
phpunit --configuration <myconfig.xml> Doctrine/Tests/ORM/Functional/Locking/GearmanLockTest.php
This can run considerable time, because it is using sleep() to test for the timing ranges of locks.
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment