Merge "Provide a way to restore an old revision with multiple slots."
[lhc/web/wiklou.git] / tests / phpunit / includes / changetags / ChangeTagsTest.php
1 <?php
2
3 use MediaWiki\MediaWikiServices;
4
5 /**
6 * @covers ChangeTags
7 * @group Database
8 */
9 class ChangeTagsTest extends MediaWikiTestCase {
10
11 public function setUp() {
12 parent::setUp();
13
14 $this->tablesUsed[] = 'change_tag';
15 $this->tablesUsed[] = 'change_tag_def';
16 $this->tablesUsed[] = 'tag_summary';
17 $this->tablesUsed[] = 'valid_tag';
18 }
19
20 // TODO only modifyDisplayQuery and getSoftwareTags are tested, nothing else is
21
22 /** @dataProvider provideModifyDisplayQuery */
23 public function testModifyDisplayQuery( $origQuery, $filter_tag, $useTags, $modifiedQuery ) {
24 $this->setMwGlobals( 'wgUseTagFilter', $useTags );
25 // HACK resolve deferred group concats (see comment in provideModifyDisplayQuery)
26 if ( isset( $modifiedQuery['fields']['ts_tags'] ) ) {
27 $modifiedQuery['fields']['ts_tags'] = call_user_func_array(
28 [ wfGetDB( DB_REPLICA ), 'buildGroupConcatField' ],
29 $modifiedQuery['fields']['ts_tags']
30 );
31 }
32 if ( isset( $modifiedQuery['exception'] ) ) {
33 $this->setExpectedException( $modifiedQuery['exception'] );
34 }
35 ChangeTags::modifyDisplayQuery(
36 $origQuery['tables'],
37 $origQuery['fields'],
38 $origQuery['conds'],
39 $origQuery['join_conds'],
40 $origQuery['options'],
41 $filter_tag
42 );
43 if ( !isset( $modifiedQuery['exception'] ) ) {
44 $this->assertArrayEquals(
45 $modifiedQuery,
46 $origQuery,
47 /* ordered = */ false,
48 /* named = */ true
49 );
50 }
51 }
52
53 public function provideModifyDisplayQuery() {
54 // HACK if we call $dbr->buildGroupConcatField() now, it will return the wrong table names
55 // We have to have the test runner call it instead
56 $groupConcats = [
57 'recentchanges' => [ ',', 'change_tag', 'ct_tag', 'ct_rc_id=rc_id' ],
58 'logging' => [ ',', 'change_tag', 'ct_tag', 'ct_log_id=log_id' ],
59 'revision' => [ ',', 'change_tag', 'ct_tag', 'ct_rev_id=rev_id' ],
60 'archive' => [ ',', 'change_tag', 'ct_tag', 'ct_rev_id=ar_rev_id' ],
61 ];
62
63 return [
64 'simple recentchanges query' => [
65 [
66 'tables' => [ 'recentchanges' ],
67 'fields' => [ 'rc_id', 'rc_timestamp' ],
68 'conds' => [ "rc_timestamp > '20170714183203'" ],
69 'join_conds' => [],
70 'options' => [ 'ORDER BY' => 'rc_timestamp DESC' ],
71 ],
72 '', // no tag filter
73 true, // tag filtering enabled
74 [
75 'tables' => [ 'recentchanges' ],
76 'fields' => [ 'rc_id', 'rc_timestamp', 'ts_tags' => $groupConcats['recentchanges'] ],
77 'conds' => [ "rc_timestamp > '20170714183203'" ],
78 'join_conds' => [],
79 'options' => [ 'ORDER BY' => 'rc_timestamp DESC' ],
80 ]
81 ],
82 'simple query with strings' => [
83 [
84 'tables' => 'recentchanges',
85 'fields' => 'rc_id',
86 'conds' => "rc_timestamp > '20170714183203'",
87 'join_conds' => [],
88 'options' => 'ORDER BY rc_timestamp DESC',
89 ],
90 '', // no tag filter
91 true, // tag filtering enabled
92 [
93 'tables' => [ 'recentchanges' ],
94 'fields' => [ 'rc_id', 'ts_tags' => $groupConcats['recentchanges'] ],
95 'conds' => [ "rc_timestamp > '20170714183203'" ],
96 'join_conds' => [],
97 'options' => [ 'ORDER BY rc_timestamp DESC' ],
98 ]
99 ],
100 'recentchanges query with single tag filter' => [
101 [
102 'tables' => [ 'recentchanges' ],
103 'fields' => [ 'rc_id', 'rc_timestamp' ],
104 'conds' => [ "rc_timestamp > '20170714183203'" ],
105 'join_conds' => [],
106 'options' => [ 'ORDER BY' => 'rc_timestamp DESC' ],
107 ],
108 'foo',
109 true, // tag filtering enabled
110 [
111 'tables' => [ 'recentchanges', 'change_tag' ],
112 'fields' => [ 'rc_id', 'rc_timestamp', 'ts_tags' => $groupConcats['recentchanges'] ],
113 'conds' => [ "rc_timestamp > '20170714183203'", 'ct_tag' => 'foo' ],
114 'join_conds' => [ 'change_tag' => [ 'INNER JOIN', 'ct_rc_id=rc_id' ] ],
115 'options' => [ 'ORDER BY' => 'rc_timestamp DESC' ],
116 ]
117 ],
118 'logging query with single tag filter and strings' => [
119 [
120 'tables' => 'logging',
121 'fields' => 'log_id',
122 'conds' => "log_timestamp > '20170714183203'",
123 'join_conds' => [],
124 'options' => 'ORDER BY log_timestamp DESC',
125 ],
126 'foo',
127 true, // tag filtering enabled
128 [
129 'tables' => [ 'logging', 'change_tag' ],
130 'fields' => [ 'log_id', 'ts_tags' => $groupConcats['logging'] ],
131 'conds' => [ "log_timestamp > '20170714183203'", 'ct_tag' => 'foo' ],
132 'join_conds' => [ 'change_tag' => [ 'INNER JOIN', 'ct_log_id=log_id' ] ],
133 'options' => [ 'ORDER BY log_timestamp DESC' ],
134 ]
135 ],
136 'revision query with single tag filter' => [
137 [
138 'tables' => [ 'revision' ],
139 'fields' => [ 'rev_id', 'rev_timestamp' ],
140 'conds' => [ "rev_timestamp > '20170714183203'" ],
141 'join_conds' => [],
142 'options' => [ 'ORDER BY' => 'rev_timestamp DESC' ],
143 ],
144 'foo',
145 true, // tag filtering enabled
146 [
147 'tables' => [ 'revision', 'change_tag' ],
148 'fields' => [ 'rev_id', 'rev_timestamp', 'ts_tags' => $groupConcats['revision'] ],
149 'conds' => [ "rev_timestamp > '20170714183203'", 'ct_tag' => 'foo' ],
150 'join_conds' => [ 'change_tag' => [ 'INNER JOIN', 'ct_rev_id=rev_id' ] ],
151 'options' => [ 'ORDER BY' => 'rev_timestamp DESC' ],
152 ]
153 ],
154 'archive query with single tag filter' => [
155 [
156 'tables' => [ 'archive' ],
157 'fields' => [ 'ar_id', 'ar_timestamp' ],
158 'conds' => [ "ar_timestamp > '20170714183203'" ],
159 'join_conds' => [],
160 'options' => [ 'ORDER BY' => 'ar_timestamp DESC' ],
161 ],
162 'foo',
163 true, // tag filtering enabled
164 [
165 'tables' => [ 'archive', 'change_tag' ],
166 'fields' => [ 'ar_id', 'ar_timestamp', 'ts_tags' => $groupConcats['archive'] ],
167 'conds' => [ "ar_timestamp > '20170714183203'", 'ct_tag' => 'foo' ],
168 'join_conds' => [ 'change_tag' => [ 'INNER JOIN', 'ct_rev_id=ar_rev_id' ] ],
169 'options' => [ 'ORDER BY' => 'ar_timestamp DESC' ],
170 ]
171 ],
172 'unsupported table name throws exception (even without tag filter)' => [
173 [
174 'tables' => [ 'foobar' ],
175 'fields' => [ 'fb_id', 'fb_timestamp' ],
176 'conds' => [ "fb_timestamp > '20170714183203'" ],
177 'join_conds' => [],
178 'options' => [ 'ORDER BY' => 'fb_timestamp DESC' ],
179 ],
180 '',
181 true, // tag filtering enabled
182 [ 'exception' => MWException::class ]
183 ],
184 'tag filter ignored when tag filtering is disabled' => [
185 [
186 'tables' => [ 'archive' ],
187 'fields' => [ 'ar_id', 'ar_timestamp' ],
188 'conds' => [ "ar_timestamp > '20170714183203'" ],
189 'join_conds' => [],
190 'options' => [ 'ORDER BY' => 'ar_timestamp DESC' ],
191 ],
192 'foo',
193 false, // tag filtering disabled
194 [
195 'tables' => [ 'archive' ],
196 'fields' => [ 'ar_id', 'ar_timestamp', 'ts_tags' => $groupConcats['archive'] ],
197 'conds' => [ "ar_timestamp > '20170714183203'" ],
198 'join_conds' => [],
199 'options' => [ 'ORDER BY' => 'ar_timestamp DESC' ],
200 ]
201 ],
202 'recentchanges query with multiple tag filter' => [
203 [
204 'tables' => [ 'recentchanges' ],
205 'fields' => [ 'rc_id', 'rc_timestamp' ],
206 'conds' => [ "rc_timestamp > '20170714183203'" ],
207 'join_conds' => [],
208 'options' => [ 'ORDER BY' => 'rc_timestamp DESC' ],
209 ],
210 [ 'foo', 'bar' ],
211 true, // tag filtering enabled
212 [
213 'tables' => [ 'recentchanges', 'change_tag' ],
214 'fields' => [ 'rc_id', 'rc_timestamp', 'ts_tags' => $groupConcats['recentchanges'] ],
215 'conds' => [ "rc_timestamp > '20170714183203'", 'ct_tag' => [ 'foo', 'bar' ] ],
216 'join_conds' => [ 'change_tag' => [ 'INNER JOIN', 'ct_rc_id=rc_id' ] ],
217 'options' => [ 'ORDER BY' => 'rc_timestamp DESC', 'DISTINCT' ],
218 ]
219 ],
220 'recentchanges query with multiple tag filter that already has DISTINCT' => [
221 [
222 'tables' => [ 'recentchanges' ],
223 'fields' => [ 'rc_id', 'rc_timestamp' ],
224 'conds' => [ "rc_timestamp > '20170714183203'" ],
225 'join_conds' => [],
226 'options' => [ 'DISTINCT', 'ORDER BY' => 'rc_timestamp DESC' ],
227 ],
228 [ 'foo', 'bar' ],
229 true, // tag filtering enabled
230 [
231 'tables' => [ 'recentchanges', 'change_tag' ],
232 'fields' => [ 'rc_id', 'rc_timestamp', 'ts_tags' => $groupConcats['recentchanges'] ],
233 'conds' => [ "rc_timestamp > '20170714183203'", 'ct_tag' => [ 'foo', 'bar' ] ],
234 'join_conds' => [ 'change_tag' => [ 'INNER JOIN', 'ct_rc_id=rc_id' ] ],
235 'options' => [ 'DISTINCT', 'ORDER BY' => 'rc_timestamp DESC' ],
236 ]
237 ],
238 'recentchanges query with multiple tag filter with strings' => [
239 [
240 'tables' => 'recentchanges',
241 'fields' => 'rc_id',
242 'conds' => "rc_timestamp > '20170714183203'",
243 'join_conds' => [],
244 'options' => 'ORDER BY rc_timestamp DESC',
245 ],
246 [ 'foo', 'bar' ],
247 true, // tag filtering enabled
248 [
249 'tables' => [ 'recentchanges', 'change_tag' ],
250 'fields' => [ 'rc_id', 'ts_tags' => $groupConcats['recentchanges'] ],
251 'conds' => [ "rc_timestamp > '20170714183203'", 'ct_tag' => [ 'foo', 'bar' ] ],
252 'join_conds' => [ 'change_tag' => [ 'INNER JOIN', 'ct_rc_id=rc_id' ] ],
253 'options' => [ 'ORDER BY rc_timestamp DESC', 'DISTINCT' ],
254 ]
255 ],
256 ];
257 }
258
259 public static function dataGetSoftwareTags() {
260 return [
261 [
262 [
263 'mw-contentModelChange' => true,
264 'mw-redirect' => true,
265 'mw-rollback' => true,
266 'mw-blank' => true,
267 'mw-replace' => true
268 ],
269 [
270 'mw-rollback',
271 'mw-replace',
272 'mw-blank'
273 ]
274 ],
275
276 [
277 [
278 'mw-contentmodelchanged' => true,
279 'mw-replace' => true,
280 'mw-new-redirects' => true,
281 'mw-changed-redirect-target' => true,
282 'mw-rolback' => true,
283 'mw-blanking' => false
284 ],
285 [
286 'mw-replace',
287 'mw-changed-redirect-target'
288 ]
289 ],
290
291 [
292 [
293 null,
294 false,
295 'Lorem ipsum',
296 'mw-translation'
297 ],
298 []
299 ],
300
301 [
302 [],
303 []
304 ]
305 ];
306 }
307
308 /**
309 * @dataProvider dataGetSoftwareTags
310 * @covers ChangeTags::getSoftwareTags
311 */
312 public function testGetSoftwareTags( $softwareTags, $expected ) {
313 $this->setMwGlobals( 'wgSoftwareTags', $softwareTags );
314
315 $actual = ChangeTags::getSoftwareTags();
316 // Order of tags in arrays is not important
317 sort( $expected );
318 sort( $actual );
319 $this->assertEquals( $expected, $actual );
320 }
321
322 public function testUpdateTagsMigrationOld() {
323 $this->setMwGlobals( 'wgChangeTagsSchemaMigrationStage', MIGRATION_OLD );
324 $dbw = wfGetDB( DB_MASTER );
325 $dbw->delete( 'change_tag', '*' );
326 $dbw->delete( 'change_tag_def', '*' );
327
328 $rcId = 123;
329 ChangeTags::updateTags( [ 'tag1', 'tag2' ], [], $rcId );
330
331 $dbr = wfGetDB( DB_REPLICA );
332
333 $res = $dbr->select( 'change_tag_def', [ 'ctd_name', 'ctd_id', 'ctd_count' ], '' );
334 $this->assertEquals( [], iterator_to_array( $res, false ) );
335
336 $expected2 = [
337 (object)[
338 'ct_tag' => 'tag1',
339 'ct_tag_id' => null,
340 'ct_rc_id' => 123
341 ],
342 (object)[
343 'ct_tag' => 'tag2',
344 'ct_tag_id' => null,
345 'ct_rc_id' => 123
346 ],
347 ];
348 $res2 = $dbr->select( 'change_tag', [ 'ct_tag', 'ct_tag_id', 'ct_rc_id' ], '' );
349 $this->assertEquals( $expected2, iterator_to_array( $res2, false ) );
350
351 $rcId = 124;
352 ChangeTags::updateTags( [ 'tag1', 'tag3' ], [], $rcId );
353
354 $dbr = wfGetDB( DB_REPLICA );
355
356 $res = $dbr->select( 'change_tag_def', [ 'ctd_name', 'ctd_id', 'ctd_count' ], '' );
357 $this->assertEquals( [], iterator_to_array( $res, false ) );
358
359 $expected2 = [
360 (object)[
361 'ct_tag' => 'tag1',
362 'ct_tag_id' => null,
363 'ct_rc_id' => 123
364 ],
365 (object)[
366 'ct_tag' => 'tag2',
367 'ct_tag_id' => null,
368 'ct_rc_id' => 123
369 ],
370 (object)[
371 'ct_tag' => 'tag1',
372 'ct_tag_id' => null,
373 'ct_rc_id' => 124
374 ],
375 (object)[
376 'ct_tag' => 'tag3',
377 'ct_tag_id' => null,
378 'ct_rc_id' => 124
379 ],
380 ];
381 $res2 = $dbr->select( 'change_tag', [ 'ct_tag', 'ct_tag_id', 'ct_rc_id' ], '' );
382 $this->assertEquals( $expected2, iterator_to_array( $res2, false ) );
383 }
384
385 public function testUpdateTagsMigrationWriteBoth() {
386 // FIXME: fails under postgres
387 $this->markTestSkippedIfDbType( 'postgres' );
388
389 $this->setMwGlobals( 'wgChangeTagsSchemaMigrationStage', MIGRATION_WRITE_BOTH );
390 $dbw = wfGetDB( DB_MASTER );
391 $dbw->delete( 'change_tag', '*' );
392 $dbw->delete( 'change_tag_def', '*' );
393
394 $rcId = 123;
395 ChangeTags::updateTags( [ 'tag1', 'tag2' ], [], $rcId );
396
397 $dbr = wfGetDB( DB_REPLICA );
398
399 $expected = [
400 (object)[
401 'ctd_name' => 'tag1',
402 'ctd_id' => 1,
403 'ctd_count' => 1
404 ],
405 (object)[
406 'ctd_name' => 'tag2',
407 'ctd_id' => 2,
408 'ctd_count' => 1
409 ],
410 ];
411 $res = $dbr->select( 'change_tag_def', [ 'ctd_name', 'ctd_id', 'ctd_count' ], '' );
412 $this->assertEquals( $expected, iterator_to_array( $res, false ) );
413
414 $expected2 = [
415 (object)[
416 'ct_tag' => 'tag1',
417 'ct_tag_id' => 1,
418 'ct_rc_id' => 123
419 ],
420 (object)[
421 'ct_tag' => 'tag2',
422 'ct_tag_id' => 2,
423 'ct_rc_id' => 123
424 ],
425 ];
426 $res2 = $dbr->select( 'change_tag', [ 'ct_tag', 'ct_tag_id', 'ct_rc_id' ], '' );
427 $this->assertEquals( $expected2, iterator_to_array( $res2, false ) );
428
429 $rcId = 124;
430 ChangeTags::updateTags( [ 'tag1' ], [], $rcId );
431
432 ChangeTags::updateTags( [ 'tag3' ], [], $rcId );
433
434 $dbr = wfGetDB( DB_REPLICA );
435
436 $expected = [
437 (object)[
438 'ctd_name' => 'tag1',
439 'ctd_id' => 1,
440 'ctd_count' => 2
441 ],
442 (object)[
443 'ctd_name' => 'tag2',
444 'ctd_id' => 2,
445 'ctd_count' => 1
446 ],
447 (object)[
448 'ctd_name' => 'tag3',
449 'ctd_id' => 3,
450 'ctd_count' => 1
451 ],
452 ];
453 $res = $dbr->select( 'change_tag_def', [ 'ctd_name', 'ctd_id', 'ctd_count' ], '' );
454 $this->assertEquals( $expected, iterator_to_array( $res, false ) );
455
456 $expected2 = [
457 (object)[
458 'ct_tag' => 'tag1',
459 'ct_tag_id' => 1,
460 'ct_rc_id' => 123
461 ],
462 (object)[
463 'ct_tag' => 'tag2',
464 'ct_tag_id' => 2,
465 'ct_rc_id' => 123
466 ],
467 (object)[
468 'ct_tag' => 'tag1',
469 'ct_tag_id' => 1,
470 'ct_rc_id' => 124
471 ],
472 (object)[
473 'ct_tag' => 'tag3',
474 'ct_tag_id' => 3,
475 'ct_rc_id' => 124
476 ],
477 ];
478 $res2 = $dbr->select( 'change_tag', [ 'ct_tag', 'ct_tag_id', 'ct_rc_id' ], '' );
479 $this->assertEquals( $expected2, iterator_to_array( $res2, false ) );
480 }
481
482 public function testDeleteTagsMigrationOld() {
483 $this->setMwGlobals( 'wgChangeTagsSchemaMigrationStage', MIGRATION_OLD );
484 $dbw = wfGetDB( DB_MASTER );
485 $dbw->delete( 'change_tag', '*' );
486 $dbw->delete( 'change_tag_def', '*' );
487
488 $rcId = 123;
489 ChangeTags::updateTags( [ 'tag1', 'tag2' ], [], $rcId );
490
491 ChangeTags::updateTags( [], [ 'tag2' ], $rcId );
492
493 $dbr = wfGetDB( DB_REPLICA );
494
495 $res = $dbr->select( 'change_tag_def', [ 'ctd_name', 'ctd_id', 'ctd_count' ], '' );
496 $this->assertEquals( [], iterator_to_array( $res, false ) );
497
498 $expected2 = [
499 (object)[
500 'ct_tag' => 'tag1',
501 'ct_tag_id' => null,
502 'ct_rc_id' => 123
503 ]
504 ];
505 $res2 = $dbr->select( 'change_tag', [ 'ct_tag', 'ct_tag_id', 'ct_rc_id' ], '' );
506 $this->assertEquals( $expected2, iterator_to_array( $res2, false ) );
507 }
508
509 public function testDeleteTagsMigrationWriteBoth() {
510 $this->setMwGlobals( 'wgChangeTagsSchemaMigrationStage', MIGRATION_WRITE_BOTH );
511 $dbw = wfGetDB( DB_MASTER );
512 $dbw->delete( 'change_tag', '*' );
513 $dbw->delete( 'change_tag_def', '*' );
514 MediaWikiServices::getInstance()->resetServiceForTesting( 'NameTableStoreFactory' );
515
516 $rcId = 123;
517 ChangeTags::updateTags( [ 'tag1', 'tag2' ], [], $rcId );
518
519 ChangeTags::updateTags( [], [ 'tag2' ], $rcId );
520
521 $dbr = wfGetDB( DB_REPLICA );
522
523 $expected = [
524 (object)[
525 'ctd_name' => 'tag1',
526 'ctd_id' => 1,
527 'ctd_count' => 1
528 ],
529 ];
530 $res = $dbr->select( 'change_tag_def', [ 'ctd_name', 'ctd_id', 'ctd_count' ], '' );
531 $this->assertEquals( $expected, iterator_to_array( $res, false ) );
532
533 $expected2 = [
534 (object)[
535 'ct_tag' => 'tag1',
536 'ct_tag_id' => 1,
537 'ct_rc_id' => 123
538 ]
539 ];
540 $res2 = $dbr->select( 'change_tag', [ 'ct_tag', 'ct_tag_id', 'ct_rc_id' ], '' );
541 $this->assertEquals( $expected2, iterator_to_array( $res2, false ) );
542 }
543
544 public function testTagUsageStatisticsOldBackend() {
545 $this->setMwGlobals( 'wgChangeTagsSchemaMigrationStage', MIGRATION_OLD );
546 $this->setMwGlobals( 'wgTagStatisticsNewTable', false );
547
548 $dbw = wfGetDB( DB_MASTER );
549 $dbw->delete( 'change_tag', '*' );
550 $dbw->delete( 'change_tag_def', '*' );
551
552 $rcId = 123;
553 ChangeTags::updateTags( [ 'tag1', 'tag2' ], [], $rcId );
554
555 $rcId = 124;
556 ChangeTags::updateTags( [ 'tag1' ], [], $rcId );
557
558 $this->assertEquals( [ 'tag1' => 2, 'tag2' => 1 ], ChangeTags::tagUsageStatistics() );
559 }
560
561 public function testTagUsageStatisticsNewMigrationOldBackedn() {
562 $this->setMwGlobals( 'wgChangeTagsSchemaMigrationStage', MIGRATION_WRITE_BOTH );
563 $this->setMwGlobals( 'wgTagStatisticsNewTable', false );
564
565 $dbw = wfGetDB( DB_MASTER );
566 $dbw->delete( 'change_tag', '*' );
567 $dbw->delete( 'change_tag_def', '*' );
568 MediaWikiServices::getInstance()->resetServiceForTesting( 'NameTableStoreFactory' );
569
570 $rcId = 123;
571 ChangeTags::updateTags( [ 'tag1', 'tag2' ], [], $rcId );
572
573 $rcId = 124;
574 ChangeTags::updateTags( [ 'tag1' ], [], $rcId );
575
576 $this->assertEquals( [ 'tag1' => 2, 'tag2' => 1 ], ChangeTags::tagUsageStatistics() );
577 }
578
579 public function testTagUsageStatisticsNewBackend() {
580 $this->setMwGlobals( 'wgChangeTagsSchemaMigrationStage', MIGRATION_WRITE_BOTH );
581 $this->setMwGlobals( 'wgTagStatisticsNewTable', true );
582
583 $dbw = wfGetDB( DB_MASTER );
584 $dbw->delete( 'change_tag', '*' );
585 $dbw->delete( 'change_tag_def', '*' );
586 MediaWikiServices::getInstance()->resetServiceForTesting( 'NameTableStoreFactory' );
587
588 $rcId = 123;
589 ChangeTags::updateTags( [ 'tag1', 'tag2' ], [], $rcId );
590
591 $rcId = 124;
592 ChangeTags::updateTags( [ 'tag1' ], [], $rcId );
593
594 $this->assertEquals( [ 'tag1' => 2, 'tag2' => 1 ], ChangeTags::tagUsageStatistics() );
595 }
596
597 public function testListExplicitlyDefinedTagsOld() {
598 $this->setMwGlobals( 'wgChangeTagsSchemaMigrationStage', MIGRATION_OLD );
599 $dbw = wfGetDB( DB_MASTER );
600 $dbw->delete( 'change_tag', '*' );
601 $dbw->delete( 'change_tag_def', '*' );
602 $dbw->delete( 'valid_tag', '*' );
603
604 $rcId = 123;
605 ChangeTags::updateTags( [ 'tag1', 'tag2' ], [], $rcId );
606 ChangeTags::defineTag( 'tag2' );
607
608 $this->assertEquals( [ 'tag2' ], ChangeTags::listExplicitlyDefinedTags() );
609 $dbr = wfGetDB( DB_REPLICA );
610 $res = $dbr->select( 'change_tag_def', [ 'ctd_name', 'ctd_user_defined' ], '' );
611 $this->assertEquals( [], iterator_to_array( $res, false ) );
612
613 $this->assertEquals( [ 'tag2' ], $dbr->selectFieldValues( 'valid_tag', 'vt_tag', '' ) );
614 }
615
616 public function testListExplicitlyDefinedTagsWriteBoth() {
617 $this->setMwGlobals( 'wgChangeTagsSchemaMigrationStage', MIGRATION_WRITE_BOTH );
618 $dbw = wfGetDB( DB_MASTER );
619 $dbw->delete( 'change_tag', '*' );
620 $dbw->delete( 'change_tag_def', '*' );
621 $dbw->delete( 'valid_tag', '*' );
622
623 $rcId = 123;
624 ChangeTags::updateTags( [ 'tag1', 'tag2' ], [], $rcId );
625 ChangeTags::defineTag( 'tag2' );
626
627 $this->assertEquals( [ 'tag2' ], ChangeTags::listExplicitlyDefinedTags() );
628 $dbr = wfGetDB( DB_REPLICA );
629
630 $expected = [
631 (object)[
632 'ctd_name' => 'tag1',
633 'ctd_user_defined' => 0
634 ],
635 (object)[
636 'ctd_name' => 'tag2',
637 'ctd_user_defined' => 1
638 ],
639 ];
640 $res = $dbr->select( 'change_tag_def', [ 'ctd_name', 'ctd_user_defined' ], '' );
641 $this->assertEquals( $expected, iterator_to_array( $res, false ) );
642
643 $this->assertEquals( [ 'tag2' ], $dbr->selectFieldValues( 'valid_tag', 'vt_tag', '' ) );
644 }
645
646 public function testListExplicitlyDefinedTagsNew() {
647 $this->setMwGlobals( 'wgChangeTagsSchemaMigrationStage', MIGRATION_NEW );
648 $dbw = wfGetDB( DB_MASTER );
649 $dbw->delete( 'change_tag', '*' );
650 $dbw->delete( 'change_tag_def', '*' );
651 $dbw->delete( 'valid_tag', '*' );
652
653 $rcId = 123;
654 ChangeTags::updateTags( [ 'tag1', 'tag2' ], [], $rcId );
655 ChangeTags::defineTag( 'tag2' );
656
657 $this->assertEquals( [ 'tag2' ], ChangeTags::listExplicitlyDefinedTags() );
658 $dbr = wfGetDB( DB_REPLICA );
659
660 $expected = [
661 (object)[
662 'ctd_name' => 'tag1',
663 'ctd_user_defined' => 0
664 ],
665 (object)[
666 'ctd_name' => 'tag2',
667 'ctd_user_defined' => 1
668 ],
669 ];
670 $res = $dbr->select( 'change_tag_def', [ 'ctd_name', 'ctd_user_defined' ], '' );
671 $this->assertEquals( $expected, iterator_to_array( $res, false ) );
672
673 $this->assertEquals( [], $dbr->selectFieldValues( 'valid_tag', 'vt_tag', '' ) );
674 }
675 }