|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace Wikibase\DataAccess\Tests; |
|
4
|
|
|
|
|
5
|
|
|
use LogicException; |
|
6
|
|
|
use PHPUnit\Framework\TestCase; |
|
7
|
|
|
use Wikibase\DataAccess\EntitySource; |
|
8
|
|
|
use Wikibase\DataAccess\EntitySourceDefinitions; |
|
9
|
|
|
use Wikibase\DataAccess\GenericServices; |
|
10
|
|
|
use Wikibase\DataAccess\MultipleEntitySourceServices; |
|
11
|
|
|
use Wikibase\DataAccess\SingleEntitySourceServices; |
|
12
|
|
|
use Wikibase\DataModel\Entity\EntityRedirect; |
|
13
|
|
|
use Wikibase\DataModel\Entity\Item; |
|
14
|
|
|
use Wikibase\DataModel\Entity\ItemId; |
|
15
|
|
|
use Wikibase\DataModel\Entity\PropertyId; |
|
16
|
|
|
use Wikibase\DataModel\Term\Term; |
|
17
|
|
|
use Wikibase\Lib\EntityTypeDefinitions; |
|
18
|
|
|
use Wikibase\Lib\Interactors\TermSearchInteractor; |
|
19
|
|
|
use Wikibase\Lib\Interactors\TermSearchInteractorFactory; |
|
20
|
|
|
use Wikibase\Lib\Interactors\TermSearchResult; |
|
21
|
|
|
use Wikibase\Lib\Store\EntityRevision; |
|
22
|
|
|
use Wikibase\Lib\Store\EntityRevisionLookup; |
|
23
|
|
|
use Wikibase\Lib\Store\PropertyInfoLookup; |
|
24
|
|
|
use Wikibase\Lib\TermIndexEntry; |
|
25
|
|
|
use Wikibase\Lib\Tests\Store\MockPropertyInfoLookup; |
|
26
|
|
|
|
|
27
|
|
|
/** |
|
28
|
|
|
* @covers \Wikibase\DataAccess\MultipleEntitySourceServices |
|
29
|
|
|
* |
|
30
|
|
|
* @group Wikibase |
|
31
|
|
|
* |
|
32
|
|
|
* @license GPL-2.0-or-later |
|
33
|
|
|
*/ |
|
34
|
|
|
class MultipleEntitySourceServicesTest extends TestCase { |
|
35
|
|
|
|
|
36
|
|
|
public function testGetEntityRevisionLookupReturnsLookupThatReturnsExpectedRevisionData() { |
|
37
|
|
|
$itemRevisionData = 'item revision data'; |
|
38
|
|
|
$itemRevisionLookup = $this->createMock( EntityRevisionLookup::class ); |
|
39
|
|
|
$itemRevisionLookup->method( 'getEntityRevision' ) |
|
40
|
|
|
->willReturn( $itemRevisionData ); |
|
41
|
|
|
|
|
42
|
|
|
$itemServices = $this->createMock( SingleEntitySourceServices::class ); |
|
43
|
|
|
$itemServices->method( 'getEntityRevisionLookup' ) |
|
44
|
|
|
->willReturn( $itemRevisionLookup ); |
|
45
|
|
|
|
|
46
|
|
|
$propertyServices = $this->createMock( SingleEntitySourceServices::class ); |
|
47
|
|
|
$propertyServices->method( 'getEntityRevisionLookup' ) |
|
48
|
|
|
->willReturn( $this->newThrowingEntityRevisionLookup() ); |
|
49
|
|
|
|
|
50
|
|
|
$services = $this->newMultipleEntitySourceServices( [ 'items' => $itemServices, 'props' => $propertyServices ] ); |
|
51
|
|
|
|
|
52
|
|
|
$lookup = $services->getEntityRevisionLookup(); |
|
53
|
|
|
|
|
54
|
|
|
$this->assertSame( $itemRevisionData, $lookup->getEntityRevision( new ItemId( 'Q123' ) ) ); |
|
55
|
|
|
} |
|
56
|
|
|
|
|
57
|
|
|
private function newThrowingEntityRevisionLookup() { |
|
58
|
|
|
$propertyRevisionLookup = $this->createMock( EntityRevisionLookup::class ); |
|
59
|
|
|
$propertyRevisionLookup->method( $this->anything() ) |
|
60
|
|
|
->willThrowException( new LogicException( 'This service should not be used' ) ); |
|
61
|
|
|
return $propertyRevisionLookup; |
|
62
|
|
|
} |
|
63
|
|
|
|
|
64
|
|
|
public function testGetTermSearchInteractorFactoryGeneratesInteractorsReturningResultsForConfiguredSources() { |
|
65
|
|
|
$itemResult = new TermSearchResult( new Term( 'en', 'test' ), TermIndexEntry::TYPE_LABEL, new ItemId( 'Q123' ) ); |
|
66
|
|
|
|
|
67
|
|
|
$itemInteractor = $this->createMock( TermSearchInteractor::class ); |
|
68
|
|
|
$itemInteractor->method( 'searchForEntities' ) |
|
69
|
|
|
->willReturn( $itemResult ); |
|
70
|
|
|
|
|
71
|
|
|
$itemInteractorFactory = $this->createMock( TermSearchInteractorFactory::class ); |
|
72
|
|
|
$itemInteractorFactory->method( 'newInteractor' ) |
|
73
|
|
|
->willReturn( $itemInteractor ); |
|
74
|
|
|
|
|
75
|
|
|
$itemServices = $this->createMock( SingleEntitySourceServices::class ); |
|
76
|
|
|
$itemServices->method( 'getTermSearchInteractorFactory' ) |
|
77
|
|
|
->willReturn( $itemInteractorFactory ); |
|
78
|
|
|
|
|
79
|
|
|
$dummyInteractorFactory = $this->createMock( TermSearchInteractorFactory::class ); |
|
80
|
|
|
$dummyInteractorFactory->method( 'newInteractor' ) |
|
81
|
|
|
->willReturn( $this->createMock( TermSearchInteractor::class ) ); |
|
82
|
|
|
|
|
83
|
|
|
$propertyServices = $this->createMock( SingleEntitySourceServices::class ); |
|
84
|
|
|
$propertyServices->method( 'getTermSearchInteractorFactory' ) |
|
85
|
|
|
->willReturn( $dummyInteractorFactory ); |
|
86
|
|
|
|
|
87
|
|
|
$services = $this->newMultipleEntitySourceServices( [ 'items' => $itemServices, 'props' => $propertyServices ] ); |
|
88
|
|
|
|
|
89
|
|
|
$interactor = $services->getTermSearchInteractorFactory()->newInteractor( 'en' ); |
|
90
|
|
|
|
|
91
|
|
|
$searchResult = $interactor->searchForEntities( 'test', 'en', 'item', [ TermIndexEntry::TYPE_LABEL ] ); |
|
92
|
|
|
|
|
93
|
|
|
$this->assertEquals( $itemResult, $searchResult ); |
|
94
|
|
|
} |
|
95
|
|
|
|
|
96
|
|
|
public function testGetPrefetchingTermLookupReturnsLookupBufferingDataOfSourceEntities() { |
|
97
|
|
|
$itemId = new ItemId( 'Q200' ); |
|
98
|
|
|
$propertyId = new PropertyId( 'P500' ); |
|
99
|
|
|
$fakeItemLabel = 'Q200 en label'; |
|
100
|
|
|
$fakePropertyLabel = 'P500 en label'; |
|
101
|
|
|
|
|
102
|
|
|
$itemLookup = new FakePrefetchingTermLookup(); |
|
103
|
|
|
|
|
104
|
|
|
$itemServices = $this->createMock( SingleEntitySourceServices::class ); |
|
105
|
|
|
$itemServices->method( 'getPrefetchingTermLookup' ) |
|
106
|
|
|
->willReturn( $itemLookup ); |
|
107
|
|
|
|
|
108
|
|
|
$propertyLookup = new FakePrefetchingTermLookup(); |
|
109
|
|
|
|
|
110
|
|
|
$propertyServices = $this->createMock( SingleEntitySourceServices::class ); |
|
111
|
|
|
$propertyServices->method( 'getPrefetchingTermLookup' ) |
|
112
|
|
|
->willReturn( $propertyLookup ); |
|
113
|
|
|
|
|
114
|
|
|
$services = $this->newMultipleEntitySourceServices( [ 'items' => $itemServices, 'props' => $propertyServices ] ); |
|
115
|
|
|
|
|
116
|
|
|
$lookup = $services->getPrefetchingTermLookup(); |
|
117
|
|
|
$lookup->prefetchTerms( [ $itemId, $propertyId ], [ 'label' ], [ 'en' ] ); |
|
118
|
|
|
|
|
119
|
|
|
$this->assertEquals( $fakeItemLabel, $lookup->getPrefetchedTerm( $itemId, 'label', 'en' ) ); |
|
120
|
|
|
$this->assertEquals( $fakePropertyLabel, $lookup->getPrefetchedTerm( $propertyId, 'label', 'en' ) ); |
|
121
|
|
|
} |
|
122
|
|
|
|
|
123
|
|
|
public function testGetPrefetchingTermLookupReturnsLookupReturningTermsOfEntitiesConfiguredInSources() { |
|
124
|
|
|
$itemId = new ItemId( 'Q200' ); |
|
125
|
|
|
$fakeItemLabel = 'Q200 en label'; |
|
126
|
|
|
|
|
127
|
|
|
$itemLookup = new FakePrefetchingTermLookup(); |
|
128
|
|
|
|
|
129
|
|
|
$itemServices = $this->createMock( SingleEntitySourceServices::class ); |
|
130
|
|
|
$itemServices->method( 'getPrefetchingTermLookup' ) |
|
131
|
|
|
->willReturn( $itemLookup ); |
|
132
|
|
|
|
|
133
|
|
|
$entityTypeDefinitions = new EntityTypeDefinitions( [] ); |
|
134
|
|
|
|
|
135
|
|
|
$services = new MultipleEntitySourceServices( |
|
136
|
|
|
new EntitySourceDefinitions( [ |
|
137
|
|
|
new EntitySource( |
|
138
|
|
|
'items', |
|
139
|
|
|
'itemdb', |
|
140
|
|
|
[ 'item' => [ 'namespaceId' => 100, 'slot' => 'main' ] ], |
|
141
|
|
|
'', |
|
142
|
|
|
'', |
|
143
|
|
|
'', |
|
144
|
|
|
'' |
|
145
|
|
|
) |
|
146
|
|
|
], $entityTypeDefinitions ), |
|
147
|
|
|
new GenericServices( $entityTypeDefinitions, [], [] ), |
|
|
|
|
|
|
148
|
|
|
[ 'items' => $itemServices ] |
|
149
|
|
|
); |
|
150
|
|
|
|
|
151
|
|
|
$lookup = $services->getPrefetchingTermLookup(); |
|
152
|
|
|
|
|
153
|
|
|
$this->assertEquals( $fakeItemLabel, $lookup->getLabel( $itemId, 'en' ) ); |
|
154
|
|
|
} |
|
155
|
|
|
|
|
156
|
|
|
public function testGetPrefetchingTermLookupReturnsLookupReturningNullWhenGivenEntitiesUnknownInSources() { |
|
157
|
|
|
$itemLookup = new FakePrefetchingTermLookup(); |
|
158
|
|
|
|
|
159
|
|
|
$itemServices = $this->createMock( SingleEntitySourceServices::class ); |
|
160
|
|
|
$itemServices->method( 'getPrefetchingTermLookup' ) |
|
161
|
|
|
->willReturn( $itemLookup ); |
|
162
|
|
|
|
|
163
|
|
|
$entityTypeDefinitions = new EntityTypeDefinitions( [] ); |
|
164
|
|
|
|
|
165
|
|
|
$services = new MultipleEntitySourceServices( |
|
166
|
|
|
new EntitySourceDefinitions( [ |
|
167
|
|
|
new EntitySource( |
|
168
|
|
|
'items', |
|
169
|
|
|
'itemdb', |
|
170
|
|
|
[ 'item' => [ 'namespaceId' => 100, 'slot' => 'main' ] ], |
|
171
|
|
|
'', |
|
172
|
|
|
'', |
|
173
|
|
|
'', |
|
174
|
|
|
'' |
|
175
|
|
|
) |
|
176
|
|
|
], $entityTypeDefinitions ), |
|
177
|
|
|
new GenericServices( $entityTypeDefinitions, [], [] ), |
|
|
|
|
|
|
178
|
|
|
[ 'items' => $itemServices ] |
|
179
|
|
|
); |
|
180
|
|
|
|
|
181
|
|
|
$lookup = $services->getPrefetchingTermLookup(); |
|
182
|
|
|
|
|
183
|
|
|
$this->assertNull( $lookup->getLabel( new PropertyId( 'P123' ), 'en' ) ); |
|
184
|
|
|
} |
|
185
|
|
|
|
|
186
|
|
|
public function testGetEntityPrefetcherReturnsServiceBufferingDataOfSourceEntities() { |
|
187
|
|
|
$itemId = new ItemId( 'Q200' ); |
|
188
|
|
|
$propertyId = new PropertyId( 'P500' ); |
|
189
|
|
|
|
|
190
|
|
|
$itemPrefetcher = new EntityPrefetcherSpy(); |
|
191
|
|
|
|
|
192
|
|
|
$itemServices = $this->createMock( SingleEntitySourceServices::class ); |
|
193
|
|
|
$itemServices->method( 'getEntityPrefetcher' ) |
|
194
|
|
|
->willReturn( $itemPrefetcher ); |
|
195
|
|
|
|
|
196
|
|
|
$propertyPrefetcher = new EntityPrefetcherSpy(); |
|
197
|
|
|
|
|
198
|
|
|
$propertyServices = $this->createMock( SingleEntitySourceServices::class ); |
|
199
|
|
|
$propertyServices->method( 'getEntityPrefetcher' ) |
|
200
|
|
|
->willReturn( $propertyPrefetcher ); |
|
201
|
|
|
|
|
202
|
|
|
$services = $this->newMultipleEntitySourceServices( [ 'items' => $itemServices, 'props' => $propertyServices ] ); |
|
203
|
|
|
|
|
204
|
|
|
$prefetcher = $services->getEntityPrefetcher(); |
|
205
|
|
|
$prefetcher->prefetch( [ $itemId, $propertyId ] ); |
|
206
|
|
|
|
|
207
|
|
|
$this->assertEquals( |
|
208
|
|
|
[ $itemId, $propertyId ], |
|
209
|
|
|
array_merge( $itemPrefetcher->getPrefetchedEntities(), $propertyPrefetcher->getPrefetchedEntities() ) |
|
210
|
|
|
); |
|
211
|
|
|
} |
|
212
|
|
|
|
|
213
|
|
|
public function testGetEntityPrefetcherReturnsServiceThatDoesNotPrefetchEntitiesNotConfiguredInSources() { |
|
214
|
|
|
$itemId = new ItemId( 'Q200' ); |
|
215
|
|
|
$propertyId = new PropertyId( 'P500' ); |
|
216
|
|
|
|
|
217
|
|
|
$itemPrefetcher = new EntityPrefetcherSpy(); |
|
218
|
|
|
|
|
219
|
|
|
$itemServices = $this->createMock( SingleEntitySourceServices::class ); |
|
220
|
|
|
$itemServices->method( 'getEntityPrefetcher' ) |
|
221
|
|
|
->willReturn( $itemPrefetcher ); |
|
222
|
|
|
|
|
223
|
|
|
$entityTypeDefinitions = new EntityTypeDefinitions( [] ); |
|
224
|
|
|
|
|
225
|
|
|
$services = new MultipleEntitySourceServices( |
|
226
|
|
|
new EntitySourceDefinitions( [ |
|
227
|
|
|
new EntitySource( |
|
228
|
|
|
'items', |
|
229
|
|
|
'itemdb', |
|
230
|
|
|
[ 'item' => [ 'namespaceId' => 100, 'slot' => 'main' ] ], |
|
231
|
|
|
'', |
|
232
|
|
|
'', |
|
233
|
|
|
'', |
|
234
|
|
|
'' |
|
235
|
|
|
) |
|
236
|
|
|
], $entityTypeDefinitions ), |
|
237
|
|
|
new GenericServices( $entityTypeDefinitions, [], [] ), |
|
|
|
|
|
|
238
|
|
|
[ 'items' => $itemServices ] |
|
239
|
|
|
); |
|
240
|
|
|
|
|
241
|
|
|
$prefetcher = $services->getEntityPrefetcher(); |
|
242
|
|
|
$prefetcher->prefetch( [ $itemId, $propertyId ] ); |
|
243
|
|
|
|
|
244
|
|
|
$this->assertNotContains( [ $propertyId ], $itemPrefetcher->getPrefetchedEntities() ); |
|
245
|
|
|
} |
|
246
|
|
|
|
|
247
|
|
|
public function testGetPropertyInfoLookupReturnsPropertyDataAccessingService() { |
|
248
|
|
|
$propertyId = new PropertyId( 'P6' ); |
|
249
|
|
|
|
|
250
|
|
|
$propertyLookup = new MockPropertyInfoLookup(); |
|
251
|
|
|
$propertyLookup->addPropertyInfo( $propertyId, [ PropertyInfoLookup::KEY_DATA_TYPE => 'string' ] ); |
|
252
|
|
|
|
|
253
|
|
|
$sourceServices = $this->createMock( SingleEntitySourceServices::class ); |
|
254
|
|
|
$sourceServices->method( 'getPropertyInfoLookup' ) |
|
255
|
|
|
->willReturn( $propertyLookup ); |
|
256
|
|
|
|
|
257
|
|
|
$services = $this->newMultipleEntitySourceServices( [ 'props' => $sourceServices ] ); |
|
258
|
|
|
|
|
259
|
|
|
$lookup = $services->getPropertyInfoLookup(); |
|
260
|
|
|
|
|
261
|
|
|
$this->assertEquals( [ 'type' => 'string' ], $lookup->getPropertyInfo( $propertyId ) ); |
|
262
|
|
|
} |
|
263
|
|
|
|
|
264
|
|
|
public function testGivenNoSourceProvidingProperties_getPropertyInfoLookupThrowsException() { |
|
265
|
|
|
$entityTypeDefinitions = new EntityTypeDefinitions( [] ); |
|
266
|
|
|
$services = new MultipleEntitySourceServices( |
|
267
|
|
|
new EntitySourceDefinitions( [ |
|
268
|
|
|
new EntitySource( |
|
269
|
|
|
'items', |
|
270
|
|
|
'itemdb', |
|
271
|
|
|
[ 'item' => [ 'namespaceId' => 100, 'slot' => 'main' ] ], |
|
272
|
|
|
'', |
|
273
|
|
|
'', |
|
274
|
|
|
'', |
|
275
|
|
|
'' |
|
276
|
|
|
), |
|
277
|
|
|
], $entityTypeDefinitions ), |
|
278
|
|
|
new GenericServices( $entityTypeDefinitions, [], [] ), |
|
|
|
|
|
|
279
|
|
|
[] |
|
280
|
|
|
); |
|
281
|
|
|
|
|
282
|
|
|
$this->expectException( LogicException::class ); |
|
283
|
|
|
$services->getPropertyInfoLookup(); |
|
284
|
|
|
} |
|
285
|
|
|
|
|
286
|
|
|
public function testEntityFromKnownSourceUpdated_entityUpdatedPassedToRelevantServiceContainer() { |
|
287
|
|
|
$itemRevision = new EntityRevision( new Item( new ItemId( 'Q1' ) ) ); |
|
288
|
|
|
|
|
289
|
|
|
$itemServices = $this->createMock( SingleEntitySourceServices::class ); |
|
290
|
|
|
$itemServices->expects( $this->atLeastOnce() ) |
|
291
|
|
|
->method( 'entityUpdated' ) |
|
292
|
|
|
->with( $itemRevision ); |
|
293
|
|
|
$propertyServices = $this->createMock( SingleEntitySourceServices::class ); |
|
294
|
|
|
$propertyServices->expects( $this->never() ) |
|
295
|
|
|
->method( 'entityUpdated' ); |
|
296
|
|
|
|
|
297
|
|
|
$services = $this->newMultipleEntitySourceServices( [ 'items' => $itemServices, 'props' => $propertyServices ] ); |
|
298
|
|
|
|
|
299
|
|
|
$services->entityUpdated( $itemRevision ); |
|
300
|
|
|
} |
|
301
|
|
|
|
|
302
|
|
|
public function testEntityFromKnownSourceDeleted_entityDeletedPassedToRelevantServiceContainer() { |
|
303
|
|
|
$itemId = new ItemId( 'Q1' ); |
|
304
|
|
|
|
|
305
|
|
|
$itemServices = $this->createMock( SingleEntitySourceServices::class ); |
|
306
|
|
|
$itemServices->expects( $this->atLeastOnce() ) |
|
307
|
|
|
->method( 'entityDeleted' ) |
|
308
|
|
|
->with( $itemId ); |
|
309
|
|
|
$propertyServices = $this->createMock( SingleEntitySourceServices::class ); |
|
310
|
|
|
$propertyServices->expects( $this->never() ) |
|
311
|
|
|
->method( 'entityDeleted' ); |
|
312
|
|
|
|
|
313
|
|
|
$services = $this->newMultipleEntitySourceServices( [ 'items' => $itemServices, 'props' => $propertyServices ] ); |
|
314
|
|
|
|
|
315
|
|
|
$services->entityDeleted( $itemId ); |
|
316
|
|
|
} |
|
317
|
|
|
|
|
318
|
|
|
public function testRedirectOfEntityFromKnownSourceDeleted_redirectUpdatedPassedToRelevantServiceContainer() { |
|
319
|
|
|
$itemRedirect = new EntityRedirect( new ItemId( 'Q1' ), new ItemId( 'Q300' ) ); |
|
320
|
|
|
$revisionId = 333; |
|
321
|
|
|
|
|
322
|
|
|
$itemServices = $this->createMock( SingleEntitySourceServices::class ); |
|
323
|
|
|
$itemServices->expects( $this->atLeastOnce() ) |
|
324
|
|
|
->method( 'redirectUpdated' ) |
|
325
|
|
|
->with( $itemRedirect, $revisionId ); |
|
326
|
|
|
$propertyServices = $this->createMock( SingleEntitySourceServices::class ); |
|
327
|
|
|
$propertyServices->expects( $this->never() ) |
|
328
|
|
|
->method( 'redirectUpdated' ); |
|
329
|
|
|
|
|
330
|
|
|
$services = $this->newMultipleEntitySourceServices( [ 'items' => $itemServices, 'props' => $propertyServices ] ); |
|
331
|
|
|
|
|
332
|
|
|
$services->redirectUpdated( $itemRedirect, $revisionId ); |
|
333
|
|
|
} |
|
334
|
|
|
|
|
335
|
|
|
/** |
|
336
|
|
|
* @param SingleEntitySourceServices[] $perSourceServices |
|
337
|
|
|
* @return MultipleEntitySourceServices |
|
338
|
|
|
*/ |
|
339
|
|
|
private function newMultipleEntitySourceServices( array $perSourceServices ) { |
|
340
|
|
|
$entityTypeDefinitions = new EntityTypeDefinitions( [] ); |
|
341
|
|
|
return new MultipleEntitySourceServices( |
|
342
|
|
|
new EntitySourceDefinitions( [ |
|
343
|
|
|
new EntitySource( |
|
344
|
|
|
'items', |
|
345
|
|
|
'itemdb', |
|
346
|
|
|
[ 'item' => [ 'namespaceId' => 100, 'slot' => 'main' ] ], |
|
347
|
|
|
'', |
|
348
|
|
|
'', |
|
349
|
|
|
'', |
|
350
|
|
|
'' |
|
351
|
|
|
), |
|
352
|
|
|
new EntitySource( |
|
353
|
|
|
'props', |
|
354
|
|
|
'propb', |
|
355
|
|
|
[ 'property' => [ 'namespaceId' => 200, 'slot' => 'main' ] ], |
|
356
|
|
|
'', |
|
357
|
|
|
'prop', |
|
358
|
|
|
'prop', |
|
359
|
|
|
'props' |
|
360
|
|
|
), |
|
361
|
|
|
], $entityTypeDefinitions ), |
|
362
|
|
|
new GenericServices( $entityTypeDefinitions, [], [] ), |
|
|
|
|
|
|
363
|
|
|
$perSourceServices |
|
364
|
|
|
); |
|
365
|
|
|
} |
|
366
|
|
|
|
|
367
|
|
|
} |
|
368
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignorePhpDoc annotation to the duplicate definition and it will be ignored.