Allow integration tests to be run from IDE
This commit is contained in:
committed by
Seth Michael Larson
parent
45616bd862
commit
82b3daf6aa
@@ -7,7 +7,7 @@
|
|||||||
# Export the TEST_SUITE variable, eg. 'free' or 'platinum' defaults to 'free'.
|
# Export the TEST_SUITE variable, eg. 'free' or 'platinum' defaults to 'free'.
|
||||||
# Export the NUMBER_OF_NODES variable to start more than 1 node
|
# Export the NUMBER_OF_NODES variable to start more than 1 node
|
||||||
|
|
||||||
# Version 1.3.0
|
# Version 1.4.0
|
||||||
# - Initial version of the run-elasticsearch.sh script
|
# - Initial version of the run-elasticsearch.sh script
|
||||||
# - Deleting the volume should not dependent on the container still running
|
# - Deleting the volume should not dependent on the container still running
|
||||||
# - Fixed `ES_JAVA_OPTS` config
|
# - Fixed `ES_JAVA_OPTS` config
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
# - Added 5 retries on docker pull for fixing transient network errors
|
# - Added 5 retries on docker pull for fixing transient network errors
|
||||||
# - Added flags to make local CCR configurations work
|
# - Added flags to make local CCR configurations work
|
||||||
# - Added action.destructive_requires_name=false as the default will be true in v8
|
# - Added action.destructive_requires_name=false as the default will be true in v8
|
||||||
|
# - Added ingest.geoip.downloader.enabled=false as it causes false positives in testing
|
||||||
|
|
||||||
script_path=$(dirname $(realpath -s $0))
|
script_path=$(dirname $(realpath -s $0))
|
||||||
source $script_path/functions/imports.sh
|
source $script_path/functions/imports.sh
|
||||||
@@ -40,6 +41,7 @@ environment=($(cat <<-END
|
|||||||
--env path.repo=/tmp
|
--env path.repo=/tmp
|
||||||
--env repositories.url.allowed_urls=http://snapshot.test*
|
--env repositories.url.allowed_urls=http://snapshot.test*
|
||||||
--env action.destructive_requires_name=false
|
--env action.destructive_requires_name=false
|
||||||
|
--env ingest.geoip.downloader.enabled=false
|
||||||
END
|
END
|
||||||
))
|
))
|
||||||
if [[ "$TEST_SUITE" == "platinum" ]]; then
|
if [[ "$TEST_SUITE" == "platinum" ]]; then
|
||||||
@@ -48,6 +50,7 @@ if [[ "$TEST_SUITE" == "platinum" ]]; then
|
|||||||
--env xpack.license.self_generated.type=trial
|
--env xpack.license.self_generated.type=trial
|
||||||
--env xpack.security.enabled=true
|
--env xpack.security.enabled=true
|
||||||
--env xpack.security.http.ssl.enabled=true
|
--env xpack.security.http.ssl.enabled=true
|
||||||
|
--env xpack.security.http.ssl.verification_mode=certificate
|
||||||
--env xpack.security.http.ssl.key=certs/testnode.key
|
--env xpack.security.http.ssl.key=certs/testnode.key
|
||||||
--env xpack.security.http.ssl.certificate=certs/testnode.crt
|
--env xpack.security.http.ssl.certificate=certs/testnode.crt
|
||||||
--env xpack.security.http.ssl.certificate_authorities=certs/ca.crt
|
--env xpack.security.http.ssl.certificate_authorities=certs/ca.crt
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ async def async_streaming_bulk(
|
|||||||
raise_on_error,
|
raise_on_error,
|
||||||
ignore_status,
|
ignore_status,
|
||||||
*args,
|
*args,
|
||||||
**kwargs
|
**kwargs,
|
||||||
),
|
),
|
||||||
):
|
):
|
||||||
|
|
||||||
@@ -462,5 +462,5 @@ async def async_reindex(
|
|||||||
target_client,
|
target_client,
|
||||||
_change_doc_index(docs, target_index),
|
_change_doc_index(docs, target_index),
|
||||||
chunk_size=chunk_size,
|
chunk_size=chunk_size,
|
||||||
**kwargs
|
**kwargs,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
from os.path import abspath, dirname, join
|
||||||
from unittest import SkipTest, TestCase
|
from unittest import SkipTest, TestCase
|
||||||
|
|
||||||
from elasticsearch import Elasticsearch
|
from elasticsearch import Elasticsearch
|
||||||
@@ -29,10 +30,12 @@ if "ELASTICSEARCH_URL" in os.environ:
|
|||||||
else:
|
else:
|
||||||
ELASTICSEARCH_URL = "https://elastic:changeme@localhost:9200"
|
ELASTICSEARCH_URL = "https://elastic:changeme@localhost:9200"
|
||||||
|
|
||||||
|
CA_CERTS = join(dirname(dirname(dirname(abspath(__file__)))), ".ci/certs/ca.pem")
|
||||||
|
|
||||||
|
|
||||||
def get_test_client(nowait=False, **kwargs):
|
def get_test_client(nowait=False, **kwargs):
|
||||||
# construct kwargs from the environment
|
# construct kwargs from the environment
|
||||||
kw = {"timeout": 30, "ca_certs": ".ci/certs/ca.pem"}
|
kw = {"timeout": 30, "ca_certs": CA_CERTS}
|
||||||
|
|
||||||
if "PYTHON_CONNECTION_CLASS" in os.environ:
|
if "PYTHON_CONNECTION_CLASS" in os.environ:
|
||||||
from elasticsearch import connection
|
from elasticsearch import connection
|
||||||
@@ -56,13 +59,6 @@ def get_test_client(nowait=False, **kwargs):
|
|||||||
raise SkipTest("Elasticsearch failed to start.")
|
raise SkipTest("Elasticsearch failed to start.")
|
||||||
|
|
||||||
|
|
||||||
def _get_version(version_string):
|
|
||||||
if "." not in version_string:
|
|
||||||
return ()
|
|
||||||
version = version_string.strip().split(".")
|
|
||||||
return tuple(int(v) if v.isdigit() else 999 for v in version)
|
|
||||||
|
|
||||||
|
|
||||||
class ElasticsearchTestCase(TestCase):
|
class ElasticsearchTestCase(TestCase):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_client():
|
def _get_client():
|
||||||
@@ -85,6 +81,16 @@ class ElasticsearchTestCase(TestCase):
|
|||||||
|
|
||||||
def es_version(self):
|
def es_version(self):
|
||||||
if not hasattr(self, "_es_version"):
|
if not hasattr(self, "_es_version"):
|
||||||
version_string = self.client.info()["version"]["number"]
|
self._es_version = es_version(self.client)
|
||||||
self._es_version = _get_version(version_string)
|
|
||||||
return self._es_version
|
return self._es_version
|
||||||
|
|
||||||
|
|
||||||
|
def _get_version(version_string):
|
||||||
|
if "." not in version_string:
|
||||||
|
return ()
|
||||||
|
version = version_string.strip().split(".")
|
||||||
|
return tuple(int(v) if v.isdigit() else 999 for v in version)
|
||||||
|
|
||||||
|
|
||||||
|
def es_version(client):
|
||||||
|
return _get_version(client.info()["version"]["number"])
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ from unittest import TestCase
|
|||||||
from ..client import Elasticsearch
|
from ..client import Elasticsearch
|
||||||
|
|
||||||
ELASTICSEARCH_URL: str
|
ELASTICSEARCH_URL: str
|
||||||
|
CA_CERTS: str
|
||||||
|
|
||||||
def get_test_client(nowait: bool = ..., **kwargs: Any) -> Elasticsearch: ...
|
def get_test_client(nowait: bool = ..., **kwargs: Any) -> Elasticsearch: ...
|
||||||
def _get_version(version_string: str) -> Tuple[int, ...]: ...
|
def _get_version(version_string: str) -> Tuple[int, ...]: ...
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import asyncio
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import elasticsearch
|
import elasticsearch
|
||||||
from elasticsearch.helpers.test import ELASTICSEARCH_URL
|
from elasticsearch.helpers.test import CA_CERTS, ELASTICSEARCH_URL
|
||||||
|
|
||||||
from ...utils import wipe_cluster
|
from ...utils import wipe_cluster
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ async def async_client():
|
|||||||
if not hasattr(elasticsearch, "AsyncElasticsearch"):
|
if not hasattr(elasticsearch, "AsyncElasticsearch"):
|
||||||
pytest.skip("test requires 'AsyncElasticsearch'")
|
pytest.skip("test requires 'AsyncElasticsearch'")
|
||||||
|
|
||||||
kw = {"timeout": 3, "ca_certs": ".ci/certs/ca.pem"}
|
kw = {"timeout": 3, "ca_certs": CA_CERTS}
|
||||||
client = elasticsearch.AsyncElasticsearch(ELASTICSEARCH_URL, **kw)
|
client = elasticsearch.AsyncElasticsearch(ELASTICSEARCH_URL, **kw)
|
||||||
|
|
||||||
# wait for yellow status
|
# wait for yellow status
|
||||||
|
|||||||
@@ -50,11 +50,26 @@ async def await_if_coro(x):
|
|||||||
|
|
||||||
class AsyncYamlRunner(YamlRunner):
|
class AsyncYamlRunner(YamlRunner):
|
||||||
async def setup(self):
|
async def setup(self):
|
||||||
|
# Pull skips from individual tests to not do unnecessary setup.
|
||||||
|
skip_code = []
|
||||||
|
for action in self._run_code:
|
||||||
|
assert len(action) == 1
|
||||||
|
action_type, _ = list(action.items())[0]
|
||||||
|
if action_type == "skip":
|
||||||
|
skip_code.append(action)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
if self._setup_code or skip_code:
|
||||||
|
self.section("setup")
|
||||||
|
if skip_code:
|
||||||
|
await self.run_code(skip_code)
|
||||||
if self._setup_code:
|
if self._setup_code:
|
||||||
await self.run_code(self._setup_code)
|
await self.run_code(self._setup_code)
|
||||||
|
|
||||||
async def teardown(self):
|
async def teardown(self):
|
||||||
if self._teardown_code:
|
if self._teardown_code:
|
||||||
|
self.section("teardown")
|
||||||
await self.run_code(self._teardown_code)
|
await self.run_code(self._teardown_code)
|
||||||
|
|
||||||
async def es_version(self):
|
async def es_version(self):
|
||||||
@@ -67,19 +82,26 @@ class AsyncYamlRunner(YamlRunner):
|
|||||||
ES_VERSION = tuple(int(v) if v.isdigit() else 999 for v in version)
|
ES_VERSION = tuple(int(v) if v.isdigit() else 999 for v in version)
|
||||||
return ES_VERSION
|
return ES_VERSION
|
||||||
|
|
||||||
|
def section(self, name):
|
||||||
|
print(("=" * 10) + " " + name + " " + ("=" * 10))
|
||||||
|
|
||||||
async def run(self):
|
async def run(self):
|
||||||
try:
|
try:
|
||||||
await self.setup()
|
await self.setup()
|
||||||
|
self.section("test")
|
||||||
await self.run_code(self._run_code)
|
await self.run_code(self._run_code)
|
||||||
finally:
|
finally:
|
||||||
|
try:
|
||||||
await self.teardown()
|
await self.teardown()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
async def run_code(self, test):
|
async def run_code(self, test):
|
||||||
"""Execute an instruction based on it's type."""
|
"""Execute an instruction based on it's type."""
|
||||||
print(test)
|
|
||||||
for action in test:
|
for action in test:
|
||||||
assert len(action) == 1
|
assert len(action) == 1
|
||||||
action_type, action = list(action.items())[0]
|
action_type, action = list(action.items())[0]
|
||||||
|
print(action_type, action)
|
||||||
|
|
||||||
if hasattr(self, "run_" + action_type):
|
if hasattr(self, "run_" + action_type):
|
||||||
await await_if_coro(getattr(self, "run_" + action_type)(action))
|
await await_if_coro(getattr(self, "run_" + action_type)(action))
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import time
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import elasticsearch
|
import elasticsearch
|
||||||
from elasticsearch.helpers.test import ELASTICSEARCH_URL
|
from elasticsearch.helpers.test import CA_CERTS, ELASTICSEARCH_URL
|
||||||
|
|
||||||
from ..utils import wipe_cluster
|
from ..utils import wipe_cluster
|
||||||
|
|
||||||
@@ -38,7 +38,11 @@ def sync_client_factory():
|
|||||||
try:
|
try:
|
||||||
# Configure the client with certificates and optionally
|
# Configure the client with certificates and optionally
|
||||||
# an HTTP conn class depending on 'PYTHON_CONNECTION_CLASS' envvar
|
# an HTTP conn class depending on 'PYTHON_CONNECTION_CLASS' envvar
|
||||||
kw = {"timeout": 3, "ca_certs": ".ci/certs/ca.pem"}
|
kw = {
|
||||||
|
"timeout": 3,
|
||||||
|
"ca_certs": CA_CERTS,
|
||||||
|
"headers": {"Authorization": "Basic ZWxhc3RpYzpjaGFuZ2VtZQ=="},
|
||||||
|
}
|
||||||
if "PYTHON_CONNECTION_CLASS" in os.environ:
|
if "PYTHON_CONNECTION_CLASS" in os.environ:
|
||||||
from elasticsearch import connection
|
from elasticsearch import connection
|
||||||
|
|
||||||
@@ -46,7 +50,11 @@ def sync_client_factory():
|
|||||||
connection, os.environ["PYTHON_CONNECTION_CLASS"]
|
connection, os.environ["PYTHON_CONNECTION_CLASS"]
|
||||||
)
|
)
|
||||||
|
|
||||||
client = elasticsearch.Elasticsearch(ELASTICSEARCH_URL, **kw)
|
# We do this little dance with the URL to force
|
||||||
|
# Requests to respect 'headers: None' within rest API spec tests.
|
||||||
|
client = elasticsearch.Elasticsearch(
|
||||||
|
ELASTICSEARCH_URL.replace("elastic:changeme@", ""), **kw
|
||||||
|
)
|
||||||
|
|
||||||
# Wait for the cluster to report a status of 'yellow'
|
# Wait for the cluster to report a status of 'yellow'
|
||||||
for _ in range(100):
|
for _ in range(100):
|
||||||
|
|||||||
@@ -62,35 +62,51 @@ IMPLEMENTED_FEATURES = {
|
|||||||
|
|
||||||
# broken YAML tests on some releases
|
# broken YAML tests on some releases
|
||||||
SKIP_TESTS = {
|
SKIP_TESTS = {
|
||||||
"ml/job_cat_apis[0]",
|
# Warning about date_histogram.interval deprecation is raised randomly
|
||||||
"ml/post_data[0]",
|
"search/aggregation/250_moving_fn[1]",
|
||||||
"ml/post_data[1]",
|
# body: null
|
||||||
"ml/post_data[2]",
|
"indices/simulate_index_template/10_basic[2]",
|
||||||
"ml/post_data[3]",
|
# No ML node with sufficient capacity / random ML failing
|
||||||
"ml/post_data[4]",
|
"ml/start_stop_datafeed",
|
||||||
"ml/post_data[5]",
|
"ml/post_data",
|
||||||
"ml/post_data[6]",
|
"ml/jobs_crud",
|
||||||
"ml/get_trained_model_stats[1]",
|
"ml/datafeeds_crud",
|
||||||
"ml/get_trained_model_stats[2]",
|
"ml/set_upgrade_mode",
|
||||||
"ml/get_trained_model_stats[3]",
|
"ml/reset_job[2]",
|
||||||
"ml/set_upgrade_mode[0]",
|
"ml/jobs_get_stats",
|
||||||
"ml/set_upgrade_mode[1]",
|
"ml/get_datafeed_stats",
|
||||||
"ml/set_upgrade_mode[2]",
|
"ml/get_trained_model_stats",
|
||||||
"ml/set_upgrade_mode[3]",
|
"ml/delete_job_force",
|
||||||
"ml/jobs_get_stats[0]",
|
"ml/jobs_get_result_overall_buckets",
|
||||||
"ml/jobs_get_stats[1]",
|
"ml/bucket_correlation_agg[0]",
|
||||||
"ml/jobs_get_stats[2]",
|
"ml/job_groups",
|
||||||
"ml/jobs_get_stats[3]",
|
"transform/transforms_stats_continuous[0]",
|
||||||
"ml/jobs_get_stats[4]",
|
# Fails bad request instead of 404?
|
||||||
"ml/jobs_get_stats[5]",
|
"ml/inference_crud",
|
||||||
"ml/jobs_get_stats[6]",
|
# rollup/security_tests time out?
|
||||||
"ml/jobs_get_stats[7]",
|
"rollup/security_tests",
|
||||||
"ml/jobs_get_stats[8]",
|
# Our TLS certs are custom
|
||||||
"ml/jobs_get_stats[9]",
|
"ssl/10_basic[0]",
|
||||||
"ml/jobs_get_stats[10]",
|
# Our user is custom
|
||||||
"service_accounts/10_basic[0]",
|
"users/10_basic[3]",
|
||||||
|
# Shards/snapshots aren't right?
|
||||||
|
"searchable_snapshots/10_usage[1]",
|
||||||
|
# flaky data streams?
|
||||||
|
"data_stream/10_basic[1]",
|
||||||
|
"data_stream/80_resolve_index_data_streams[1]",
|
||||||
|
# bad formatting?
|
||||||
|
"cat/allocation/10_basic",
|
||||||
|
# service account number not right?
|
||||||
"service_accounts/10_basic[1]",
|
"service_accounts/10_basic[1]",
|
||||||
"snapshot/20_operator_privileges_disabled[0]",
|
# doesn't use 'contains' properly?
|
||||||
|
"xpack/10_basic[0]",
|
||||||
|
"privileges/40_get_user_privs[0]",
|
||||||
|
"privileges/40_get_user_privs[1]",
|
||||||
|
# bad use of 'is_false'?
|
||||||
|
"indices/get_alias/10_basic[22]",
|
||||||
|
# unique usage of 'set'
|
||||||
|
"indices/stats/50_disk_usage[0]",
|
||||||
|
"indices/stats/60_field_usage[0]",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -101,6 +117,8 @@ RUN_ASYNC_REST_API_TESTS = (
|
|||||||
and os.environ.get("PYTHON_CONNECTION_CLASS") == "RequestsHttpConnection"
|
and os.environ.get("PYTHON_CONNECTION_CLASS") == "RequestsHttpConnection"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
FALSEY_VALUES = ("", None, False, 0, 0.0)
|
||||||
|
|
||||||
|
|
||||||
class YamlRunner:
|
class YamlRunner:
|
||||||
def __init__(self, client):
|
def __init__(self, client):
|
||||||
@@ -118,11 +136,26 @@ class YamlRunner:
|
|||||||
self._teardown_code = test_spec.pop("teardown", None)
|
self._teardown_code = test_spec.pop("teardown", None)
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
|
# Pull skips from individual tests to not do unnecessary setup.
|
||||||
|
skip_code = []
|
||||||
|
for action in self._run_code:
|
||||||
|
assert len(action) == 1
|
||||||
|
action_type, _ = list(action.items())[0]
|
||||||
|
if action_type == "skip":
|
||||||
|
skip_code.append(action)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
if self._setup_code or skip_code:
|
||||||
|
self.section("setup")
|
||||||
|
if skip_code:
|
||||||
|
self.run_code(skip_code)
|
||||||
if self._setup_code:
|
if self._setup_code:
|
||||||
self.run_code(self._setup_code)
|
self.run_code(self._setup_code)
|
||||||
|
|
||||||
def teardown(self):
|
def teardown(self):
|
||||||
if self._teardown_code:
|
if self._teardown_code:
|
||||||
|
self.section("teardown")
|
||||||
self.run_code(self._teardown_code)
|
self.run_code(self._teardown_code)
|
||||||
|
|
||||||
def es_version(self):
|
def es_version(self):
|
||||||
@@ -135,19 +168,26 @@ class YamlRunner:
|
|||||||
ES_VERSION = tuple(int(v) if v.isdigit() else 999 for v in version)
|
ES_VERSION = tuple(int(v) if v.isdigit() else 999 for v in version)
|
||||||
return ES_VERSION
|
return ES_VERSION
|
||||||
|
|
||||||
|
def section(self, name):
|
||||||
|
print(("=" * 10) + " " + name + " " + ("=" * 10))
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
try:
|
try:
|
||||||
self.setup()
|
self.setup()
|
||||||
|
self.section("test")
|
||||||
self.run_code(self._run_code)
|
self.run_code(self._run_code)
|
||||||
finally:
|
finally:
|
||||||
|
try:
|
||||||
self.teardown()
|
self.teardown()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
def run_code(self, test):
|
def run_code(self, test):
|
||||||
"""Execute an instruction based on it's type."""
|
"""Execute an instruction based on it's type."""
|
||||||
print(test)
|
|
||||||
for action in test:
|
for action in test:
|
||||||
assert len(action) == 1
|
assert len(action) == 1
|
||||||
action_type, action = list(action.items())[0]
|
action_type, action = list(action.items())[0]
|
||||||
|
print(action_type, action)
|
||||||
|
|
||||||
if hasattr(self, "run_" + action_type):
|
if hasattr(self, "run_" + action_type):
|
||||||
getattr(self, "run_" + action_type)(action)
|
getattr(self, "run_" + action_type)(action)
|
||||||
@@ -300,11 +340,11 @@ class YamlRunner:
|
|||||||
except AssertionError:
|
except AssertionError:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
assert value in ("", None, False, 0)
|
assert value in FALSEY_VALUES
|
||||||
|
|
||||||
def run_is_true(self, action):
|
def run_is_true(self, action):
|
||||||
value = self._lookup(action)
|
value = self._lookup(action)
|
||||||
assert value not in ("", None, False, 0)
|
assert value not in FALSEY_VALUES
|
||||||
|
|
||||||
def run_length(self, action):
|
def run_length(self, action):
|
||||||
for path, expected in action.items():
|
for path, expected in action.items():
|
||||||
@@ -328,7 +368,7 @@ class YamlRunner:
|
|||||||
expected,
|
expected,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
assert expected == value, "%r does not match %r" % (value, expected)
|
self._assert_match_equals(value, expected)
|
||||||
|
|
||||||
def run_contains(self, action):
|
def run_contains(self, action):
|
||||||
for path, expected in action.items():
|
for path, expected in action.items():
|
||||||
@@ -352,12 +392,18 @@ class YamlRunner:
|
|||||||
# resolve variables
|
# resolve variables
|
||||||
if isinstance(value, string_types) and "$" in value:
|
if isinstance(value, string_types) and "$" in value:
|
||||||
for k, v in self._state.items():
|
for k, v in self._state.items():
|
||||||
key_construct = "${" + k + "}"
|
for key_replace in ("${" + k + "}", "$" + k):
|
||||||
if key_construct in value:
|
if value == key_replace:
|
||||||
value = value.replace(key_construct, v)
|
value = v
|
||||||
key_construct = "$" + k
|
break
|
||||||
if key_construct in value:
|
# We only do the in-string replacement if using ${...}
|
||||||
value = value.replace(key_construct, v)
|
elif (
|
||||||
|
key_replace.startswith("${")
|
||||||
|
and isinstance(value, string_types)
|
||||||
|
and key_replace in value
|
||||||
|
):
|
||||||
|
value = value.replace(key_replace, v)
|
||||||
|
break
|
||||||
|
|
||||||
if isinstance(value, string_types):
|
if isinstance(value, string_types):
|
||||||
value = value.strip()
|
value = value.strip()
|
||||||
@@ -378,7 +424,12 @@ class YamlRunner:
|
|||||||
continue
|
continue
|
||||||
step = step.replace("\1", ".")
|
step = step.replace("\1", ".")
|
||||||
step = self._resolve(step)
|
step = self._resolve(step)
|
||||||
if step.isdigit() and step not in value:
|
|
||||||
|
if (
|
||||||
|
isinstance(step, string_types)
|
||||||
|
and step.isdigit()
|
||||||
|
and isinstance(value, list)
|
||||||
|
):
|
||||||
step = int(step)
|
step = int(step)
|
||||||
assert isinstance(value, list)
|
assert isinstance(value, list)
|
||||||
assert len(value) > step
|
assert len(value) > step
|
||||||
@@ -403,6 +454,13 @@ class YamlRunner:
|
|||||||
IMPLEMENTED_FEATURES.add("no_xpack")
|
IMPLEMENTED_FEATURES.add("no_xpack")
|
||||||
return name in XPACK_FEATURES
|
return name in XPACK_FEATURES
|
||||||
|
|
||||||
|
def _assert_match_equals(self, a, b):
|
||||||
|
# Handle for large floating points with 'E'
|
||||||
|
if isinstance(b, string_types) and isinstance(a, float) and "e" in repr(a):
|
||||||
|
a = repr(a).replace("e+", "E")
|
||||||
|
|
||||||
|
assert a == b, "%r does not match %r" % (a, b)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="function")
|
@pytest.fixture(scope="function")
|
||||||
def sync_runner(sync_client):
|
def sync_runner(sync_client):
|
||||||
@@ -419,13 +477,14 @@ try:
|
|||||||
|
|
||||||
# Make a request to Elasticsearch for the build hash, we'll be looking for
|
# Make a request to Elasticsearch for the build hash, we'll be looking for
|
||||||
# an artifact with this same hash to download test specs for.
|
# an artifact with this same hash to download test specs for.
|
||||||
build_hash = client.info()["version"]["build_hash"]
|
client_info = client.info()
|
||||||
|
version_number = client_info["version"]["number"]
|
||||||
|
build_hash = client_info["version"]["build_hash"]
|
||||||
|
|
||||||
# Now talk to the artifacts API with the 'STACK_VERSION' environment variable
|
# Now talk to the artifacts API with the 'STACK_VERSION' environment variable
|
||||||
resp = http.request(
|
resp = http.request(
|
||||||
"GET",
|
"GET",
|
||||||
"https://artifacts-api.elastic.co/v1/versions/%s"
|
"https://artifacts-api.elastic.co/v1/versions/%s" % (version_number,),
|
||||||
% (os.environ["STACK_VERSION"],),
|
|
||||||
)
|
)
|
||||||
resp = json.loads(resp.data.decode("utf-8"))
|
resp = json.loads(resp.data.decode("utf-8"))
|
||||||
|
|
||||||
@@ -493,7 +552,8 @@ try:
|
|||||||
"run": test_step,
|
"run": test_step,
|
||||||
"teardown": teardown_steps,
|
"teardown": teardown_steps,
|
||||||
}
|
}
|
||||||
if pytest_param_id in SKIP_TESTS:
|
# Skip either 'test_name' or 'test_name[x]'
|
||||||
|
if pytest_test_name in SKIP_TESTS or pytest_param_id in SKIP_TESTS:
|
||||||
pytest_param["skip"] = True
|
pytest_param["skip"] = True
|
||||||
|
|
||||||
YAML_TEST_SPECS.append(pytest.param(pytest_param, id=pytest_param_id))
|
YAML_TEST_SPECS.append(pytest.param(pytest_param, id=pytest_param_id))
|
||||||
|
|||||||
@@ -589,6 +589,26 @@ def test_verify_elasticsearch_passes(headers, response):
|
|||||||
{},
|
{},
|
||||||
'{"version":{"number":"6.99.0"},"tagline":"You Know, for Search"}',
|
'{"version":{"number":"6.99.0"},"tagline":"You Know, for Search"}',
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
{},
|
||||||
|
"""{
|
||||||
|
"name" : "io",
|
||||||
|
"cluster_name" : "elasticsearch",
|
||||||
|
"cluster_uuid" : "HaMHUswUSGGnzla8B17Iqw",
|
||||||
|
"version" : {
|
||||||
|
"number" : "7.6.0",
|
||||||
|
"build_flavor" : "default",
|
||||||
|
"build_type" : "tar",
|
||||||
|
"build_hash" : "7f634e9f44834fbc12724506cc1da681b0c3b1e3",
|
||||||
|
"build_date" : "2020-02-06T00:09:00.449973Z",
|
||||||
|
"build_snapshot" : false,
|
||||||
|
"lucene_version" : "8.4.0",
|
||||||
|
"minimum_wire_compatibility_version" : "6.8.0",
|
||||||
|
"minimum_index_compatibility_version" : "6.0.0-beta1"
|
||||||
|
},
|
||||||
|
"tagline" : "You Know, for Search"
|
||||||
|
}""",
|
||||||
|
),
|
||||||
(
|
(
|
||||||
{},
|
{},
|
||||||
'{"version":{"number":"7.13.0","build_flavor":"default"},"tagline":"You Know, for Search"}',
|
'{"version":{"number":"7.13.0","build_flavor":"default"},"tagline":"You Know, for Search"}',
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
from elasticsearch import Elasticsearch, NotFoundError, RequestError
|
from elasticsearch import Elasticsearch, NotFoundError, RequestError
|
||||||
|
from elasticsearch.helpers.test import es_version
|
||||||
|
|
||||||
|
|
||||||
def wipe_cluster(client):
|
def wipe_cluster(client):
|
||||||
@@ -40,6 +41,10 @@ def wipe_cluster(client):
|
|||||||
wait_for_pending_tasks(client, filter="xpack/rollup/job")
|
wait_for_pending_tasks(client, filter="xpack/rollup/job")
|
||||||
wipe_slm_policies(client)
|
wipe_slm_policies(client)
|
||||||
|
|
||||||
|
# Searchable snapshot indices start in 7.8+
|
||||||
|
if es_version(client) >= (7, 8):
|
||||||
|
wipe_searchable_snapshot_indices(client)
|
||||||
|
|
||||||
wipe_snapshots(client)
|
wipe_snapshots(client)
|
||||||
if is_xpack:
|
if is_xpack:
|
||||||
wipe_data_streams(client)
|
wipe_data_streams(client)
|
||||||
@@ -58,6 +63,8 @@ def wipe_cluster(client):
|
|||||||
wipe_ilm_policies(client)
|
wipe_ilm_policies(client)
|
||||||
wipe_auto_follow_patterns(client)
|
wipe_auto_follow_patterns(client)
|
||||||
wipe_tasks(client)
|
wipe_tasks(client)
|
||||||
|
wipe_node_shutdown_metadata(client)
|
||||||
|
wait_for_pending_datafeeds_and_jobs(client)
|
||||||
|
|
||||||
wait_for_cluster_state_updates_to_finish(client)
|
wait_for_cluster_state_updates_to_finish(client)
|
||||||
if close_after_wipe:
|
if close_after_wipe:
|
||||||
@@ -86,19 +93,33 @@ def wipe_rollup_jobs(client):
|
|||||||
|
|
||||||
def wipe_snapshots(client):
|
def wipe_snapshots(client):
|
||||||
"""Deletes all the snapshots and repositories from the cluster"""
|
"""Deletes all the snapshots and repositories from the cluster"""
|
||||||
repos = client.snapshot.get_repository()
|
in_progress_snapshots = []
|
||||||
for name, repo in repos.items():
|
|
||||||
|
repos = client.snapshot.get_repository(repository="_all")
|
||||||
|
for repo_name, repo in repos.items():
|
||||||
if repo["type"] == "fs":
|
if repo["type"] == "fs":
|
||||||
|
snapshots = client.snapshot.get(
|
||||||
|
repository=repo_name, snapshot="_all", ignore_unavailable=True
|
||||||
|
)
|
||||||
|
for snapshot in snapshots["snapshots"]:
|
||||||
|
if snapshot["state"] == "IN_PROGRESS":
|
||||||
|
in_progress_snapshots.append(snapshot)
|
||||||
|
else:
|
||||||
client.snapshot.delete(
|
client.snapshot.delete(
|
||||||
repository=name,
|
repository=repo_name,
|
||||||
snapshot="*",
|
snapshot=snapshot["snapshot"],
|
||||||
ignore=404,
|
ignore=404,
|
||||||
)
|
)
|
||||||
|
|
||||||
client.snapshot.delete_repository(repository=name, ignore=404)
|
client.snapshot.delete_repository(repository=repo_name, ignore=404)
|
||||||
|
|
||||||
|
assert in_progress_snapshots == []
|
||||||
|
|
||||||
|
|
||||||
def wipe_data_streams(client):
|
def wipe_data_streams(client):
|
||||||
|
try:
|
||||||
|
client.indices.delete_data_stream(name="*", expand_wildcards="all")
|
||||||
|
except Exception:
|
||||||
client.indices.delete_data_stream(name="*")
|
client.indices.delete_data_stream(name="*")
|
||||||
|
|
||||||
|
|
||||||
@@ -110,6 +131,16 @@ def wipe_indices(client):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def wipe_searchable_snapshot_indices(client):
|
||||||
|
cluster_metadata = client.cluster.state(
|
||||||
|
metric="metadata",
|
||||||
|
filter_path="metadata.indices.*.settings.index.store.snapshot",
|
||||||
|
)
|
||||||
|
if cluster_metadata:
|
||||||
|
for index in cluster_metadata["metadata"]["indices"].keys():
|
||||||
|
client.indices.delete(index=index)
|
||||||
|
|
||||||
|
|
||||||
def wipe_xpack_templates(client):
|
def wipe_xpack_templates(client):
|
||||||
templates = [
|
templates = [
|
||||||
x.strip() for x in client.cat.templates(h="name").split("\n") if x.strip()
|
x.strip() for x in client.cat.templates(h="name").split("\n") if x.strip()
|
||||||
@@ -168,6 +199,18 @@ def wipe_auto_follow_patterns(client):
|
|||||||
client.ccr.delete_auto_follow_pattern(name=pattern["name"])
|
client.ccr.delete_auto_follow_pattern(name=pattern["name"])
|
||||||
|
|
||||||
|
|
||||||
|
def wipe_node_shutdown_metadata(client):
|
||||||
|
shutdown_status = client.shutdown.get_node()
|
||||||
|
# If response contains these two keys the feature flag isn't enabled
|
||||||
|
# on this cluster so skip this step now.
|
||||||
|
if "_nodes" in shutdown_status and "cluster_name" in shutdown_status:
|
||||||
|
return
|
||||||
|
|
||||||
|
for shutdown_node in shutdown_status.get("nodes", []):
|
||||||
|
node_id = shutdown_node["node_id"]
|
||||||
|
client.shutdown.delete_node(node_id=node_id)
|
||||||
|
|
||||||
|
|
||||||
def wipe_tasks(client):
|
def wipe_tasks(client):
|
||||||
tasks = client.tasks.list()
|
tasks = client.tasks.list()
|
||||||
for node_name, node in tasks.get("node", {}).items():
|
for node_name, node in tasks.get("node", {}).items():
|
||||||
@@ -183,6 +226,19 @@ def wait_for_pending_tasks(client, filter, timeout=30):
|
|||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
|
def wait_for_pending_datafeeds_and_jobs(client, timeout=30):
|
||||||
|
end_time = time.time() + timeout
|
||||||
|
while time.time() < end_time:
|
||||||
|
if (
|
||||||
|
client.ml.get_datafeeds(datafeed_id="*", allow_no_datafeeds=True)["count"]
|
||||||
|
== 0
|
||||||
|
):
|
||||||
|
break
|
||||||
|
while time.time() < end_time:
|
||||||
|
if client.ml.get_jobs(job_id="*", allow_no_jobs=True)["count"] == 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
def wait_for_cluster_state_updates_to_finish(client, timeout=30):
|
def wait_for_cluster_state_updates_to_finish(client, timeout=30):
|
||||||
end_time = time.time() + timeout
|
end_time = time.time() + timeout
|
||||||
while time.time() < end_time:
|
while time.time() < end_time:
|
||||||
@@ -221,6 +277,7 @@ def is_xpack_template(name):
|
|||||||
"synthetics-settings",
|
"synthetics-settings",
|
||||||
"synthetics-mappings",
|
"synthetics-mappings",
|
||||||
".snapshot-blob-cache",
|
".snapshot-blob-cache",
|
||||||
|
"data-streams-mappings",
|
||||||
}:
|
}:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|||||||
Reference in New Issue
Block a user