diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eaa6a013..ee6ef869 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: - php: [8.0, 8.1, 8.2, 8.3] + php: [8.2, 8.3, 8.4] experimental: [ false ] include: - php: 8.4 diff --git a/.github/workflows/review.yml b/.github/workflows/review.yml index 13eaff32..5c7a7d13 100644 --- a/.github/workflows/review.yml +++ b/.github/workflows/review.yml @@ -10,7 +10,7 @@ jobs: strategy: matrix: - php: [8.1, 8.2, 8.3] + php: [8.2, 8.3, 8.4] name: Mutation Testing Code Review Annotations ${{ matrix.php }} diff --git a/.gitignore b/.gitignore index ca3b3805..efdf54e9 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,6 @@ /node_modules /report .phpunit.result.cache +.phpunit.cache composer.lock infection.log diff --git a/changelog.md b/changelog.md index 75e8b36e..97dbdbea 100644 --- a/changelog.md +++ b/changelog.md @@ -6,6 +6,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## [4.0.0] + +### Added + +- Support for ElasticSearch 8. + +### Removed + +- ElasticSearch 7 support: the elastic 8 client is not backwards compatible. See 'changed' for the breaking changes. +- Support for Laravel 9 and below to make package maintenance easier. +- Support for PHP 8.0 and 8.1, as required by Laravel. + +### Changed + +- The import path for `selector` has changed from `Elasticsearch\ConnectionPool\Selectors\RoundRobinSelector` to `Elastic\Transport\NodePool\Selector\RoundRobin` + ## [3.15.0] ### Fixed diff --git a/composer.json b/composer.json index 7b67f12a..1818c9f1 100755 --- a/composer.json +++ b/composer.json @@ -12,21 +12,22 @@ "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", - "illuminate/support": "^9.0||^10.0||^11.0", - "laravel/scout": "^9.0||^10.0||^11.0", + "php": "^8.2", + "elasticsearch/elasticsearch": "^8.0", + "illuminate/support": "^11.0", + "laravel/scout": "^10.0", "webmozart/assert": "^1.10", - "psr/log": "^1|^2|^3" + "psr/log": "^3" }, "require-dev": { - "phpunit/phpunit": "~9.0", + "phpunit/phpunit": "^10.0", "mockery/mockery": "^1.5", - "infection/infection": "^0.26", + "infection/infection": "^0.29", "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/docs/connection.md b/docs/connection.md index 423fa3f5..13679998 100644 --- a/docs/connection.md +++ b/docs/connection.md @@ -117,7 +117,7 @@ To disable TLS verification set it to `false`. **NOT recommended for production* Elastic can also have multiple possible connections ```php - use Elasticsearch\ConnectionPool\Selectors\RoundRobinSelector; + use Elastic\Transport\NodePool\Selector\RoundRobin; return [ 'connection' => [ @@ -127,7 +127,7 @@ Elastic can also have multiple possible connections 'ssl' => [ 'verify' => false, ], - 'selector' => RoundRobinSelector::class + 'selector' => RoundRobin::class ], 'additionalConnections' => [ [ diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index ff74d5f9..166a3b4d 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 587ad7b6..7f922610 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,13 +1,13 @@ - - - - src/ - - + ./tests/Unit + + + src/ + + diff --git a/src/Application/IndexAdapterInterface.php b/src/Application/IndexAdapterInterface.php index c838f82a..92ffae37 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 070fcbc7..067a7003 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 00000000..c6fc44d8 --- /dev/null +++ b/src/Domain/IndexManagement/AliasedIndexConfigurationInterface.php @@ -0,0 +1,10 @@ +field = $field; $this->value = $value; diff --git a/src/ExplorerServiceProvider.php b/src/ExplorerServiceProvider.php index f0f2368c..6a3f5b3f 100644 --- a/src/ExplorerServiceProvider.php +++ b/src/ExplorerServiceProvider.php @@ -4,12 +4,11 @@ namespace JeroenG\Explorer; -use Elasticsearch\Client; +use Elastic\Elasticsearch\Client; use Illuminate\Foundation\Application; use Illuminate\Support\ServiceProvider; use JeroenG\Explorer\Application\DocumentAdapterInterface; use JeroenG\Explorer\Application\IndexAdapterInterface; -use JeroenG\Explorer\Domain\Aggregations\AggregationSyntaxInterface; use JeroenG\Explorer\Domain\IndexManagement\IndexConfigurationRepositoryInterface; use JeroenG\Explorer\Infrastructure\Console\ElasticSearch; use JeroenG\Explorer\Infrastructure\Console\ElasticUpdate; @@ -17,7 +16,6 @@ use JeroenG\Explorer\Infrastructure\Elastic\ElasticClientBuilder; use JeroenG\Explorer\Infrastructure\Elastic\ElasticDocumentAdapter; use JeroenG\Explorer\Infrastructure\Elastic\ElasticIndexAdapter; -use JeroenG\Explorer\Infrastructure\IndexManagement\ElasticIndexChangedChecker; use JeroenG\Explorer\Infrastructure\IndexManagement\ElasticIndexConfigurationRepository; use JeroenG\Explorer\Infrastructure\Scout\Builder; use JeroenG\Explorer\Infrastructure\Scout\ElasticEngine; diff --git a/src/Infrastructure/Elastic/ElasticClientBuilder.php b/src/Infrastructure/Elastic/ElasticClientBuilder.php index 470ecfd3..7225e372 100644 --- a/src/Infrastructure/Elastic/ElasticClientBuilder.php +++ b/src/Infrastructure/Elastic/ElasticClientBuilder.php @@ -4,9 +4,13 @@ namespace JeroenG\Explorer\Infrastructure\Elastic; -use Elasticsearch\ClientBuilder; +use Elastic\Elasticsearch\ClientBuilder; +use Elastic\Transport\NodePool\Resurrect\ElasticsearchResurrect; +use Elastic\Transport\NodePool\Selector\SelectorInterface; +use Elastic\Transport\NodePool\SimpleNodePool; use Illuminate\Contracts\Config\Repository; use Illuminate\Support\Facades\Log; +use InvalidArgumentException; final class ElasticClientBuilder { @@ -22,13 +26,33 @@ public static function fromConfig(Repository $config): ClientBuilder ARRAY_FILTER_USE_KEY ); - $builder->setHosts([$hostConnectionProperties]); + if (!empty($hostConnectionProperties)) { + $builder->setHosts([ + sprintf( + "%s://%s:%s", + $hostConnectionProperties['scheme'], + $hostConnectionProperties['host'], + $hostConnectionProperties['port'] + ), + ]); + } 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 d08002be..90b553e4 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 3116c33e..da468eaa 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 f0483348..22bb43f2 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 41917717..d012374a 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 714ae37f..78df70c5 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/Support/ClientExpectation.php b/tests/Support/ClientExpectation.php new file mode 100644 index 00000000..67069334 --- /dev/null +++ b/tests/Support/ClientExpectation.php @@ -0,0 +1,37 @@ +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/Support/FakeElasticResponse.php b/tests/Support/FakeElasticResponse.php new file mode 100644 index 00000000..e447001b --- /dev/null +++ b/tests/Support/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/Support/QueryTypeProvider.php b/tests/Support/QueryTypeProvider.php index 9e7dfe97..5b3853a2 100644 --- a/tests/Support/QueryTypeProvider.php +++ b/tests/Support/QueryTypeProvider.php @@ -8,13 +8,13 @@ trait QueryTypeProvider { - public function getQueryTypes(): array + public static function getQueryTypes(): array { return QueryType::ALL; } - public function queryTypeProvider(): array + public static function queryTypeProvider(): array { - return array_map(fn ($item) => [$item], $this->getQueryTypes()); + return array_map(fn ($item) => [$item], self::getQueryTypes()); } } diff --git a/tests/Support/SyntaxProvider.php b/tests/Support/SyntaxProvider.php index a70e6a63..94cefdad 100644 --- a/tests/Support/SyntaxProvider.php +++ b/tests/Support/SyntaxProvider.php @@ -10,12 +10,12 @@ trait SyntaxProvider { - public function syntaxProvider(): array + public static function syntaxProvider(): array { - return array_map(fn ($item) => [$item], $this->getSyntaxClasses()); + return array_map(fn ($item) => [$item], self::getSyntaxClasses()); } - public function getSyntaxClasses(): array + public static function getSyntaxClasses(): array { return [ Matching::class, diff --git a/tests/Unit/Domain/Query/QueryProperties/SourceFilterTest.php b/tests/Unit/Domain/Query/QueryProperties/SourceFilterTest.php index b1166992..328f8a5b 100644 --- a/tests/Unit/Domain/Query/QueryProperties/SourceFilterTest.php +++ b/tests/Unit/Domain/Query/QueryProperties/SourceFilterTest.php @@ -21,7 +21,7 @@ public function test_it_builds_empty_array(): void Assert::assertSame([], SourceFilter::empty()->build()); } - public function provideSourceFilterValues(): iterable + public static function provideSourceFilterValues(): iterable { yield 'include 2 fields' => [ [ 'include' => ['a', 'b'] ], diff --git a/tests/Unit/Domain/Query/QueryProperties/TrackTotalHitsTest.php b/tests/Unit/Domain/Query/QueryProperties/TrackTotalHitsTest.php index 15eaec6d..4b52c009 100644 --- a/tests/Unit/Domain/Query/QueryProperties/TrackTotalHitsTest.php +++ b/tests/Unit/Domain/Query/QueryProperties/TrackTotalHitsTest.php @@ -26,7 +26,7 @@ public function test_it_tracks_none(): void Assert::assertSame([ 'track_total_hits' => false ], TrackTotalHits::none()->build()); } - public function provideTrackTotalHitCounts(): iterable + public static function provideTrackTotalHitCounts(): iterable { yield 'count 100' => [100]; yield 'count -100' => [-100]; diff --git a/tests/Unit/Domain/Syntax/SortOrderTest.php b/tests/Unit/Domain/Syntax/SortOrderTest.php index 95ae4b59..b043e901 100644 --- a/tests/Unit/Domain/Syntax/SortOrderTest.php +++ b/tests/Unit/Domain/Syntax/SortOrderTest.php @@ -7,17 +7,17 @@ use PHPUnit\Framework\TestCase; final class SortOrderTest extends TestCase -{ +{ public function test_it_uses_default_missing_when_creating_sort_order(): void { $sort = SortOrder::for(SortOrder::DESCENDING); - + Assert::assertSame([ 'missing' => SortOrder::MISSING_LAST, 'order' => SortOrder::DESCENDING ], $sort->build()); } - + /** * @dataProvider provideSortOrderStrings */ @@ -26,7 +26,7 @@ public function test_sort_order_can_be_created_from_sort_string(string $expected $subject = SortOrder::fromString($sortString); Assert::assertSame($expectedResult, $subject->build()); } - + /** * @dataProvider provideMissingSortOrderStrings */ @@ -35,18 +35,18 @@ public function test_sort_order_can_be_created_from_sort_string_and_missing(arra $subject = SortOrder::for($sortString, $missing); Assert::assertSame($expectedResult, $subject->build()); } - - public function provideSortOrderStrings(): iterable + + public static function provideSortOrderStrings(): iterable { yield 'asc' => ['asc', 'asc']; yield 'desc' => ['desc', 'desc']; } - - public function provideMissingSortOrderStrings(): iterable + + public static function provideMissingSortOrderStrings(): iterable { yield 'asc order with _last missing' => [['missing' => '_last', 'order' => 'asc'], 'asc', '_last']; yield 'desc order with _last missing' => [['missing' => '_last', 'order' => 'desc'], 'desc', '_last']; yield 'asc order with _first missing' => [['missing' => '_first', 'order' => 'asc'], 'asc', '_first']; yield 'desc order with _first missing' => [['missing' => '_first', 'order' => 'desc'], 'desc', '_first']; - } + } } diff --git a/tests/Unit/ElasticClientBuilderTest.php b/tests/Unit/ElasticClientBuilderTest.php index d83ef53c..0b11f9d1 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; @@ -17,6 +20,8 @@ final class ElasticClientBuilderTest extends MockeryTestCase private const CONNECTION = [ 'host' => 'example.com', 'port' => '9222', 'scheme' => 'https' ]; + private const CONNECTION_STRING = 'https://example.com:9222'; + /** @dataProvider provideClientConfigs */ public function test_it_creates_client_with_config(array $config, ClientBuilder $expectedBuilder): void { @@ -29,14 +34,14 @@ public function test_it_creates_client_with_config(array $config, ClientBuilder self::assertEquals($expectedBuilder, $resultBuilder); } - public function provideClientConfigs(): ?\Generator + public static function provideClientConfigs(): ?\Generator { yield 'simple host' => [ [ 'connection' => self::CONNECTION ], ClientBuilder::create() - ->setHosts([self::CONNECTION]) + ->setHosts([self::CONNECTION_STRING]) ]; yield 'elastic cloud id' => [ @@ -59,7 +64,7 @@ public function provideClientConfigs(): ?\Generator ], self::CONNECTION) ], ClientBuilder::create() - ->setHosts([self::CONNECTION]) + ->setHosts([self::CONNECTION_STRING]) ->setBasicAuthentication('myName', 'myPassword'), ]; @@ -73,19 +78,19 @@ public function provideClientConfigs(): ?\Generator ], self::CONNECTION) ], ClientBuilder::create() - ->setHosts([self::CONNECTION]) + ->setHosts([self::CONNECTION_STRING]) ->setApiKey('myId', 'myKey'), ]; yield 'with selector' => [ [ 'connection' => array_merge([ - 'selector' => StickyRoundRobinSelector::class + 'selector' => RoundRobin::class ], self::CONNECTION) ], ClientBuilder::create() - ->setHosts([self::CONNECTION]) - ->setSelector(StickyRoundRobinSelector::class), + ->setHosts([self::CONNECTION_STRING]) + ->setNodePool(new SimpleNodePool(new RoundRobin(), new ElasticsearchResurrect())), ]; yield 'with additional connections' => [ @@ -107,7 +112,7 @@ public function provideClientConfigs(): ?\Generator ], self::CONNECTION) ], ClientBuilder::create() - ->setHosts([self::CONNECTION]) + ->setHosts([self::CONNECTION_STRING]) ->setSSLVerification(false), ]; @@ -118,7 +123,7 @@ public function provideClientConfigs(): ?\Generator ], self::CONNECTION) ], ClientBuilder::create() - ->setHosts([self::CONNECTION]) + ->setHosts([self::CONNECTION_STRING]) ->setSSLVerification(), ]; @@ -132,7 +137,7 @@ public function provideClientConfigs(): ?\Generator ], self::CONNECTION) ], ClientBuilder::create() - ->setHosts([self::CONNECTION]) + ->setHosts([self::CONNECTION_STRING]) ->setSSLCert('path/to/cert.pem', 'passphrase') ->setSSLKey('path/to/key.pem', 'passphrase'), ]; @@ -147,7 +152,7 @@ public function provideClientConfigs(): ?\Generator ], self::CONNECTION) ], ClientBuilder::create() - ->setHosts([self::CONNECTION]) + ->setHosts([self::CONNECTION_STRING]) ->setSSLCert('path/to/cert.pem') ->setSSLKey('path/to/key.pem'), ]; @@ -159,7 +164,7 @@ public function provideClientConfigs(): ?\Generator 'connection' => self::CONNECTION, ], ClientBuilder::create() - ->setHosts([self::CONNECTION]) + ->setHosts([self::CONNECTION_STRING]) ->setLogger(new NullLogger()), ]; @@ -170,7 +175,7 @@ public function provideClientConfigs(): ?\Generator 'connection' => self::CONNECTION, ], ClientBuilder::create() - ->setHosts([self::CONNECTION]), + ->setHosts([self::CONNECTION_STRING]), ]; yield 'without logger' => [ @@ -179,7 +184,17 @@ public function provideClientConfigs(): ?\Generator 'connection' => self::CONNECTION, ], ClientBuilder::create() - ->setHosts([self::CONNECTION]), + ->setHosts([self::CONNECTION_STRING]), ]; } + + 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 171913bb..3ac52341 100644 --- a/tests/Unit/ElasticClientFactoryTest.php +++ b/tests/Unit/ElasticClientFactoryTest.php @@ -4,13 +4,13 @@ namespace JeroenG\Explorer\Tests\Unit; -use Elasticsearch\Client; use JeroenG\Explorer\Application\SearchCommand; use JeroenG\Explorer\Domain\Query\Query; use JeroenG\Explorer\Domain\Syntax\Compound\BoolQuery; use JeroenG\Explorer\Infrastructure\Elastic\ElasticClientFactory; use JeroenG\Explorer\Infrastructure\Elastic\FakeResponse; use JeroenG\Explorer\Infrastructure\Elastic\Finder; +use JeroenG\Explorer\Tests\Support\ClientExpectation; use Mockery; use Mockery\Adapter\Phpunit\MockeryTestCase; @@ -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/FinderTest.php b/tests/Unit/FinderTest.php index 82dfb4f4..3f138636 100644 --- a/tests/Unit/FinderTest.php +++ b/tests/Unit/FinderTest.php @@ -4,11 +4,11 @@ namespace JeroenG\Explorer\Tests\Unit; -use Elasticsearch\Client; use InvalidArgumentException; use JeroenG\Explorer\Application\AggregationResult; use JeroenG\Explorer\Application\SearchCommand; use JeroenG\Explorer\Domain\Aggregations\MaxAggregation; +use JeroenG\Explorer\Domain\Aggregations\NestedAggregation; use JeroenG\Explorer\Domain\Aggregations\NestedFilteredAggregation; use JeroenG\Explorer\Domain\Aggregations\TermsAggregation; use JeroenG\Explorer\Domain\Query\Query; @@ -18,10 +18,9 @@ use JeroenG\Explorer\Domain\Syntax\Term; use JeroenG\Explorer\Infrastructure\Elastic\Finder; use JeroenG\Explorer\Infrastructure\Scout\ScoutSearchCommandBuilder; -use Mockery; +use JeroenG\Explorer\Tests\Support\ClientExpectation; +use JeroenG\Explorer\Tests\Support\FakeElasticResponse; use Mockery\Adapter\Phpunit\MockeryTestCase; -use JeroenG\Explorer\Domain\Aggregations\NestedAggregation; -use function var_dump; class FinderTest extends MockeryTestCase { @@ -31,11 +30,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 +44,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 +57,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 +77,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 +99,8 @@ public function test_it_accepts_must_should_filter_and_where_queries(): void ], ], ], - ]) - ->andReturn([ + ], + FakeElasticResponse::array([ 'hits' => [ 'total' => ['value' => 2], 'hits' => [ @@ -108,7 +108,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 +120,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 +128,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 +143,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 +158,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 +166,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 +182,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 +203,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 +217,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 +239,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 +253,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 +275,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 +288,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 +310,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 +327,8 @@ public function test_it_adds_aggregates(): void 'metricAggregation' => ['max' => ['field' => 'yetAnotherField']], ], ], - ]) - ->andReturn([ + ], + FakeElasticResponse::array([ 'hits' => [ 'total' => ['value' => 1], 'hits' => [$this->hit()], @@ -345,7 +348,8 @@ public function test_it_adds_aggregates(): void 'value' => 10, ], ], - ]); + ]) + ); $query = Query::with(new BoolQuery()); $query->addAggregation('specificAggregation', new TermsAggregation('specificField')); @@ -354,7 +358,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 +382,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 +442,8 @@ public function test_it_adds_nested_aggregations(): void ], ], ], - ]) - ->andReturn([ + ], + FakeElasticResponse::array([ 'hits' => [ 'total' => ['value' => 1], 'hits' => [$this->hit()], @@ -480,7 +483,8 @@ public function test_it_adds_nested_aggregations(): void ], ], ], - ]); + ]) + ); $query = Query::with(new BoolQuery()); $query->addAggregation('anotherAggregation', new TermsAggregation('anotherField')); @@ -499,7 +503,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 +533,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 +548,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 +566,8 @@ public function test_with_single_aggregation(): void ], ], ], - ]); + ]) + ); $query = Query::with(new BoolQuery()); $query->addAggregation('anotherAggregation', new TermsAggregation('anotherField')); @@ -571,7 +575,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 +583,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 +595,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/Unit/IndexManagement/ElasticIndexConfigurationRepositoryTest.php b/tests/Unit/IndexManagement/ElasticIndexConfigurationRepositoryTest.php index f0cb6136..1ccc572e 100644 --- a/tests/Unit/IndexManagement/ElasticIndexConfigurationRepositoryTest.php +++ b/tests/Unit/IndexManagement/ElasticIndexConfigurationRepositoryTest.php @@ -13,6 +13,8 @@ use JeroenG\Explorer\Tests\Support\Models\TestModelWithoutSettings; use JeroenG\Explorer\Tests\Support\Models\TestModelWithSettings; use Mockery\Adapter\Phpunit\MockeryTestCase; +use RuntimeException; +use StdClass; final class ElasticIndexConfigurationRepositoryTest extends MockeryTestCase { @@ -105,14 +107,14 @@ public function test_it_can_create_the_configuration_from_a_class_without_settin public function test_it_throws_on_invalid_model(): void { - $indices = [ - self::class - ]; + $indices = [get_class(new StdClass())]; $repository = new ElasticIndexConfigurationRepository($indices); - $this->expectException(\RuntimeException::class); - $this->expectExceptionMessage(sprintf('Unable to create index %s, ensure it implements Explored', self::class)); + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage( + sprintf('Unable to create index %s, ensure it implements Explored', get_class(new StdClass())) + ); iterator_to_array($repository->getConfigurations())[0] ?? null; } @@ -121,12 +123,12 @@ public function test_it_errors_on_invalid_indices($indices, string $error): void { $repository = new ElasticIndexConfigurationRepository($indices); - $this->expectException(\RuntimeException::class); + $this->expectException(RuntimeException::class); $this->expectExceptionMessage($error); iterator_to_array($repository->getConfigurations()); } - public function invalidIndices(): iterable + public static function invalidIndices(): iterable { yield [ [false], diff --git a/tests/Unit/IndexManagement/IndexAliasConfigurationTest.php b/tests/Unit/IndexManagement/IndexAliasConfigurationTest.php index 046503dc..004d239e 100644 --- a/tests/Unit/IndexManagement/IndexAliasConfigurationTest.php +++ b/tests/Unit/IndexManagement/IndexAliasConfigurationTest.php @@ -34,7 +34,7 @@ public function test_it_can_get_the_different_aliases(string $alias, string $met self::assertSame("shipIt-$alias", $config->$method()); } - public function aliasProvider(): \Generator + public static function aliasProvider(): \Generator { yield ['history', 'getHistoryAliasName']; yield ['write', 'getWriteAliasName']; diff --git a/tests/Unit/Operations/Bulk/BulkUpdateOperationTest.php b/tests/Unit/Operations/Bulk/BulkUpdateOperationTest.php index aff04117..d5133870 100644 --- a/tests/Unit/Operations/Bulk/BulkUpdateOperationTest.php +++ b/tests/Unit/Operations/Bulk/BulkUpdateOperationTest.php @@ -57,7 +57,7 @@ public function test_it_builds_from_sources($input): void ], $operation->build()); } - public function iterableInputDataProvider(): \Generator + public static function iterableInputDataProvider(): \Generator { yield 'collection' => [collect([new TestModelWithoutSettings()])]; yield 'array' => [[new TestModelWithoutSettings()]]; diff --git a/tests/Unit/ScoutSearchCommandBuilderTest.php b/tests/Unit/ScoutSearchCommandBuilderTest.php index 49358416..309f1506 100644 --- a/tests/Unit/ScoutSearchCommandBuilderTest.php +++ b/tests/Unit/ScoutSearchCommandBuilderTest.php @@ -102,7 +102,7 @@ public function test_it_works_with_setters_and_getters(string $method, mixed $ex self::assertSame($expected, $command->$getter()); } - public function buildCommandProvider(): array + public static function buildCommandProvider(): array { return [ ['Must', [new Term('field', 'value')]], @@ -140,44 +140,44 @@ public function test_it_can_set_the_sort_order(): void $command->setSort([new Sort('id', 'invalid')]); } - + public function test_it_can_set_the_sort_order_as_array(): void { $command = new ScoutSearchCommandBuilder(); - + self::assertFalse($command->hasSort()); - + $command->setSort([new Sort('id')]); - + self::assertTrue($command->hasSort()); self::assertSame([['id' => 'asc']], $command->getSort()); - + $command->setSort([]); - + self::assertFalse($command->hasSort()); self::assertSame([], $command->getSort()); - + $command->setSort([new Sort('id', SortOrder::for('desc'))]); - + self::assertTrue($command->hasSort()); self::assertSame([['id' => ['missing' => '_last', 'order' => 'desc']]], $command->getSort()); - + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Expected one of: "asc", "desc". Got: "invalid"'); - + $command->setSort([new Sort('id', SortOrder::for('invalid'))]); } - + public function test_it_throws_exception_when_missing_is_invalid(): void { $command = new ScoutSearchCommandBuilder(); - + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Expected one of: "_first", "_last". Got: "invalid"'); - + $command->setSort([new Sort('id', SortOrder::for('desc', 'invalid'))]); } - + public function test_it_only_accepts_sort_classes(): void { $command = new ScoutSearchCommandBuilder(); @@ -289,7 +289,7 @@ public function test_it_respects_minimum_should_match_on_custom_compound(): void ]; self::assertEquals($expectedQuery, $query); - } + } public function test_it_has_bool_query_as_default_compound(): void { @@ -443,7 +443,7 @@ public function test_it_wraps_a_compound_using_minimum_should_match(): void ]; self::assertEquals($expectedQuery, $query); - } + } public function test_it_wraps_scout_builder_query_properties(): void { diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 00000000..95b7122a --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,10 @@ +