Merge "(bug 44385) move jquery.collapsibleTabs module to Vector extension"
[lhc/web/wiklou.git] / tests / phpunit / includes / jobqueue / JobQueueTest.php
1 <?php
2
3 /**
4 * @group JobQueue
5 * @group medium
6 * @group Database
7 */
8 class JobQueueTest extends MediaWikiTestCase {
9 protected $old = array();
10
11 function __construct( $name = null, array $data = array(), $dataName = '' ) {
12 parent::__construct( $name, $data, $dataName );
13
14 $this->tablesUsed[] = 'job';
15 }
16
17 protected function setUp() {
18 global $wgMemc;
19 parent::setUp();
20 $this->old['wgMemc'] = $wgMemc;
21 $wgMemc = new HashBagOStuff();
22 $this->queueRand = JobQueue::factory( array( 'class' => 'JobQueueDB',
23 'wiki' => wfWikiID(), 'type' => 'null', 'order' => 'random' ) );
24 $this->queueRandTTL = JobQueue::factory( array( 'class' => 'JobQueueDB',
25 'wiki' => wfWikiID(), 'type' => 'null', 'order' => 'random', 'claimTTL' => 10 ) );
26 $this->queueFifo = JobQueue::factory( array( 'class' => 'JobQueueDB',
27 'wiki' => wfWikiID(), 'type' => 'null', 'order' => 'fifo' ) );
28 $this->queueFifoTTL = JobQueue::factory( array( 'class' => 'JobQueueDB',
29 'wiki' => wfWikiID(), 'type' => 'null', 'order' => 'fifo', 'claimTTL' => 10 ) );
30 }
31
32 protected function tearDown() {
33 global $wgMemc;
34 parent::tearDown();
35 foreach ( array( 'queueRand', 'queueRandTTL', 'queueFifo', 'queueFifoTTL' ) as $q ) {
36 do {
37 $job = $this->$q->pop();
38 if ( $job ) {
39 $this->$q->ack( $job );
40 }
41 } while ( $job );
42 }
43 $this->queueRand = null;
44 $this->queueRandTTL = null;
45 $this->queueFifo = null;
46 $this->queueFifoTTL = null;
47 $wgMemc = $this->old['wgMemc'];
48 }
49
50 /**
51 * @dataProvider provider_queueLists
52 */
53 function testProperties( $queue, $order, $recycles, $desc ) {
54 $queue = $this->$queue;
55
56 $this->assertEquals( wfWikiID(), $queue->getWiki(), "Proper wiki ID ($desc)" );
57 $this->assertEquals( 'null', $queue->getType(), "Proper job type ($desc)" );
58 }
59
60 /**
61 * @dataProvider provider_queueLists
62 */
63 function testBasicOperations( $queue, $order, $recycles, $desc ) {
64 $queue = $this->$queue;
65 $this->assertTrue( $queue->isEmpty(), "Queue is empty ($desc)" );
66
67 $queue->flushCaches();
68 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
69 $this->assertEquals( 0, $queue->getAcquiredCount(), "Queue is empty ($desc)" );
70
71 $this->assertTrue( $queue->push( $this->newJob() ), "Push worked ($desc)" );
72 $this->assertTrue( $queue->batchPush( array( $this->newJob() ) ), "Push worked ($desc)" );
73
74 $this->assertFalse( $queue->isEmpty(), "Queue is not empty ($desc)" );
75
76 $queue->flushCaches();
77 $this->assertEquals( 2, $queue->getSize(), "Queue size is correct ($desc)" );
78 $this->assertEquals( 0, $queue->getAcquiredCount(), "No jobs active ($desc)" );
79
80 $job1 = $queue->pop();
81 $this->assertFalse( $queue->isEmpty(), "Queue is not empty ($desc)" );
82
83 $queue->flushCaches();
84 $this->assertEquals( 1, $queue->getSize(), "Queue size is correct ($desc)" );
85
86 $queue->flushCaches();
87 if ( $recycles ) {
88 $this->assertEquals( 1, $queue->getAcquiredCount(), "Active job count ($desc)" );
89 } else {
90 $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
91 }
92
93 $job2 = $queue->pop();
94 $this->assertTrue( $queue->isEmpty(), "Queue is empty ($desc)" );
95 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
96
97 $queue->flushCaches();
98 if ( $recycles ) {
99 $this->assertEquals( 2, $queue->getAcquiredCount(), "Active job count ($desc)" );
100 } else {
101 $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
102 }
103
104 $queue->ack( $job1 );
105
106 $queue->flushCaches();
107 if ( $recycles ) {
108 $this->assertEquals( 1, $queue->getAcquiredCount(), "Active job count ($desc)" );
109 } else {
110 $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
111 }
112
113 $queue->ack( $job2 );
114
115 $queue->flushCaches();
116 $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
117 }
118
119 /**
120 * @dataProvider provider_queueLists
121 */
122 function testBasicDeduplication( $queue, $order, $recycles, $desc ) {
123 $queue = $this->$queue;
124
125 $this->assertTrue( $queue->isEmpty(), "Queue is empty ($desc)" );
126
127 $queue->flushCaches();
128 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
129 $this->assertEquals( 0, $queue->getAcquiredCount(), "Queue is empty ($desc)" );
130
131 $this->assertTrue( $queue->batchPush(
132 array( $this->newDedupedJob(), $this->newDedupedJob(), $this->newDedupedJob() ) ),
133 "Push worked ($desc)" );
134
135 $this->assertFalse( $queue->isEmpty(), "Queue is not empty ($desc)" );
136
137 $queue->flushCaches();
138 $this->assertEquals( 1, $queue->getSize(), "Queue size is correct ($desc)" );
139 $this->assertEquals( 0, $queue->getAcquiredCount(), "No jobs active ($desc)" );
140
141 $this->assertTrue( $queue->batchPush(
142 array( $this->newDedupedJob(), $this->newDedupedJob(), $this->newDedupedJob() ) ),
143 "Push worked ($desc)" );
144
145 $this->assertFalse( $queue->isEmpty(), "Queue is not empty ($desc)" );
146
147 $queue->flushCaches();
148 $this->assertEquals( 1, $queue->getSize(), "Queue size is correct ($desc)" );
149 $this->assertEquals( 0, $queue->getAcquiredCount(), "No jobs active ($desc)" );
150
151 $job1 = $queue->pop();
152 $this->assertTrue( $queue->isEmpty(), "Queue is empty ($desc)" );
153
154 $queue->flushCaches();
155 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
156 if ( $recycles ) {
157 $this->assertEquals( 1, $queue->getAcquiredCount(), "Active job count ($desc)" );
158 } else {
159 $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
160 }
161
162 $queue->ack( $job1 );
163
164 $queue->flushCaches();
165 $this->assertEquals( 0, $queue->getAcquiredCount(), "Active job count ($desc)" );
166 }
167
168 /**
169 * @dataProvider provider_queueLists
170 */
171 function testRootDeduplication( $queue, $order, $recycles, $desc ) {
172 $queue = $this->$queue;
173
174 $this->assertTrue( $queue->isEmpty(), "Queue is empty ($desc)" );
175
176 $queue->flushCaches();
177 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
178 $this->assertEquals( 0, $queue->getAcquiredCount(), "Queue is empty ($desc)" );
179
180 $id = wfRandomString( 32 );
181 $root1 = Job::newRootJobParams( "nulljobspam:$id" ); // task ID/timestamp
182 for ( $i = 0; $i < 5; ++$i ) {
183 $this->assertTrue( $queue->push( $this->newJob( 0, $root1 ) ), "Push worked ($desc)" );
184 }
185 $queue->deduplicateRootJob( $this->newJob( 0, $root1 ) );
186 sleep( 1 ); // roo job timestamp will increase
187 $root2 = Job::newRootJobParams( "nulljobspam:$id" ); // task ID/timestamp
188 $this->assertNotEquals( $root1['rootJobTimestamp'], $root2['rootJobTimestamp'],
189 "Root job signatures have different timestamps." );
190 for ( $i = 0; $i < 5; ++$i ) {
191 $this->assertTrue( $queue->push( $this->newJob( 0, $root2 ) ), "Push worked ($desc)" );
192 }
193 $queue->deduplicateRootJob( $this->newJob( 0, $root2 ) );
194
195 $this->assertFalse( $queue->isEmpty(), "Queue is not empty ($desc)" );
196
197 $queue->flushCaches();
198 $this->assertEquals( 10, $queue->getSize(), "Queue size is correct ($desc)" );
199 $this->assertEquals( 0, $queue->getAcquiredCount(), "No jobs active ($desc)" );
200
201 $dupcount = 0;
202 $jobs = array();
203 do {
204 $job = $queue->pop();
205 if ( $job ) {
206 $jobs[] = $job;
207 $queue->ack( $job );
208 }
209 if ( $job instanceof DuplicateJob ) {
210 ++$dupcount;
211 }
212 } while ( $job );
213
214 $this->assertEquals( 10, count( $jobs ), "Correct number of jobs popped ($desc)" );
215 $this->assertEquals( 5, $dupcount, "Correct number of duplicate jobs popped ($desc)" );
216 }
217
218 /**
219 * @dataProvider provider_fifoQueueLists
220 */
221 function testJobOrder( $queue, $recycles, $desc ) {
222 $queue = $this->$queue;
223
224 $this->assertTrue( $queue->isEmpty(), "Queue is empty ($desc)" );
225
226 $queue->flushCaches();
227 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
228 $this->assertEquals( 0, $queue->getAcquiredCount(), "Queue is empty ($desc)" );
229
230 for ( $i = 0; $i < 10; ++$i ) {
231 $this->assertTrue( $queue->push( $this->newJob( $i ) ), "Push worked ($desc)" );
232 }
233
234 for ( $i = 0; $i < 10; ++$i ) {
235 $job = $queue->pop();
236 $this->assertTrue( $job instanceof Job, "Jobs popped from queue ($desc)" );
237 $params = $job->getParams();
238 $this->assertEquals( $i, $params['i'], "Job popped from queue is FIFO ($desc)" );
239 $queue->ack( $job );
240 }
241
242 $this->assertFalse( $queue->isEmpty(), "Queue is not empty ($desc)" );
243
244 $queue->flushCaches();
245 $this->assertEquals( 0, $queue->getSize(), "Queue is empty ($desc)" );
246 $this->assertEquals( 0, $queue->getAcquiredCount(), "No jobs active ($desc)" );
247 }
248
249 function provider_queueLists() {
250 return array(
251 array( 'queueRand', 'rand', false, 'Random queue without ack()' ),
252 array( 'queueRandTTL', 'rand', true, 'Random queue with ack()' ),
253 array( 'queueFifo', 'fifo', false, 'Ordered queue without ack()' ),
254 array( 'queueFifoTTL', 'fifo', true, 'Ordered queue with ack()' )
255 );
256 }
257
258 function provider_fifoQueueLists() {
259 return array(
260 array( 'queueFifo', false, 'Ordered queue without ack()' ),
261 array( 'queueFifoTTL', true, 'Ordered queue with ack()' )
262 );
263 }
264
265 function newJob( $i = 0, $rootJob = array() ) {
266 return new NullJob( Title::newMainPage(),
267 array( 'lives' => 0, 'usleep' => 0, 'removeDuplicates' => 0, 'i' => $i ) + $rootJob );
268 }
269
270 function newDedupedJob( $i = 0, $rootJob = array() ) {
271 return new NullJob( Title::newMainPage(),
272 array( 'lives' => 0, 'usleep' => 0, 'removeDuplicates' => 1, 'i' => $i ) + $rootJob );
273 }
274 }