From a7a10eee3367a99c1bfe9a91c6362a61bb2b6645 Mon Sep 17 00:00:00 2001 From: Leszek Manicki Date: Wed, 9 Nov 2016 14:54:59 +0100 Subject: [PATCH] Add ForeignEntityRevisionLookupFactory providing a WikiPageEntityMetaDataLookup for the given foreign repository Bug: T150330 Change-Id: Iac2de8d73fbc7e49ad2de358d69cc29456da25a5 --- composer.json | 2 +- .../ForeignEntityRevisionLookupFactory.php | 145 ++++++++++++++++++ ...ForeignEntityRevisionLookupFactoryTest.php | 138 +++++++++++++++++ 3 files changed, 284 insertions(+), 1 deletion(-) create mode 100644 lib/includes/Store/ForeignEntityRevisionLookupFactory.php create mode 100644 lib/tests/phpunit/Store/ForeignEntityRevisionLookupFactoryTest.php diff --git a/composer.json b/composer.json index 8d37538ce9..eeabaaa503 100644 --- a/composer.json +++ b/composer.json @@ -36,7 +36,7 @@ "wikibase/data-model": "~6.3", "wikibase/data-model-serialization": "~2.2", "wikibase/internal-serialization": "~2.3", - "wikibase/data-model-services": "~3.5", + "wikibase/data-model-services": "~3.7", "wikibase/data-model-javascript": "~3.0.0", "wikibase/javascript-api": "~2.2.0", "wikibase/serialization-javascript": "~2.0.6", diff --git a/lib/includes/Store/ForeignEntityRevisionLookupFactory.php b/lib/includes/Store/ForeignEntityRevisionLookupFactory.php new file mode 100644 index 0000000000..27364a0220 --- /dev/null +++ b/lib/includes/Store/ForeignEntityRevisionLookupFactory.php @@ -0,0 +1,145 @@ +parserFactory = $parserFactory; + $this->entitySerializer = $entitySerializer; + $this->dataValueDeserializer = $dataValueDeserializer; + $this->entityNamespaceLookup = $entityNamespaceLookup; + $this->maxBlobSize = $maxBlobSize; + $this->databaseNames = $databaseNames; + } + + /** + * @param string $repositoryName + * + * @return WikiPageEntityRevisionLookup + * + * @throws UnknownForeignRepositoryException + */ + public function getLookup( $repositoryName ) { + if ( !isset( $this->lookups[$repositoryName] ) ) { + $this->lookups[$repositoryName] = $this->newLookupForRepository( $repositoryName ); + + } + return $this->lookups[$repositoryName]; + } + + /** + * @param string $repositoryName + * + * @return WikiPageEntityRevisionLookup + * + * @throws UnknownForeignRepositoryException + */ + private function newLookupForRepository( $repositoryName ) { + if ( !array_key_exists( $repositoryName, $this->databaseNames ) ) { + throw new UnknownForeignRepositoryException( 'No database configured for repository: ' . $repositoryName ); + } + + $prefixMappingIdParser = $this->parserFactory->getIdParser( $repositoryName ); + $entityDeserializerFactory = new DeserializerFactory( + $this->dataValueDeserializer, + $prefixMappingIdParser, + null + ); + $codec = new EntityContentDataCodec( + $prefixMappingIdParser, + $this->entitySerializer, + $entityDeserializerFactory->newEntityDeserializer(), + $this->maxBlobSize + ); + + $metaDataLookup = new PrefetchingWikiPageEntityMetaDataAccessor( + new WikiPageEntityMetaDataLookup( + $this->entityNamespaceLookup, + $this->databaseNames[$repositoryName], + $repositoryName + ) + ); + + return new WikiPageEntityRevisionLookup( + $codec, + $metaDataLookup, + $this->databaseNames[$repositoryName] + ); + } + +} diff --git a/lib/tests/phpunit/Store/ForeignEntityRevisionLookupFactoryTest.php b/lib/tests/phpunit/Store/ForeignEntityRevisionLookupFactoryTest.php new file mode 100644 index 0000000000..deebb5b0ff --- /dev/null +++ b/lib/tests/phpunit/Store/ForeignEntityRevisionLookupFactoryTest.php @@ -0,0 +1,138 @@ +getMock( EntityIdParser::class ); + } + + /** + * @return PrefixMappingEntityIdParserFactory + */ + private function getPrefixMappingEntityIdParserFactory() { + $factory = $this->getMockBuilder( PrefixMappingEntityIdParserFactory::class ) + ->disableOriginalConstructor() + ->getMock(); + $factory->expects( $this->any() ) + ->method( 'getIdParser' ) + ->will( $this->returnValue( $this->getEntityIdParser() ) ); + return $factory; + } + + /** + * @return Serializer + */ + private function getEntitySerializer() { + return $this->getMock( Serializer::class ); + } + + /** + * @return DataValueDeserializer + */ + private function getDataValueDeserializer() { + return $this->getMock( DataValueDeserializer::class ); + } + + /** + * @return EntityNamespaceLookup + */ + private function getEntityNamespaceLookup() { + return new EntityNamespaceLookup( [ 'item' => 100 ] ); + } + + public function testGivenKnownRepository_getLookupReturnsInstanceOfWikiPageEntityRevisionLookup() { + $factory = new ForeignEntityRevisionLookupFactory( + $this->getPrefixMappingEntityIdParserFactory(), + $this->getEntitySerializer(), + $this->getDataValueDeserializer(), + $this->getEntityNamespaceLookup(), + 0, + [ 'foo' => 'foodb' ] + ); + + $this->assertInstanceOf( WikiPageEntityRevisionLookup::class, $factory->getLookup( 'foo' ) ); + } + + public function testGivenUnknownRepository_getLookupThrowsException() { + $factory = new ForeignEntityRevisionLookupFactory( + $this->getPrefixMappingEntityIdParserFactory(), + $this->getEntitySerializer(), + $this->getDataValueDeserializer(), + $this->getEntityNamespaceLookup(), + 0, + [ 'foo' => 'foodb' ] + ); + + $this->setExpectedException( UnknownForeignRepositoryException::class ); + + $this->assertInstanceOf( WikiPageEntityRevisionLookup::class, $factory->getLookup( 'bar' ) ); + } + + public function testGetLookupReusesTheInstanceOverMultipleCalls() { + $factory = new ForeignEntityRevisionLookupFactory( + $this->getPrefixMappingEntityIdParserFactory(), + $this->getEntitySerializer(), + $this->getDataValueDeserializer(), + $this->getEntityNamespaceLookup(), + 0, + [ 'foo' => 'foodb' ] + ); + + $lookupOne = $factory->getLookup( 'foo' ); + $lookupTwo = $factory->getLookup( 'foo' ); + + $this->assertSame( $lookupOne, $lookupTwo ); + } + + public function provideInvalidDatabaseNamesValue() { + return [ + 'repository name containing a colon' => [ [ 'fo:o' => 'foodb' ] ], + 'providing database name for local repository' => [ [ '' => 'foodb' ] ], + 'non-string key' => [ [ 0 => 'foodb' ] ], + 'not a string as a database name (false)' => [ [ 'foo' => false ] ], + 'not a string as a database name (true)' => [ [ 'foo' => true ] ], + 'not a string as a database name (null)' => [ [ 'foo' => null ] ], + 'not a string as a database name (int)' => [ [ 'foo' => 100 ] ], + ]; + } + + /** + * @dataProvider provideInvalidDatabaseNamesValue + */ + public function testGivenInvalidDatabaseNamesValue_exceptionIsThrown( array $databaseNames ) { + $this->setExpectedException( ParameterAssertionException::class ); + + new ForeignEntityRevisionLookupFactory( + $this->getPrefixMappingEntityIdParserFactory(), + $this->getEntitySerializer(), + $this->getDataValueDeserializer(), + $this->getEntityNamespaceLookup(), + 0, + $databaseNames + ); + } + +}