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() {
56 'queueRand', 'queueRandTTL', 'queueTimestamp', 'queueTimestampTTL',
57 'queueFifo', 'queueFifoTTL'
61 $job = $this->$q->pop();
63 $this->$q->ack( $job );
72 * @dataProvider provider_queueLists
74 function testProperties( $queue, $recycles, $desc ) {
75 $queue = $this->$queue;
77 $this->markTestSkipped( $desc );
80 $this->assertEquals( wfWikiID(), $queue->getWiki(), "Proper wiki ID ($desc)" );
81 $this->assertEquals( 'null', $queue->getType(), "Proper job type ($desc)" );
85 * @dataProvider provider_queueLists
87 function testBasicOperations( $queue, $recycles, $desc ) {
88 $queue = $this->$queue;
90 $this->markTestSkipped( $desc );
93 $this->assertTrue( $queue->isEmpty(), "Queue is empty ($desc)" );
95 $queue->flushCaches();
96 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
97 $this->assertEquals( 0, $queue->getAcquiredCount(), "Queue is empty ($desc)" );
99 $this->assertTrue( $queue->push( $this->newJob() ), "Push worked ($desc)" );
100 $this->assertTrue( $queue->batchPush( array( $this->newJob() ) ), "Push worked ($desc)" );
102 $this->assertFalse( $queue->isEmpty(), "Queue is not empty ($desc)" );
104 $queue->flushCaches();
105 $this->assertEquals( 2, $queue->getSize(), "Queue size is correct ($desc)" );
106 $this->assertEquals( 0, $queue->getAcquiredCount(), "No jobs active ($desc)" );
108 $job1 = $queue->pop();
109 $this->assertFalse( $queue->isEmpty(), "Queue is not empty ($desc)" );
111 $queue->flushCaches();
112 $this->assertEquals( 1, $queue->getSize(), "Queue size is correct ($desc)" );
114 $queue->flushCaches();
116 $this->assertEquals( 1, $queue->getAcquiredCount(), "Active job count ($desc)" );
118 $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
121 $job2 = $queue->pop();
122 $this->assertTrue( $queue->isEmpty(), "Queue is empty ($desc)" );
123 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
125 $queue->flushCaches();
127 $this->assertEquals( 2, $queue->getAcquiredCount(), "Active job count ($desc)" );
129 $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
132 $queue->ack( $job1 );
134 $queue->flushCaches();
136 $this->assertEquals( 1, $queue->getAcquiredCount(), "Active job count ($desc)" );
138 $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
141 $queue->ack( $job2 );
143 $queue->flushCaches();
144 $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
148 * @dataProvider provider_queueLists
150 function testBasicDeduplication( $queue, $recycles, $desc ) {
151 $queue = $this->$queue;
153 $this->markTestSkipped( $desc );
157 $this->assertTrue( $queue->isEmpty(), "Queue is empty ($desc)" );
159 $queue->flushCaches();
160 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
161 $this->assertEquals( 0, $queue->getAcquiredCount(), "Queue is empty ($desc)" );
163 $this->assertTrue( $queue->batchPush(
164 array( $this->newDedupedJob(), $this->newDedupedJob(), $this->newDedupedJob() ) ),
165 "Push worked ($desc)" );
167 $this->assertFalse( $queue->isEmpty(), "Queue is not empty ($desc)" );
169 $queue->flushCaches();
170 $this->assertEquals( 1, $queue->getSize(), "Queue size is correct ($desc)" );
171 $this->assertEquals( 0, $queue->getAcquiredCount(), "No jobs active ($desc)" );
173 $this->assertTrue( $queue->batchPush(
174 array( $this->newDedupedJob(), $this->newDedupedJob(), $this->newDedupedJob() ) ),
175 "Push worked ($desc)" );
177 $this->assertFalse( $queue->isEmpty(), "Queue is not empty ($desc)" );
179 $queue->flushCaches();
180 $this->assertEquals( 1, $queue->getSize(), "Queue size is correct ($desc)" );
181 $this->assertEquals( 0, $queue->getAcquiredCount(), "No jobs active ($desc)" );
183 $job1 = $queue->pop();
184 $this->assertTrue( $queue->isEmpty(), "Queue is empty ($desc)" );
186 $queue->flushCaches();
187 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
189 $this->assertEquals( 1, $queue->getAcquiredCount(), "Active job count ($desc)" );
191 $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
194 $queue->ack( $job1 );
196 $queue->flushCaches();
197 $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
201 * @dataProvider provider_queueLists
203 function testRootDeduplication( $queue, $recycles, $desc ) {
204 $queue = $this->$queue;
206 $this->markTestSkipped( $desc );
210 $this->assertTrue( $queue->isEmpty(), "Queue is empty ($desc)" );
212 $queue->flushCaches();
213 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
214 $this->assertEquals( 0, $queue->getAcquiredCount(), "Queue is empty ($desc)" );
216 $id = wfRandomString( 32 );
217 $root1 = Job
::newRootJobParams( "nulljobspam:$id" ); // task ID/timestamp
218 for ( $i = 0; $i < 5; ++
$i ) {
219 $this->assertTrue( $queue->push( $this->newJob( 0, $root1 ) ), "Push worked ($desc)" );
221 $queue->deduplicateRootJob( $this->newJob( 0, $root1 ) );
222 sleep( 1 ); // roo job timestamp will increase
223 $root2 = Job
::newRootJobParams( "nulljobspam:$id" ); // task ID/timestamp
224 $this->assertNotEquals( $root1['rootJobTimestamp'], $root2['rootJobTimestamp'],
225 "Root job signatures have different timestamps." );
226 for ( $i = 0; $i < 5; ++
$i ) {
227 $this->assertTrue( $queue->push( $this->newJob( 0, $root2 ) ), "Push worked ($desc)" );
229 $queue->deduplicateRootJob( $this->newJob( 0, $root2 ) );
231 $this->assertFalse( $queue->isEmpty(), "Queue is not empty ($desc)" );
233 $queue->flushCaches();
234 $this->assertEquals( 10, $queue->getSize(), "Queue size is correct ($desc)" );
235 $this->assertEquals( 0, $queue->getAcquiredCount(), "No jobs active ($desc)" );
240 $job = $queue->pop();
245 if ( $job instanceof DuplicateJob
) {
250 $this->assertEquals( 10, count( $jobs ), "Correct number of jobs popped ($desc)" );
251 $this->assertEquals( 5, $dupcount, "Correct number of duplicate jobs popped ($desc)" );
255 * @dataProvider provider_fifoQueueLists
257 function testJobOrder( $queue, $recycles, $desc ) {
258 $queue = $this->$queue;
260 $this->markTestSkipped( $desc );
264 $this->assertTrue( $queue->isEmpty(), "Queue is empty ($desc)" );
266 $queue->flushCaches();
267 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
268 $this->assertEquals( 0, $queue->getAcquiredCount(), "Queue is empty ($desc)" );
270 for ( $i = 0; $i < 10; ++
$i ) {
271 $this->assertTrue( $queue->push( $this->newJob( $i ) ), "Push worked ($desc)" );
274 for ( $i = 0; $i < 10; ++
$i ) {
275 $job = $queue->pop();
276 $this->assertTrue( $job instanceof Job
, "Jobs popped from queue ($desc)" );
277 $params = $job->getParams();
278 $this->assertEquals( $i, $params['i'], "Job popped from queue is FIFO ($desc)" );
282 $this->assertFalse( $queue->pop(), "Queue is not empty ($desc)" );
284 $queue->flushCaches();
285 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
286 $this->assertEquals( 0, $queue->getAcquiredCount(), "No jobs active ($desc)" );
289 public static function provider_queueLists() {
291 array( 'queueRand', false, 'Random queue without ack()' ),
292 array( 'queueRandTTL', true, 'Random queue with ack()' ),
293 array( 'queueTimestamp', false, 'Time ordered queue without ack()' ),
294 array( 'queueTimestampTTL', true, 'Time ordered queue with ack()' ),
295 array( 'queueFifo', false, 'FIFO ordered queue without ack()' ),
296 array( 'queueFifoTTL', true, 'FIFO ordered queue with ack()' )
300 public static function provider_fifoQueueLists() {
302 array( 'queueFifo', false, 'Ordered queue without ack()' ),
303 array( 'queueFifoTTL', true, 'Ordered queue with ack()' )
307 function newJob( $i = 0, $rootJob = array() ) {
308 return new NullJob( Title
::newMainPage(),
309 array( 'lives' => 0, 'usleep' => 0, 'removeDuplicates' => 0, 'i' => $i ) +
$rootJob );
312 function newDedupedJob( $i = 0, $rootJob = array() ) {
313 return new NullJob( Title
::newMainPage(),
314 array( 'lives' => 0, 'usleep' => 0, 'removeDuplicates' => 1, 'i' => $i ) +
$rootJob );