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