diff --git a/Makefile b/Makefile index 283afd1..80d9a5f 100644 --- a/Makefile +++ b/Makefile @@ -89,4 +89,4 @@ do-test-report: do-phpstan: @echo "\n=== Running PHPStan ===\n" - vendor/bin/phpstan analyse + vendor/bin/phpstan --memory-limit=1G analyse diff --git a/composer.json b/composer.json index 7b67f12..b844d04 100755 --- a/composer.json +++ b/composer.json @@ -12,8 +12,8 @@ "homepage": "https://jeroen-g.github.io/Explorer/", "keywords": ["Laravel", "Scout", "Elasticsearch", "Elastic", "search", "Explorer"], "require": { - "php": "8.0.*||8.1.*||8.2.*||8.3.*", - "elasticsearch/elasticsearch": "^7.16", + "php": "^8.0", + "elasticsearch/elasticsearch": "^8.0", "illuminate/support": "^9.0||^10.0||^11.0", "laravel/scout": "^9.0||^10.0||^11.0", "webmozart/assert": "^1.10", @@ -26,7 +26,8 @@ "symplify/easy-coding-standard": "^9.0", "nunomaduro/larastan": "^2.5", "phpstan/phpstan-mockery": "^1.1", - "orchestra/testbench": "*" + "orchestra/testbench": "*", + "dg/bypass-finals": "^1.8" }, "autoload": { "psr-4": { diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index ff74d5f..166a3b4 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -10,11 +10,6 @@ parameters: count: 1 path: src/Infrastructure/Console/ElasticSearch.php - - - message: "#^Call to an undefined method JeroenG\\\\Explorer\\\\Domain\\\\IndexManagement\\\\IndexConfigurationInterface\\:\\:getAliasConfiguration\\(\\)\\.$#" - count: 1 - path: src/Infrastructure/Elastic/ElasticIndexAdapter.php - - message: "#^Call to an undefined method JeroenG\\\\Explorer\\\\Domain\\\\IndexManagement\\\\IndexConfigurationInterface\\:\\:getAliasConfiguration\\(\\)\\.$#" count: 2 diff --git a/phpunit.xml b/phpunit.xml index 587ad7b..13cd180 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,5 +1,5 @@ - + src/ diff --git a/src/Application/IndexAdapterInterface.php b/src/Application/IndexAdapterInterface.php index c838f82..92ffae3 100644 --- a/src/Application/IndexAdapterInterface.php +++ b/src/Application/IndexAdapterInterface.php @@ -4,6 +4,7 @@ namespace JeroenG\Explorer\Application; +use JeroenG\Explorer\Domain\IndexManagement\AliasedIndexConfigurationInterface; use JeroenG\Explorer\Domain\IndexManagement\IndexConfigurationInterface; interface IndexAdapterInterface @@ -16,7 +17,7 @@ public function delete(IndexConfigurationInterface $indexConfiguration): void; public function flush(string $index): void; - public function createNewWriteIndex(IndexConfigurationInterface $indexConfiguration): string; + public function createNewWriteIndex(AliasedIndexConfigurationInterface $indexConfiguration): string; public function ensureIndex(IndexConfigurationInterface $indexConfiguration): void; } diff --git a/src/Domain/IndexManagement/AliasedIndexConfiguration.php b/src/Domain/IndexManagement/AliasedIndexConfiguration.php index 070fcbc..067a700 100644 --- a/src/Domain/IndexManagement/AliasedIndexConfiguration.php +++ b/src/Domain/IndexManagement/AliasedIndexConfiguration.php @@ -4,7 +4,7 @@ namespace JeroenG\Explorer\Domain\IndexManagement; -final class AliasedIndexConfiguration implements IndexConfigurationInterface +final class AliasedIndexConfiguration implements AliasedIndexConfigurationInterface { private function __construct( private string $name, diff --git a/src/Domain/IndexManagement/AliasedIndexConfigurationInterface.php b/src/Domain/IndexManagement/AliasedIndexConfigurationInterface.php new file mode 100644 index 0000000..c6fc44d --- /dev/null +++ b/src/Domain/IndexManagement/AliasedIndexConfigurationInterface.php @@ -0,0 +1,10 @@ +setHosts([$hostConnectionProperties]); + if (!empty($hostConnectionProperties)) { + $builder->setHosts([$hostConnectionProperties]); + } if ($config->has('explorer.additionalConnections')) { $builder->setHosts([$config->get('explorer.connection'), ...$config->get('explorer.additionalConnections')]); } if ($config->has('explorer.connection.selector')) { - $builder->setSelector($config->get('explorer.connection.selector')); + $selectorClass = $config->get('explorer.connection.selector'); + if (!is_a($selectorClass, SelectorInterface::class, true)) { + throw new InvalidArgumentException( + 'Expect explorer.connection.selector to implement elastic SelectorInterface' + ); + } + + $nodePool = new SimpleNodePool( + new $selectorClass(), + new ElasticsearchResurrect(), + ); + $builder->setNodePool($nodePool); } if($config->has('explorer.connection.api')) { diff --git a/src/Infrastructure/Elastic/ElasticClientFactory.php b/src/Infrastructure/Elastic/ElasticClientFactory.php index d08002b..90b553e 100644 --- a/src/Infrastructure/Elastic/ElasticClientFactory.php +++ b/src/Infrastructure/Elastic/ElasticClientFactory.php @@ -4,9 +4,10 @@ namespace JeroenG\Explorer\Infrastructure\Elastic; -use Elasticsearch\Client; -use Elasticsearch\ClientBuilder; -use GuzzleHttp\Ring\Client\MockHandler; +use Elastic\Elasticsearch\Client; +use Elastic\Elasticsearch\ClientBuilder; +use GuzzleHttp\Client as GuzzleClient; +use GuzzleHttp\Handler\MockHandler; final class ElasticClientFactory { @@ -24,10 +25,11 @@ public function client(): Client public static function fake(FakeResponse $response): ElasticClientFactory { - $handler = new MockHandler($response->toArray()); + $handler = new MockHandler([$response->toResponse()]); + $builder = ClientBuilder::create(); $builder->setHosts(['testhost']); - $builder->setHandler($handler); + $builder->setHttpClient(new GuzzleClient(['handler' => $handler])); return new self($builder->build()); } } diff --git a/src/Infrastructure/Elastic/ElasticDocumentAdapter.php b/src/Infrastructure/Elastic/ElasticDocumentAdapter.php index 3116c33..da468ea 100644 --- a/src/Infrastructure/Elastic/ElasticDocumentAdapter.php +++ b/src/Infrastructure/Elastic/ElasticDocumentAdapter.php @@ -4,8 +4,8 @@ namespace JeroenG\Explorer\Infrastructure\Elastic; -use Elasticsearch\Client; -use Elasticsearch\Common\Exceptions\Missing404Exception; +use Elastic\Elasticsearch\Client; +use Elastic\Elasticsearch\Exception\ClientResponseException; use JeroenG\Explorer\Application\DocumentAdapterInterface; use JeroenG\Explorer\Application\Operations\Bulk\BulkOperationInterface; use JeroenG\Explorer\Application\Results; @@ -22,7 +22,7 @@ public function bulk(BulkOperationInterface $command): callable|array { return $this->client->bulk([ 'body' => $command->build(), - ]); + ])->asArray(); } public function update(string $index, $id, array $data): callable|array @@ -31,7 +31,7 @@ public function update(string $index, $id, array $data): callable|array 'index' => $index, 'id' => $id, 'body' => $data, - ]); + ])->asArray(); } public function delete(string $index, $id): void @@ -41,7 +41,13 @@ public function delete(string $index, $id): void 'index' => $index, 'id' => $id ]); - } catch (Missing404Exception) {} + } catch (ClientResponseException $clientResponseException) { + if ($clientResponseException->getCode() === 404) { + return; + } + + throw $clientResponseException; + } } public function search(SearchCommandInterface $command): Results diff --git a/src/Infrastructure/Elastic/ElasticIndexAdapter.php b/src/Infrastructure/Elastic/ElasticIndexAdapter.php index f048334..22bb43f 100644 --- a/src/Infrastructure/Elastic/ElasticIndexAdapter.php +++ b/src/Infrastructure/Elastic/ElasticIndexAdapter.php @@ -4,9 +4,10 @@ namespace JeroenG\Explorer\Infrastructure\Elastic; -use Elasticsearch\Client; +use Elastic\Elasticsearch\Client; use JeroenG\Explorer\Application\IndexAdapterInterface; use JeroenG\Explorer\Domain\IndexManagement\AliasedIndexConfiguration; +use JeroenG\Explorer\Domain\IndexManagement\AliasedIndexConfigurationInterface; use JeroenG\Explorer\Domain\IndexManagement\IndexAliasConfigurationInterface; use JeroenG\Explorer\Domain\IndexManagement\DirectIndexConfiguration; use JeroenG\Explorer\Domain\IndexManagement\IndexConfigurationInterface; @@ -59,11 +60,11 @@ public function delete(IndexConfigurationInterface $indexConfiguration): void $aliasConfiguration = $indexConfiguration->getAliasConfiguration(); $aliasName = $aliasConfiguration->getHistoryAliasName(); - if (!$this->client->indices()->existsAlias(['name' => $aliasName])) { + if (!$this->client->indices()->existsAlias(['name' => $aliasName])->asBool()) { return; } - $indicesForAlias = $this->client->indices()->getAlias(['name' => $aliasName]); + $indicesForAlias = $this->client->indices()->getAlias(['name' => $aliasName])->asArray(); foreach ($indicesForAlias as $index => $data) { $this->client->indices()->delete(['index' => $index]); @@ -81,12 +82,12 @@ public function flush(string $index): void public function getWriteIndexName(IndexAliasConfigurationInterface $aliasConfiguration): ?string { - $aliasConfig = $this->client->indices()->getAlias(['name' => $aliasConfiguration->getWriteAliasName() ]); + $aliasConfig = $this->client->indices()->getAlias(['name' => $aliasConfiguration->getWriteAliasName() ])->asArray(); return last(array_keys($aliasConfig)); } - public function createNewWriteIndex(IndexConfigurationInterface $indexConfiguration): string + public function createNewWriteIndex(AliasedIndexConfigurationInterface $indexConfiguration): string { $aliasConfig = $indexConfiguration->getAliasConfiguration(); $indexName = $this->getUniqueAliasIndexName($aliasConfig); @@ -110,7 +111,7 @@ public function ensureIndex(IndexConfigurationInterface $indexConfiguration): vo { $exists = $this->client->indices()->exists([ 'index' => $indexConfiguration->getWriteIndexName(), - ]); + ])->asBool(); if (!$exists) { $this->create($indexConfiguration); @@ -119,7 +120,7 @@ public function ensureIndex(IndexConfigurationInterface $indexConfiguration): vo private function makeAliasActive(IndexAliasConfigurationInterface $aliasConfiguration): void { - $exists = $this->client->indices()->existsAlias(['name' => $aliasConfiguration->getAliasName()]); + $exists = $this->client->indices()->existsAlias(['name' => $aliasConfiguration->getAliasName()])->asBool(); $index = $this->getWriteIndexName($aliasConfiguration); $alias = $aliasConfiguration->getAliasName(); @@ -145,11 +146,11 @@ private function makeAliasActive(IndexAliasConfigurationInterface $aliasConfigur private function pruneAliases(IndexAliasConfigurationInterface $indexAliasConfiguration): void { $aliasName = $indexAliasConfiguration->getHistoryAliasName(); - if (!$this->client->indices()->existsAlias(['name' => $aliasName])) { + if (!$this->client->indices()->existsAlias(['name' => $aliasName])->asBool()) { return; } - $indicesForAlias = $this->client->indices()->getAlias(['name' => $aliasName]); + $indicesForAlias = $this->client->indices()->getAlias(['name' => $aliasName])->asArray(); $writeAlias = $this->getWriteIndexName($indexAliasConfiguration); foreach ($indicesForAlias as $index => $data) { @@ -174,7 +175,7 @@ private function getUniqueAliasIndexName(IndexAliasConfigurationInterface $alias $name = $aliasConfig->getIndexName() . '_' . time(); $iX = 0; - while ($this->client->indices()->exists([ 'index' => $name ])) { + while ($this->client->indices()->exists([ 'index' => $name ])->asBool()) { $name .= '_' . $iX++; } diff --git a/src/Infrastructure/Elastic/FakeResponse.php b/src/Infrastructure/Elastic/FakeResponse.php index 4191771..d012374 100644 --- a/src/Infrastructure/Elastic/FakeResponse.php +++ b/src/Infrastructure/Elastic/FakeResponse.php @@ -4,6 +4,9 @@ namespace JeroenG\Explorer\Infrastructure\Elastic; +use Elastic\Elasticsearch\Response\Elasticsearch; +use GuzzleHttp\Psr7\Response; +use Psr\Http\Message\ResponseInterface; use Webmozart\Assert\Assert; class FakeResponse @@ -31,4 +34,16 @@ public function toArray(): array 'effective_url' => 'localhost' ]; } + + public function toResponse(): ResponseInterface + { + return new Response( + $this->statusCode, + [ + Elasticsearch::HEADER_CHECK => Elasticsearch::PRODUCT_NAME, + 'Content-Type' => 'application/json', + ], + $this->body + ); + } } diff --git a/src/Infrastructure/Elastic/Finder.php b/src/Infrastructure/Elastic/Finder.php index 714ae37..78df70c 100644 --- a/src/Infrastructure/Elastic/Finder.php +++ b/src/Infrastructure/Elastic/Finder.php @@ -4,14 +4,18 @@ namespace JeroenG\Explorer\Infrastructure\Elastic; -use Elasticsearch\Client; +use Elastic\Elasticsearch\Client; +use Elastic\Elasticsearch\ClientInterface; use JeroenG\Explorer\Application\Results; use JeroenG\Explorer\Application\SearchCommandInterface; class Finder { + /** + * @param Client $client + */ public function __construct( - private Client $client, + private ClientInterface $client, private SearchCommandInterface $builder, ) { } @@ -23,7 +27,7 @@ public function find(): Results 'body' => $this->builder->buildQuery(), ]; - $rawResults = $this->client->search($query); + $rawResults = $this->client->search($query)->asArray(); return new Results($rawResults); } diff --git a/tests/Unit/ClientExpectation.php b/tests/Unit/ClientExpectation.php new file mode 100644 index 0000000..1cfdd5a --- /dev/null +++ b/tests/Unit/ClientExpectation.php @@ -0,0 +1,38 @@ +mock = $mock; + } + + public static function create(): self + { + + return new self(Mockery::mock(Client::class)); + } + + public function getMock(): Client + { + return $this->mock; + } + + public function expectSearch(array $input, FakeElasticResponse $response): void + { + $this->mock + ->expects('search') + ->with($input) + ->andReturn($response); + } +} diff --git a/tests/Unit/ElasticClientBuilderTest.php b/tests/Unit/ElasticClientBuilderTest.php index d83ef53..4f2ce50 100644 --- a/tests/Unit/ElasticClientBuilderTest.php +++ b/tests/Unit/ElasticClientBuilderTest.php @@ -3,9 +3,12 @@ namespace JeroenG\Explorer\Tests\Unit; -use Elasticsearch\ClientBuilder; -use Elasticsearch\ConnectionPool\Selectors\StickyRoundRobinSelector; +use Elastic\Elasticsearch\ClientBuilder; +use Elastic\Transport\NodePool\Resurrect\ElasticsearchResurrect; +use Elastic\Transport\NodePool\Selector\RoundRobin; +use Elastic\Transport\NodePool\SimpleNodePool; use Illuminate\Container\Container; +use InvalidArgumentException; use JeroenG\Explorer\Infrastructure\Elastic\ElasticClientBuilder; use JeroenG\Explorer\Tests\Support\ConfigRepository; use Mockery\Adapter\Phpunit\MockeryTestCase; @@ -80,12 +83,12 @@ public function provideClientConfigs(): ?\Generator yield 'with selector' => [ [ 'connection' => array_merge([ - 'selector' => StickyRoundRobinSelector::class + 'selector' => RoundRobin::class ], self::CONNECTION) ], ClientBuilder::create() ->setHosts([self::CONNECTION]) - ->setSelector(StickyRoundRobinSelector::class), + ->setNodePool(new SimpleNodePool(new RoundRobin(), new ElasticsearchResurrect())), ]; yield 'with additional connections' => [ @@ -182,4 +185,14 @@ public function provideClientConfigs(): ?\Generator ->setHosts([self::CONNECTION]), ]; } + + public function testThrowsOnInvalidSelector(): void + { + $configRepository = new ConfigRepository([ 'explorer' => [ 'connection' => [ 'selector' => self::class ] ] ]); + + Container::getInstance()->instance('config', $configRepository); + + $this->expectException(InvalidArgumentException::class); + ElasticClientBuilder::fromConfig($configRepository); + } } diff --git a/tests/Unit/ElasticClientFactoryTest.php b/tests/Unit/ElasticClientFactoryTest.php index 171913b..93cc7fa 100644 --- a/tests/Unit/ElasticClientFactoryTest.php +++ b/tests/Unit/ElasticClientFactoryTest.php @@ -4,7 +4,7 @@ namespace JeroenG\Explorer\Tests\Unit; -use Elasticsearch\Client; +use Elastic\Elasticsearch\ClientInterface; use JeroenG\Explorer\Application\SearchCommand; use JeroenG\Explorer\Domain\Query\Query; use JeroenG\Explorer\Domain\Syntax\Compound\BoolQuery; @@ -18,20 +18,11 @@ class ElasticClientFactoryTest extends MockeryTestCase { public function test_it_can_construct_a_client(): void { - $client = Mockery::mock(Client::class); - $factory = new ElasticClientFactory($client); + $client = ClientExpectation::create(); + $factory = new ElasticClientFactory($client->getMock()); self::assertInstanceOf(Mockery\MockInterface::class, $factory->client()); - self::assertEquals($client, $factory->client()); - } - - public function test_it_can_create_a_real_client_with_fake_response(): void - { - $file = fopen(__DIR__.'/../Support/fakeresponse.json', 'rb'); - $factory = ElasticClientFactory::fake(new FakeResponse(200, $file)); - - self::assertEquals('testhost', $factory->client()->transport->getConnection()->getHost()); - self::assertNotInstanceOf(Mockery\MockInterface::class, $factory->client()); + self::assertEquals($client->getMock(), $factory->client()); } public function test_it_can_make_a_faked_call(): void diff --git a/tests/Unit/FakeElasticResponse.php b/tests/Unit/FakeElasticResponse.php new file mode 100644 index 0000000..abd18e2 --- /dev/null +++ b/tests/Unit/FakeElasticResponse.php @@ -0,0 +1,24 @@ +asArray = $data; + return $self; + } + + public static function bool(bool $bool): self + { + $self = new self(); + $self->response = new Response($bool ? 200 : 404); + return $self; + } +} diff --git a/tests/Unit/FinderTest.php b/tests/Unit/FinderTest.php index 82dfb4f..9c41f69 100644 --- a/tests/Unit/FinderTest.php +++ b/tests/Unit/FinderTest.php @@ -4,7 +4,6 @@ namespace JeroenG\Explorer\Tests\Unit; -use Elasticsearch\Client; use InvalidArgumentException; use JeroenG\Explorer\Application\AggregationResult; use JeroenG\Explorer\Application\SearchCommand; @@ -18,10 +17,8 @@ use JeroenG\Explorer\Domain\Syntax\Term; use JeroenG\Explorer\Infrastructure\Elastic\Finder; use JeroenG\Explorer\Infrastructure\Scout\ScoutSearchCommandBuilder; -use Mockery; use Mockery\Adapter\Phpunit\MockeryTestCase; use JeroenG\Explorer\Domain\Aggregations\NestedAggregation; -use function var_dump; class FinderTest extends MockeryTestCase { @@ -31,11 +28,11 @@ class FinderTest extends MockeryTestCase public function test_it_needs_an_index_to_even_try_to_find_your_stuff(): void { - $client = Mockery::mock(Client::class); + $client = ClientExpectation::create(); $builder = new SearchCommand(); - $subject = new Finder($client, $builder); + $subject = new Finder($client->getMock(), $builder); $this->expectException(InvalidArgumentException::class); $subject->find(); @@ -45,9 +42,9 @@ public function test_it_finds_all_items_if_no_queries_are_provided(): void { $hit = $this->hit(); - $client = Mockery::mock(Client::class); - $client->expects('search') - ->with([ + $client = ClientExpectation::create(); + $client->expectSearch( + [ 'index' => self::TEST_INDEX, 'body' => [ 'query' => [ @@ -58,17 +55,18 @@ public function test_it_finds_all_items_if_no_queries_are_provided(): void ], ], ], - ]) - ->andReturn([ + ], + FakeElasticResponse::array([ 'hits' => [ 'total' => ['value' => 1], 'hits' => [$hit], ], - ]); + ]) + ); $builder = new SearchCommand(self::TEST_INDEX, Query::with(new BoolQuery())); - $subject = new Finder($client, $builder); + $subject = new Finder($client->getMock(), $builder); $results = $subject->find(); self::assertCount(1, $results); @@ -77,9 +75,9 @@ public function test_it_finds_all_items_if_no_queries_are_provided(): void public function test_it_accepts_must_should_filter_and_where_queries(): void { - $client = Mockery::mock(Client::class); - $client->expects('search') - ->with([ + $client = ClientExpectation::create(); + $client->expectSearch( + [ 'index' => self::TEST_INDEX, 'body' => [ 'query' => [ @@ -99,8 +97,8 @@ public function test_it_accepts_must_should_filter_and_where_queries(): void ], ], ], - ]) - ->andReturn([ + ], + FakeElasticResponse::array([ 'hits' => [ 'total' => ['value' => 2], 'hits' => [ @@ -108,7 +106,8 @@ public function test_it_accepts_must_should_filter_and_where_queries(): void $this->hit(), ], ], - ]); + ]) + ); $builder = new ScoutSearchCommandBuilder(); $builder->setIndex(self::TEST_INDEX); @@ -119,7 +118,7 @@ public function test_it_accepts_must_should_filter_and_where_queries(): void $builder->setWhereIns(['tags' => ['t1', 't2']]); $builder->setQuery('fuzzy search'); - $subject = new Finder($client, $builder); + $subject = new Finder($client->getMock(), $builder); $results = $subject->find(); self::assertCount(2, $results); @@ -127,9 +126,9 @@ public function test_it_accepts_must_should_filter_and_where_queries(): void public function test_it_accepts_a_query_for_paginated_search(): void { - $client = Mockery::mock(Client::class); - $client->expects('search') - ->with([ + $client = ClientExpectation::create(); + $client->expectSearch( + [ 'index' => self::TEST_INDEX, 'body' => [ 'query' => [ @@ -142,13 +141,14 @@ public function test_it_accepts_a_query_for_paginated_search(): void 'from' => 10, 'size' => 100, ], - ]) - ->andReturn([ + ], + FakeElasticResponse::array([ 'hits' => [ 'total' => ['value' => 1], 'hits' => [$this->hit()], ], - ]); + ]) + ); $query = Query::with(new BoolQuery()); $builder = new SearchCommand(self::TEST_INDEX); @@ -156,7 +156,7 @@ public function test_it_accepts_a_query_for_paginated_search(): void $query->setOffset(10); $query->setLimit(100); - $subject = new Finder($client, $builder); + $subject = new Finder($client->getMock(), $builder); $results = $subject->find(); self::assertCount(1, $results); @@ -164,9 +164,9 @@ public function test_it_accepts_a_query_for_paginated_search(): void public function test_it_accepts_a_sortable_query(): void { - $client = Mockery::mock(Client::class); - $client->expects('search') - ->with([ + $client = ClientExpectation::create(); + $client->expectSearch( + [ 'index' => self::TEST_INDEX, 'body' => [ 'query' => [ @@ -180,19 +180,20 @@ public function test_it_accepts_a_sortable_query(): void ['id' => 'desc'], ], ], - ]) - ->andReturn([ + ], + FakeElasticResponse::array([ 'hits' => [ 'total' => ['value' => 1], 'hits' => [$this->hit()], ], - ]); + ]) + ); $query = Query::with(new BoolQuery()); $builder = new SearchCommand(self::TEST_INDEX, $query); $query->setSort([new Sort('id', Sort::DESCENDING)]); - $subject = new Finder($client, $builder); + $subject = new Finder($client->getMock(), $builder); $results = $subject->find(); self::assertCount(1, $results); @@ -200,9 +201,9 @@ public function test_it_accepts_a_sortable_query(): void public function test_it_must_provide_offset_and_limit_for_pagination(): void { - $client = Mockery::mock(Client::class); - $client->expects('search') - ->with([ + $client = ClientExpectation::create(); + $client->expectSearch( + [ 'index' => self::TEST_INDEX, 'body' => [ 'size' => 100, @@ -214,20 +215,21 @@ public function test_it_must_provide_offset_and_limit_for_pagination(): void ], ], ], - ]) - ->andReturn([ + ], + FakeElasticResponse::array([ 'hits' => [ 'total' => ['value' => 1], 'hits' => [$this->hit()], ], - ]); + ]) + ); $query = Query::with(new BoolQuery()); $builder = new SearchCommand(self::TEST_INDEX, $query); $builder->setIndex(self::TEST_INDEX); $query->setLimit(100); - $subject = new Finder($client, $builder); + $subject = new Finder($client->getMock(), $builder); $results = $subject->find(); self::assertCount(1, $results); @@ -235,9 +237,8 @@ public function test_it_must_provide_offset_and_limit_for_pagination(): void public function test_it_builds_with_default_fields(): void { - $client = Mockery::mock(Client::class); - $client->expects('search') - ->with([ + $client = ClientExpectation::create(); + $client->expectSearch([ 'index' => self::TEST_INDEX, 'body' => [ 'query' => [ @@ -250,20 +251,21 @@ public function test_it_builds_with_default_fields(): void ], ], ], - ]) - ->andReturn([ + ], + FakeElasticResponse::array([ 'hits' => [ 'total' => ['value' => 1], 'hits' => [$this->hit()], ], - ]); + ]) + ); $builder = new ScoutSearchCommandBuilder(); $builder->setIndex(self::TEST_INDEX); $builder->setDefaultSearchFields(self::SEARCHABLE_FIELDS); $builder->setQuery('fuzzy search'); - $subject = new Finder($client, $builder); + $subject = new Finder($client->getMock(), $builder); $results = $subject->find(); self::assertCount(1, $results); @@ -271,9 +273,8 @@ public function test_it_builds_with_default_fields(): void public function test_it_adds_fields_to_query(): void { - $client = Mockery::mock(Client::class); - $client->expects('search') - ->with([ + $client = ClientExpectation::create(); + $client->expectSearch([ 'index' => self::TEST_INDEX, 'body' => [ 'query' => [ @@ -285,20 +286,21 @@ public function test_it_adds_fields_to_query(): void ], 'fields' => ['*.length', 'specific.field'], ], - ]) - ->andReturn([ + ], + FakeElasticResponse::array([ 'hits' => [ 'total' => ['value' => 1], 'hits' => [$this->hit()], ], - ]); + ]) + ); $query = Query::with(new BoolQuery()); $builder = new SearchCommand(self::TEST_INDEX, $query); $builder->setIndex(self::TEST_INDEX); $query->setFields(['*.length', 'specific.field']); - $subject = new Finder($client, $builder); + $subject = new Finder($client->getMock(), $builder); $results = $subject->find(); self::assertCount(1, $results); @@ -306,9 +308,8 @@ public function test_it_adds_fields_to_query(): void public function test_it_adds_aggregates(): void { - $client = Mockery::mock(Client::class); - $client->expects('search') - ->with([ + $client = ClientExpectation::create(); + $client->expectSearch([ 'index' => self::TEST_INDEX, 'body' => [ 'query' => [ @@ -324,8 +325,8 @@ public function test_it_adds_aggregates(): void 'metricAggregation' => ['max' => ['field' => 'yetAnotherField']], ], ], - ]) - ->andReturn([ + ], + FakeElasticResponse::array([ 'hits' => [ 'total' => ['value' => 1], 'hits' => [$this->hit()], @@ -345,7 +346,8 @@ public function test_it_adds_aggregates(): void 'value' => 10, ], ], - ]); + ]) + ); $query = Query::with(new BoolQuery()); $query->addAggregation('specificAggregation', new TermsAggregation('specificField')); @@ -354,7 +356,7 @@ public function test_it_adds_aggregates(): void $builder = new SearchCommand(self::TEST_INDEX, $query); $builder->setIndex(self::TEST_INDEX); - $subject = new Finder($client, $builder); + $subject = new Finder($client->getMock(), $builder); $results = $subject->find(); self::assertCount(3, $results->aggregations()); @@ -378,9 +380,8 @@ public function test_it_adds_aggregates(): void public function test_it_adds_nested_aggregations(): void { - $client = Mockery::mock(Client::class); - $client->expects('search') - ->with([ + $client = ClientExpectation::create(); + $client->expectSearch([ 'index' => self::TEST_INDEX, 'body' => [ 'query' => [ @@ -439,8 +440,8 @@ public function test_it_adds_nested_aggregations(): void ], ], ], - ]) - ->andReturn([ + ], + FakeElasticResponse::array([ 'hits' => [ 'total' => ['value' => 1], 'hits' => [$this->hit()], @@ -480,7 +481,8 @@ public function test_it_adds_nested_aggregations(): void ], ], ], - ]); + ]) + ); $query = Query::with(new BoolQuery()); $query->addAggregation('anotherAggregation', new TermsAggregation('anotherField')); @@ -499,7 +501,7 @@ public function test_it_adds_nested_aggregations(): void $builder = new SearchCommand(self::TEST_INDEX, $query); $builder->setIndex(self::TEST_INDEX); - $subject = new Finder($client, $builder); + $subject = new Finder($client->getMock(), $builder); $results = $subject->find(); self::assertCount(4, $results->aggregations()); @@ -529,9 +531,8 @@ public function test_it_adds_nested_aggregations(): void public function test_with_single_aggregation(): void { - $client = Mockery::mock(Client::class); - $client->expects('search') - ->with([ + $client = ClientExpectation::create(); + $client->expectSearch([ 'index' => self::TEST_INDEX, 'body' => [ 'query' => [ @@ -545,8 +546,8 @@ public function test_with_single_aggregation(): void 'anotherAggregation' => ['terms' => ['field' => 'anotherField', 'size' => 10]], ], ], - ]) - ->andReturn([ + ], + FakeElasticResponse::array([ 'hits' => [ 'total' => ['value' => 1], 'hits' => [$this->hit()], @@ -563,7 +564,8 @@ public function test_with_single_aggregation(): void ], ], ], - ]); + ]) + ); $query = Query::with(new BoolQuery()); $query->addAggregation('anotherAggregation', new TermsAggregation('anotherField')); @@ -571,7 +573,7 @@ public function test_with_single_aggregation(): void $builder = new SearchCommand(self::TEST_INDEX, $query); $builder->setIndex(self::TEST_INDEX); - $subject = new Finder($client, $builder); + $subject = new Finder($client->getMock(), $builder); $results = $subject->find(); self::assertCount(1, $results->aggregations()); @@ -579,9 +581,8 @@ public function test_with_single_aggregation(): void public function test_it_with_no_aggregations(): void { - $client = Mockery::mock(Client::class); - $client->expects('search') - ->with([ + $client = ClientExpectation::create(); + $client->expectSearch([ 'index' => self::TEST_INDEX, 'body' => [ 'query' => [ @@ -592,19 +593,20 @@ public function test_it_with_no_aggregations(): void ], ], ], - ]) - ->andReturn([ + ], + FakeElasticResponse::array([ 'hits' => [ 'total' => ['value' => 1], 'hits' => [$this->hit()], ], - ]); + ]) + ); $query = Query::with(new BoolQuery()); $builder = new SearchCommand(self::TEST_INDEX, $query); $builder->setIndex(self::TEST_INDEX); - $subject = new Finder($client, $builder); + $subject = new Finder($client->getMock(), $builder); $results = $subject->find(); self::assertCount(0, $results->aggregations()); diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 0000000..95b7122 --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,10 @@ +