|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace Wikibase\Repo\Tests\Api; |
|
4
|
|
|
|
|
5
|
|
|
use ApiTestCase; |
|
6
|
|
|
use ApiUsageException; |
|
7
|
|
|
use ChangeTags; |
|
8
|
|
|
use MediaWiki\MediaWikiServices; |
|
9
|
|
|
use OutOfBoundsException; |
|
10
|
|
|
use PHPUnit\Framework\Constraint\Constraint; |
|
11
|
|
|
use TestSites; |
|
12
|
|
|
use TestUser; |
|
13
|
|
|
use Title; |
|
14
|
|
|
use User; |
|
15
|
|
|
use Wikibase\Repo\WikibaseRepo; |
|
16
|
|
|
use Wikimedia\TestingAccessWrapper; |
|
17
|
|
|
use WikiPage; |
|
18
|
|
|
|
|
19
|
|
|
/** |
|
20
|
|
|
* @license GPL-2.0-or-later |
|
21
|
|
|
* @author John Erling Blad < [email protected] > |
|
22
|
|
|
* @author Daniel Kinzler |
|
23
|
|
|
* @author Addshore |
|
24
|
|
|
*/ |
|
25
|
|
|
abstract class WikibaseApiTestCase extends ApiTestCase { |
|
26
|
|
|
|
|
27
|
|
|
/** @var User */ |
|
28
|
|
|
protected $user; |
|
29
|
|
|
|
|
30
|
|
|
protected function setUp(): void { |
|
31
|
|
|
|
|
32
|
|
|
parent::setUp(); |
|
33
|
|
|
|
|
34
|
|
|
$this->setupUser(); |
|
35
|
|
|
|
|
36
|
|
|
$this->setupSiteLinkGroups(); |
|
37
|
|
|
|
|
38
|
|
|
$siteStore = new \HashSiteStore( TestSites::getSites() ); |
|
39
|
|
|
$this->setService( 'SiteStore', $siteStore ); |
|
40
|
|
|
$this->setService( 'SiteLookup', $siteStore ); |
|
41
|
|
|
} |
|
42
|
|
|
|
|
43
|
|
|
protected function createTestUser() { |
|
44
|
|
|
return new TestUser( |
|
45
|
|
|
'Apitesteditor', |
|
46
|
|
|
'Api Test Editor', |
|
47
|
|
|
'[email protected]', |
|
48
|
|
|
[ 'wbeditor' ] |
|
49
|
|
|
); |
|
50
|
|
|
} |
|
51
|
|
|
|
|
52
|
|
|
private function setupUser() { |
|
53
|
|
|
self::$users['wbeditor'] = $this->createTestUser(); |
|
54
|
|
|
|
|
55
|
|
|
$this->user = self::$users['wbeditor']->getUser(); |
|
56
|
|
|
$this->setMwGlobals( 'wgGroupPermissions', [ '*' => [ |
|
57
|
|
|
'property-create' => true, |
|
58
|
|
|
'createpage' => true, |
|
59
|
|
|
'bot' => true, |
|
60
|
|
|
'item-term' => true, |
|
61
|
|
|
'item-merge' => true, |
|
62
|
|
|
'item-redirect' => true, |
|
63
|
|
|
'property-term' => true, |
|
64
|
|
|
'read' => true, |
|
65
|
|
|
'edit' => true, |
|
66
|
|
|
'writeapi' => true |
|
67
|
|
|
] ] ); |
|
68
|
|
|
} |
|
69
|
|
|
|
|
70
|
|
|
private function setupSiteLinkGroups() { |
|
71
|
|
|
global $wgWBRepoSettings; |
|
72
|
|
|
|
|
73
|
|
|
$customRepoSettings = $wgWBRepoSettings; |
|
74
|
|
|
$customRepoSettings['siteLinkGroups'] = [ 'wikipedia' ]; |
|
75
|
|
|
$this->setMwGlobals( 'wgWBRepoSettings', $customRepoSettings ); |
|
76
|
|
|
MediaWikiServices::getInstance()->resetServiceForTesting( 'SiteLookup' ); |
|
77
|
|
|
} |
|
78
|
|
|
|
|
79
|
|
|
/** |
|
80
|
|
|
* Appends an edit token to a request. |
|
81
|
|
|
* |
|
82
|
|
|
* @param array $params |
|
83
|
|
|
* @param array|null $session |
|
84
|
|
|
* @param User|null $user |
|
85
|
|
|
* @param string $tokenType |
|
86
|
|
|
* |
|
87
|
|
|
* @throws ApiUsageException |
|
88
|
|
|
* @return array( array|null $resultData, WebRequest $request, array $sessionArray ) |
|
|
|
|
|
|
89
|
|
|
*/ |
|
90
|
|
|
protected function doApiRequestWithToken( |
|
91
|
|
|
array $params, |
|
92
|
|
|
array $session = null, |
|
93
|
|
|
User $user = null, |
|
94
|
|
|
$tokenType = 'csrf' |
|
95
|
|
|
) { |
|
96
|
|
|
if ( !$user ) { |
|
97
|
|
|
$user = \RequestContext::getMain()->getUser(); |
|
98
|
|
|
} |
|
99
|
|
|
|
|
100
|
|
|
if ( !array_key_exists( 'token', $params ) ) { |
|
101
|
|
|
$params['token'] = $user->getEditToken(); |
|
102
|
|
|
} |
|
103
|
|
|
|
|
104
|
|
|
return $this->doApiRequest( $params, $session, false, $user, $tokenType ); |
|
105
|
|
|
} |
|
106
|
|
|
|
|
107
|
|
|
/** |
|
108
|
|
|
* @param string[] $handles |
|
109
|
|
|
* @param string[] $idMap |
|
110
|
|
|
*/ |
|
111
|
|
|
protected function initTestEntities( array $handles, array $idMap = [] ) { |
|
112
|
|
|
$activeHandles = EntityTestHelper::getActiveHandles(); |
|
113
|
|
|
$user = $this->getTestSysop()->getUser(); |
|
114
|
|
|
|
|
115
|
|
|
foreach ( $activeHandles as $handle => $id ) { |
|
116
|
|
|
$title = $this->getTestEntityTitle( $handle ); |
|
117
|
|
|
|
|
118
|
|
|
$page = WikiPage::factory( $title ); |
|
119
|
|
|
$page->doDeleteArticleReal( 'Test reset', $user ); |
|
120
|
|
|
EntityTestHelper::unRegisterEntity( $handle ); |
|
121
|
|
|
} |
|
122
|
|
|
|
|
123
|
|
|
foreach ( $handles as $handle ) { |
|
124
|
|
|
$params = EntityTestHelper::getEntity( $handle ); |
|
125
|
|
|
$params['action'] = 'wbeditentity'; |
|
126
|
|
|
|
|
127
|
|
|
EntityTestHelper::injectIds( $params, $idMap ); |
|
128
|
|
|
EntityTestHelper::injectIds( $params, EntityTestHelper::$defaultPlaceholderValues ); |
|
129
|
|
|
|
|
130
|
|
|
list( $res, , ) = $this->doApiRequestWithToken( $params ); |
|
131
|
|
|
EntityTestHelper::registerEntity( $handle, $res['entity']['id'], $res['entity'] ); |
|
132
|
|
|
|
|
133
|
|
|
$idMap["%$handle%"] = $res['entity']['id']; |
|
134
|
|
|
} |
|
135
|
|
|
} |
|
136
|
|
|
|
|
137
|
|
|
/** |
|
138
|
|
|
* @param string $handle |
|
139
|
|
|
* |
|
140
|
|
|
* @return null|Title |
|
141
|
|
|
*/ |
|
142
|
|
|
protected function getTestEntityTitle( $handle ) { |
|
143
|
|
|
try { |
|
144
|
|
|
$wikibaseRepo = WikibaseRepo::getDefaultInstance(); |
|
145
|
|
|
$idString = EntityTestHelper::getId( $handle ); |
|
146
|
|
|
$id = $wikibaseRepo->getEntityIdParser()->parse( $idString ); |
|
147
|
|
|
$title = $wikibaseRepo->getEntityTitleLookup()->getTitleForId( $id ); |
|
148
|
|
|
} catch ( OutOfBoundsException $ex ) { |
|
149
|
|
|
$title = null; |
|
150
|
|
|
} |
|
151
|
|
|
|
|
152
|
|
|
return $title; |
|
153
|
|
|
} |
|
154
|
|
|
|
|
155
|
|
|
/** |
|
156
|
|
|
* Loads an entity from the database (via an API call). |
|
157
|
|
|
* |
|
158
|
|
|
* @param string $id |
|
159
|
|
|
* |
|
160
|
|
|
* @return array |
|
161
|
|
|
*/ |
|
162
|
|
|
protected function loadEntity( $id ) { |
|
163
|
|
|
list( $res, , ) = $this->doApiRequest( |
|
164
|
|
|
[ |
|
165
|
|
|
'action' => 'wbgetentities', |
|
166
|
|
|
'format' => 'json', // make sure IDs are used as keys. |
|
167
|
|
|
'ids' => $id ] |
|
168
|
|
|
); |
|
169
|
|
|
|
|
170
|
|
|
return $res['entities'][$id]; |
|
171
|
|
|
} |
|
172
|
|
|
|
|
173
|
|
|
/** |
|
174
|
|
|
* Do the test for exceptions from Api queries. |
|
175
|
|
|
* |
|
176
|
|
|
* @param array $params Array of params for the API query. |
|
177
|
|
|
* @param array $exception Details of the exception to expect (type, code, message, message-key). |
|
178
|
|
|
* @param User|null $user |
|
179
|
|
|
* @param bool $token Whether to include a CSRF token |
|
180
|
|
|
*/ |
|
181
|
|
|
protected function doTestQueryExceptions( |
|
182
|
|
|
array $params, |
|
183
|
|
|
array $exception, |
|
184
|
|
|
User $user = null, |
|
185
|
|
|
$token = true |
|
186
|
|
|
) { |
|
187
|
|
|
try { |
|
188
|
|
|
if ( $token ) { |
|
189
|
|
|
$this->doApiRequestWithToken( $params, null, $user ); |
|
190
|
|
|
} else { |
|
191
|
|
|
$this->doApiRequest( $params, null, false, $user ); |
|
192
|
|
|
} |
|
193
|
|
|
|
|
194
|
|
|
$this->fail( 'Failed to throw ApiUsageException' ); |
|
195
|
|
|
} catch ( ApiUsageException $e ) { |
|
|
|
|
|
|
196
|
|
|
if ( array_key_exists( 'type', $exception ) ) { |
|
197
|
|
|
$this->assertInstanceOf( $exception['type'], $e ); |
|
198
|
|
|
} |
|
199
|
|
|
|
|
200
|
|
|
if ( array_key_exists( 'code', $exception ) ) { |
|
201
|
|
|
$msg = TestingAccessWrapper::newFromObject( $e )->getApiMessage(); |
|
202
|
|
|
$this->assertThat( |
|
203
|
|
|
$msg->getApiCode(), |
|
204
|
|
|
$exception['code'] instanceof Constraint |
|
|
|
|
|
|
205
|
|
|
? $exception['code'] |
|
206
|
|
|
: $this->equalTo( $exception['code'] ) |
|
207
|
|
|
); |
|
208
|
|
|
} |
|
209
|
|
|
|
|
210
|
|
|
if ( array_key_exists( 'message', $exception ) ) { |
|
211
|
|
|
$this->assertStringContainsString( $exception['message'], $e->getMessage() ); |
|
212
|
|
|
} |
|
213
|
|
|
|
|
214
|
|
|
if ( array_key_exists( 'message-key', $exception ) ) { |
|
215
|
|
|
$status = $e->getStatusValue(); |
|
216
|
|
|
$this->assertTrue( |
|
217
|
|
|
$status->hasMessage( $exception['message-key'] ), |
|
218
|
|
|
'Status message key' |
|
219
|
|
|
); |
|
220
|
|
|
} |
|
221
|
|
|
} |
|
222
|
|
|
} |
|
223
|
|
|
|
|
224
|
|
|
/** |
|
225
|
|
|
* Utility function for converting an array from "deep" (indexed) to "flat" (keyed) structure. |
|
226
|
|
|
* Arrays that already use a flat structure are left unchanged. |
|
227
|
|
|
* |
|
228
|
|
|
* Arrays with a deep structure are expected to be list of entries that are associative arrays, |
|
229
|
|
|
* where which entry has at least the fields given by $keyField and $valueField. |
|
230
|
|
|
* |
|
231
|
|
|
* Arrays with a flat structure are associative and assign values to meaningful keys. |
|
232
|
|
|
* |
|
233
|
|
|
* @param array $data the input array. |
|
234
|
|
|
* @param string $keyField The name of the field in each entry that shall be used as the key in |
|
235
|
|
|
* the flat structure. |
|
236
|
|
|
* @param string $valueField The name of the field in each entry that shall be used as the value |
|
237
|
|
|
* in the flat structure. |
|
238
|
|
|
* @param bool $multiValue Whether the value in the flat structure shall be an indexed array of |
|
239
|
|
|
* values instead of a single value. |
|
240
|
|
|
* @param array &$into optional aggregator. |
|
241
|
|
|
* |
|
242
|
|
|
* @return array The flat version of $data. |
|
243
|
|
|
*/ |
|
244
|
|
|
protected function flattenArray( array $data, $keyField, $valueField, $multiValue = false, array &$into = [] ) { |
|
245
|
|
|
foreach ( $data as $index => $value ) { |
|
246
|
|
|
if ( is_array( $value ) ) { |
|
247
|
|
|
if ( isset( $value[$keyField] ) && isset( $value[$valueField] ) ) { |
|
248
|
|
|
// found "deep" entry in the array |
|
249
|
|
|
$k = $value[ $keyField ]; |
|
250
|
|
|
$v = $value[ $valueField ]; |
|
251
|
|
|
} elseif ( isset( $value[0] ) && !is_array( $value[0] ) && $multiValue ) { |
|
252
|
|
|
// found "flat" multi-value entry in the array |
|
253
|
|
|
$k = $index; |
|
254
|
|
|
$v = $value; |
|
255
|
|
|
} else { |
|
256
|
|
|
// found list, recurse |
|
257
|
|
|
$this->flattenArray( $value, $keyField, $valueField, $multiValue, $into ); |
|
258
|
|
|
continue; |
|
259
|
|
|
} |
|
260
|
|
|
} else { |
|
261
|
|
|
// found "flat" entry in the array |
|
262
|
|
|
$k = $index; |
|
263
|
|
|
$v = $value; |
|
264
|
|
|
} |
|
265
|
|
|
|
|
266
|
|
|
if ( $multiValue ) { |
|
267
|
|
|
if ( is_array( $v ) ) { |
|
268
|
|
|
$into[$k] = empty( $into[$k] ) ? $v : array_merge( $into[$k], $v ); |
|
269
|
|
|
} else { |
|
270
|
|
|
$into[$k][] = $v; |
|
271
|
|
|
} |
|
272
|
|
|
} else { |
|
273
|
|
|
$into[$k] = $v; |
|
274
|
|
|
} |
|
275
|
|
|
} |
|
276
|
|
|
|
|
277
|
|
|
return $into; |
|
278
|
|
|
} |
|
279
|
|
|
|
|
280
|
|
|
/** |
|
281
|
|
|
* Compares two entity structures and asserts that they are equal. Only fields present in $expected are considered. |
|
282
|
|
|
* $expected and $actual can both be either in "flat" or in "deep" form, they are converted as needed before comparison. |
|
283
|
|
|
* |
|
284
|
|
|
* @param array $expected |
|
285
|
|
|
* @param array $actual |
|
286
|
|
|
* @param bool $expectEmptyArrays Should we expect empty arrays or just ignore them? |
|
287
|
|
|
*/ |
|
288
|
|
|
protected function assertEntityEquals( array $expected, array $actual, $expectEmptyArrays = true ) { |
|
289
|
|
|
if ( isset( $expected['id'] ) && !empty( $expected['id'] ) ) { |
|
290
|
|
|
$this->assertEquals( $expected['id'], $actual['id'], 'id' ); |
|
291
|
|
|
} |
|
292
|
|
|
if ( isset( $expected['lastrevid'] ) ) { |
|
293
|
|
|
$this->assertEquals( $expected['lastrevid'], $actual['lastrevid'], 'lastrevid' ); |
|
294
|
|
|
} |
|
295
|
|
|
if ( isset( $expected['type'] ) ) { |
|
296
|
|
|
$this->assertEquals( $expected['type'], $actual['type'], 'type' ); |
|
297
|
|
|
} |
|
298
|
|
|
|
|
299
|
|
|
if ( isset( $expected['labels'] ) ) { |
|
300
|
|
|
if ( !( $expectEmptyArrays === false && $expected['labels'] === [] ) ) { |
|
301
|
|
|
$data = $this->flattenArray( $actual['labels'], 'language', 'value' ); |
|
302
|
|
|
$exp = $this->flattenArray( $expected['labels'], 'language', 'value' ); |
|
303
|
|
|
|
|
304
|
|
|
// keys are significant in flat form |
|
305
|
|
|
$this->assertArrayEquals( $exp, $data, false, true ); |
|
306
|
|
|
} |
|
307
|
|
|
} |
|
308
|
|
|
|
|
309
|
|
|
if ( isset( $expected['descriptions'] ) ) { |
|
310
|
|
|
if ( !( $expectEmptyArrays === false && $expected['descriptions'] === [] ) ) { |
|
311
|
|
|
$data = $this->flattenArray( $actual['descriptions'], 'language', 'value' ); |
|
312
|
|
|
$exp = $this->flattenArray( $expected['descriptions'], 'language', 'value' ); |
|
313
|
|
|
|
|
314
|
|
|
// keys are significant in flat form |
|
315
|
|
|
$this->assertArrayEquals( $exp, $data, false, true ); |
|
316
|
|
|
} |
|
317
|
|
|
} |
|
318
|
|
|
|
|
319
|
|
|
if ( isset( $expected['sitelinks'] ) ) { |
|
320
|
|
|
if ( !( $expectEmptyArrays === false && $expected['sitelinks'] === [] ) ) { |
|
321
|
|
|
$data = $this->flattenArray( $actual['sitelinks'] ?? [], 'site', 'title' ); |
|
322
|
|
|
$exp = $this->flattenArray( $expected['sitelinks'], 'site', 'title' ); |
|
323
|
|
|
|
|
324
|
|
|
// keys are significant in flat form |
|
325
|
|
|
$this->assertArrayEquals( $exp, $data, false, true ); |
|
326
|
|
|
} |
|
327
|
|
|
} |
|
328
|
|
|
|
|
329
|
|
|
if ( isset( $expected['aliases'] ) ) { |
|
330
|
|
|
if ( !( $expectEmptyArrays === false && $expected['aliases'] === [] ) ) { |
|
331
|
|
|
$data = $this->flattenArray( $actual['aliases'], 'language', 'value', true ); |
|
332
|
|
|
$exp = $this->flattenArray( $expected['aliases'], 'language', 'value', true ); |
|
333
|
|
|
|
|
334
|
|
|
// keys are significant in flat form |
|
335
|
|
|
$this->assertArrayEquals( $exp, $data, false, true ); |
|
336
|
|
|
} |
|
337
|
|
|
} |
|
338
|
|
|
|
|
339
|
|
|
if ( isset( $expected['claims'] ) ) { |
|
340
|
|
|
if ( !( $expectEmptyArrays === false && $expected['claims'] === [] ) ) { |
|
341
|
|
|
$data = $this->flattenArray( $actual['claims'], 'mainsnak', 'value', true ); |
|
342
|
|
|
$exp = $this->flattenArray( $expected['claims'], 'language', 'value', true ); |
|
343
|
|
|
$count = count( $expected['claims'] ); |
|
344
|
|
|
|
|
345
|
|
|
for ( $i = 0; $i < $count; $i++ ) { |
|
346
|
|
|
$this->assertArrayHasKey( $i, $data['id'] ); |
|
347
|
|
|
$this->assertGreaterThanOrEqual( 39, strlen( $data['id'][$i] ) ); |
|
348
|
|
|
} |
|
349
|
|
|
//unset stuff we dont actually want to compare |
|
350
|
|
|
if ( isset( $exp['id'] ) ) { |
|
351
|
|
|
$this->assertArrayHasKey( 'id', $data ); |
|
352
|
|
|
} |
|
353
|
|
|
unset( $exp['id'] ); |
|
354
|
|
|
unset( $exp['datatype'] ); |
|
355
|
|
|
unset( $exp['hash'] ); |
|
356
|
|
|
unset( $exp['qualifiers-order'] ); |
|
357
|
|
|
unset( $data['datatype'] ); |
|
358
|
|
|
unset( $data['id'] ); |
|
359
|
|
|
unset( $data['hash'] ); |
|
360
|
|
|
unset( $data['qualifiers-order'] ); |
|
361
|
|
|
$this->assertArrayEquals( $exp, $data, false, true ); |
|
362
|
|
|
} |
|
363
|
|
|
} |
|
364
|
|
|
} |
|
365
|
|
|
|
|
366
|
|
|
/** |
|
367
|
|
|
* Asserts that the given API response represents a successful call. |
|
368
|
|
|
* |
|
369
|
|
|
* @param array $response |
|
370
|
|
|
*/ |
|
371
|
|
|
protected function assertResultSuccess( array $response ) { |
|
372
|
|
|
$this->assertArrayHasKey( 'success', $response, "Missing 'success' marker in response." ); |
|
373
|
|
|
$this->assertResultHasEntityType( $response ); |
|
374
|
|
|
} |
|
375
|
|
|
|
|
376
|
|
|
/** |
|
377
|
|
|
* Asserts that the given API response has a valid entity type if the result contains an entity |
|
378
|
|
|
* |
|
379
|
|
|
* @param array $response |
|
380
|
|
|
*/ |
|
381
|
|
|
protected function assertResultHasEntityType( array $response ) { |
|
382
|
|
|
$wikibaseRepo = WikibaseRepo::getDefaultInstance(); |
|
383
|
|
|
|
|
384
|
|
|
if ( isset( $response['entity'] ) ) { |
|
385
|
|
|
if ( isset( $response['entity']['type'] ) ) { |
|
386
|
|
|
$this->assertContains( |
|
387
|
|
|
$response['entity']['type'], |
|
388
|
|
|
$wikibaseRepo->getEnabledEntityTypes(), |
|
389
|
|
|
"Missing valid 'type' in response." |
|
390
|
|
|
); |
|
391
|
|
|
} |
|
392
|
|
|
} elseif ( isset( $response['entities'] ) ) { |
|
393
|
|
|
foreach ( $response['entities'] as $entity ) { |
|
394
|
|
|
if ( isset( $entity['type'] ) ) { |
|
395
|
|
|
$this->assertContains( |
|
396
|
|
|
$entity['type'], |
|
397
|
|
|
$wikibaseRepo->getEnabledEntityTypes(), |
|
398
|
|
|
"Missing valid 'type' in response." |
|
399
|
|
|
); |
|
400
|
|
|
} |
|
401
|
|
|
} |
|
402
|
|
|
} |
|
403
|
|
|
} |
|
404
|
|
|
|
|
405
|
|
|
/** |
|
406
|
|
|
* Asserts that the revision with the given ID has a summary matching $regex |
|
407
|
|
|
* |
|
408
|
|
|
* @param string|string[] $regex The regex to match, or an array to build a regex from. |
|
409
|
|
|
* @param int $revid |
|
410
|
|
|
*/ |
|
411
|
|
|
protected function assertRevisionSummary( $regex, $revid ) { |
|
412
|
|
|
if ( is_array( $regex ) ) { |
|
413
|
|
|
$r = ''; |
|
414
|
|
|
|
|
415
|
|
|
foreach ( $regex as $s ) { |
|
416
|
|
|
if ( $r !== '' ) { |
|
417
|
|
|
$r .= '.*'; |
|
418
|
|
|
} |
|
419
|
|
|
|
|
420
|
|
|
$r .= preg_quote( $s, '!' ); |
|
421
|
|
|
} |
|
422
|
|
|
|
|
423
|
|
|
$regex = "!$r!"; |
|
424
|
|
|
} |
|
425
|
|
|
|
|
426
|
|
|
$revRecord = MediaWikiServices::getInstance() |
|
427
|
|
|
->getRevisionLookup() |
|
428
|
|
|
->getRevisionById( $revid ); |
|
429
|
|
|
$this->assertNotNull( $revRecord, "revision not found: $revid" ); |
|
430
|
|
|
|
|
431
|
|
|
$comment = $revRecord->getComment(); |
|
432
|
|
|
$this->assertInstanceOf( 'CommentStoreComment', $comment ); |
|
433
|
|
|
$this->assertRegExp( $regex, $comment->text ); |
|
434
|
|
|
} |
|
435
|
|
|
|
|
436
|
|
|
protected function assertCanTagSuccessfulRequest( |
|
437
|
|
|
array $params, |
|
438
|
|
|
array $session = null, |
|
439
|
|
|
User $user = null, |
|
440
|
|
|
$tokenType = 'csrf' |
|
441
|
|
|
) { |
|
442
|
|
|
$dummyTag = __METHOD__ . '-dummy-tag'; |
|
443
|
|
|
ChangeTags::defineTag( $dummyTag ); |
|
444
|
|
|
|
|
445
|
|
|
$params[ 'tags' ] = $dummyTag; |
|
446
|
|
|
|
|
447
|
|
|
list( $result, , ) = $this->doApiRequestWithToken( $params, $session, $user, $tokenType ); |
|
448
|
|
|
|
|
449
|
|
|
$this->assertArrayNotHasKey( 'warnings', $result, json_encode( $result ) ); |
|
450
|
|
|
$this->assertArrayHasKey( 'success', $result ); |
|
451
|
|
|
$lastRevid = $this->getLastRevIdFromResult( $result ); |
|
452
|
|
|
if ( $lastRevid === null ) { |
|
453
|
|
|
$this->fail( |
|
454
|
|
|
'API result does not have lastrevid. Actual result: ' |
|
455
|
|
|
. json_encode( $result, JSON_PRETTY_PRINT ) |
|
456
|
|
|
); |
|
457
|
|
|
} |
|
458
|
|
|
|
|
459
|
|
|
$this->assertTrue( in_array( |
|
460
|
|
|
$dummyTag, |
|
461
|
|
|
ChangeTags::getTags( wfGetDB( DB_MASTER ), null, $lastRevid ) |
|
462
|
|
|
) ); |
|
463
|
|
|
} |
|
464
|
|
|
|
|
465
|
|
|
private function getLastRevIdFromResult( array $result ) { |
|
466
|
|
|
if ( isset( $result['entity']['lastrevid'] ) ) { |
|
467
|
|
|
return $result['entity']['lastrevid']; |
|
468
|
|
|
} |
|
469
|
|
|
if ( isset( $result['pageinfo']['lastrevid'] ) ) { |
|
470
|
|
|
return $result['pageinfo']['lastrevid']; |
|
471
|
|
|
} |
|
472
|
|
|
|
|
473
|
|
|
return null; |
|
474
|
|
|
} |
|
475
|
|
|
|
|
476
|
|
|
} |
|
477
|
|
|
|
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.