Fix typo in tests/phpunit/includes/Revision/MainSlotRoleHandlerTest.php
[lhc/web/wiklou.git] / tests / phpunit / includes / ActorMigrationTest.php
1 <?php
2
3 use MediaWiki\User\UserIdentity;
4 use MediaWiki\MediaWikiServices;
5 use Wikimedia\TestingAccessWrapper;
6
7 /**
8 * @group Database
9 * @covers ActorMigration
10 */
11 class ActorMigrationTest extends MediaWikiLangTestCase {
12
13 protected $tablesUsed = [
14 'revision',
15 'revision_actor_temp',
16 'ipblocks',
17 'recentchanges',
18 'actor',
19 ];
20
21 /**
22 * Create an ActorMigration for a particular stage
23 * @param int $stage
24 * @return ActorMigration
25 */
26 protected function makeMigration( $stage ) {
27 return new ActorMigration( $stage );
28 }
29
30 /**
31 * @dataProvider provideConstructor
32 * @param int $stage
33 * @param string|null $exceptionMsg
34 */
35 public function testConstructor( $stage, $exceptionMsg ) {
36 try {
37 $m = new ActorMigration( $stage );
38 if ( $exceptionMsg !== null ) {
39 $this->fail( 'Expected exception not thrown' );
40 }
41 $this->assertInstanceOf( ActorMigration::class, $m );
42 } catch ( InvalidArgumentException $ex ) {
43 $this->assertSame( $exceptionMsg, $ex->getMessage() );
44 }
45 }
46
47 public static function provideConstructor() {
48 return [
49 [ 0, '$stage must include a write mode' ],
50 [ SCHEMA_COMPAT_READ_OLD, '$stage must include a write mode' ],
51 [ SCHEMA_COMPAT_READ_NEW, '$stage must include a write mode' ],
52 [ SCHEMA_COMPAT_READ_BOTH, '$stage must include a write mode' ],
53
54 [ SCHEMA_COMPAT_WRITE_OLD, '$stage must include a read mode' ],
55 [ SCHEMA_COMPAT_WRITE_OLD | SCHEMA_COMPAT_READ_OLD, null ],
56 [
57 SCHEMA_COMPAT_WRITE_OLD | SCHEMA_COMPAT_READ_NEW,
58 'Cannot read the new schema without also writing it'
59 ],
60 [ SCHEMA_COMPAT_WRITE_OLD | SCHEMA_COMPAT_READ_BOTH, 'Cannot read both schemas' ],
61
62 [ SCHEMA_COMPAT_WRITE_NEW, '$stage must include a read mode' ],
63 [
64 SCHEMA_COMPAT_WRITE_NEW | SCHEMA_COMPAT_READ_OLD,
65 'Cannot read the old schema without also writing it'
66 ],
67 [ SCHEMA_COMPAT_WRITE_NEW | SCHEMA_COMPAT_READ_NEW, null ],
68 [ SCHEMA_COMPAT_WRITE_NEW | SCHEMA_COMPAT_READ_BOTH, 'Cannot read both schemas' ],
69
70 [ SCHEMA_COMPAT_WRITE_BOTH, '$stage must include a read mode' ],
71 [ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, null ],
72 [ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, null ],
73 [ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_BOTH, 'Cannot read both schemas' ],
74 ];
75 }
76
77 /**
78 * @dataProvider provideGetJoin
79 * @param int $stage
80 * @param string $key
81 * @param array $expect
82 */
83 public function testGetJoin( $stage, $key, $expect ) {
84 $m = $this->makeMigration( $stage );
85 $result = $m->getJoin( $key );
86 $this->assertEquals( $expect, $result );
87 }
88
89 public static function provideGetJoin() {
90 return [
91 'Simple table, old' => [
92 SCHEMA_COMPAT_OLD, 'rc_user', [
93 'tables' => [],
94 'fields' => [
95 'rc_user' => 'rc_user',
96 'rc_user_text' => 'rc_user_text',
97 'rc_actor' => 'NULL',
98 ],
99 'joins' => [],
100 ],
101 ],
102 'Simple table, read-old' => [
103 SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'rc_user', [
104 'tables' => [],
105 'fields' => [
106 'rc_user' => 'rc_user',
107 'rc_user_text' => 'rc_user_text',
108 'rc_actor' => 'NULL',
109 ],
110 'joins' => [],
111 ],
112 ],
113 'Simple table, read-new' => [
114 SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'rc_user', [
115 'tables' => [ 'actor_rc_user' => 'actor' ],
116 'fields' => [
117 'rc_user' => 'actor_rc_user.actor_user',
118 'rc_user_text' => 'actor_rc_user.actor_name',
119 'rc_actor' => 'rc_actor',
120 ],
121 'joins' => [
122 'actor_rc_user' => [ 'JOIN', 'actor_rc_user.actor_id = rc_actor' ],
123 ],
124 ],
125 ],
126 'Simple table, new' => [
127 SCHEMA_COMPAT_NEW, 'rc_user', [
128 'tables' => [ 'actor_rc_user' => 'actor' ],
129 'fields' => [
130 'rc_user' => 'actor_rc_user.actor_user',
131 'rc_user_text' => 'actor_rc_user.actor_name',
132 'rc_actor' => 'rc_actor',
133 ],
134 'joins' => [
135 'actor_rc_user' => [ 'JOIN', 'actor_rc_user.actor_id = rc_actor' ],
136 ],
137 ],
138 ],
139
140 'ipblocks, old' => [
141 SCHEMA_COMPAT_OLD, 'ipb_by', [
142 'tables' => [],
143 'fields' => [
144 'ipb_by' => 'ipb_by',
145 'ipb_by_text' => 'ipb_by_text',
146 'ipb_by_actor' => 'NULL',
147 ],
148 'joins' => [],
149 ],
150 ],
151 'ipblocks, read-old' => [
152 SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'ipb_by', [
153 'tables' => [],
154 'fields' => [
155 'ipb_by' => 'ipb_by',
156 'ipb_by_text' => 'ipb_by_text',
157 'ipb_by_actor' => 'NULL',
158 ],
159 'joins' => [],
160 ],
161 ],
162 'ipblocks, read-new' => [
163 SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'ipb_by', [
164 'tables' => [ 'actor_ipb_by' => 'actor' ],
165 'fields' => [
166 'ipb_by' => 'actor_ipb_by.actor_user',
167 'ipb_by_text' => 'actor_ipb_by.actor_name',
168 'ipb_by_actor' => 'ipb_by_actor',
169 ],
170 'joins' => [
171 'actor_ipb_by' => [ 'JOIN', 'actor_ipb_by.actor_id = ipb_by_actor' ],
172 ],
173 ],
174 ],
175 'ipblocks, new' => [
176 SCHEMA_COMPAT_NEW, 'ipb_by', [
177 'tables' => [ 'actor_ipb_by' => 'actor' ],
178 'fields' => [
179 'ipb_by' => 'actor_ipb_by.actor_user',
180 'ipb_by_text' => 'actor_ipb_by.actor_name',
181 'ipb_by_actor' => 'ipb_by_actor',
182 ],
183 'joins' => [
184 'actor_ipb_by' => [ 'JOIN', 'actor_ipb_by.actor_id = ipb_by_actor' ],
185 ],
186 ],
187 ],
188
189 'Revision, old' => [
190 SCHEMA_COMPAT_OLD, 'rev_user', [
191 'tables' => [],
192 'fields' => [
193 'rev_user' => 'rev_user',
194 'rev_user_text' => 'rev_user_text',
195 'rev_actor' => 'NULL',
196 ],
197 'joins' => [],
198 ],
199 ],
200 'Revision, read-old' => [
201 SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'rev_user', [
202 'tables' => [],
203 'fields' => [
204 'rev_user' => 'rev_user',
205 'rev_user_text' => 'rev_user_text',
206 'rev_actor' => 'NULL',
207 ],
208 'joins' => [],
209 ],
210 ],
211 'Revision, read-new' => [
212 SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'rev_user', [
213 'tables' => [
214 'temp_rev_user' => 'revision_actor_temp',
215 'actor_rev_user' => 'actor',
216 ],
217 'fields' => [
218 'rev_user' => 'actor_rev_user.actor_user',
219 'rev_user_text' => 'actor_rev_user.actor_name',
220 'rev_actor' => 'temp_rev_user.revactor_actor',
221 ],
222 'joins' => [
223 'temp_rev_user' => [ 'JOIN', 'temp_rev_user.revactor_rev = rev_id' ],
224 'actor_rev_user' => [ 'JOIN', 'actor_rev_user.actor_id = temp_rev_user.revactor_actor' ],
225 ],
226 ],
227 ],
228 'Revision, new' => [
229 SCHEMA_COMPAT_NEW, 'rev_user', [
230 'tables' => [
231 'temp_rev_user' => 'revision_actor_temp',
232 'actor_rev_user' => 'actor',
233 ],
234 'fields' => [
235 'rev_user' => 'actor_rev_user.actor_user',
236 'rev_user_text' => 'actor_rev_user.actor_name',
237 'rev_actor' => 'temp_rev_user.revactor_actor',
238 ],
239 'joins' => [
240 'temp_rev_user' => [ 'JOIN', 'temp_rev_user.revactor_rev = rev_id' ],
241 'actor_rev_user' => [ 'JOIN', 'actor_rev_user.actor_id = temp_rev_user.revactor_actor' ],
242 ],
243 ],
244 ],
245 ];
246 }
247
248 /**
249 * @dataProvider provideGetWhere
250 * @param int $stage
251 * @param string $key
252 * @param UserIdentity[] $users
253 * @param bool $useId
254 * @param array $expect
255 */
256 public function testGetWhere( $stage, $key, $users, $useId, $expect ) {
257 $expect['conds'] = '(' . implode( ') OR (', $expect['orconds'] ) . ')';
258
259 if ( count( $users ) === 1 ) {
260 $users = reset( $users );
261 }
262
263 $m = $this->makeMigration( $stage );
264 $result = $m->getWhere( $this->db, $key, $users, $useId );
265 $this->assertEquals( $expect, $result );
266 }
267
268 public function provideGetWhere() {
269 $makeUserIdentity = function ( $id, $name, $actor ) {
270 $u = $this->getMock( UserIdentity::class );
271 $u->method( 'getId' )->willReturn( $id );
272 $u->method( 'getName' )->willReturn( $name );
273 $u->method( 'getActorId' )->willReturn( $actor );
274 return $u;
275 };
276
277 $genericUser = [ $makeUserIdentity( 1, 'User1', 11 ) ];
278 $complicatedUsers = [
279 $makeUserIdentity( 1, 'User1', 11 ),
280 $makeUserIdentity( 2, 'User2', 12 ),
281 $makeUserIdentity( 3, 'User3', 0 ),
282 $makeUserIdentity( 0, '192.168.12.34', 34 ),
283 $makeUserIdentity( 0, '192.168.12.35', 0 ),
284 ];
285
286 return [
287 'Simple table, old' => [
288 SCHEMA_COMPAT_OLD, 'rc_user', $genericUser, true, [
289 'tables' => [],
290 'orconds' => [ 'userid' => "rc_user = '1'" ],
291 'joins' => [],
292 ],
293 ],
294 'Simple table, read-old' => [
295 SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'rc_user', $genericUser, true, [
296 'tables' => [],
297 'orconds' => [ 'userid' => "rc_user = '1'" ],
298 'joins' => [],
299 ],
300 ],
301 'Simple table, read-new' => [
302 SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'rc_user', $genericUser, true, [
303 'tables' => [],
304 'orconds' => [ 'actor' => "rc_actor = '11'" ],
305 'joins' => [],
306 ],
307 ],
308 'Simple table, new' => [
309 SCHEMA_COMPAT_NEW, 'rc_user', $genericUser, true, [
310 'tables' => [],
311 'orconds' => [ 'actor' => "rc_actor = '11'" ],
312 'joins' => [],
313 ],
314 ],
315
316 'ipblocks, old' => [
317 SCHEMA_COMPAT_OLD, 'ipb_by', $genericUser, true, [
318 'tables' => [],
319 'orconds' => [ 'userid' => "ipb_by = '1'" ],
320 'joins' => [],
321 ],
322 ],
323 'ipblocks, read-old' => [
324 SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'ipb_by', $genericUser, true, [
325 'tables' => [],
326 'orconds' => [ 'userid' => "ipb_by = '1'" ],
327 'joins' => [],
328 ],
329 ],
330 'ipblocks, read-new' => [
331 SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'ipb_by', $genericUser, true, [
332 'tables' => [],
333 'orconds' => [ 'actor' => "ipb_by_actor = '11'" ],
334 'joins' => [],
335 ],
336 ],
337 'ipblocks, new' => [
338 SCHEMA_COMPAT_NEW, 'ipb_by', $genericUser, true, [
339 'tables' => [],
340 'orconds' => [ 'actor' => "ipb_by_actor = '11'" ],
341 'joins' => [],
342 ],
343 ],
344
345 'Revision, old' => [
346 SCHEMA_COMPAT_OLD, 'rev_user', $genericUser, true, [
347 'tables' => [],
348 'orconds' => [ 'userid' => "rev_user = '1'" ],
349 'joins' => [],
350 ],
351 ],
352 'Revision, read-old' => [
353 SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'rev_user', $genericUser, true, [
354 'tables' => [],
355 'orconds' => [ 'userid' => "rev_user = '1'" ],
356 'joins' => [],
357 ],
358 ],
359 'Revision, read-new' => [
360 SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'rev_user', $genericUser, true, [
361 'tables' => [
362 'temp_rev_user' => 'revision_actor_temp',
363 ],
364 'orconds' => [ 'actor' => "temp_rev_user.revactor_actor = '11'" ],
365 'joins' => [
366 'temp_rev_user' => [ 'JOIN', 'temp_rev_user.revactor_rev = rev_id' ],
367 ],
368 ],
369 ],
370 'Revision, new' => [
371 SCHEMA_COMPAT_NEW, 'rev_user', $genericUser, true, [
372 'tables' => [
373 'temp_rev_user' => 'revision_actor_temp',
374 ],
375 'orconds' => [ 'actor' => "temp_rev_user.revactor_actor = '11'" ],
376 'joins' => [
377 'temp_rev_user' => [ 'JOIN', 'temp_rev_user.revactor_rev = rev_id' ],
378 ],
379 ],
380 ],
381
382 'Multiple users, old' => [
383 SCHEMA_COMPAT_OLD, 'rc_user', $complicatedUsers, true, [
384 'tables' => [],
385 'orconds' => [
386 'userid' => "rc_user IN ('1','2','3') ",
387 'username' => "rc_user_text IN ('192.168.12.34','192.168.12.35') "
388 ],
389 'joins' => [],
390 ],
391 ],
392 'Multiple users, read-old' => [
393 SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'rc_user', $complicatedUsers, true, [
394 'tables' => [],
395 'orconds' => [
396 'userid' => "rc_user IN ('1','2','3') ",
397 'username' => "rc_user_text IN ('192.168.12.34','192.168.12.35') "
398 ],
399 'joins' => [],
400 ],
401 ],
402 'Multiple users, read-new' => [
403 SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'rc_user', $complicatedUsers, true, [
404 'tables' => [],
405 'orconds' => [ 'actor' => "rc_actor IN ('11','12','34') " ],
406 'joins' => [],
407 ],
408 ],
409 'Multiple users, new' => [
410 SCHEMA_COMPAT_NEW, 'rc_user', $complicatedUsers, true, [
411 'tables' => [],
412 'orconds' => [ 'actor' => "rc_actor IN ('11','12','34') " ],
413 'joins' => [],
414 ],
415 ],
416
417 'Multiple users, no use ID, old' => [
418 SCHEMA_COMPAT_OLD, 'rc_user', $complicatedUsers, false, [
419 'tables' => [],
420 'orconds' => [
421 'username' => "rc_user_text IN ('User1','User2','User3','192.168.12.34','192.168.12.35') "
422 ],
423 'joins' => [],
424 ],
425 ],
426 'Multiple users, read-old' => [
427 SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'rc_user', $complicatedUsers, false, [
428 'tables' => [],
429 'orconds' => [
430 'username' => "rc_user_text IN ('User1','User2','User3','192.168.12.34','192.168.12.35') "
431 ],
432 'joins' => [],
433 ],
434 ],
435 'Multiple users, read-new' => [
436 SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'rc_user', $complicatedUsers, false, [
437 'tables' => [],
438 'orconds' => [ 'actor' => "rc_actor IN ('11','12','34') " ],
439 'joins' => [],
440 ],
441 ],
442 'Multiple users, new' => [
443 SCHEMA_COMPAT_NEW, 'rc_user', $complicatedUsers, false, [
444 'tables' => [],
445 'orconds' => [ 'actor' => "rc_actor IN ('11','12','34') " ],
446 'joins' => [],
447 ],
448 ],
449 ];
450 }
451
452 /**
453 * @dataProvider provideInsertRoundTrip
454 * @param string $table
455 * @param string $key
456 * @param string $pk
457 * @param array $extraFields
458 */
459 public function testInsertRoundTrip( $table, $key, $pk, $extraFields ) {
460 $u = $this->getTestUser()->getUser();
461 $user = $this->getMock( UserIdentity::class );
462 $user->method( 'getId' )->willReturn( $u->getId() );
463 $user->method( 'getName' )->willReturn( $u->getName() );
464 if ( $u->getActorId( $this->db ) ) {
465 $user->method( 'getActorId' )->willReturn( $u->getActorId() );
466 } else {
467 $this->db->insert(
468 'actor',
469 [ 'actor_user' => $u->getId(), 'actor_name' => $u->getName() ],
470 __METHOD__
471 );
472 $user->method( 'getActorId' )->willReturn( $this->db->insertId() );
473 }
474
475 $stageNames = [
476 SCHEMA_COMPAT_OLD => 'old',
477 SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD => 'write-both-read-old',
478 SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW => 'write-both-read-new',
479 SCHEMA_COMPAT_NEW => 'new',
480 ];
481
482 $stages = [
483 SCHEMA_COMPAT_OLD => [
484 SCHEMA_COMPAT_OLD,
485 SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD,
486 ],
487 SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD => [
488 SCHEMA_COMPAT_OLD,
489 SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD,
490 SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW,
491 SCHEMA_COMPAT_NEW
492 ],
493 SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW => [
494 SCHEMA_COMPAT_OLD,
495 SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD,
496 SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW,
497 SCHEMA_COMPAT_NEW
498 ],
499 SCHEMA_COMPAT_NEW => [
500 SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW,
501 SCHEMA_COMPAT_NEW
502 ],
503 ];
504
505 $nameKey = $key . '_text';
506 $actorKey = $key === 'ipb_by' ? 'ipb_by_actor' : substr( $key, 0, -5 ) . '_actor';
507
508 foreach ( $stages as $writeStage => $possibleReadStages ) {
509 if ( $key === 'ipb_by' ) {
510 $extraFields['ipb_address'] = __CLASS__ . "#{$stageNames[$writeStage]}";
511 }
512
513 $w = $this->makeMigration( $writeStage );
514 $usesTemp = $key === 'rev_user';
515
516 if ( $usesTemp ) {
517 list( $fields, $callback ) = $w->getInsertValuesWithTempTable( $this->db, $key, $user );
518 } else {
519 $fields = $w->getInsertValues( $this->db, $key, $user );
520 }
521
522 if ( $writeStage & SCHEMA_COMPAT_WRITE_OLD ) {
523 $this->assertSame( $user->getId(), $fields[$key],
524 "old field, stage={$stageNames[$writeStage]}" );
525 $this->assertSame( $user->getName(), $fields[$nameKey],
526 "old field, stage={$stageNames[$writeStage]}" );
527 } else {
528 $this->assertArrayNotHasKey( $key, $fields, "old field, stage={$stageNames[$writeStage]}" );
529 $this->assertArrayNotHasKey( $nameKey, $fields, "old field, stage={$stageNames[$writeStage]}" );
530 }
531 if ( ( $writeStage & SCHEMA_COMPAT_WRITE_NEW ) && !$usesTemp ) {
532 $this->assertSame( $user->getActorId(), $fields[$actorKey],
533 "new field, stage={$stageNames[$writeStage]}" );
534 } else {
535 $this->assertArrayNotHasKey( $actorKey, $fields,
536 "new field, stage={$stageNames[$writeStage]}" );
537 }
538
539 $this->db->insert( $table, $extraFields + $fields, __METHOD__ );
540 $id = $this->db->insertId();
541 if ( $usesTemp ) {
542 $callback( $id, $extraFields );
543 }
544
545 foreach ( $possibleReadStages as $readStage ) {
546 $r = $this->makeMigration( $readStage );
547
548 $queryInfo = $r->getJoin( $key );
549 $row = $this->db->selectRow(
550 [ $table ] + $queryInfo['tables'],
551 $queryInfo['fields'],
552 [ $pk => $id ],
553 __METHOD__,
554 [],
555 $queryInfo['joins']
556 );
557
558 $this->assertSame( $user->getId(), (int)$row->$key,
559 "w={$stageNames[$writeStage]}, r={$stageNames[$readStage]}, id" );
560 $this->assertSame( $user->getName(), $row->$nameKey,
561 "w={$stageNames[$writeStage]}, r={$stageNames[$readStage]}, name" );
562 $this->assertSame(
563 ( $readStage & SCHEMA_COMPAT_READ_OLD ) ? 0 : $user->getActorId(),
564 (int)$row->$actorKey,
565 "w={$stageNames[$writeStage]}, r={$stageNames[$readStage]}, actor"
566 );
567 }
568 }
569 }
570
571 public static function provideInsertRoundTrip() {
572 $db = wfGetDB( DB_REPLICA ); // for timestamps
573
574 $ipbfields = [
575 ];
576 $revfields = [
577 ];
578
579 return [
580 'recentchanges' => [ 'recentchanges', 'rc_user', 'rc_id', [
581 'rc_timestamp' => $db->timestamp(),
582 'rc_namespace' => 0,
583 'rc_title' => 'Test',
584 'rc_this_oldid' => 42,
585 'rc_last_oldid' => 41,
586 'rc_source' => 'test',
587 ] ],
588 'ipblocks' => [ 'ipblocks', 'ipb_by', 'ipb_id', [
589 'ipb_range_start' => '',
590 'ipb_range_end' => '',
591 'ipb_timestamp' => $db->timestamp(),
592 'ipb_expiry' => $db->getInfinity(),
593 ] ],
594 'revision' => [ 'revision', 'rev_user', 'rev_id', [
595 'rev_page' => 42,
596 'rev_text_id' => 42,
597 'rev_len' => 0,
598 'rev_timestamp' => $db->timestamp(),
599 ] ],
600 ];
601 }
602
603 public static function provideStages() {
604 return [
605 'old' => [ SCHEMA_COMPAT_OLD ],
606 'read-old' => [ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD ],
607 'read-new' => [ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW ],
608 'new' => [ SCHEMA_COMPAT_NEW ],
609 ];
610 }
611
612 /**
613 * @dataProvider provideStages
614 * @param int $stage
615 * @expectedException InvalidArgumentException
616 * @expectedExceptionMessage Must use getInsertValuesWithTempTable() for rev_user
617 */
618 public function testInsertWrong( $stage ) {
619 $m = $this->makeMigration( $stage );
620 $m->getInsertValues( $this->db, 'rev_user', $this->getTestUser()->getUser() );
621 }
622
623 /**
624 * @dataProvider provideStages
625 * @param int $stage
626 * @expectedException InvalidArgumentException
627 * @expectedExceptionMessage Must use getInsertValues() for rc_user
628 */
629 public function testInsertWithTempTableWrong( $stage ) {
630 $m = $this->makeMigration( $stage );
631 $m->getInsertValuesWithTempTable( $this->db, 'rc_user', $this->getTestUser()->getUser() );
632 }
633
634 /**
635 * @dataProvider provideStages
636 * @param int $stage
637 */
638 public function testInsertWithTempTableDeprecated( $stage ) {
639 $wrap = TestingAccessWrapper::newFromClass( ActorMigration::class );
640 $wrap->formerTempTables += [ 'rc_user' => '1.30' ];
641
642 $this->hideDeprecated( 'ActorMigration::getInsertValuesWithTempTable for rc_user' );
643 $m = $this->makeMigration( $stage );
644 list( $fields, $callback )
645 = $m->getInsertValuesWithTempTable( $this->db, 'rc_user', $this->getTestUser()->getUser() );
646 $this->assertTrue( is_callable( $callback ) );
647 }
648
649 /**
650 * @dataProvider provideStages
651 * @param int $stage
652 * @expectedException InvalidArgumentException
653 * @expectedExceptionMessage $extra[rev_timestamp] is not provided
654 */
655 public function testInsertWithTempTableCallbackMissingFields( $stage ) {
656 $m = $this->makeMigration( $stage );
657 list( $fields, $callback )
658 = $m->getInsertValuesWithTempTable( $this->db, 'rev_user', $this->getTestUser()->getUser() );
659 $callback( 1, [] );
660 }
661
662 public function testInsertUserIdentity() {
663 $this->setMwGlobals( [
664 // for User::getActorId()
665 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
666 ] );
667 $this->overrideMwServices();
668
669 $user = $this->getTestUser()->getUser();
670 $userIdentity = $this->getMock( UserIdentity::class );
671 $userIdentity->method( 'getId' )->willReturn( $user->getId() );
672 $userIdentity->method( 'getName' )->willReturn( $user->getName() );
673 $userIdentity->method( 'getActorId' )->willReturn( 0 );
674
675 list( $cFields, $cCallback ) = MediaWikiServices::getInstance()->getCommentStore()
676 ->insertWithTempTable( $this->db, 'rev_comment', '' );
677 $m = $this->makeMigration( SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW );
678 list( $fields, $callback ) =
679 $m->getInsertValuesWithTempTable( $this->db, 'rev_user', $userIdentity );
680 $extraFields = [
681 'rev_page' => 42,
682 'rev_text_id' => 42,
683 'rev_len' => 0,
684 'rev_timestamp' => $this->db->timestamp(),
685 ] + $cFields;
686 $this->db->insert( 'revision', $extraFields + $fields, __METHOD__ );
687 $id = $this->db->insertId();
688 $callback( $id, $extraFields );
689 $cCallback( $id );
690
691 $qi = $m->getJoin( 'rev_user' );
692 $row = $this->db->selectRow(
693 [ 'revision' ] + $qi['tables'], $qi['fields'], [ 'rev_id' => $id ], __METHOD__, [], $qi['joins']
694 );
695 $this->assertSame( $user->getId(), (int)$row->rev_user );
696 $this->assertSame( $user->getName(), $row->rev_user_text );
697 $this->assertSame( $user->getActorId(), (int)$row->rev_actor );
698
699 $m = $this->makeMigration( SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW );
700 $fields = $m->getInsertValues( $this->db, 'dummy_user', $userIdentity );
701 $this->assertSame( $user->getId(), $fields['dummy_user'] );
702 $this->assertSame( $user->getName(), $fields['dummy_user_text'] );
703 $this->assertSame( $user->getActorId(), $fields['dummy_actor'] );
704 }
705
706 public function testNewMigration() {
707 $m = ActorMigration::newMigration();
708 $this->assertInstanceOf( ActorMigration::class, $m );
709 $this->assertSame( $m, ActorMigration::newMigration() );
710 }
711
712 /**
713 * @dataProvider provideIsAnon
714 * @param int $stage
715 * @param string $isAnon
716 * @param string $isNotAnon
717 */
718 public function testIsAnon( $stage, $isAnon, $isNotAnon ) {
719 $m = $this->makeMigration( $stage );
720 $this->assertSame( $isAnon, $m->isAnon( 'foo' ) );
721 $this->assertSame( $isNotAnon, $m->isNotAnon( 'foo' ) );
722 }
723
724 public static function provideIsAnon() {
725 return [
726 'old' => [ SCHEMA_COMPAT_OLD, 'foo = 0', 'foo != 0' ],
727 'read-old' => [ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, 'foo = 0', 'foo != 0' ],
728 'read-new' => [
729 SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, 'foo IS NULL', 'foo IS NOT NULL'
730 ],
731 'new' => [ SCHEMA_COMPAT_NEW, 'foo IS NULL', 'foo IS NOT NULL' ],
732 ];
733 }
734
735 }