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