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