diff --git a/CHANGELOG.md b/CHANGELOG.md index 96c65266a2..bb035169c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,6 +65,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * `Elastica\Search::setOptionsAndQuery()` * `Elastica\Index::search()` * `Elastica\Index::createSearch()` +* Removed classes [#2188](https://github.com/ruflin/Elastica/pull/2188) + * `Elastica\Connection` + * `Elastica\Connection\ConnectionPool` + * `Elastica\Connection\Strategy\CallbackStrategy` + * `Elastica\Connection\Strategy\RoundRobin` + * `Elastica\Connection\Strategy\Simple` + * `Elastica\Connection\Strategy\StrategyFactory` + * `Elastica\Connection\Strategy\StrategyInterface` +* Removed `Elastica\Client::setLogger()` method [#2148](https://github.com/ruflin/Elastica/pull/2148) ### Added * Added support for PHP 8.2 [#2136](https://github.com/ruflin/Elastica/pull/2136) @@ -79,6 +88,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed * Removed the JSONParseException class, which is replaced by \JsonException * Removed the JSONParseException test class +* Removed `nyholm/dsn` as no longer needed. +* Removed `symfony/deprecation-contracts` as no longer needed. ### Fixed * Fix types order in `Elastica\Query` to work with psalm & expand the `aggs` type to include raw arrays ### Security diff --git a/composer.json b/composer.json index d23331d6b8..dd19812664 100644 --- a/composer.json +++ b/composer.json @@ -17,12 +17,9 @@ "require": { "php": "~8.0.0 || ~8.1.0 || ~8.2.0", "ext-json": "*", - "elastic/transport": "^8.4", + "elastic/transport": "^8.8", "elasticsearch/elasticsearch": "^8.4.1", - "guzzlehttp/psr7": "^2.0", - "nyholm/dsn": "^2.0.0", - "psr/log": "^1.0 || ^2.0 || ^3.0", - "symfony/deprecation-contracts": "^3.0" + "psr/log": "^1.0 || ^2.0 || ^3.0" }, "require-dev": { "guzzlehttp/guzzle": "^7.2", @@ -31,9 +28,11 @@ "phpunit/phpunit": "^9.5", "symfony/phpunit-bridge": "^6.0" }, + "conflict": { + "guzzlehttp/psr7": "<2.0.0" + }, "suggest": { "aws/aws-sdk-php": "Allow using IAM authentication with Amazon ElasticSearch Service", - "guzzlehttp/guzzle": "Allow using guzzle as transport", "monolog/monolog": "Logging request" }, "autoload": { @@ -49,11 +48,12 @@ "config": { "allow-plugins": { "php-http/discovery": true - } + }, + "sort-packages": true }, "extra": { "branch-alias": { - "dev-master": "7.0.x-dev" + "dev-master": "8.0.x-dev" } } } diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 274eb46148..4f9f08ca91 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -60,11 +60,6 @@ parameters: count: 1 path: tests/ClientFunctionalTest.php - - - message: "#^Parameter \\#1 \\$params of static method Elastica\\\\Connection\\:\\:create\\(\\) expects array\\|Elastica\\\\Connection, string given\\.$#" - count: 1 - path: tests/ConnectionTest.php - - message: "#^Access to an undefined property Elastica\\\\Document\\:\\:\\$field1\\.$#" count: 1 diff --git a/src/Bulk.php b/src/Bulk.php index 98aea084cf..cb31b6eeef 100644 --- a/src/Bulk.php +++ b/src/Bulk.php @@ -133,8 +133,12 @@ public function getActions(): array */ public function addDocument(Document $document, ?string $opType = null): self { - if (!$document->hasRetryOnConflict() && $this->_client->hasConnection() && $this->_client->getConnection()->hasParam('retryOnConflict') && ($retry = $this->_client->getConnection()->getParam('retryOnConflict')) > 0) { - $document->setRetryOnConflict($retry); + if (!$document->hasRetryOnConflict()) { + $retry = $this->_client->getConfigValue('retryOnConflict', 0); + + if ($retry > 0) { + $document->setRetryOnConflict($retry); + } } $action = AbstractDocumentAction::create($document, $opType); @@ -161,8 +165,12 @@ public function addDocuments(array $documents, ?string $opType = null): self */ public function addScript(AbstractScript $script, ?string $opType = null): self { - if (!$script->hasRetryOnConflict() && $this->_client->hasConnection() && $this->_client->getConnection()->hasParam('retryOnConflict') && ($retry = $this->_client->getConnection()->getParam('retryOnConflict')) > 0) { - $script->setRetryOnConflict($retry); + if (!$script->hasRetryOnConflict()) { + $retry = $this->_client->getConfigValue('retryOnConflict', 0); + + if ($retry > 0) { + $script->setRetryOnConflict($retry); + } } $action = AbstractDocumentAction::create($script, $opType); diff --git a/src/Client.php b/src/Client.php index 521ddaa7af..780cd9567c 100644 --- a/src/Client.php +++ b/src/Client.php @@ -23,8 +23,6 @@ use Elastica\Exception\ClientException; use Elastica\Exception\InvalidException; use Elastica\Script\AbstractScript; -use GuzzleHttp\Psr7\Uri; -use Http\Promise\Promise; use Psr\Http\Client\ClientInterface as HttpClientInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; @@ -47,69 +45,25 @@ class Client implements ClientInterface private bool $elasticMetaHeader = true; - /** - * @var ClientConfiguration - */ - protected $_config; - - /** - * @var callable - */ - protected $_callback; + protected ClientConfiguration $_config; - /** - * @var Connection\ConnectionPool - */ - protected $_connectionPool; - - /** - * @var RequestInterface|null - */ - protected $_lastRequest; + protected ?RequestInterface $_lastRequest = null; - /** - * @var Elasticsearch|null - */ - protected $_lastResponse; + protected ?Elasticsearch $_lastResponse = null; - /** - * @var LoggerInterface - */ - protected $_logger; + protected LoggerInterface $_logger; - /** - * @var string - */ - protected $_version; + protected ?string $_version = null; - /** - * The endpoint namespace storage. - */ - protected array $namespace; + private Transport $_transport; - /** - * Creates a new Elastica client. - * - * @param array|string $config OPTIONAL Additional config or DSN of options - * @param callable|null $callback OPTIONAL Callback function which can be used to be notified about errors (for example connection down) - * - * @throws InvalidException - */ - public function __construct($config = [], ?callable $callback = null, ?LoggerInterface $logger = null) + public function __construct(string|array $config = [], ?LoggerInterface $logger = null) { - if (\is_string($config)) { - $configuration = ClientConfiguration::fromDsn($config); - } elseif (\is_array($config)) { - $configuration = ClientConfiguration::fromArray($config); - } else { - throw new InvalidException('Config parameter must be an array or a string.'); - } + $config = \is_string($config) ? ['hosts' => [$config]] : $config; - $this->_config = $configuration; - $this->_callback = $callback; + $this->_config = ClientConfiguration::fromArray($config); $this->_logger = $logger ?? new NullLogger(); - - $this->_initConnections(); + $this->_transport = $this->_buildTransport($this->getConfig()); } /** @@ -125,7 +79,7 @@ public function getLogger(): LoggerInterface */ public function getTransport(): Transport { - throw new \Exception('Not supported'); + return $this->_transport; } /** @@ -181,10 +135,9 @@ public function getResponseException(): bool /** * Get current version. * - * @throws MissingParameterException if a required parameter is missing - * @throws NoNodeAvailableException if all the hosts are offline - * @throws ClientResponseException if the status code of response is 4xx - * @throws ServerResponseException if the status code of response is 5xx + * @throws NoNodeAvailableException if all the hosts are offline + * @throws ClientResponseException if the status code of response is 4xx + * @throws ServerResponseException if the status code of response is 5xx * @throws ClientException */ public function getVersion(): string @@ -262,36 +215,6 @@ public function getIndex(string $name): Index return new Index($this, $name); } - /** - * Adds a HTTP Header. - */ - public function addHeader(string $header, string $value): self - { - if ($this->_config->has('headers')) { - $headers = $this->_config->get('headers'); - } else { - $headers = []; - } - $headers[$header] = $value; - $this->_config->set('headers', $headers); - - return $this; - } - - /** - * Remove a HTTP Header. - */ - public function removeHeader(string $header): self - { - if ($this->_config->has('headers')) { - $headers = $this->_config->get('headers'); - unset($headers[$header]); - $this->_config->set('headers', $headers); - } - - return $this; - } - /** * Uses _bulk to send documents to the server. * @@ -464,90 +387,20 @@ public function deleteDocuments(array $docs, array $requestParams = []): Respons /** * Returns the status object for all indices. - * - * @return Status */ - public function getStatus() + public function getStatus(): Status { return new Status($this); } /** * Returns the current cluster. - * - * @return Cluster */ - public function getCluster() + public function getCluster(): Cluster { return new Cluster($this); } - /** - * Establishes the client connections. - */ - public function connect() - { - $this->_initConnections(); - } - - /** - * @return $this - */ - public function addConnection(Connection $connection) - { - $this->_connectionPool->addConnection($connection); - - return $this; - } - - /** - * Determines whether a valid connection is available for use. - * - * @return bool - */ - public function hasConnection() - { - return $this->_connectionPool->hasConnection(); - } - - /** - * @throws ClientException - * - * @return Connection - */ - public function getConnection() - { - return $this->_connectionPool->getConnection(); - } - - /** - * @return Connection[] - */ - public function getConnections() - { - return $this->_connectionPool->getConnections(); - } - - /** - * @return \Elastica\Connection\Strategy\StrategyInterface - */ - public function getConnectionStrategy() - { - return $this->_connectionPool->getStrategy(); - } - - /** - * @param array|Connection[] $connections - * - * @return $this - */ - public function setConnections(array $connections) - { - $this->_connectionPool->setConnections($connections); - - return $this; - } - /** * Deletes documents with the given ids, index, type from the index. * @@ -627,46 +480,36 @@ public function bulk(array $params): ResponseSet return $bulk->send(); } - public function baseBulk(array $params) + public function baseBulk(array $params): Response { return $this->toElasticaResponse($this->elasticClientBulk($params)); } - public function sendRequest(RequestInterface $sentRequest): Elasticsearch|Promise + public function sendRequest(RequestInterface $request): Elasticsearch { - $connection = $this->getConnection(); - $transport = $connection->getTransportObject(); - - $this->_lastRequest = $sentRequest; + $this->_lastRequest = $request; $this->_lastResponse = null; try { - $response = $transport->sendRequest($sentRequest); + $response = $this->_transport->sendRequest($request); $result = new Elasticsearch(); - $result->setResponse($response, 'HEAD' === $sentRequest->getMethod() ? false : true); + $result->setResponse($response, 'HEAD' !== $request->getMethod()); $this->_lastResponse = $result; } catch (ServerResponseException|NoNodeAvailableException $e) { - $this->_connectionPool->onFail($connection, $e, $this); $this->_logger->error('Elastica Request Failure', [ 'exception' => $e, - 'request' => $sentRequest, - 'request_content' => \json_decode($sentRequest->getBody()->__toString(), true), - 'retry' => $this->hasConnection(), + 'request' => $request, + 'request_content' => \json_decode($request->getBody()->__toString(), true), ]); - // In case there is no valid connection left, throw exception which caused the disabling of the connection. - if (!$this->hasConnection()) { - throw $e; - } - - return $this->sendRequest($sentRequest); + throw $e; } $this->_logger->debug('Elastica Request', [ - 'request' => \json_decode($sentRequest->getBody()->__toString(), true), - 'response' => 'HEAD' !== $sentRequest->getMethod() ? $result->asArray() : $result->asString(), + 'request' => \json_decode($request->getBody()->__toString(), true), + 'response' => 'HEAD' !== $request->getMethod() ? $result->asArray() : $result->asString(), 'responseStatus' => $response->getStatusCode(), ]); @@ -676,17 +519,14 @@ public function sendRequest(RequestInterface $sentRequest): Elasticsearch|Promis /** * Force merges all search indices. * - * @param array $args OPTIONAL Optional arguments - * * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-forcemerge.html * - * @throws MissingParameterException if a required parameter is missing - * @throws NoNodeAvailableException if all the hosts are offline - * @throws ClientResponseException if the status code of response is 4xx - * @throws ServerResponseException if the status code of response is 5xx + * @throws NoNodeAvailableException if all the hosts are offline + * @throws ClientResponseException if the status code of response is 4xx + * @throws ServerResponseException if the status code of response is 5xx * @throws ClientException */ - public function forcemergeAll($args = []): Response + public function forcemergeAll(array $args = []): Response { return $this->toElasticaResponse($this->indices()->forcemerge($args)); } @@ -731,109 +571,20 @@ public function getLastResponse(): ?Elasticsearch return $this->_lastResponse; } - /** - * Replace the existing logger. - * - * @return $this - */ - public function setLogger(LoggerInterface $logger) - { - $this->_logger = $logger; - - return $this; - } - public function toElasticaResponse(Elasticsearch|ResponseInterface $elasticsearchResponse): Response { return ResponseConverter::toElastica($elasticsearchResponse); } - /** - * Inits the client connections. - */ - protected function _initConnections(): void - { - $connections = []; - - foreach ($this->getConfig('connections') as $connection) { - $connections[] = Connection::create($this->_prepareConnectionParams($connection)); - } - - if ($this->_config->has('servers')) { - $servers = $this->_config->get('servers'); - foreach ($servers as $server) { - $connections[] = Connection::create($this->_prepareConnectionParams($server)); - } - } - - // If no connections set, create default connection - if (!$connections) { - $connections[] = Connection::create($this->_prepareConnectionParams($this->getConfig())); - } - - if (!$this->_config->has('connectionStrategy')) { - if (true === $this->getConfig('roundRobin')) { - $this->setConfigValue('connectionStrategy', 'RoundRobin'); - } else { - $this->setConfigValue('connectionStrategy', 'Simple'); - } - } - - $strategy = Connection\Strategy\StrategyFactory::create($this->getConfig('connectionStrategy')); - - $this->_connectionPool = new Connection\ConnectionPool($connections, $strategy, $this->_callback); - } - - /** - * Creates a Connection params array from a Client or server config array. - */ - protected function _prepareConnectionParams(array $config): array - { - $params = []; - $params['config'] = []; - foreach ($config as $key => $value) { - if (\in_array($key, ['bigintConversion', 'curl', 'headers', 'url'])) { - $params['config'][$key] = $value; - } else { - $params[$key] = $value; - } - } - - $params['transport'] = $this->_buildTransport($config); - - return $params; - } - protected function _buildTransport(array $config): Transport { + $hosts = isset($config['hosts']) && \is_array($config['hosts']) ? $config['hosts'] : [ClientConfiguration::DEFAULT_HOST]; $transportConfig = $config['transport_config'] ?? []; - $hosts = []; - - if (isset($config['url'])) { - $hosts = [$config['url']]; - } else { - if (isset($config['hosts'])) { - $hosts = $config['hosts']; - } else { - $hosts = [(string) Uri::fromParts([ - 'scheme' => $config['schema'] ?? 'http', - 'host' => $config['host'] ?? Connection::DEFAULT_HOST, - 'port' => $config['port'] ?? Connection::DEFAULT_PORT, - 'path' => isset($config['path']) ? '/'.\ltrim($config['path'], '/') : '', - ]), - ]; - } - } - // Transport builder $builder = TransportBuilder::create(); $builder->setHosts($hosts); - - // Logger - if (null !== $this->_logger) { - $builder->setLogger($this->_logger); - } + $builder->setLogger($this->_logger); // Http client if (isset($transportConfig['http_client'])) { @@ -856,7 +607,7 @@ protected function _buildTransport(array $config): Transport // Node Pool if (isset($transportConfig['node_pool'])) { - $builder->setNodePool($config['node_pool']); + $builder->setNodePool($transportConfig['node_pool']); } $transport = $builder->build(); @@ -874,10 +625,11 @@ protected function _buildTransport(array $config): Transport } // API key - if (isset($config['api_key']) && !empty($config['api_key'])) { - if (isset($config['username']) && !empty($config['username'])) { - throw new InvalidException('You cannot use APIKey and Basic Authenication together'); + if (!empty($config['api_key'])) { + if (!empty($config['username'])) { + throw new InvalidException('You cannot use APIKey and Basic Authentication together.'); } + $transport->setHeader('Authorization', \sprintf('ApiKey %s', $config['api_key'])); } @@ -897,18 +649,15 @@ protected function _buildTransport(array $config): Transport */ protected function isSymfonyHttpClient(Transport $transport): bool { - if (false !== \strpos(\get_class($transport->getClient()), 'Symfony\Component\HttpClient')) { + if (\str_contains($transport->getClient()::class, 'Symfony\Component\HttpClient')) { return true; } + try { - if (false !== \strpos(\get_class($transport->getAsyncClient()), 'Symfony\Component\HttpClient')) { - return true; - } + return \str_contains($transport->getAsyncClient()::class, 'Symfony\Component\HttpClient'); } catch (NoAsyncClientException $e) { return false; } - - return false; } protected function setTransportClientOptions(HttpClientInterface $client, array $config, array $clientOptions = []): HttpClientInterface @@ -916,16 +665,13 @@ protected function setTransportClientOptions(HttpClientInterface $client, array if (empty($config) && empty($clientOptions)) { return $client; } - $class = \get_class($client); - if (!isset(AdapterOptions::HTTP_ADAPTERS[$class])) { - throw new HttpClientException(\sprintf('The HTTP client %s is not supported for custom options', $class)); - } - $adapterClass = AdapterOptions::HTTP_ADAPTERS[$class]; - if (!\class_exists($adapterClass) || !\in_array(AdapterInterface::class, \class_implements($adapterClass))) { + + $adapterClass = AdapterOptions::HTTP_ADAPTERS[$client::class] ?? throw new HttpClientException(\sprintf('The HTTP client %s is not supported for custom options', $client::class)); + + if (!\class_exists($adapterClass) || !\in_array(AdapterInterface::class, \class_implements($adapterClass), true)) { throw new HttpClientException(\sprintf('The class %s does not exists or does not implement %s', $adapterClass, AdapterInterface::class)); } - $adapter = new $adapterClass(); - return $adapter->setConfig($client, $config, $clientOptions); + return (new $adapterClass())->setConfig($client, $config, $clientOptions); } } diff --git a/src/ClientConfiguration.php b/src/ClientConfiguration.php index 61020e5d05..f518e5d18f 100644 --- a/src/ClientConfiguration.php +++ b/src/ClientConfiguration.php @@ -3,10 +3,6 @@ namespace Elastica; use Elastica\Exception\InvalidException; -use Nyholm\Dsn\Configuration\Url; -use Nyholm\Dsn\DsnParser; -use Nyholm\Dsn\Exception\ExceptionInterface as DsnException; -use Nyholm\Dsn\Exception\FunctionNotSupportedException; /** * Elastica client configuration. @@ -15,6 +11,8 @@ */ class ClientConfiguration { + public const DEFAULT_HOST = 'localhost:9200'; + /** * Config with defaults. * @@ -22,25 +20,15 @@ class ClientConfiguration * bigintConversion: Set to true to enable the JSON bigint to string conversion option (see issue #717) * * @var array{ - * host: string|null, - * port: string|null, - * path: string|null, - * url:string|null, - * connections: array, - * roundRobin: bool, - * retryOnConflict: int, - * username: string|null, - * password: string|null, - * transport_config: array, + * hosts: list, + * retryOnConflict: int, + * username: string|null, + * password: string|null, + * transport_config: array, * } */ - protected $configuration = [ - 'host' => null, - 'port' => null, - 'path' => null, - 'url' => null, - 'connections' => [], // host, port, path, transport_config -> [http_client, http_client_config, http_client_options, node_pool], username, password - 'roundRobin' => false, + protected array $configuration = [ + 'hosts' => [self::DEFAULT_HOST], 'retryOnConflict' => 0, 'username' => null, 'password' => null, @@ -62,51 +50,6 @@ public static function fromArray(array $config): self return $clientConfiguration; } - /** - * Create configuration from Dsn string. Example of valid DSN strings: - * - http://localhost - * - http://foo:bar@localhost:1234?timeout=4&persistant=false - * - pool(http://127.0.0.1 http://127.0.0.2/bar?timeout=4). - */ - public static function fromDsn(string $dsnString): self - { - try { - $func = DsnParser::parseFunc($dsnString); - } catch (DsnException $e) { - throw new InvalidException(\sprintf('DSN "%s" is invalid.', $dsnString), 0, $e); - } - - if ('dsn' === $func->getName()) { - /** @var Url $dsn */ - $dsn = $func->first(); - $clientConfiguration = self::fromArray(self::parseDsn($dsn)); - } elseif ('pool' === $func->getName()) { - $connections = []; - $clientConfiguration = new static(); - /** @var Url $arg */ - foreach ($func->getArguments() as $arg) { - $connections[] = self::parseDsn($arg); - } - $clientConfiguration->set('connections', $connections); - } else { - throw new FunctionNotSupportedException($dsnString, $func->getName()); - } - - foreach ($func->getParameters() as $optionName => $optionValue) { - if ('false' === $optionValue) { - $optionValue = false; - } elseif ('true' === $optionValue) { - $optionValue = true; - } elseif (\is_numeric($optionValue)) { - $optionValue = (int) $optionValue; - } - - $clientConfiguration->set($optionName, $optionValue); - } - - return $clientConfiguration; - } - /** * Returns a specific config key or the whole config array if not set. * @@ -170,39 +113,4 @@ public function add(string $key, $value): void } } } - - private static function parseDsn(Url $dsn): array - { - $data = ['host' => $dsn->getHost()]; - - if (null !== $dsn->getUser()) { - $data['username'] = $dsn->getUser(); - } - - if (null !== $dsn->getPassword()) { - $data['password'] = $dsn->getPassword(); - } - - if (null !== $dsn->getPort()) { - $data['port'] = $dsn->getPort(); - } - - if (null !== $dsn->getPath()) { - $data['path'] = $dsn->getPath(); - } - - foreach ($dsn->getParameters() as $optionName => $optionValue) { - if ('false' === $optionValue) { - $optionValue = false; - } elseif ('true' === $optionValue) { - $optionValue = true; - } elseif (\is_numeric($optionValue)) { - $optionValue = (int) $optionValue; - } - - $data[$optionName] = $optionValue; - } - - return $data; - } } diff --git a/src/Connection.php b/src/Connection.php deleted file mode 100644 index 8779e27e40..0000000000 --- a/src/Connection.php +++ /dev/null @@ -1,262 +0,0 @@ - - */ -class Connection extends Param -{ - /** - * Default elastic search port. - */ - public const DEFAULT_PORT = 9200; - - /** - * Default host. - */ - public const DEFAULT_HOST = 'localhost'; - - /** - * Default transport. - * - * @var string - */ - public const DEFAULT_TRANSPORT = 'Http'; - - /** - * Default compression. - * - * @var bool - */ - public const DEFAULT_COMPRESSION = false; - - /** - * Creates a new connection object. A connection is enabled by default. - * - * @param array $params OPTIONAL Connection params: host, port. All are optional - */ - public function __construct(array $params = []) - { - $this->setParams($params); - $this->setEnabled(true); - - // Set empty config param if not exists - if (!$this->hasParam('config')) { - $this->setParam('config', []); - } - } - - /** - * @return int Server port - */ - public function getPort() - { - return $this->hasParam('port') ? $this->getParam('port') : self::DEFAULT_PORT; - } - - /** - * @param int $port - * - * @return $this - */ - public function setPort($port) - { - return $this->setParam('port', (int) $port); - } - - /** - * @return string Host - */ - public function getHost() - { - return $this->hasParam('host') ? $this->getParam('host') : self::DEFAULT_HOST; - } - - /** - * @param string $host - * - * @return $this - */ - public function setHost($host) - { - return $this->setParam('host', $host); - } - - public function getTransport(): Transport - { - return $this->getParam('transport'); - } - - /** - * @return $this - */ - public function setTransport(Transport $transport) - { - return $this->setParam('transport', $transport); - } - - /** - * @return bool - */ - public function hasCompression() - { - return (bool) $this->hasParam('compression') ? $this->getParam('compression') : self::DEFAULT_COMPRESSION; - } - - /** - * @param bool $compression - * - * @return $this - */ - public function setCompression($compression = null) - { - return $this->setParam('compression', $compression); - } - - /** - * @return string - */ - public function getPath() - { - return $this->hasParam('path') ? $this->getParam('path') : ''; - } - - /** - * @param string $path - * - * @return $this - */ - public function setPath($path) - { - return $this->setParam('path', $path); - } - - /** - * Enables a connection. - * - * @param bool $enabled OPTIONAL (default = true) - * - * @return $this - */ - public function setEnabled($enabled = true) - { - return $this->setParam('enabled', $enabled); - } - - /** - * @return bool True if enabled - */ - public function isEnabled() - { - return (bool) $this->getParam('enabled'); - } - - /** - * Returns an instance of the transport type. - * - * @return Transport Transport object - */ - public function getTransportObject(): Transport - { - return $this->getTransport(); - } - - /** - * @return $this - */ - public function setConfig(array $config) - { - return $this->setParam('config', $config); - } - - /** - * @param string $key - * @param mixed $value - * - * @return $this - */ - public function addConfig($key, $value) - { - $this->_params['config'][$key] = $value; - - return $this; - } - - /** - * @param string $key - * - * @return bool - */ - public function hasConfig($key) - { - $config = $this->getConfig(); - - return isset($config[$key]); - } - - /** - * Returns a specific config key or the whole - * config array if not set. - * - * @param string $key Config key - * - * @throws InvalidException - * - * @return array|bool|int|string|null Config value - */ - public function getConfig($key = '') - { - $config = $this->getParam('config'); - if (empty($key)) { - return $config; - } - - if (!\array_key_exists($key, $config)) { - throw new InvalidException('Config key is not set: '.$key); - } - - return $config[$key]; - } - - /** - * @param array|Connection $params Params to create a connection - * - * @throws Exception\InvalidException - * - * @return self - */ - public static function create($params = []) - { - if (\is_array($params)) { - return new static($params); - } - - if ($params instanceof self) { - return $params; - } - - throw new InvalidException('Invalid data type'); - } - - /** - * @return string|null User - */ - public function getUsername() - { - return $this->hasParam('username') ? $this->getParam('username') : null; - } - - /** - * @return string|null Password - */ - public function getPassword() - { - return $this->hasParam('password') ? $this->getParam('password') : null; - } -} diff --git a/src/Connection/ConnectionPool.php b/src/Connection/ConnectionPool.php deleted file mode 100644 index 116fda3490..0000000000 --- a/src/Connection/ConnectionPool.php +++ /dev/null @@ -1,101 +0,0 @@ -_connections = $connections; - $this->_strategy = $strategy; - $this->_callback = $callback; - } - - /** - * @return $this - */ - public function addConnection(Connection $connection): self - { - $this->_connections[] = $connection; - - return $this; - } - - /** - * @param Connection[] $connections - * - * @return $this - */ - public function setConnections(array $connections): self - { - $this->_connections = $connections; - - return $this; - } - - public function hasConnection(): bool - { - foreach ($this->_connections as $connection) { - if ($connection->isEnabled()) { - return true; - } - } - - return false; - } - - /** - * @return Connection[] - */ - public function getConnections(): array - { - return $this->_connections; - } - - /** - * @throws ClientException - */ - public function getConnection(): Connection - { - return $this->_strategy->getConnection($this->getConnections()); - } - - public function onFail(Connection $connection, \Exception $e, Client $client): void - { - $connection->setEnabled(false); - - if ($this->_callback) { - ($this->_callback)($connection, $e, $client); - } - } - - public function getStrategy(): StrategyInterface - { - return $this->_strategy; - } -} diff --git a/src/Connection/Strategy/CallbackStrategy.php b/src/Connection/Strategy/CallbackStrategy.php deleted file mode 100644 index 1507f01ddc..0000000000 --- a/src/Connection/Strategy/CallbackStrategy.php +++ /dev/null @@ -1,31 +0,0 @@ -_callback = $callback; - } - - /** - * {@inheritdoc} - */ - public function getConnection(array $connections): Connection - { - return ($this->_callback)($connections); - } -} diff --git a/src/Connection/Strategy/RoundRobin.php b/src/Connection/Strategy/RoundRobin.php deleted file mode 100644 index 661ee2924e..0000000000 --- a/src/Connection/Strategy/RoundRobin.php +++ /dev/null @@ -1,23 +0,0 @@ -isEnabled()) { - return $connection; - } - } - - throw new ClientException('No enabled connection'); - } -} diff --git a/src/Connection/Strategy/StrategyFactory.php b/src/Connection/Strategy/StrategyFactory.php deleted file mode 100644 index 1c0dc1fef2..0000000000 --- a/src/Connection/Strategy/StrategyFactory.php +++ /dev/null @@ -1,43 +0,0 @@ - $this->_getHost(), - 'port' => $this->_getPort(), - ]; + $config = $params ?: [$this->_getHost().':'.$this->_getPort()]; - $config = \array_merge($config, $params); + $config['transport_config']['node_pool'] = $config['transport_config']['node_pool'] ?? new TraceableSimpleNodePool( + new RoundRobin(), + new NoResurrect() + ); - return new Client($config, $callback, $logger); + return new Client($config, $logger); } protected function _getHost(): string { - return \getenv('ES_HOST') ?: Connection::DEFAULT_HOST; + return \getenv('ES_HOST') ?: 'localhost'; } protected function _getPort(): int { - return \getenv('ES_PORT') ?: Connection::DEFAULT_PORT; + return \getenv('ES_PORT') ?: 9200; } protected function _getProxyUrl(): string { - $proxyHost = \getenv('PROXY_HOST') ?: Connection::DEFAULT_HOST; + $proxyHost = \getenv('PROXY_HOST') ?: 'localhost'; return 'http://'.$proxyHost.':8000'; } protected function _getProxyUrl403(): string { - $proxyHost = \getenv('PROXY_HOST') ?: Connection::DEFAULT_HOST; + $proxyHost = \getenv('PROXY_HOST') ?: 'localhost'; return 'http://'.$proxyHost.':8001'; } diff --git a/tests/BulkTest.php b/tests/BulkTest.php index 4e9c06cd47..c8fd59c333 100644 --- a/tests/BulkTest.php +++ b/tests/BulkTest.php @@ -705,7 +705,7 @@ public function testRetry(): void $this->assertEquals(5, $metadata['retry_on_conflict']); // Test retry via client - $client->getConnection()->setParam('retryOnConflict', 5); + $client->setConfigValue('retryOnConflict', 5); $doc2 = new Document('2', ['name' => 'Invisible Woman']); $doc2->setOpType(Action::OP_TYPE_UPDATE); diff --git a/tests/ClientConfigurationTest.php b/tests/ClientConfigurationTest.php index 4bc6c274a3..5566843811 100644 --- a/tests/ClientConfigurationTest.php +++ b/tests/ClientConfigurationTest.php @@ -13,96 +13,12 @@ */ class ClientConfigurationTest extends TestCase { - public function testInvalidDsn(): void - { - $this->expectException(InvalidException::class); - $this->expectExceptionMessage('DSN "test foo" is invalid.'); - - ClientConfiguration::fromDsn('test foo'); - } - - public function testInvalidDsnPortOnly(): void - { - $this->expectException(InvalidException::class); - $this->expectExceptionMessage('DSN ":0" is invalid.'); - - ClientConfiguration::fromDsn(':0'); - } - - public function testFromSimpleDsn(): void - { - $configuration = ClientConfiguration::fromDsn('192.168.1.1:9201'); - - $expected = [ - 'host' => '192.168.1.1', - 'port' => 9201, - 'path' => null, - 'url' => null, - 'connections' => [], - 'roundRobin' => false, - 'retryOnConflict' => 0, - 'username' => null, - 'password' => null, - 'transport_config' => [], - ]; - - $this->assertEquals($expected, $configuration->getAll()); - } - - public function testFromDsnWithParameters(): void - { - $configuration = ClientConfiguration::fromDsn('https://user:p4ss@foo.com:9201/my-path?roundRobin=true&retryOnConflict=2&extra=abc'); - $expected = [ - 'host' => 'foo.com', - 'port' => 9201, - 'path' => '/my-path', - 'url' => null, - 'connections' => [], - 'roundRobin' => true, - 'retryOnConflict' => 2, - 'username' => 'user', - 'password' => 'p4ss', - 'extra' => 'abc', - 'transport_config' => [], - ]; - - $this->assertEquals($expected, $configuration->getAll()); - } - - public function testFromDsnWithPool(): void - { - $configuration = ClientConfiguration::fromDsn('pool(http://nicolas@127.0.0.1 http://127.0.0.2/bar?timeout=4)?extra=abc&username=tobias'); - $expected = [ - 'host' => null, - 'port' => null, - 'path' => null, - 'url' => null, - 'connections' => [ - ['host' => '127.0.0.1', 'username' => 'nicolas'], - ['host' => '127.0.0.2', 'path' => '/bar', 'timeout' => 4], - ], - 'roundRobin' => false, - 'retryOnConflict' => 0, - 'username' => 'tobias', - 'password' => null, - 'extra' => 'abc', - 'transport_config' => [], - ]; - - $this->assertEquals($expected, $configuration->getAll()); - } - public function testFromEmptyArray(): void { $configuration = ClientConfiguration::fromArray([]); $expected = [ - 'host' => null, - 'port' => null, - 'path' => null, - 'url' => null, - 'connections' => [], // host, port, path, timeout, transport, compression, timeout, username, password, config -> (curl, headers, url) - 'roundRobin' => false, + 'hosts' => [ClientConfiguration::DEFAULT_HOST], 'retryOnConflict' => 0, 'username' => null, 'password' => null, @@ -120,12 +36,7 @@ public function testFromArray(): void ]); $expected = [ - 'host' => null, - 'port' => null, - 'path' => null, - 'url' => null, - 'connections' => [], // host, port, path, timeout, transport, compression, timeout, username, password, config -> (curl, headers, url) - 'roundRobin' => false, + 'hosts' => [ClientConfiguration::DEFAULT_HOST], 'retryOnConflict' => 0, 'username' => 'Jdoe', 'password' => null, @@ -139,7 +50,7 @@ public function testFromArray(): void public function testHas(): void { $configuration = new ClientConfiguration(); - $this->assertTrue($configuration->has('host')); + $this->assertTrue($configuration->has('hosts')); $this->assertFalse($configuration->has('inexistantKey')); } @@ -148,12 +59,7 @@ public function testGet(): void $configuration = new ClientConfiguration(); $expected = [ - 'host' => null, - 'port' => null, - 'path' => null, - 'url' => null, - 'connections' => [], - 'roundRobin' => false, + 'hosts' => [ClientConfiguration::DEFAULT_HOST], 'retryOnConflict' => 0, 'username' => null, 'password' => null, diff --git a/tests/ClientFunctionalTest.php b/tests/ClientFunctionalTest.php index ddc2c82677..78bf18b752 100644 --- a/tests/ClientFunctionalTest.php +++ b/tests/ClientFunctionalTest.php @@ -5,15 +5,13 @@ use Elastic\Elasticsearch\Response\Elasticsearch; use Elastic\Elasticsearch\Transport\Adapter\AdapterOptions; use Elastic\Transport\Exception\NoNodeAvailableException; -use Elastic\Transport\TransportBuilder; use Elastica\Bulk; use Elastica\Bulk\ResponseSet; -use Elastica\Client; -use Elastica\Connection; use Elastica\Document; use Elastica\Exception\NotFoundException; use Elastica\Script\Script; use Elastica\Test\Base as BaseTest; +use Elastica\Test\Transport\NodePool\TraceableSimpleNodePool; use GuzzleHttp\RequestOptions; use Psr\Http\Client\ClientInterface as HttpClientInterface; use Psr\Http\Message\RequestInterface; @@ -29,7 +27,7 @@ public function testConnectionErrors(): void { $this->expectException(NoNodeAvailableException::class); - $client = $this->_getClient(['host' => 'foo.bar', 'port' => '9201']); + $client = $this->_getClient(['hosts' => ['foo.bar:9201']]); $client->getVersion(); } @@ -37,15 +35,7 @@ public function testClientBadHost(): void { $this->expectException(NoNodeAvailableException::class); - $client = $this->_getClient(['host' => 'localhost', 'port' => '9201']); - $client->getVersion(); - } - - public function testClientBadHostWithTimeout(): void - { - $this->expectException(NoNodeAvailableException::class); - - $client = $this->_getClient(['host' => 'foo.bar', 'timeout' => 10]); + $client = $this->_getClient(['hosts' => ['localhost:9201']]); $client->getVersion(); } @@ -58,7 +48,7 @@ public function testGetVersion(): void public function testConnectionsArray(): void { // Creates a new index 'xodoa' and a type 'user' inside this index - $client = $this->_getClient(['connections' => [['host' => $this->_getHost(), 'port' => 9200]]]); + $client = $this->_getClient(['hosts' => [$this->_getHost().':9200']]); $index = $client->getIndex('elastica_test1'); $index->create([], [ 'recreate' => true, @@ -92,10 +82,12 @@ public function testConnectionsArray(): void public function testTwoServersSame(): void { // Creates a new index 'xodoa' and a type 'user' inside this index - $client = $this->_getClient(['connections' => [ - ['host' => $this->_getHost(), 'port' => 9200], - ['host' => $this->_getHost(), 'port' => 9200], - ]]); + $client = $this->_getClient([ + 'hosts' => [ + $this->_getHost().':9200', + $this->_getHost().':9200', + ], + ]); $index = $client->getIndex('elastica_test1'); $index->create([], [ 'recreate' => true, @@ -359,148 +351,63 @@ public function testDeleteIdsIdxObjectTypeObject(): void public function testOneInvalidConnection(): void { - $client = $this->_getClient(); - - $httpClientOptions = [ - RequestOptions::TIMEOUT => 1, - RequestOptions::CONNECT_TIMEOUT => 1, - ]; - - $transportConnectionBuilder1 = TransportBuilder::create(); - $transportConnectionBuilder1->setHosts([$this->_getHost().':9100']); - $transportConnectionBuilder1->setClient( - $this->setHttpClientOptions($transportConnectionBuilder1->getClient(), [], $httpClientOptions) - ); - - $transportConnectionBuilder2 = TransportBuilder::create(); - $transportConnectionBuilder2->setHosts([$this->_getHost().':9200']); - $transportConnectionBuilder2->setClient( - $this->setHttpClientOptions($transportConnectionBuilder1->getClient(), [], $httpClientOptions) - ); - - // First connection work, second should not work - $connection1 = new Connection(['port' => '9100', 'timeout' => 2, 'host' => $this->_getHost(), 'transport' => $transportConnectionBuilder1->build()]); - $connection2 = new Connection(['port' => '9200', 'timeout' => 2, 'host' => $this->_getHost(), 'transport' => $transportConnectionBuilder2->build()]); - - $client->setConnections([$connection1, $connection2]); + $client = $this->_getClient([ + 'hosts' => [ + // First connection is invalid and second should work + $this->_getHost().':9999', + $this->_getHost().':9200', + ], + 'transport_config' => [ + 'http_client_options' => [ + RequestOptions::TIMEOUT => 1, + RequestOptions::CONNECT_TIMEOUT => 1, + ], + ], + ]); $client->indices()->stats(); - $connections = $client->getConnections(); - + /** @var TraceableSimpleNodePool $nodePool */ + $nodePool = $client->getTransport()->getNodePool(); + $nodes = $nodePool->getNodes(); // two connections are setup - $this->assertCount(2, $connections); + $this->assertCount(2, $nodes); // One connection has to be disabled - $this->assertTrue(false === $connections[0]->isEnabled() || false === $connections[1]->isEnabled()); + $this->assertTrue(false === $nodes[0]->isAlive() || false === $nodes[1]->isAlive()); } public function testTwoInvalidConnection(): void { - $client = $this->_getClient(); - - $httpClientOptions = [ - RequestOptions::TIMEOUT => 1, - RequestOptions::CONNECT_TIMEOUT => 1, - ]; - - $transportConnectionBuilder1 = TransportBuilder::create(); - $transportConnectionBuilder1->setHosts([$this->_getHost().':9101']); - $transportConnectionBuilder1->setClient( - $this->setHttpClientOptions($transportConnectionBuilder1->getClient(), [], $httpClientOptions) - ); - - $transportConnectionBuilder2 = TransportBuilder::create(); - $transportConnectionBuilder2->setHosts([$this->_getHost().':9102']); - $transportConnectionBuilder2->setClient( - $this->setHttpClientOptions($transportConnectionBuilder1->getClient(), [], $httpClientOptions) - ); - - // First connection work, second should not work - $connection1 = new Connection(['host' => $this->_getHost(), 'port' => '9101', 'timeout' => 2, 'transport' => $transportConnectionBuilder1->build()]); - $connection2 = new Connection(['host' => $this->_getHost(), 'port' => '9102', 'timeout' => 2, 'transport' => $transportConnectionBuilder2->build()]); - - $client->setConnections([$connection1, $connection2]); + $client = $this->_getClient([ + 'hosts' => [ + // First connection works, second should not work + $this->_getHost().':9101', + $this->_getHost().':9102', + ], + 'transport_config' => [ + 'http_client_options' => [ + RequestOptions::TIMEOUT => 1, + RequestOptions::CONNECT_TIMEOUT => 1, + ], + ], + ]); try { $client->indices()->stats(); $this->fail('Should throw exception as no connection valid'); - } catch (NoNodeAvailableException $e) { + } catch (NoNodeAvailableException) { } - $connections = $client->getConnections(); + /** @var TraceableSimpleNodePool $nodePool */ + $nodePool = $client->getTransport()->getNodePool(); + $nodes = $nodePool->getNodes(); // two connections are setup - $this->assertCount(2, $connections); + $this->assertCount(2, $nodes); // One connection has to be disabled - $this->assertTrue(false === $connections[0]->isEnabled() && false === $connections[1]->isEnabled()); - } - - /** - * Tests if the callback works in case a connection is down. - */ - public function testCallback(): void - { - $count = 0; - - $httpClientOptions = [ - RequestOptions::TIMEOUT => 1, - RequestOptions::CONNECT_TIMEOUT => 1, - ]; - - $transportConnectionBuilder1 = TransportBuilder::create(); - $transportConnectionBuilder1->setHosts([$this->_getHost().':9101']); - $transportConnectionBuilder1->setClient( - $this->setHttpClientOptions($transportConnectionBuilder1->getClient(), [], $httpClientOptions) - ); - - $transportConnectionBuilder2 = TransportBuilder::create(); - $transportConnectionBuilder2->setHosts([$this->_getHost().':9102']); - $transportConnectionBuilder2->setClient( - $this->setHttpClientOptions($transportConnectionBuilder1->getClient(), [], $httpClientOptions) - ); - - // Callback function which verifies that disabled connection objects are returned - $callback = function (Connection $connection, \Exception $exception, Client $client) use (&$count): void { - $this->assertInstanceOf(Connection::class, $connection); - $this->assertInstanceOf(NoNodeAvailableException::class, $exception); - $this->assertInstanceOf(Client::class, $client); - $this->assertFalse($connection->isEnabled()); - ++$count; - }; - - $client = $this->_getClient([], $callback); - - // First connection work, second should not work - $connection1 = new Connection(['port' => '9101', 'timeout' => 2, 'transport' => $transportConnectionBuilder1->build()]); - $connection2 = new Connection(['port' => '9102', 'timeout' => 2, 'transport' => $transportConnectionBuilder2->build()]); - - $client->setConnections([$connection1, $connection2]); - - $this->assertEquals(0, $count); - - try { - $client->indices()->stats(); - $this->fail('Should throw exception as no connection valid'); - } catch (NoNodeAvailableException $e) { - $this->assertTrue(true); - } - - // Two disabled connections (from closure call) - $this->assertEquals(2, $count); - } - - public function testUrlConstructor(): void - { - $url = 'http://'.$this->_getHost().':9200/'; - - // Url should overwrite invalid host - $client = $this->_getClient(['url' => $url, 'port' => '9101', 'timeout' => 2]); - - $response = $client->toElasticaResponse($client->indices()->stats()); - - $this->assertTrue($response->isOk()); + $this->assertTrue(false === $nodes[0]->isAlive() && false === $nodes[1]->isAlive()); } public function testUpdateDocumentByDocument(): void diff --git a/tests/ClientTest.php b/tests/ClientTest.php index 2d2685335d..f7ac859294 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -2,9 +2,8 @@ namespace Elastica\Test; -use Elastic\Transport\Transport; use Elastica\Client; -use Elastica\Connection; +use Elastica\ClientConfiguration; use Elastica\Exception\InvalidException; use Elastica\Test\Base as BaseTest; @@ -15,59 +14,44 @@ */ class ClientTest extends BaseTest { - public function testConstruct(): void + public function testItConstruct(): void { - $client = $this->_getClient(); - $this->assertCount(1, $client->getConnections()); - } - - public function testConstructWithDsn(): void - { - $client = new Client('https://user:p4ss@foo.com:9200?retryOnConflict=2'); - $this->assertCount(1, $client->getConnections()); + $client = new Client(); $expected = [ - 'host' => 'foo.com', - 'port' => 9200, - 'path' => null, - 'url' => null, - 'connections' => [], - 'roundRobin' => false, - 'retryOnConflict' => 2, - 'username' => 'user', - 'password' => 'p4ss', - 'connectionStrategy' => 'Simple', + 'hosts' => [ClientConfiguration::DEFAULT_HOST], + 'retryOnConflict' => 0, + 'username' => null, + 'password' => null, 'transport_config' => [], ]; $this->assertEquals($expected, $client->getConfig()); } - public function testConnectionParamsArePreparedForConnectionsOption(): void + public function testItConstructWithStringAsConfig(): void { - $url = 'https://'.$this->_getHost().':9200'; - $client = $this->_getClient(['connections' => [['url' => $url]]]); - $connection = $client->getConnection(); - - $this->assertEquals($url, $connection->getConfig('url')); - } + $client = new Client('https://user:p4ss@foo.com:9200?retryOnConflict=2'); - public function testConnectionParamsArePreparedForServersOption(): void - { - $url = 'https://'.$this->_getHost().':9200'; - $client = $this->_getClient(['servers' => [['url' => $url]]]); - $connection = $client->getConnection(); + $expected = [ + 'hosts' => ['https://user:p4ss@foo.com:9200?retryOnConflict=2'], + 'retryOnConflict' => 0, + 'username' => null, + 'password' => null, + 'transport_config' => [], + ]; - $this->assertEquals($url, $connection->getConfig('url')); + $this->assertEquals($expected, $client->getConfig()); } - public function testConnectionParamsArePreparedForDefaultOptions(): void + public function testItAddsHosts(): void { - $url = 'https://'.$this->_getHost().':9200'; - $client = $this->_getClient(['url' => $url]); - $connection = $client->getConnection(); + $hosts = ['https://my-host.com:9300']; - $this->assertEquals($url, $connection->getConfig('url')); + $client = new Client(['hosts' => $hosts]); + + $this->assertEquals($hosts, $client->getConfig('hosts')); + $this->assertEquals('https://my-host.com:9300', $client->getTransport()->getNodePool()->nextNode()->getUri()); } public function testAddDocumentsEmpty(): void @@ -89,7 +73,7 @@ public function testConfigValue(): void ], 'level11' => 'value11', ]; - $client = $this->_getClient($config); + $client = new Client($config); $this->assertNull($client->getConfigValue('level12')); $this->assertFalse($client->getConfigValue('level12', false)); @@ -104,45 +88,11 @@ public function testConfigValue(): void $this->assertIsArray($client->getConfigValue(['level1', 'level2'])); } - public function testAddHeader(): void - { - $client = $this->_getClient(); - - $client->addHeader('foo', 'bar'); - $this->assertEquals(['foo' => 'bar'], $client->getConfigValue('headers')); - } - - public function testRemoveHeader(): void - { - $client = $this->_getClient(); - - $client->addHeader('first', 'first value'); - $client->addHeader('second', 'second value'); - - $client->removeHeader('second'); - $this->assertEquals(['first' => 'first value'], $client->getConfigValue('headers')); - } - public function testPassBigIntSettingsToConnectionConfig(): void { $client = new Client(['bigintConversion' => true]); - $this->assertTrue($client->getConnection()->getConfig('bigintConversion')); - } - - public function testClientConnectWithConfigSetByMethod(): void - { - $client = new Client(); - $client->setConfigValue('host', $this->_getHost()); - $client->setConfigValue('port', $this->_getPort()); - - $client->connect(); - $this->assertTrue($client->hasConnection()); - - $connection = $client->getConnection(); - $this->assertInstanceOf(Connection::class, $connection); - $this->assertEquals($this->_getHost(), $connection->getHost()); - $this->assertEquals($this->_getPort(), $connection->getPort()); + $this->assertTrue($client->getConfig('bigintConversion')); } public function testGetAsync(): void @@ -150,33 +100,24 @@ public function testGetAsync(): void $this->expectException(\Exception::class); $this->expectExceptionMessage('Not supported'); - $client = $this->_getClient(); + $client = new Client(); $client->getAsync(); } public function testSetElasticMetaHeader(): void { - $client = $this->_getClient(); + $client = new Client(); $client->setElasticMetaHeader(true); $this->assertTrue($client->getElasticMetaHeader()); } - public function testGetTransport(): void - { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Not supported'); - - $client = $this->_getClient(); - $client->getTransport(); - } - public function testSetAsync(): void { $this->expectException(\Exception::class); $this->expectExceptionMessage('Not supported'); - $client = $this->_getClient(); + $client = new Client(); $client->setAsync(true); } @@ -185,7 +126,7 @@ public function testSetResponseException(): void $this->expectException(\Exception::class); $this->expectExceptionMessage('Not supported'); - $client = $this->_getClient(); + $client = new Client(); $client->setResponseException(true); } @@ -194,30 +135,43 @@ public function testGetResponseException(): void $this->expectException(\Exception::class); $this->expectExceptionMessage('Not supported'); - $client = $this->_getClient(); + $client = new Client(); $client->getResponseException(); } public function testClientConnectionWithCloudId(): void { $client = new Client([ - 'host' => 'foo.com', - 'port' => 9200, - 'path' => null, - 'url' => null, + 'hosts' => ['foo.com:9200'], 'cloud_id' => 'Test:ZXUtY2VudHJhbC0xLmF3cy5jbG91ZC5lcy5pbyQ0ZGU0NmNlZDhkOGQ0NTk2OTZlNTQ0ZmU1ZjMyYjk5OSRlY2I0YTJlZmY0OTA0ZDliOTE5NzMzMmQwOWNjOTY5Ng==', - 'connections' => [], - 'roundRobin' => false, 'retryOnConflict' => 2, 'username' => 'user', 'password' => 'p4ss', - 'connectionStrategy' => 'Simple', 'transport_config' => [], ]); - $transport = $client->getConnection()->getTransportObject(); - $node = $transport->getNodePool()->nextNode(); - $this->assertInstanceOf(Transport::class, $transport); + $node = $client->getTransport()->getNodePool()->nextNode(); + $this->assertEquals('4de46ced8d8d459696e544fe5f32b999.eu-central-1.aws.cloud.es.io', $node->getUri()->getHost()); } + + public function testItThrowsAnExceptionWhenApiKeyAndUserNameInConfigAtTheSameTime(): void + { + $this->expectException(InvalidException::class); + $this->expectExceptionMessage('You cannot use APIKey and Basic Authentication together.'); + + new Client([ + 'username' => 'user', + 'api_key' => 'key', + ]); + } + + public function testItSetsAuthorizationHeaderIfApiKeyPassed(): void + { + $apiKey = 'key'; + + $client = new Client(['api_key' => $apiKey]); + + self::assertSame(['Authorization' => \sprintf('ApiKey %s', $apiKey)], $client->getTransport()->getHeaders()); + } } diff --git a/tests/Connection/ConnectionPoolTest.php b/tests/Connection/ConnectionPoolTest.php deleted file mode 100644 index 65ba8de4a5..0000000000 --- a/tests/Connection/ConnectionPoolTest.php +++ /dev/null @@ -1,99 +0,0 @@ -createPool(); - - $this->assertEquals($this->getConnections(), $pool->getConnections()); - } - - /** - * @group unit - */ - public function testSetConnections(): void - { - $pool = $this->createPool(); - - $connections = $this->getConnections(5); - - $pool->setConnections($connections); - - $this->assertSame($connections, $pool->getConnections()); - } - - /** - * @group unit - */ - public function testAddConnection(): void - { - $pool = $this->createPool(); - $pool->setConnections([]); - - $connections = $this->getConnections(5); - - foreach ($connections as $connection) { - $pool->addConnection($connection); - } - - $this->assertSame($connections, $pool->getConnections()); - } - - /** - * @group unit - */ - public function testHasConnection(): void - { - $pool = $this->createPool(); - - $this->assertTrue($pool->hasConnection()); - } - - /** - * @group unit - */ - public function testFailHasConnections(): void - { - $pool = $this->createPool(); - - $pool->setConnections([]); - - $this->assertFalse($pool->hasConnection()); - } - - protected function getConnections(int $quantity = 1): array - { - $params = []; - $connections = []; - - for ($i = 0; $i < $quantity; ++$i) { - $connections[] = new Connection($params); - } - - return $connections; - } - - protected function createPool(): ConnectionPool - { - $connections = $this->getConnections(); - $strategy = StrategyFactory::create('Simple'); - - return new ConnectionPool($connections, $strategy); - } -} diff --git a/tests/Connection/Strategy/CallbackStrategyTest.php b/tests/Connection/Strategy/CallbackStrategyTest.php deleted file mode 100644 index 3690bb7f47..0000000000 --- a/tests/Connection/Strategy/CallbackStrategyTest.php +++ /dev/null @@ -1,62 +0,0 @@ -createMock(Connection::class); - $strategy = new CallbackStrategy($callback); - $strategy->getConnection([$mock]); - - $this->assertEquals(1, $count); - } - - /** - * @group functional - */ - public function testConnection(): void - { - $count = 0; - - $config = ['connectionStrategy' => static function ($connections) use (&$count): Connection { - ++$count; - - return \current($connections); - }]; - - $client = $this->_getClient($config); - $response = $client->toElasticaResponse($client->indices()->getAlias()); - - $this->assertEquals(1, $count); - - $this->assertTrue($response->isOk()); - - $strategy = $client->getConnectionStrategy(); - - $this->assertInstanceOf(CallbackStrategy::class, $strategy); - } -} diff --git a/tests/Connection/Strategy/EmptyStrategy.php b/tests/Connection/Strategy/EmptyStrategy.php deleted file mode 100644 index 41b20f4653..0000000000 --- a/tests/Connection/Strategy/EmptyStrategy.php +++ /dev/null @@ -1,22 +0,0 @@ - 'RoundRobin']; - $client = $this->_getClient($config); - $response = $client->indices()->getAlias(); - - $this->_checkResponse($response); - - $this->_checkStrategy($client); - } - - /** - * @group unit - */ - public function testOldStrategySet(): void - { - $config = ['roundRobin' => true]; - $client = $this->_getClient($config); - - $this->_checkStrategy($client); - } - - /** - * @group functional - */ - public function testFailConnection(): void - { - $this->expectException(NoNodeAvailableException::class); - - $config = [ - 'connectionStrategy' => 'RoundRobin', - 'host' => '255.255.255.0', - 'timeout' => $this->_timeout, - 'transport_config' => [ - 'http_client_options' => [ - RequestOptions::TIMEOUT => 1, - RequestOptions::CONNECT_TIMEOUT => 1, - ], - ], - ]; - $client = $this->_getClient($config); - - $this->_checkStrategy($client); - - $client->indices()->getAlias(); - } - - /** - * @group functional - */ - public function testWithOneFailConnection(): void - { - $httpClientOptions = [ - RequestOptions::TIMEOUT => 1, - RequestOptions::CONNECT_TIMEOUT => 1, - ]; - - $transportConnectionBuilder1 = TransportBuilder::create(); - $transportConnectionBuilder1->setHosts(['255.255.255.0']); - $transportConnectionBuilder1->setClient( - $this->setHttpClientOptions($transportConnectionBuilder1->getClient(), [], $httpClientOptions) - ); - - $transportConnectionBuilder2 = TransportBuilder::create(); - $transportConnectionBuilder2->setHosts([$this->_getHost().':'.$this->_getPort()]); - $transportConnectionBuilder2->setClient( - $this->setHttpClientOptions($transportConnectionBuilder1->getClient(), [], $httpClientOptions) - ); - - $connections = [ - new Connection(['host' => '255.255.255.0', 'timeout' => $this->_timeout, 'transport' => $transportConnectionBuilder1->build()]), - new Connection(['host' => $this->_getHost(), 'timeout' => $this->_timeout, 'transport' => $transportConnectionBuilder2->build()]), - ]; - - $count = 0; - $callback = static function ($connection, $exception, $client) use (&$count): void { - ++$count; - }; - - $client = $this->_getClient(['connectionStrategy' => 'RoundRobin'], $callback); - $client->setConnections($connections); - - $response = $client->indices()->getAlias(); - - $this->_checkResponse($response); - - $this->_checkStrategy($client); - - $this->assertLessThan(\count($connections), $count); - } - - /** - * @group functional - */ - public function testWithNoValidConnection(): void - { - $httpClientOptions = [ - RequestOptions::TIMEOUT => 1, - RequestOptions::CONNECT_TIMEOUT => 1, - ]; - - $transportConnectionBuilder1 = TransportBuilder::create(); - $transportConnectionBuilder1->setHosts(['255.255.255.0']); - $transportConnectionBuilder1->setClient( - $this->setHttpClientOptions($transportConnectionBuilder1->getClient(), [], $httpClientOptions) - ); - - $transportConnectionBuilder2 = TransportBuilder::create(); - $transportConnectionBuilder2->setHosts(['45.45.45.45:80']); - $transportConnectionBuilder2->setClient( - $this->setHttpClientOptions($transportConnectionBuilder1->getClient(), [], $httpClientOptions) - ); - - $transportConnectionBuilder3 = TransportBuilder::create(); - $transportConnectionBuilder3->setHosts(['10.123.213.123']); - $transportConnectionBuilder3->setClient( - $this->setHttpClientOptions($transportConnectionBuilder1->getClient(), [], $httpClientOptions) - ); - - $connections = [ - new Connection([ - 'host' => '255.255.255.0', - 'timeout' => $this->_timeout, - 'transport' => $transportConnectionBuilder1->build(), - ]), - new Connection([ - 'host' => '45.45.45.45', - 'port' => '80', - 'timeout' => $this->_timeout, - 'transport' => $transportConnectionBuilder2->build(), - ]), - new Connection([ - 'host' => '10.123.213.123', - 'timeout' => $this->_timeout, - 'transport' => $transportConnectionBuilder3->build(), - ]), - ]; - - $count = 0; - $client = $this->_getClient(['roundRobin' => true], static function () use (&$count): void { - ++$count; - }); - - $client->setConnections($connections); - - try { - $client->indices()->getAlias(); - $this->fail('Should throw exception as no connection valid'); - } catch (NoNodeAvailableException $e) { - $this->assertEquals(\count($connections), $count); - $this->_checkStrategy($client); - } - } - - protected function _checkStrategy(Client $client): void - { - $strategy = $client->getConnectionStrategy(); - - $this->assertInstanceOf(RoundRobin::class, $strategy); - } - - protected function _checkResponse(Elasticsearch $response): void - { - $responseElastica = ResponseConverter::toElastica($response); - - $this->assertTrue($responseElastica->isOk()); - } - - protected function setHttpClientOptions(HttpClientInterface $client, array $config, array $clientOptions = []): HttpClientInterface - { - if (empty($config) && empty($clientOptions)) { - return $client; - } - $class = \get_class($client); - $adapterClass = AdapterOptions::HTTP_ADAPTERS[$class]; - - $adapter = new $adapterClass(); - - return $adapter->setConfig($client, $config, $clientOptions); - } -} diff --git a/tests/Connection/Strategy/SimpleTest.php b/tests/Connection/Strategy/SimpleTest.php deleted file mode 100644 index c93e89adbe..0000000000 --- a/tests/Connection/Strategy/SimpleTest.php +++ /dev/null @@ -1,201 +0,0 @@ -_getClient(); - $response = $client->indices()->getAlias(); - - $this->_checkResponse($response); - - $this->_checkStrategy($client); - } - - /** - * @group functional - */ - public function testFailConnection(): void - { - $this->expectException(NoNodeAvailableException::class); - - $config = [ - 'connectionStrategy' => 'RoundRobin', - 'host' => '255.255.255.0', - 'timeout' => $this->_timeout, - 'transport_config' => [ - 'http_client_options' => [ - RequestOptions::TIMEOUT => 1, - RequestOptions::CONNECT_TIMEOUT => 1, - ], - ], - ]; - $client = $this->_getClient($config); - - $this->_checkStrategy($client); - - $client->indices()->getAlias(); - } - - /** - * @group functional - */ - public function testWithOneFailConnection(): void - { - $httpClientOptions = [ - RequestOptions::TIMEOUT => 1, - RequestOptions::CONNECT_TIMEOUT => 1, - ]; - - $transportConnectionBuilder1 = TransportBuilder::create(); - $transportConnectionBuilder1->setHosts(['255.255.255.0']); - $transportConnectionBuilder1->setClient( - $this->setHttpClientOptions($transportConnectionBuilder1->getClient(), [], $httpClientOptions) - ); - - $transportConnectionBuilder2 = TransportBuilder::create(); - $transportConnectionBuilder2->setHosts([$this->_getHost().':'.$this->_getPort()]); - $transportConnectionBuilder2->setClient( - $this->setHttpClientOptions($transportConnectionBuilder1->getClient(), [], $httpClientOptions) - ); - - $connections = [ - new Connection(['host' => '255.255.255.0', 'timeout' => $this->_timeout, 'transport' => $transportConnectionBuilder1->build()]), - new Connection(['host' => $this->_getHost(), 'timeout' => $this->_timeout, 'transport' => $transportConnectionBuilder2->build()]), - ]; - - $count = 0; - $callback = static function ($connection, $exception, $client) use (&$count): void { - ++$count; - }; - - $client = $this->_getClient([], $callback); - $client->setConnections($connections); - - $response = $client->indices()->getAlias(); - - $this->_checkResponse($response); - - $this->_checkStrategy($client); - - $this->assertLessThan(\count($connections), $count); - } - - /** - * @group functional - */ - public function testWithNoValidConnection(): void - { - $httpClientOptions = [ - RequestOptions::TIMEOUT => 1, - RequestOptions::CONNECT_TIMEOUT => 1, - ]; - - $transportConnectionBuilder1 = TransportBuilder::create(); - $transportConnectionBuilder1->setHosts(['255.255.255.0']); - $transportConnectionBuilder1->setClient( - $this->setHttpClientOptions($transportConnectionBuilder1->getClient(), [], $httpClientOptions) - ); - - $transportConnectionBuilder2 = TransportBuilder::create(); - $transportConnectionBuilder2->setHosts(['45.45.45.45:80']); - $transportConnectionBuilder2->setClient( - $this->setHttpClientOptions($transportConnectionBuilder1->getClient(), [], $httpClientOptions) - ); - - $transportConnectionBuilder3 = TransportBuilder::create(); - $transportConnectionBuilder3->setHosts(['10.123.213.123']); - $transportConnectionBuilder3->setClient( - $this->setHttpClientOptions($transportConnectionBuilder1->getClient(), [], $httpClientOptions) - ); - - $connections = [ - new Connection([ - 'host' => '255.255.255.0', - 'timeout' => $this->_timeout, - 'transport' => $transportConnectionBuilder1->build(), - ]), - new Connection([ - 'host' => '45.45.45.45', - 'port' => '80', - 'timeout' => $this->_timeout, - 'transport' => $transportConnectionBuilder2->build(), - ]), - new Connection([ - 'host' => '10.123.213.123', - 'timeout' => $this->_timeout, - 'transport' => $transportConnectionBuilder3->build(), - ]), - ]; - - $count = 0; - $client = $this->_getClient([], static function () use (&$count): void { - ++$count; - }); - - $client->setConnections($connections); - - try { - $client->indices()->getAlias(); - $this->fail('Should throw exception as no connection valid'); - } catch (NoNodeAvailableException $e) { - $this->assertEquals(\count($connections), $count); - } - } - - protected function _checkStrategy(Client $client): void - { - $strategy = $client->getConnectionStrategy(); - - $this->assertInstanceOf(Simple::class, $strategy); - } - - protected function _checkResponse(Elasticsearch $response): void - { - $responseElastica = ResponseConverter::toElastica($response); - - $this->assertTrue($responseElastica->isOk()); - } - - protected function setHttpClientOptions(HttpClientInterface $client, array $config, array $clientOptions = []): HttpClientInterface - { - if (empty($config) && empty($clientOptions)) { - return $client; - } - $class = \get_class($client); - $adapterClass = AdapterOptions::HTTP_ADAPTERS[$class]; - - $adapter = new $adapterClass(); - - return $adapter->setConfig($client, $config, $clientOptions); - } -} diff --git a/tests/Connection/Strategy/StrategyFactoryTest.php b/tests/Connection/Strategy/StrategyFactoryTest.php deleted file mode 100644 index af96ebf5e2..0000000000 --- a/tests/Connection/Strategy/StrategyFactoryTest.php +++ /dev/null @@ -1,89 +0,0 @@ -assertInstanceOf(CallbackStrategy::class, $strategy); - } - - /** - * @group unit - */ - public function testCreateByName(): void - { - $strategyName = 'Simple'; - - $strategy = StrategyFactory::create($strategyName); - - $this->assertInstanceOf(Simple::class, $strategy); - } - - /** - * @group unit - */ - public function testCreateByClass(): void - { - $strategy = new EmptyStrategy(); - - $this->assertEquals($strategy, StrategyFactory::create($strategy)); - } - - /** - * @group unit - */ - public function testCreateByClassName(): void - { - $strategy = StrategyFactory::create(EmptyStrategy::class); - - $this->assertInstanceOf(EmptyStrategy::class, $strategy); - } - - /** - * @group unit - */ - public function testFailCreate(): void - { - $this->expectException(\InvalidArgumentException::class); - - $strategy = new \stdClass(); - - StrategyFactory::create($strategy); - } - - /** - * @group unit - */ - public function testNoCollisionWithGlobalNamespace(): void - { - // create collision - if (!\class_exists('Simple')) { - \class_alias(Util::class, 'Simple'); - } - $strategy = StrategyFactory::create('Simple'); - $this->assertInstanceOf(Simple::class, $strategy); - } -} diff --git a/tests/ConnectionTest.php b/tests/ConnectionTest.php deleted file mode 100644 index c4fdfb7003..0000000000 --- a/tests/ConnectionTest.php +++ /dev/null @@ -1,215 +0,0 @@ -assertEquals(Connection::DEFAULT_HOST, $connection->getHost()); - $this->assertEquals(Connection::DEFAULT_PORT, $connection->getPort()); - $this->assertEquals([], $connection->getConfig()); - $this->assertTrue($connection->isEnabled()); - } - - /** - * @group unit - */ - public function testEnabledDisable(): void - { - $connection = new Connection(); - $this->assertTrue($connection->isEnabled()); - $connection->setEnabled(false); - $this->assertFalse($connection->isEnabled()); - $connection->setEnabled(true); - $this->assertTrue($connection->isEnabled()); - } - - /** - * @group unit - */ - public function testCreate(): void - { - $connection = Connection::create(); - $this->assertInstanceOf(Connection::class, $connection); - - $connection = Connection::create([]); - $this->assertInstanceOf(Connection::class, $connection); - - $port = 9999; - $connection = Connection::create(['port' => $port]); - $this->assertInstanceOf(Connection::class, $connection); - $this->assertEquals($port, $connection->getPort()); - } - - /** - * @group unit - */ - public function testCreateInvalid(): void - { - $this->expectException(InvalidException::class); - - Connection::create('test'); - } - - /** - * @group unit - */ - public function testGetConfig(): void - { - $url = 'test'; - $connection = new Connection(['config' => ['url' => $url]]); - $this->assertTrue($connection->hasConfig('url')); - $this->assertEquals($url, $connection->getConfig('url')); - - $connection->setConfig([]); - $this->assertFalse($connection->hasConfig('url')); - - $connection->addConfig('url', $url); - $this->assertTrue($connection->hasConfig('url')); - $this->assertEquals($url, $connection->getConfig('url')); - } - - /** - * @group unit - */ - public function testGetConfigWithArrayUsedForTransport(): void - { - $transportConnectionBuilder = TransportBuilder::create(); - $transportConnectionBuilder->setHosts([$this->_getHost().':9101']); - - $connection = new Connection(['transport' => $transportConnectionBuilder->build()]); - $this->assertInstanceOf(Transport::class, $connection->getTransportObject()); - } - - /** - * @group unit - */ - public function testGetConfigInvalidValue(): void - { - $this->expectException(InvalidException::class); - - $connection = new Connection(); - $connection->getConfig('url'); - } - - /** - * @group unit - */ - public function testCompression(): void - { - $connection = new Connection(); - - $this->assertFalse($connection->hasCompression()); - $connection->setCompression(true); - $this->assertTrue($connection->hasCompression()); - } - - /** - * @group unit - */ - public function testCompressionDefaultWithClient(): void - { - $client = new Client(); - $connection = $client->getConnection(); - $this->assertFalse($connection->hasCompression()); - } - - /** - * @group unit - */ - public function testCompressionEnabledWithClient(): void - { - $client = new Client(['connections' => [['compression' => true]]]); - $connection = $client->getConnection(); - - $this->assertTrue($connection->hasCompression()); - } - - /** - * @group unit - */ - public function testUsernameFromClient(): void - { - $username = 'foo'; - $client = new Client(['username' => $username]); - - $this->assertEquals($username, $client->getConnection()->getUsername()); - } - - /** - * @group unit - */ - public function testPasswordFromClient(): void - { - $password = 'bar'; - $client = new Client(['password' => $password]); - - $this->assertEquals($password, $client->getConnection()->getPassword()); - } - - /** - * @group unit - */ - public function testPathFromClient(): void - { - $path = 'test'; - $client = new Client(['path' => $path]); - - $this->assertEquals($path, $client->getConnection()->getPath()); - - $changedPath = 'test2'; - - $client->getConnection()->setPath($changedPath); - - $this->assertEquals($changedPath, $client->getConnection()->getPath()); - } - - /** - * @group unit - */ - public function testPortFromClient(): void - { - $port = 9000; - $client = new Client(['port' => $port]); - - $this->assertEquals($port, $client->getConnection()->getPort()); - - $changedPort = 9001; - - $client->getConnection()->setPort($changedPort); - - $this->assertEquals($changedPort, $client->getConnection()->getPort()); - } - - /** - * @group unit - */ - public function testHostFromClient(): void - { - $host = 'localhost'; - $client = new Client(['host' => $host]); - - $this->assertEquals($host, $client->getConnection()->getHost()); - - $changedHost = 'localhostChanged'; - - $client->getConnection()->setHost($changedHost); - - $this->assertEquals($changedHost, $client->getConnection()->getHost()); - } -} diff --git a/tests/Transport/NodePool/TraceableSimpleNodePool.php b/tests/Transport/NodePool/TraceableSimpleNodePool.php new file mode 100644 index 0000000000..5be8c3e5bb --- /dev/null +++ b/tests/Transport/NodePool/TraceableSimpleNodePool.php @@ -0,0 +1,34 @@ +nodes = []; + foreach ($hosts as $host) { + $this->nodes[] = new Node($host); + } + + $this->selector->setNodes($this->nodes); + + return $this; + } + + /** + * @return array + */ + public function getNodes(): array + { + return $this->nodes; + } +}