8 class JobQueueTest
extends MediaWikiTestCase
{
10 protected $queueRand, $queueRandTTL, $queueFifo, $queueFifoTTL;
11 protected $old = array();
13 function __construct( $name = null, array $data = array(), $dataName = '' ) {
14 parent
::__construct( $name, $data, $dataName );
16 $this->tablesUsed
[] = 'job';
19 protected function setUp() {
20 global $wgMemc, $wgJobTypeConf;
22 $this->old
['wgMemc'] = $wgMemc;
23 $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();
35 $this->queueRand
= JobQueue
::factory(
36 array( 'order' => 'random', 'claimTTL' => 0 ) +
$baseConfig );
37 $this->queueRandTTL
= JobQueue
::factory(
38 array( 'order' => 'random', 'claimTTL' => 10 ) +
$baseConfig );
39 $this->queueFifo
= JobQueue
::factory(
40 array( 'order' => 'fifo', 'claimTTL' => 0 ) +
$baseConfig );
41 $this->queueFifoTTL
= JobQueue
::factory(
42 array( 'order' => 'fifo', 'claimTTL' => 10 ) +
$baseConfig );
43 if ( $baseConfig['class'] !== 'JobQueueDB' ) { // DB namespace with prefix or temp tables
44 foreach ( array( 'queueRand', 'queueRandTTL', 'queueFifo', 'queueFifoTTL' ) as $q ) {
45 $this->$q->setTestingPrefix( 'unittests-' . wfRandomString( 32 ) );
50 protected function tearDown() {
53 foreach ( array( 'queueRand', 'queueRandTTL', 'queueFifo', 'queueFifoTTL' ) as $q ) {
55 $job = $this->$q->pop();
57 $this->$q->ack( $job );
61 $this->queueRand
= null;
62 $this->queueRandTTL
= null;
63 $this->queueFifo
= null;
64 $this->queueFifoTTL
= null;
65 $wgMemc = $this->old
['wgMemc'];
69 * @dataProvider provider_queueLists
71 function testProperties( $queue, $order, $recycles, $desc ) {
72 $queue = $this->$queue;
74 $this->assertEquals( wfWikiID(), $queue->getWiki(), "Proper wiki ID ($desc)" );
75 $this->assertEquals( 'null', $queue->getType(), "Proper job type ($desc)" );
79 * @dataProvider provider_queueLists
81 function testBasicOperations( $queue, $order, $recycles, $desc ) {
82 $queue = $this->$queue;
83 $this->assertTrue( $queue->isEmpty(), "Queue is empty ($desc)" );
85 $queue->flushCaches();
86 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
87 $this->assertEquals( 0, $queue->getAcquiredCount(), "Queue is empty ($desc)" );
89 $this->assertTrue( $queue->push( $this->newJob() ), "Push worked ($desc)" );
90 $this->assertTrue( $queue->batchPush( array( $this->newJob() ) ), "Push worked ($desc)" );
92 $this->assertFalse( $queue->isEmpty(), "Queue is not empty ($desc)" );
94 $queue->flushCaches();
95 $this->assertEquals( 2, $queue->getSize(), "Queue size is correct ($desc)" );
96 $this->assertEquals( 0, $queue->getAcquiredCount(), "No jobs active ($desc)" );
98 $job1 = $queue->pop();
99 $this->assertFalse( $queue->isEmpty(), "Queue is not empty ($desc)" );
101 $queue->flushCaches();
102 $this->assertEquals( 1, $queue->getSize(), "Queue size is correct ($desc)" );
104 $queue->flushCaches();
106 $this->assertEquals( 1, $queue->getAcquiredCount(), "Active job count ($desc)" );
108 $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
111 $job2 = $queue->pop();
112 $this->assertTrue( $queue->isEmpty(), "Queue is empty ($desc)" );
113 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
115 $queue->flushCaches();
117 $this->assertEquals( 2, $queue->getAcquiredCount(), "Active job count ($desc)" );
119 $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
122 $queue->ack( $job1 );
124 $queue->flushCaches();
126 $this->assertEquals( 1, $queue->getAcquiredCount(), "Active job count ($desc)" );
128 $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
131 $queue->ack( $job2 );
133 $queue->flushCaches();
134 $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
138 * @dataProvider provider_queueLists
140 function testBasicDeduplication( $queue, $order, $recycles, $desc ) {
141 $queue = $this->$queue;
143 $this->assertTrue( $queue->isEmpty(), "Queue is empty ($desc)" );
145 $queue->flushCaches();
146 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
147 $this->assertEquals( 0, $queue->getAcquiredCount(), "Queue is empty ($desc)" );
149 $this->assertTrue( $queue->batchPush(
150 array( $this->newDedupedJob(), $this->newDedupedJob(), $this->newDedupedJob() ) ),
151 "Push worked ($desc)" );
153 $this->assertFalse( $queue->isEmpty(), "Queue is not empty ($desc)" );
155 $queue->flushCaches();
156 $this->assertEquals( 1, $queue->getSize(), "Queue size is correct ($desc)" );
157 $this->assertEquals( 0, $queue->getAcquiredCount(), "No jobs active ($desc)" );
159 $this->assertTrue( $queue->batchPush(
160 array( $this->newDedupedJob(), $this->newDedupedJob(), $this->newDedupedJob() ) ),
161 "Push worked ($desc)" );
163 $this->assertFalse( $queue->isEmpty(), "Queue is not empty ($desc)" );
165 $queue->flushCaches();
166 $this->assertEquals( 1, $queue->getSize(), "Queue size is correct ($desc)" );
167 $this->assertEquals( 0, $queue->getAcquiredCount(), "No jobs active ($desc)" );
169 $job1 = $queue->pop();
170 $this->assertTrue( $queue->isEmpty(), "Queue is empty ($desc)" );
172 $queue->flushCaches();
173 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
175 $this->assertEquals( 1, $queue->getAcquiredCount(), "Active job count ($desc)" );
177 $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
180 $queue->ack( $job1 );
182 $queue->flushCaches();
183 $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
187 * @dataProvider provider_queueLists
189 function testRootDeduplication( $queue, $order, $recycles, $desc ) {
190 $queue = $this->$queue;
192 $this->assertTrue( $queue->isEmpty(), "Queue is empty ($desc)" );
194 $queue->flushCaches();
195 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
196 $this->assertEquals( 0, $queue->getAcquiredCount(), "Queue is empty ($desc)" );
198 $id = wfRandomString( 32 );
199 $root1 = Job
::newRootJobParams( "nulljobspam:$id" ); // task ID/timestamp
200 for ( $i = 0; $i < 5; ++
$i ) {
201 $this->assertTrue( $queue->push( $this->newJob( 0, $root1 ) ), "Push worked ($desc)" );
203 $queue->deduplicateRootJob( $this->newJob( 0, $root1 ) );
204 sleep( 1 ); // roo job timestamp will increase
205 $root2 = Job
::newRootJobParams( "nulljobspam:$id" ); // task ID/timestamp
206 $this->assertNotEquals( $root1['rootJobTimestamp'], $root2['rootJobTimestamp'],
207 "Root job signatures have different timestamps." );
208 for ( $i = 0; $i < 5; ++
$i ) {
209 $this->assertTrue( $queue->push( $this->newJob( 0, $root2 ) ), "Push worked ($desc)" );
211 $queue->deduplicateRootJob( $this->newJob( 0, $root2 ) );
213 $this->assertFalse( $queue->isEmpty(), "Queue is not empty ($desc)" );
215 $queue->flushCaches();
216 $this->assertEquals( 10, $queue->getSize(), "Queue size is correct ($desc)" );
217 $this->assertEquals( 0, $queue->getAcquiredCount(), "No jobs active ($desc)" );
222 $job = $queue->pop();
227 if ( $job instanceof DuplicateJob
) {
232 $this->assertEquals( 10, count( $jobs ), "Correct number of jobs popped ($desc)" );
233 $this->assertEquals( 5, $dupcount, "Correct number of duplicate jobs popped ($desc)" );
237 * @dataProvider provider_fifoQueueLists
239 function testJobOrder( $queue, $recycles, $desc ) {
240 $queue = $this->$queue;
242 $this->assertTrue( $queue->isEmpty(), "Queue is empty ($desc)" );
244 $queue->flushCaches();
245 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
246 $this->assertEquals( 0, $queue->getAcquiredCount(), "Queue is empty ($desc)" );
248 for ( $i = 0; $i < 10; ++
$i ) {
249 $this->assertTrue( $queue->push( $this->newJob( $i ) ), "Push worked ($desc)" );
252 for ( $i = 0; $i < 10; ++
$i ) {
253 $job = $queue->pop();
254 $this->assertTrue( $job instanceof Job
, "Jobs popped from queue ($desc)" );
255 $params = $job->getParams();
256 $this->assertEquals( $i, $params['i'], "Job popped from queue is FIFO ($desc)" );
260 $this->assertFalse( $queue->pop(), "Queue is not empty ($desc)" );
262 $queue->flushCaches();
263 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
264 $this->assertEquals( 0, $queue->getAcquiredCount(), "No jobs active ($desc)" );
267 function provider_queueLists() {
269 array( 'queueRand', 'rand', false, 'Random queue without ack()' ),
270 array( 'queueRandTTL', 'rand', true, 'Random queue with ack()' ),
271 array( 'queueFifo', 'fifo', false, 'Ordered queue without ack()' ),
272 array( 'queueFifoTTL', 'fifo', true, 'Ordered queue with ack()' )
276 function provider_fifoQueueLists() {
278 array( 'queueFifo', false, 'Ordered queue without ack()' ),
279 array( 'queueFifoTTL', true, 'Ordered queue with ack()' )
283 function newJob( $i = 0, $rootJob = array() ) {
284 return new NullJob( Title
::newMainPage(),
285 array( 'lives' => 0, 'usleep' => 0, 'removeDuplicates' => 0, 'i' => $i ) +
$rootJob );
288 function newDedupedJob( $i = 0, $rootJob = array() ) {
289 return new NullJob( Title
::newMainPage(),
290 array( 'lives' => 0, 'usleep' => 0, 'removeDuplicates' => 1, 'i' => $i ) +
$rootJob );