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