8 class JobQueueTest
extends MediaWikiTestCase
{
10 protected $queueRand, $queueRandTTL, $queueFifo, $queueFifoTTL;
12 function __construct( $name = null, array $data = array(), $dataName = '' ) {
13 parent
::__construct( $name, $data, $dataName );
15 $this->tablesUsed
[] = 'job';
18 protected function setUp() {
19 global $wgJobTypeConf;
22 $this->setMwGlobals( 'wgMemc', new HashBagOStuff() );
24 if ( $this->getCliArg( 'use-jobqueue=' ) ) {
25 $name = $this->getCliArg( 'use-jobqueue=' );
26 if ( !isset( $wgJobTypeConf[$name] ) ) {
27 throw new MWException( "No \$wgJobTypeConf entry for '$name'." );
29 $baseConfig = $wgJobTypeConf[$name];
31 $baseConfig = array( 'class' => 'JobQueueDB' );
33 $baseConfig['type'] = 'null';
34 $baseConfig['wiki'] = wfWikiID();
36 'queueRand' => array( 'order' => 'random', 'claimTTL' => 0 ),
37 'queueRandTTL' => array( 'order' => 'random', 'claimTTL' => 10 ),
38 'queueTimestamp' => array( 'order' => 'timestamp', 'claimTTL' => 0 ),
39 'queueTimestampTTL' => array( 'order' => 'timestamp', 'claimTTL' => 10 ),
40 'queueFifo' => array( 'order' => 'fifo', 'claimTTL' => 0 ),
41 'queueFifoTTL' => array( 'order' => 'fifo', 'claimTTL' => 10 ),
43 foreach ( $variants as $q => $settings ) {
45 $this->$q = JobQueue
::factory( $settings +
$baseConfig );
46 if ( !( $this->$q instanceof JobQueueDB
) ) {
47 $this->$q->setTestingPrefix( 'unittests-' . wfRandomString( 32 ) );
49 } catch ( MWException
$e ) {}; // unsupported? (@TODO: what if it was another error?)
53 protected function tearDown() {
57 'queueRand', 'queueRandTTL', 'queueTimestamp', 'queueTimestampTTL',
58 'queueFifo', 'queueFifoTTL'
63 $job = $this->$q->pop();
65 $this->$q->ack( $job );
74 * @dataProvider provider_queueLists
76 function testProperties( $queue, $recycles, $desc ) {
77 $queue = $this->$queue;
79 $this->markTestSkipped( $desc );
82 $this->assertEquals( wfWikiID(), $queue->getWiki(), "Proper wiki ID ($desc)" );
83 $this->assertEquals( 'null', $queue->getType(), "Proper job type ($desc)" );
87 * @dataProvider provider_queueLists
89 function testBasicOperations( $queue, $recycles, $desc ) {
90 $queue = $this->$queue;
92 $this->markTestSkipped( $desc );
95 $this->assertTrue( $queue->isEmpty(), "Queue is empty ($desc)" );
97 $queue->flushCaches();
98 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
99 $this->assertEquals( 0, $queue->getAcquiredCount(), "Queue is empty ($desc)" );
101 $this->assertTrue( $queue->push( $this->newJob() ), "Push worked ($desc)" );
102 $this->assertTrue( $queue->batchPush( array( $this->newJob() ) ), "Push worked ($desc)" );
104 $this->assertFalse( $queue->isEmpty(), "Queue is not empty ($desc)" );
106 $queue->flushCaches();
107 $this->assertEquals( 2, $queue->getSize(), "Queue size is correct ($desc)" );
108 $this->assertEquals( 0, $queue->getAcquiredCount(), "No jobs active ($desc)" );
110 $job1 = $queue->pop();
111 $this->assertFalse( $queue->isEmpty(), "Queue is not empty ($desc)" );
113 $queue->flushCaches();
114 $this->assertEquals( 1, $queue->getSize(), "Queue size is correct ($desc)" );
116 $queue->flushCaches();
118 $this->assertEquals( 1, $queue->getAcquiredCount(), "Active job count ($desc)" );
120 $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
123 $job2 = $queue->pop();
124 $this->assertTrue( $queue->isEmpty(), "Queue is empty ($desc)" );
125 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
127 $queue->flushCaches();
129 $this->assertEquals( 2, $queue->getAcquiredCount(), "Active job count ($desc)" );
131 $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
134 $queue->ack( $job1 );
136 $queue->flushCaches();
138 $this->assertEquals( 1, $queue->getAcquiredCount(), "Active job count ($desc)" );
140 $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
143 $queue->ack( $job2 );
145 $queue->flushCaches();
146 $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
150 * @dataProvider provider_queueLists
152 function testBasicDeduplication( $queue, $recycles, $desc ) {
153 $queue = $this->$queue;
155 $this->markTestSkipped( $desc );
158 $this->assertTrue( $queue->isEmpty(), "Queue is empty ($desc)" );
160 $queue->flushCaches();
161 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
162 $this->assertEquals( 0, $queue->getAcquiredCount(), "Queue is empty ($desc)" );
166 array( $this->newDedupedJob(), $this->newDedupedJob(), $this->newDedupedJob() )
168 "Push worked ($desc)" );
170 $this->assertFalse( $queue->isEmpty(), "Queue is not empty ($desc)" );
172 $queue->flushCaches();
173 $this->assertEquals( 1, $queue->getSize(), "Queue size is correct ($desc)" );
174 $this->assertEquals( 0, $queue->getAcquiredCount(), "No jobs active ($desc)" );
178 array( $this->newDedupedJob(), $this->newDedupedJob(), $this->newDedupedJob() )
180 "Push worked ($desc)"
183 $this->assertFalse( $queue->isEmpty(), "Queue is not empty ($desc)" );
185 $queue->flushCaches();
186 $this->assertEquals( 1, $queue->getSize(), "Queue size is correct ($desc)" );
187 $this->assertEquals( 0, $queue->getAcquiredCount(), "No jobs active ($desc)" );
189 $job1 = $queue->pop();
190 $this->assertTrue( $queue->isEmpty(), "Queue is empty ($desc)" );
192 $queue->flushCaches();
193 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
195 $this->assertEquals( 1, $queue->getAcquiredCount(), "Active job count ($desc)" );
197 $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
200 $queue->ack( $job1 );
202 $queue->flushCaches();
203 $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
207 * @dataProvider provider_queueLists
209 function testRootDeduplication( $queue, $recycles, $desc ) {
210 $queue = $this->$queue;
212 $this->markTestSkipped( $desc );
215 $this->assertTrue( $queue->isEmpty(), "Queue is empty ($desc)" );
217 $queue->flushCaches();
218 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
219 $this->assertEquals( 0, $queue->getAcquiredCount(), "Queue is empty ($desc)" );
221 $id = wfRandomString( 32 );
222 $root1 = Job
::newRootJobParams( "nulljobspam:$id" ); // task ID/timestamp
223 for ( $i = 0; $i < 5; ++
$i ) {
224 $this->assertTrue( $queue->push( $this->newJob( 0, $root1 ) ), "Push worked ($desc)" );
226 $queue->deduplicateRootJob( $this->newJob( 0, $root1 ) );
227 sleep( 1 ); // roo job timestamp will increase
228 $root2 = Job
::newRootJobParams( "nulljobspam:$id" ); // task ID/timestamp
229 $this->assertNotEquals( $root1['rootJobTimestamp'], $root2['rootJobTimestamp'],
230 "Root job signatures have different timestamps." );
231 for ( $i = 0; $i < 5; ++
$i ) {
232 $this->assertTrue( $queue->push( $this->newJob( 0, $root2 ) ), "Push worked ($desc)" );
234 $queue->deduplicateRootJob( $this->newJob( 0, $root2 ) );
236 $this->assertFalse( $queue->isEmpty(), "Queue is not empty ($desc)" );
238 $queue->flushCaches();
239 $this->assertEquals( 10, $queue->getSize(), "Queue size is correct ($desc)" );
240 $this->assertEquals( 0, $queue->getAcquiredCount(), "No jobs active ($desc)" );
245 $job = $queue->pop();
250 if ( $job instanceof DuplicateJob
) {
255 $this->assertEquals( 10, count( $jobs ), "Correct number of jobs popped ($desc)" );
256 $this->assertEquals( 5, $dupcount, "Correct number of duplicate jobs popped ($desc)" );
260 * @dataProvider provider_fifoQueueLists
262 function testJobOrder( $queue, $recycles, $desc ) {
263 $queue = $this->$queue;
265 $this->markTestSkipped( $desc );
268 $this->assertTrue( $queue->isEmpty(), "Queue is empty ($desc)" );
270 $queue->flushCaches();
271 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
272 $this->assertEquals( 0, $queue->getAcquiredCount(), "Queue is empty ($desc)" );
274 for ( $i = 0; $i < 10; ++
$i ) {
275 $this->assertTrue( $queue->push( $this->newJob( $i ) ), "Push worked ($desc)" );
278 for ( $i = 0; $i < 10; ++
$i ) {
279 $job = $queue->pop();
280 $this->assertTrue( $job instanceof Job
, "Jobs popped from queue ($desc)" );
281 $params = $job->getParams();
282 $this->assertEquals( $i, $params['i'], "Job popped from queue is FIFO ($desc)" );
286 $this->assertFalse( $queue->pop(), "Queue is not empty ($desc)" );
288 $queue->flushCaches();
289 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
290 $this->assertEquals( 0, $queue->getAcquiredCount(), "No jobs active ($desc)" );
293 public static function provider_queueLists() {
295 array( 'queueRand', false, 'Random queue without ack()' ),
296 array( 'queueRandTTL', true, 'Random queue with ack()' ),
297 array( 'queueTimestamp', false, 'Time ordered queue without ack()' ),
298 array( 'queueTimestampTTL', true, 'Time ordered queue with ack()' ),
299 array( 'queueFifo', false, 'FIFO ordered queue without ack()' ),
300 array( 'queueFifoTTL', true, 'FIFO ordered queue with ack()' )
304 public static function provider_fifoQueueLists() {
306 array( 'queueFifo', false, 'Ordered queue without ack()' ),
307 array( 'queueFifoTTL', true, 'Ordered queue with ack()' )
311 function newJob( $i = 0, $rootJob = array() ) {
312 return new NullJob( Title
::newMainPage(),
313 array( 'lives' => 0, 'usleep' => 0, 'removeDuplicates' => 0, 'i' => $i ) +
$rootJob );
316 function newDedupedJob( $i = 0, $rootJob = array() ) {
317 return new NullJob( Title
::newMainPage(),
318 array( 'lives' => 0, 'usleep' => 0, 'removeDuplicates' => 1, 'i' => $i ) +
$rootJob );