Drop wfRunHooks, deprecated since 1.25
[lhc/web/wiklou.git] / tests / phpunit / includes / Revision / RevisionQueryInfoTest.php
1 <?php
2 namespace MediaWiki\Tests\Revision;
3
4 use MediaWiki\MediaWikiServices;
5 use MediaWiki\Revision\SlotRecord;
6 use MediaWikiTestCase;
7 use Revision;
8
9 /**
10 * Tests RevisionStore against the post-migration MCR DB schema.
11 *
12 * @group RevisionStore
13 * @group Storage
14 * @group Database
15 */
16 class RevisionQueryInfoTest extends MediaWikiTestCase {
17
18 protected function getRevisionQueryFields( $returnTextIdField = true ) {
19 $fields = [
20 'rev_id',
21 'rev_page',
22 'rev_timestamp',
23 'rev_minor_edit',
24 'rev_deleted',
25 'rev_len',
26 'rev_parent_id',
27 'rev_sha1',
28 ];
29 if ( $returnTextIdField ) {
30 $fields[] = 'rev_text_id';
31 }
32 return $fields;
33 }
34
35 protected function getArchiveQueryFields( $returnTextFields = true ) {
36 $fields = [
37 'ar_id',
38 'ar_page_id',
39 'ar_namespace',
40 'ar_title',
41 'ar_rev_id',
42 'ar_timestamp',
43 'ar_minor_edit',
44 'ar_deleted',
45 'ar_len',
46 'ar_parent_id',
47 'ar_sha1',
48 ];
49 if ( $returnTextFields ) {
50 $fields[] = 'ar_text_id';
51 }
52 return $fields;
53 }
54
55 protected function getOldCommentQueryFields( $prefix ) {
56 return [
57 "{$prefix}_comment_text" => "{$prefix}_comment",
58 "{$prefix}_comment_data" => 'NULL',
59 "{$prefix}_comment_cid" => 'NULL',
60 ];
61 }
62
63 protected function getCompatCommentQueryFields( $prefix ) {
64 return [
65 "{$prefix}_comment_text"
66 => "COALESCE( comment_{$prefix}_comment.comment_text, {$prefix}_comment )",
67 "{$prefix}_comment_data" => "comment_{$prefix}_comment.comment_data",
68 "{$prefix}_comment_cid" => "comment_{$prefix}_comment.comment_id",
69 ];
70 }
71
72 protected function getNewCommentQueryFields( $prefix ) {
73 return [
74 "{$prefix}_comment_text" => "comment_{$prefix}_comment.comment_text",
75 "{$prefix}_comment_data" => "comment_{$prefix}_comment.comment_data",
76 "{$prefix}_comment_cid" => "comment_{$prefix}_comment.comment_id",
77 ];
78 }
79
80 protected function getOldActorQueryFields( $prefix ) {
81 return [
82 "{$prefix}_user" => "{$prefix}_user",
83 "{$prefix}_user_text" => "{$prefix}_user_text",
84 "{$prefix}_actor" => 'NULL',
85 ];
86 }
87
88 protected function getNewActorQueryFields( $prefix, $tmp = false ) {
89 return [
90 "{$prefix}_user" => "actor_{$prefix}_user.actor_user",
91 "{$prefix}_user_text" => "actor_{$prefix}_user.actor_name",
92 "{$prefix}_actor" => $tmp ?: "{$prefix}_actor",
93 ];
94 }
95
96 protected function getCompatActorQueryFields( $prefix, $tmp = false ) {
97 return [
98 "{$prefix}_user" => "COALESCE( actor_{$prefix}_user.actor_user, {$prefix}_user )",
99 "{$prefix}_user_text" => "COALESCE( actor_{$prefix}_user.actor_name, {$prefix}_user_text )",
100 "{$prefix}_actor" => $tmp ?: "{$prefix}_actor",
101 ];
102 }
103
104 protected function getCompatActorJoins( $prefix ) {
105 return [
106 "temp_{$prefix}_user" => [
107 "LEFT JOIN",
108 "temp_{$prefix}_user.revactor_{$prefix} = {$prefix}_id",
109 ],
110 "actor_{$prefix}_user" => [
111 "LEFT JOIN",
112 "actor_{$prefix}_user.actor_id = temp_{$prefix}_user.revactor_actor",
113 ],
114 ];
115 }
116
117 protected function getCompatCommentJoins( $prefix ) {
118 return [
119 "temp_{$prefix}_comment" => [
120 "LEFT JOIN",
121 "temp_{$prefix}_comment.revcomment_{$prefix} = {$prefix}_id",
122 ],
123 "comment_{$prefix}_comment" => [
124 "LEFT JOIN",
125 "comment_{$prefix}_comment.comment_id = temp_{$prefix}_comment.revcomment_comment_id",
126 ],
127 ];
128 }
129
130 protected function getTextQueryFields() {
131 return [
132 'old_text',
133 'old_flags',
134 ];
135 }
136
137 protected function getPageQueryFields() {
138 return [
139 'page_namespace',
140 'page_title',
141 'page_id',
142 'page_latest',
143 'page_is_redirect',
144 'page_len',
145 ];
146 }
147
148 protected function getUserQueryFields() {
149 return [
150 'user_name',
151 ];
152 }
153
154 protected function getContentHandlerQueryFields( $prefix ) {
155 return [
156 "{$prefix}_content_format",
157 "{$prefix}_content_model",
158 ];
159 }
160
161 public function provideArchiveQueryInfo() {
162 yield 'MCR, comment, actor' => [
163 [
164 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_NEW,
165 'wgCommentTableSchemaMigrationStage' => MIGRATION_NEW,
166 'wgActorTableSchemaMigrationStage' => MIGRATION_NEW,
167 ],
168 [
169 'tables' => [
170 'archive',
171 'actor_ar_user' => 'actor',
172 'comment_ar_comment' => 'comment',
173 ],
174 'fields' => array_merge(
175 $this->getArchiveQueryFields( false ),
176 $this->getNewActorQueryFields( 'ar' ),
177 $this->getNewCommentQueryFields( 'ar' )
178 ),
179 'joins' => [
180 'comment_ar_comment'
181 => [ 'JOIN', 'comment_ar_comment.comment_id = ar_comment_id' ],
182 'actor_ar_user' => [ 'JOIN', 'actor_ar_user.actor_id = ar_actor' ],
183 ],
184 ]
185 ];
186 yield 'read-new MCR, comment, actor' => [
187 [
188 'wgContentHandlerUseDB' => true,
189 'wgMultiContentRevisionSchemaMigrationStage'
190 => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW,
191 'wgCommentTableSchemaMigrationStage' => MIGRATION_WRITE_NEW,
192 'wgActorTableSchemaMigrationStage' => MIGRATION_WRITE_NEW,
193 ],
194 [
195 'tables' => [
196 'archive',
197 'actor_ar_user' => 'actor',
198 'comment_ar_comment' => 'comment',
199 ],
200 'fields' => array_merge(
201 $this->getArchiveQueryFields( false ),
202 $this->getCompatActorQueryFields( 'ar' ),
203 $this->getCompatCommentQueryFields( 'ar' )
204 ),
205 'joins' => [
206 'comment_ar_comment'
207 => [ 'LEFT JOIN', 'comment_ar_comment.comment_id = ar_comment_id' ],
208 'actor_ar_user' => [ 'LEFT JOIN', 'actor_ar_user.actor_id = ar_actor' ],
209 ],
210 ]
211 ];
212 yield 'MCR write-both/read-old' => [
213 [
214 'wgContentHandlerUseDB' => true,
215 'wgMultiContentRevisionSchemaMigrationStage'
216 => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD,
217 'wgCommentTableSchemaMigrationStage' => MIGRATION_WRITE_BOTH,
218 'wgActorTableSchemaMigrationStage' => MIGRATION_WRITE_BOTH,
219 ],
220 [
221 'tables' => [
222 'archive',
223 'actor_ar_user' => 'actor',
224 'comment_ar_comment' => 'comment',
225 ],
226 'fields' => array_merge(
227 $this->getArchiveQueryFields( true ),
228 $this->getContentHandlerQueryFields( 'ar' ),
229 $this->getCompatActorQueryFields( 'ar' ),
230 $this->getCompatCommentQueryFields( 'ar' )
231 ),
232 'joins' => [
233 'comment_ar_comment'
234 => [ 'LEFT JOIN', 'comment_ar_comment.comment_id = ar_comment_id' ],
235 'actor_ar_user' => [ 'LEFT JOIN', 'actor_ar_user.actor_id = ar_actor' ],
236 ],
237 ]
238 ];
239 yield 'pre-MCR, no model' => [
240 [
241 'wgContentHandlerUseDB' => false,
242 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD,
243 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD,
244 'wgActorTableSchemaMigrationStage' => MIGRATION_OLD,
245 ],
246 [
247 'tables' => [
248 'archive',
249 ],
250 'fields' => array_merge(
251 $this->getArchiveQueryFields( true ),
252 $this->getOldActorQueryFields( 'ar' ),
253 $this->getOldCommentQueryFields( 'ar' )
254 ),
255 'joins' => [],
256 ]
257 ];
258 }
259
260 public function provideQueryInfo() {
261 // TODO: more option variations
262 yield 'MCR, page, user, comment, actor' => [
263 [
264 'wgContentHandlerUseDB' => true,
265 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_NEW,
266 'wgCommentTableSchemaMigrationStage' => MIGRATION_NEW,
267 'wgActorTableSchemaMigrationStage' => MIGRATION_NEW,
268 ],
269 [ 'page', 'user' ],
270 [
271 'tables' => [
272 'revision',
273 'page',
274 'user',
275 'temp_rev_user' => 'revision_actor_temp',
276 'temp_rev_comment' => 'revision_comment_temp',
277 'actor_rev_user' => 'actor',
278 'comment_rev_comment' => 'comment',
279 ],
280 'fields' => array_merge(
281 $this->getRevisionQueryFields( false ),
282 $this->getPageQueryFields(),
283 $this->getUserQueryFields(),
284 $this->getNewActorQueryFields( 'rev', 'temp_rev_user.revactor_actor' ),
285 $this->getNewCommentQueryFields( 'rev' )
286 ),
287 'joins' => [
288 'page' => [ 'INNER JOIN', [ 'page_id = rev_page' ] ],
289 'user' => [
290 'LEFT JOIN',
291 [ 'actor_rev_user.actor_user != 0', 'user_id = actor_rev_user.actor_user' ],
292 ],
293 'comment_rev_comment' => [
294 'JOIN',
295 'comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id',
296 ],
297 'actor_rev_user' => [
298 'JOIN',
299 'actor_rev_user.actor_id = temp_rev_user.revactor_actor',
300 ],
301 'temp_rev_user' => [ 'JOIN', 'temp_rev_user.revactor_rev = rev_id' ],
302 'temp_rev_comment' => [ 'JOIN', 'temp_rev_comment.revcomment_rev = rev_id' ],
303 ],
304 ]
305 ];
306 yield 'MCR read-new, page, user, comment, actor' => [
307 [
308 'wgContentHandlerUseDB' => true,
309 'wgMultiContentRevisionSchemaMigrationStage'
310 => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW,
311 'wgCommentTableSchemaMigrationStage' => MIGRATION_WRITE_NEW,
312 'wgActorTableSchemaMigrationStage' => MIGRATION_WRITE_NEW,
313 ],
314 [ 'page', 'user' ],
315 [
316 'tables' => [
317 'revision',
318 'page',
319 'user',
320 'temp_rev_user' => 'revision_actor_temp',
321 'temp_rev_comment' => 'revision_comment_temp',
322 'actor_rev_user' => 'actor',
323 'comment_rev_comment' => 'comment',
324 ],
325 'fields' => array_merge(
326 $this->getRevisionQueryFields( false ),
327 $this->getPageQueryFields(),
328 $this->getUserQueryFields(),
329 $this->getCompatActorQueryFields( 'rev', 'temp_rev_user.revactor_actor' ),
330 $this->getCompatCommentQueryFields( 'rev' )
331 ),
332 'joins' => array_merge(
333 [
334 'page' => [ 'INNER JOIN', [ 'page_id = rev_page' ] ],
335 'user' => [
336 'LEFT JOIN',
337 [
338 'COALESCE( actor_rev_user.actor_user, rev_user ) != 0',
339 'user_id = COALESCE( actor_rev_user.actor_user, rev_user )'
340 ]
341 ],
342 ],
343 $this->getCompatActorJoins( 'rev' ),
344 $this->getCompatCommentJoins( 'rev' )
345 ),
346 ]
347 ];
348 yield 'MCR read-new' => [
349 [
350 'wgContentHandlerUseDB' => true,
351 'wgMultiContentRevisionSchemaMigrationStage'
352 => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW,
353 'wgCommentTableSchemaMigrationStage' => MIGRATION_WRITE_NEW,
354 'wgActorTableSchemaMigrationStage' => MIGRATION_WRITE_NEW,
355 ],
356 [ 'page', 'user' ],
357 [
358 'tables' => [
359 'revision',
360 'page',
361 'user',
362 'temp_rev_user' => 'revision_actor_temp',
363 'temp_rev_comment' => 'revision_comment_temp',
364 'actor_rev_user' => 'actor',
365 'comment_rev_comment' => 'comment',
366 ],
367 'fields' => array_merge(
368 $this->getRevisionQueryFields( false ),
369 $this->getPageQueryFields(),
370 $this->getUserQueryFields(),
371 $this->getCompatActorQueryFields( 'rev', 'temp_rev_user.revactor_actor' ),
372 $this->getCompatCommentQueryFields( 'rev' )
373 ),
374 'joins' => array_merge(
375 [
376 'page' => [ 'INNER JOIN', [ 'page_id = rev_page' ] ],
377 'user' => [
378 'LEFT JOIN',
379 [
380 'COALESCE( actor_rev_user.actor_user, rev_user ) != 0',
381 'user_id = COALESCE( actor_rev_user.actor_user, rev_user )'
382 ]
383 ],
384 ],
385 $this->getCompatActorJoins( 'rev' ),
386 $this->getCompatCommentJoins( 'rev' )
387 ),
388 ]
389 ];
390 yield 'MCR write-both/read-old' => [
391 [
392 'wgContentHandlerUseDB' => true,
393 'wgMultiContentRevisionSchemaMigrationStage'
394 => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD,
395 'wgCommentTableSchemaMigrationStage' => MIGRATION_WRITE_BOTH,
396 'wgActorTableSchemaMigrationStage' => MIGRATION_WRITE_BOTH,
397 ],
398 [],
399 [
400 'tables' => [
401 'revision',
402 'temp_rev_user' => 'revision_actor_temp',
403 'temp_rev_comment' => 'revision_comment_temp',
404 'actor_rev_user' => 'actor',
405 'comment_rev_comment' => 'comment',
406 ],
407 'fields' => array_merge(
408 $this->getRevisionQueryFields( true ),
409 $this->getContentHandlerQueryFields( 'rev' ),
410 $this->getCompatActorQueryFields( 'rev', 'temp_rev_user.revactor_actor' ),
411 $this->getCompatCommentQueryFields( 'rev' )
412 ),
413 'joins' => array_merge(
414 $this->getCompatActorJoins( 'rev' ),
415 $this->getCompatCommentJoins( 'rev' )
416 ),
417 ]
418 ];
419 yield 'MCR write-both/read-old, page, user' => [
420 [
421 'wgContentHandlerUseDB' => true,
422 'wgMultiContentRevisionSchemaMigrationStage'
423 => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD,
424 'wgCommentTableSchemaMigrationStage' => MIGRATION_WRITE_BOTH,
425 'wgActorTableSchemaMigrationStage' => MIGRATION_WRITE_BOTH,
426 ],
427 [ 'page', 'user' ],
428 [
429 'tables' => [
430 'revision',
431 'page',
432 'user',
433 'temp_rev_user' => 'revision_actor_temp',
434 'temp_rev_comment' => 'revision_comment_temp',
435 'actor_rev_user' => 'actor',
436 'comment_rev_comment' => 'comment',
437 ],
438 'fields' => array_merge(
439 $this->getRevisionQueryFields( true ),
440 $this->getContentHandlerQueryFields( 'rev' ),
441 $this->getUserQueryFields(),
442 $this->getPageQueryFields(),
443 $this->getCompatActorQueryFields( 'rev', 'temp_rev_user.revactor_actor' ),
444 $this->getCompatCommentQueryFields( 'rev' )
445 ),
446 'joins' => array_merge(
447 [
448 'page' => [ 'INNER JOIN', [ 'page_id = rev_page' ] ],
449 'user' => [
450 'LEFT JOIN',
451 [
452 'COALESCE( actor_rev_user.actor_user, rev_user ) != 0',
453 'user_id = COALESCE( actor_rev_user.actor_user, rev_user )'
454 ]
455 ],
456 ],
457 $this->getCompatActorJoins( 'rev' ),
458 $this->getCompatCommentJoins( 'rev' )
459 ),
460 ]
461 ];
462 yield 'pre-MCR' => [
463 [
464 'wgContentHandlerUseDB' => true,
465 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD,
466 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD,
467 'wgActorTableSchemaMigrationStage' => MIGRATION_OLD,
468 ],
469 [],
470 [
471 'tables' => [ 'revision' ],
472 'fields' => array_merge(
473 $this->getRevisionQueryFields( true ),
474 $this->getContentHandlerQueryFields( 'rev' ),
475 $this->getOldActorQueryFields( 'rev' ),
476 $this->getOldCommentQueryFields( 'rev' )
477 ),
478 'joins' => [],
479 ]
480 ];
481 yield 'pre-MCR, page, user' => [
482 [
483 'wgContentHandlerUseDB' => true,
484 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD,
485 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD,
486 'wgActorTableSchemaMigrationStage' => MIGRATION_OLD,
487 ],
488 [ 'page', 'user' ],
489 [
490 'tables' => [ 'revision', 'page', 'user' ],
491 'fields' => array_merge(
492 $this->getRevisionQueryFields( true ),
493 $this->getContentHandlerQueryFields( 'rev' ),
494 $this->getPageQueryFields(),
495 $this->getUserQueryFields(),
496 $this->getOldActorQueryFields( 'rev' ),
497 $this->getOldCommentQueryFields( 'rev' )
498 ),
499 'joins' => [
500 'page' => [ 'INNER JOIN', [ 'page_id = rev_page' ] ],
501 'user' => [ 'LEFT JOIN', [ 'rev_user != 0', 'user_id = rev_user' ] ],
502 ],
503 ]
504 ];
505 yield 'pre-MCR, no model' => [
506 [
507 'wgContentHandlerUseDB' => false,
508 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD,
509 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD,
510 'wgActorTableSchemaMigrationStage' => MIGRATION_OLD,
511 ],
512 [],
513 [
514 'tables' => [ 'revision' ],
515 'fields' => array_merge(
516 $this->getRevisionQueryFields( true ),
517 $this->getOldActorQueryFields( 'rev' ),
518 $this->getOldCommentQueryFields( 'rev' )
519 ),
520 'joins' => [],
521 ],
522 ];
523 yield 'pre-MCR, no model, page' => [
524 [
525 'wgContentHandlerUseDB' => false,
526 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD,
527 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD,
528 'wgActorTableSchemaMigrationStage' => MIGRATION_OLD,
529 ],
530 [ 'page' ],
531 [
532 'tables' => [ 'revision', 'page' ],
533 'fields' => array_merge(
534 $this->getRevisionQueryFields( true ),
535 $this->getPageQueryFields(),
536 $this->getOldActorQueryFields( 'rev' ),
537 $this->getOldCommentQueryFields( 'rev' )
538 ),
539 'joins' => [
540 'page' => [ 'INNER JOIN', [ 'page_id = rev_page' ], ],
541 ],
542 ],
543 ];
544 yield 'pre-MCR, no model, user' => [
545 [
546 'wgContentHandlerUseDB' => false,
547 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD,
548 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD,
549 'wgActorTableSchemaMigrationStage' => MIGRATION_OLD,
550 ],
551 [ 'user' ],
552 [
553 'tables' => [ 'revision', 'user' ],
554 'fields' => array_merge(
555 $this->getRevisionQueryFields( true ),
556 $this->getUserQueryFields(),
557 $this->getOldActorQueryFields( 'rev' ),
558 $this->getOldCommentQueryFields( 'rev' )
559 ),
560 'joins' => [
561 'user' => [ 'LEFT JOIN', [ 'rev_user != 0', 'user_id = rev_user' ] ],
562 ],
563 ],
564 ];
565 yield 'pre-MCR, no model, text' => [
566 [
567 'wgContentHandlerUseDB' => false,
568 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD,
569 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD,
570 'wgActorTableSchemaMigrationStage' => MIGRATION_OLD,
571 ],
572 [ 'text' ],
573 [
574 'tables' => [ 'revision', 'text' ],
575 'fields' => array_merge(
576 $this->getRevisionQueryFields( true ),
577 $this->getTextQueryFields(),
578 $this->getOldActorQueryFields( 'rev' ),
579 $this->getOldCommentQueryFields( 'rev' )
580 ),
581 'joins' => [
582 'text' => [ 'INNER JOIN', [ 'rev_text_id=old_id' ] ],
583 ],
584 ],
585 ];
586 yield 'pre-MCR, no model, text, page, user' => [
587 [
588 'wgContentHandlerUseDB' => false,
589 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD,
590 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD,
591 'wgActorTableSchemaMigrationStage' => MIGRATION_OLD,
592 ],
593 [ 'text', 'page', 'user' ],
594 [
595 'tables' => [
596 'revision', 'page', 'user', 'text'
597 ],
598 'fields' => array_merge(
599 $this->getRevisionQueryFields( true ),
600 $this->getPageQueryFields(),
601 $this->getUserQueryFields(),
602 $this->getTextQueryFields(),
603 $this->getOldActorQueryFields( 'rev' ),
604 $this->getOldCommentQueryFields( 'rev' )
605 ),
606 'joins' => [
607 'page' => [
608 'INNER JOIN',
609 [ 'page_id = rev_page' ],
610 ],
611 'user' => [
612 'LEFT JOIN',
613 [
614 'rev_user != 0',
615 'user_id = rev_user',
616 ],
617 ],
618 'text' => [
619 'INNER JOIN',
620 [ 'rev_text_id=old_id' ],
621 ],
622 ],
623 ],
624 ];
625 }
626
627 public function provideSlotsQueryInfo() {
628 yield 'MCR, no options' => [
629 [
630 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_NEW,
631 ],
632 [],
633 [
634 'tables' => [
635 'slots'
636 ],
637 'fields' => [
638 'slot_revision_id',
639 'slot_content_id',
640 'slot_origin',
641 'slot_role_id',
642 ],
643 'joins' => [],
644 ]
645 ];
646 yield 'MCR, role option' => [
647 [
648 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_NEW,
649 ],
650 [ 'role' ],
651 [
652 'tables' => [
653 'slots',
654 'slot_roles',
655 ],
656 'fields' => [
657 'slot_revision_id',
658 'slot_content_id',
659 'slot_origin',
660 'slot_role_id',
661 'role_name',
662 ],
663 'joins' => [
664 'slot_roles' => [ 'LEFT JOIN', [ 'slot_role_id = role_id' ] ],
665 ],
666 ]
667 ];
668 yield 'MCR read-new, content option' => [
669 [
670 'wgMultiContentRevisionSchemaMigrationStage'
671 => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW,
672 ],
673 [ 'content' ],
674 [
675 'tables' => [
676 'slots',
677 'content',
678 ],
679 'fields' => [
680 'slot_revision_id',
681 'slot_content_id',
682 'slot_origin',
683 'slot_role_id',
684 'content_size',
685 'content_sha1',
686 'content_address',
687 'content_model',
688 ],
689 'joins' => [
690 'content' => [ 'INNER JOIN', [ 'slot_content_id = content_id' ] ],
691 ],
692 ]
693 ];
694 yield 'MCR read-new, content and model options' => [
695 [
696 'wgMultiContentRevisionSchemaMigrationStage'
697 => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW,
698 ],
699 [ 'content', 'model' ],
700 [
701 'tables' => [
702 'slots',
703 'content',
704 'content_models',
705 ],
706 'fields' => [
707 'slot_revision_id',
708 'slot_content_id',
709 'slot_origin',
710 'slot_role_id',
711 'content_size',
712 'content_sha1',
713 'content_address',
714 'content_model',
715 'model_name',
716 ],
717 'joins' => [
718 'content' => [ 'INNER JOIN', [ 'slot_content_id = content_id' ] ],
719 'content_models' => [ 'LEFT JOIN', [ 'content_model = model_id' ] ],
720 ],
721 ]
722 ];
723
724 $db = wfGetDB( DB_REPLICA );
725
726 yield 'MCR write-both/read-old' => [
727 [
728 'wgMultiContentRevisionSchemaMigrationStage'
729 => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD,
730 ],
731 [],
732 [
733 'tables' => [
734 'slots' => 'revision',
735 ],
736 'fields' => array_merge(
737 [
738 'slot_revision_id' => 'slots.rev_id',
739 'slot_content_id' => 'NULL',
740 'slot_origin' => 'slots.rev_id',
741 'role_name' => $db->addQuotes( SlotRecord::MAIN ),
742 ]
743 ),
744 'joins' => [],
745 ]
746 ];
747 yield 'MCR write-both/read-old, content' => [
748 [
749 'wgMultiContentRevisionSchemaMigrationStage'
750 => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD,
751 ],
752 [ 'content' ],
753 [
754 'tables' => [
755 'slots' => 'revision',
756 ],
757 'fields' => array_merge(
758 [
759 'slot_revision_id' => 'slots.rev_id',
760 'slot_content_id' => 'NULL',
761 'slot_origin' => 'slots.rev_id',
762 'role_name' => $db->addQuotes( SlotRecord::MAIN ),
763 'content_size' => 'slots.rev_len',
764 'content_sha1' => 'slots.rev_sha1',
765 'content_address' => $db->buildConcat( [
766 $db->addQuotes( 'tt:' ), 'slots.rev_text_id' ] ),
767 'model_name' => 'slots.rev_content_model',
768 ]
769 ),
770 'joins' => [],
771 ]
772 ];
773 yield 'MCR write-both/read-old, content, model, role' => [
774 [
775 'wgMultiContentRevisionSchemaMigrationStage'
776 => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD,
777 ],
778 [ 'content', 'model', 'role' ],
779 [
780 'tables' => [
781 'slots' => 'revision',
782 ],
783 'fields' => array_merge(
784 [
785 'slot_revision_id' => 'slots.rev_id',
786 'slot_content_id' => 'NULL',
787 'slot_origin' => 'slots.rev_id',
788 'role_name' => $db->addQuotes( SlotRecord::MAIN ),
789 'content_size' => 'slots.rev_len',
790 'content_sha1' => 'slots.rev_sha1',
791 'content_address' => $db->buildConcat( [
792 $db->addQuotes( 'tt:' ), 'slots.rev_text_id' ] ),
793 'model_name' => 'slots.rev_content_model',
794 ]
795 ),
796 'joins' => [],
797 ]
798 ];
799 yield 'pre-MCR' => [
800 [
801 'wgMultiContentRevisionSchemaMigrationStage'
802 => SCHEMA_COMPAT_OLD,
803 ],
804 [],
805 [
806 'tables' => [
807 'slots' => 'revision',
808 ],
809 'fields' => array_merge(
810 [
811 'slot_revision_id' => 'slots.rev_id',
812 'slot_content_id' => 'NULL',
813 'slot_origin' => 'slots.rev_id',
814 'role_name' => $db->addQuotes( SlotRecord::MAIN ),
815 ]
816 ),
817 'joins' => [],
818 ]
819 ];
820 yield 'pre-MCR, content' => [
821 [
822 'wgMultiContentRevisionSchemaMigrationStage'
823 => SCHEMA_COMPAT_OLD,
824 ],
825 [ 'content' ],
826 [
827 'tables' => [
828 'slots' => 'revision',
829 ],
830 'fields' => array_merge(
831 [
832 'slot_revision_id' => 'slots.rev_id',
833 'slot_content_id' => 'NULL',
834 'slot_origin' => 'slots.rev_id',
835 'role_name' => $db->addQuotes( SlotRecord::MAIN ),
836 'content_size' => 'slots.rev_len',
837 'content_sha1' => 'slots.rev_sha1',
838 'content_address' =>
839 $db->buildConcat( [ $db->addQuotes( 'tt:' ), 'slots.rev_text_id' ] ),
840 'model_name' => 'slots.rev_content_model',
841 ]
842 ),
843 'joins' => [],
844 ]
845 ];
846 }
847
848 public function provideSelectFields() {
849 yield 'with model, comment, and actor' => [
850 [
851 'wgContentHandlerUseDB' => true,
852 'wgCommentTableSchemaMigrationStage' => MIGRATION_WRITE_BOTH,
853 'wgActorTableSchemaMigrationStage' => MIGRATION_WRITE_BOTH,
854 ],
855 'fields' => array_merge(
856 [
857 'rev_id',
858 'rev_page',
859 'rev_text_id',
860 'rev_timestamp',
861 'rev_user_text',
862 'rev_user',
863 'rev_actor' => 'NULL',
864 'rev_minor_edit',
865 'rev_deleted',
866 'rev_len',
867 'rev_parent_id',
868 'rev_sha1',
869 ],
870 $this->getContentHandlerQueryFields( 'rev' ),
871 [
872 'rev_comment_old' => 'rev_comment',
873 'rev_comment_pk' => 'rev_id',
874 ]
875 ),
876 ];
877 yield 'no mode, no comment, no actor' => [
878 [
879 'wgContentHandlerUseDB' => false,
880 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD,
881 'wgActorTableSchemaMigrationStage' => MIGRATION_OLD,
882 ],
883 'fields' => array_merge(
884 [
885 'rev_id',
886 'rev_page',
887 'rev_text_id',
888 'rev_timestamp',
889 'rev_user_text',
890 'rev_user',
891 'rev_actor' => 'NULL',
892 'rev_minor_edit',
893 'rev_deleted',
894 'rev_len',
895 'rev_parent_id',
896 'rev_sha1',
897 ],
898 $this->getOldCommentQueryFields( 'rev' )
899 ),
900 ];
901 }
902
903 public function provideSelectArchiveFields() {
904 yield 'with model, comment, and actor' => [
905 [
906 'wgContentHandlerUseDB' => true,
907 'wgCommentTableSchemaMigrationStage' => MIGRATION_WRITE_BOTH,
908 'wgActorTableSchemaMigrationStage' => MIGRATION_WRITE_BOTH,
909 ],
910 'fields' => array_merge(
911 [
912 'ar_id',
913 'ar_page_id',
914 'ar_rev_id',
915 'ar_text_id',
916 'ar_timestamp',
917 'ar_user_text',
918 'ar_user',
919 'ar_actor' => 'NULL',
920 'ar_minor_edit',
921 'ar_deleted',
922 'ar_len',
923 'ar_parent_id',
924 'ar_sha1',
925 ],
926 $this->getContentHandlerQueryFields( 'ar' ),
927 [
928 'ar_comment_old' => 'ar_comment',
929 'ar_comment_id' => 'ar_comment_id',
930 ]
931 ),
932 ];
933 yield 'no mode, no comment, no actor' => [
934 [
935 'wgContentHandlerUseDB' => false,
936 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD,
937 'wgActorTableSchemaMigrationStage' => MIGRATION_OLD,
938 ],
939 'fields' => array_merge(
940 [
941 'ar_id',
942 'ar_page_id',
943 'ar_rev_id',
944 'ar_text_id',
945 'ar_timestamp',
946 'ar_user_text',
947 'ar_user',
948 'ar_actor' => 'NULL',
949 'ar_minor_edit',
950 'ar_deleted',
951 'ar_len',
952 'ar_parent_id',
953 'ar_sha1',
954 ],
955 $this->getOldCommentQueryFields( 'ar' )
956 ),
957 ];
958 }
959
960 /**
961 * @dataProvider provideSelectFields
962 * @covers Revision::selectFields
963 */
964 public function testRevisionSelectFields( $migrationStageSettings, $expected ) {
965 $this->setMwGlobals( $migrationStageSettings );
966 $this->overrideMwServices();
967
968 $this->hideDeprecated( 'Revision::selectFields' );
969 $this->assertArrayEqualsIgnoringIntKeyOrder( $expected, Revision::selectFields() );
970 }
971
972 /**
973 * @dataProvider provideSelectArchiveFields
974 * @covers Revision::selectArchiveFields
975 */
976 public function testRevisionSelectArchiveFields( $migrationStageSettings, $expected ) {
977 $this->setMwGlobals( $migrationStageSettings );
978 $this->overrideMwServices();
979
980 $this->hideDeprecated( 'Revision::selectArchiveFields' );
981 $this->assertArrayEqualsIgnoringIntKeyOrder( $expected, Revision::selectArchiveFields() );
982 }
983
984 /**
985 * @covers Revision::userJoinCond
986 */
987 public function testRevisionUserJoinCond() {
988 $this->hideDeprecated( 'Revision::userJoinCond' );
989 $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', MIGRATION_OLD );
990 $this->overrideMwServices();
991 $this->assertEquals(
992 [ 'LEFT JOIN', [ 'rev_user != 0', 'user_id = rev_user' ] ],
993 Revision::userJoinCond()
994 );
995 }
996
997 /**
998 * @covers Revision::pageJoinCond
999 */
1000 public function testRevisionPageJoinCond() {
1001 $this->hideDeprecated( 'Revision::pageJoinCond' );
1002 $this->assertEquals(
1003 [ 'INNER JOIN', [ 'page_id = rev_page' ] ],
1004 Revision::pageJoinCond()
1005 );
1006 }
1007
1008 /**
1009 * @covers Revision::selectTextFields
1010 */
1011 public function testRevisionSelectTextFields() {
1012 $this->hideDeprecated( 'Revision::selectTextFields' );
1013 $this->assertEquals(
1014 $this->getTextQueryFields(),
1015 Revision::selectTextFields()
1016 );
1017 }
1018
1019 /**
1020 * @covers Revision::selectPageFields
1021 */
1022 public function testRevisionSelectPageFields() {
1023 $this->hideDeprecated( 'Revision::selectPageFields' );
1024 $this->assertEquals(
1025 $this->getPageQueryFields(),
1026 Revision::selectPageFields()
1027 );
1028 }
1029
1030 /**
1031 * @covers Revision::selectUserFields
1032 */
1033 public function testRevisionSelectUserFields() {
1034 $this->hideDeprecated( 'Revision::selectUserFields' );
1035 $this->assertEquals(
1036 $this->getUserQueryFields(),
1037 Revision::selectUserFields()
1038 );
1039 }
1040
1041 /**
1042 * @covers Revision::getArchiveQueryInfo
1043 * @dataProvider provideArchiveQueryInfo
1044 */
1045 public function testRevisionGetArchiveQueryInfo( $migrationStageSettings, $expected ) {
1046 $this->setMwGlobals( $migrationStageSettings );
1047 $this->overrideMwServices();
1048
1049 $queryInfo = Revision::getArchiveQueryInfo();
1050 $this->assertQueryInfoEquals( $expected, $queryInfo );
1051 }
1052
1053 /**
1054 * @covers Revision::getQueryInfo
1055 * @dataProvider provideQueryInfo
1056 */
1057 public function testRevisionGetQueryInfo( $migrationStageSettings, $options, $expected ) {
1058 $this->setMwGlobals( $migrationStageSettings );
1059 $this->overrideMwServices();
1060
1061 $queryInfo = Revision::getQueryInfo( $options );
1062 $this->assertQueryInfoEquals( $expected, $queryInfo );
1063 }
1064
1065 /**
1066 * @dataProvider provideQueryInfo
1067 * @covers \MediaWiki\Revision\RevisionStore::getQueryInfo
1068 */
1069 public function testRevisionStoreGetQueryInfo( $migrationStageSettings, $options, $expected ) {
1070 $this->setMwGlobals( $migrationStageSettings );
1071 $this->overrideMwServices();
1072
1073 $store = MediaWikiServices::getInstance()->getRevisionStore();
1074
1075 $queryInfo = $store->getQueryInfo( $options );
1076 $this->assertQueryInfoEquals( $expected, $queryInfo );
1077 }
1078
1079 /**
1080 * @dataProvider provideSlotsQueryInfo
1081 * @covers \MediaWiki\Revision\RevisionStore::getSlotsQueryInfo
1082 */
1083 public function testRevisionStoreGetSlotsQueryInfo(
1084 $migrationStageSettings,
1085 $options,
1086 $expected
1087 ) {
1088 $this->setMwGlobals( $migrationStageSettings );
1089 $this->overrideMwServices();
1090
1091 $store = MediaWikiServices::getInstance()->getRevisionStore();
1092
1093 $queryInfo = $store->getSlotsQueryInfo( $options );
1094 $this->assertQueryInfoEquals( $expected, $queryInfo );
1095 }
1096
1097 /**
1098 * @dataProvider provideArchiveQueryInfo
1099 * @covers \MediaWiki\Revision\RevisionStore::getArchiveQueryInfo
1100 */
1101 public function testRevisionStoreGetArchiveQueryInfo( $migrationStageSettings, $expected ) {
1102 $this->setMwGlobals( $migrationStageSettings );
1103 $this->overrideMwServices();
1104
1105 $store = MediaWikiServices::getInstance()->getRevisionStore();
1106
1107 $queryInfo = $store->getArchiveQueryInfo();
1108 $this->assertQueryInfoEquals( $expected, $queryInfo );
1109 }
1110
1111 private function assertQueryInfoEquals( $expected, $queryInfo ) {
1112 $this->assertArrayEqualsIgnoringIntKeyOrder(
1113 $expected['tables'],
1114 $queryInfo['tables'],
1115 'tables'
1116 );
1117 $this->assertArrayEqualsIgnoringIntKeyOrder(
1118 $expected['fields'],
1119 $queryInfo['fields'],
1120 'fields'
1121 );
1122 $this->assertArrayEqualsIgnoringIntKeyOrder(
1123 $expected['joins'],
1124 $queryInfo['joins'],
1125 'joins'
1126 );
1127 }
1128
1129 /**
1130 * Assert that the two arrays passed are equal, ignoring the order of the values that integer
1131 * keys.
1132 *
1133 * Note: Failures of this assertion can be slightly confusing as the arrays are actually
1134 * split into a string key array and an int key array before assertions occur.
1135 *
1136 * @param array $expected
1137 * @param array $actual
1138 */
1139 private function assertArrayEqualsIgnoringIntKeyOrder(
1140 array $expected,
1141 array $actual,
1142 $message = null
1143 ) {
1144 $this->objectAssociativeSort( $expected );
1145 $this->objectAssociativeSort( $actual );
1146
1147 // Separate the int key values from the string key values so that assertion failures are
1148 // easier to understand.
1149 $expectedIntKeyValues = [];
1150 $actualIntKeyValues = [];
1151
1152 // Remove all int keys and re add them at the end after sorting by value
1153 // This will result in all int keys being in the same order with same ints at the end of
1154 // the array
1155 foreach ( $expected as $key => $value ) {
1156 if ( is_int( $key ) ) {
1157 unset( $expected[$key] );
1158 $expectedIntKeyValues[] = $value;
1159 }
1160 }
1161 foreach ( $actual as $key => $value ) {
1162 if ( is_int( $key ) ) {
1163 unset( $actual[$key] );
1164 $actualIntKeyValues[] = $value;
1165 }
1166 }
1167
1168 $this->objectAssociativeSort( $expected );
1169 $this->objectAssociativeSort( $actual );
1170
1171 $this->objectAssociativeSort( $expectedIntKeyValues );
1172 $this->objectAssociativeSort( $actualIntKeyValues );
1173
1174 $this->assertEquals( $expected, $actual, $message );
1175 $this->assertEquals( $expectedIntKeyValues, $actualIntKeyValues, $message );
1176 }
1177
1178 }