From 8fa8d92e6f6778fd61b828f4c2a19ad2b8f0d926 Mon Sep 17 00:00:00 2001 From: Sergey Korotkov Date: Wed, 16 Mar 2022 21:00:14 +0700 Subject: [PATCH] IGNITE-16569 [ducktests] Add ability to customize the test context (#9890) --- .gitignore | 2 + modules/ducktests/tests/docker/run_tests.sh | 2 +- .../utils/ignite_configuration/__init__.py | 2 +- .../utils/ignite_configuration/event_type.py | 44 +++++++++++++++++++ .../ssl/client_connector_configuration.py | 10 +++-- .../services/utils/templates/ignite.xml.j2 | 16 ++++++- .../services/utils/templates/misc_macro.j2 | 10 +++++ .../tests/ignitetest/services/zk/zookeeper.py | 9 ++++ .../tests/cellular_affinity_test.py | 2 +- .../tests/control_utility/consistency_test.py | 11 ++--- .../tests/ignitetest/tests/discovery_test.py | 2 +- .../tests/persistence_upgrade_test.py | 7 ++- .../ignitetest/tests/pme_free_switch_test.py | 2 +- .../tests/ignitetest/tests/rebalance/util.py | 2 +- .../tests/ignitetest/tests/snapshot_test.py | 5 +-- .../ducktests/tests/ignitetest/utils/_mark.py | 15 +++++-- .../tests/ignitetest/utils/ignite_test.py | 38 +++++++++++++++- 17 files changed, 150 insertions(+), 29 deletions(-) create mode 100644 modules/ducktests/tests/ignitetest/services/utils/ignite_configuration/event_type.py diff --git a/.gitignore b/.gitignore index 6315a9b4cc908..36a547edb646c 100644 --- a/.gitignore +++ b/.gitignore @@ -94,3 +94,5 @@ modules/ducktests/tests/docker/build/** modules/ducktests/tests/.tox modules/ducktests/tests/certs/* modules/ducktests/tests/ignitetest.egg-info/** +modules/ducktests/tests/build/** +modules/ducktests/tests/dist/** diff --git a/modules/ducktests/tests/docker/run_tests.sh b/modules/ducktests/tests/docker/run_tests.sh index 6fb10b17622b7..7db1dcfd1f7ab 100755 --- a/modules/ducktests/tests/docker/run_tests.sh +++ b/modules/ducktests/tests/docker/run_tests.sh @@ -160,5 +160,5 @@ if [[ -n "$MAX_PARALLEL" ]]; then DUCKTAPE_OPTIONS="$DUCKTAPE_OPTIONS --max-parallel $MAX_PARALLEL" fi -"$SCRIPT_DIR"/ducker-ignite test "$TC_PATHS" "$DUCKTAPE_OPTIONS" \ +"$SCRIPT_DIR"/ducker-ignite test $TC_PATHS "$DUCKTAPE_OPTIONS" \ || die "ducker-ignite test failed" diff --git a/modules/ducktests/tests/ignitetest/services/utils/ignite_configuration/__init__.py b/modules/ducktests/tests/ignitetest/services/utils/ignite_configuration/__init__.py index 82ceca02f5a13..d3caf008e5be2 100644 --- a/modules/ducktests/tests/ignitetest/services/utils/ignite_configuration/__init__.py +++ b/modules/ducktests/tests/ignitetest/services/utils/ignite_configuration/__init__.py @@ -62,7 +62,7 @@ class IgniteConfiguration(NamedTuple): rebalance_batches_prefetch_count: int = None rebalance_throttle: int = None local_event_listeners: str = None - include_event_types: str = None + include_event_types: list = [] event_storage_spi: str = None log4j_config: str = IgnitePathAware.IGNITE_LOG_CONFIG_NAME diff --git a/modules/ducktests/tests/ignitetest/services/utils/ignite_configuration/event_type.py b/modules/ducktests/tests/ignitetest/services/utils/ignite_configuration/event_type.py new file mode 100644 index 0000000000000..307a6adcfa017 --- /dev/null +++ b/modules/ducktests/tests/ignitetest/services/utils/ignite_configuration/event_type.py @@ -0,0 +1,44 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License + +from enum import Enum, auto + + +class EventType(Enum): + """ + Helper for includeEventTypes property in XML configuration + """ + + EVT_CACHE_STARTED = auto() + EVT_CACHE_STOPPED = auto() + EVT_CHECKPOINT_SAVED = auto() + EVT_CLUSTER_SNAPSHOT_FAILED = auto() + EVT_CLUSTER_SNAPSHOT_FINISHED = auto() + EVT_CLUSTER_SNAPSHOT_STARTED = auto() + EVT_CLUSTER_SNAPSHOT_RESTORE_FAILED = auto() + EVT_CLUSTER_SNAPSHOT_RESTORE_FINISHED = auto() + EVT_CLUSTER_SNAPSHOT_RESTORE_STARTED = auto() + EVT_CONSISTENCY_VIOLATION = auto() + EVT_NODE_JOINED = auto() + EVT_NODE_LEFT = auto() + EVT_NODE_FAILED = auto() + EVT_NODE_VALIDATION_FAILED = auto() + EVT_SQL_QUERY_EXECUTION = auto() + + def __str__(self): + return '#{{T(org.apache.ignite.events.EventType).{}}}'.format(self._name_) + + def __repr__(self): + return self.__str__() diff --git a/modules/ducktests/tests/ignitetest/services/utils/ssl/client_connector_configuration.py b/modules/ducktests/tests/ignitetest/services/utils/ssl/client_connector_configuration.py index 5757fdfb21a3b..80512ffcc5bfb 100644 --- a/modules/ducktests/tests/ignitetest/services/utils/ssl/client_connector_configuration.py +++ b/modules/ducktests/tests/ignitetest/services/utils/ssl/client_connector_configuration.py @@ -22,6 +22,11 @@ from ignitetest.services.utils.ssl.ssl_params import SslParams +class ThinClientConfiguration(NamedTuple): + max_active_compute_tasks_per_connection: int = 0 + max_active_tx_per_connection: int = 100 + + class ClientConnectorConfiguration(NamedTuple): """ Ignite ClientConnectorConfiguration. @@ -32,7 +37,4 @@ class ClientConnectorConfiguration(NamedTuple): use_ignite_ssl_context_factory: bool = True ssl_client_auth: bool = False ssl_params: SslParams = None - ssl_enabled: bool = False - use_ignite_ssl_context_factory: bool = True - ssl_client_auth: bool = False - ssl_params: SslParams = None + thin_client_configuration: ThinClientConfiguration = None diff --git a/modules/ducktests/tests/ignitetest/services/utils/templates/ignite.xml.j2 b/modules/ducktests/tests/ignitetest/services/utils/templates/ignite.xml.j2 index fb7c204595f2e..fd04894b52923 100644 --- a/modules/ducktests/tests/ignitetest/services/utils/templates/ignite.xml.j2 +++ b/modules/ducktests/tests/ignitetest/services/utils/templates/ignite.xml.j2 @@ -104,6 +104,14 @@ {% endif %} + {% if config.client_connector_configuration.thin_client_configuration %} + + + + + + + {% endif %} {% endif %} @@ -120,8 +128,8 @@ {% endif %} - {% if config.include_event_types %} - + {% if config.include_event_types | length > 0 %} + {% endif %} {% if config.event_storage_spi %} @@ -132,4 +140,8 @@ {{ misc_utils.ext_beans(config) }} + + {% if config.include_event_types | length > 0 %} + {{ misc_utils.event_types(config) }} + {% endif %} diff --git a/modules/ducktests/tests/ignitetest/services/utils/templates/misc_macro.j2 b/modules/ducktests/tests/ignitetest/services/utils/templates/misc_macro.j2 index f34f21174b5c1..809dc64e1e079 100644 --- a/modules/ducktests/tests/ignitetest/services/utils/templates/misc_macro.j2 +++ b/modules/ducktests/tests/ignitetest/services/utils/templates/misc_macro.j2 @@ -44,3 +44,13 @@ {% endfor %} {% endif %} {% endmacro %} + +{% macro event_types(config) %} + {% if config.include_event_types | length > 0 %} + + {% for event_type in config.include_event_types %} + {{ event_type }} + {% endfor %} + + {% endif %} +{% endmacro %} diff --git a/modules/ducktests/tests/ignitetest/services/zk/zookeeper.py b/modules/ducktests/tests/ignitetest/services/zk/zookeeper.py index 675899430bfa0..fc6e03caba403 100644 --- a/modules/ducktests/tests/ignitetest/services/zk/zookeeper.py +++ b/modules/ducktests/tests/ignitetest/services/zk/zookeeper.py @@ -79,7 +79,16 @@ def config_file(self): return os.path.join(self.persistent_root, "zookeeper.properties") def start(self, **kwargs): + self.start_async(**kwargs) + self.await_started() + + def start_async(self, **kwargs): + """ + Starts in async way. + """ super().start(**kwargs) + + def await_started(self): self.logger.info("Waiting for Zookeeper quorum...") for node in self.nodes: diff --git a/modules/ducktests/tests/ignitetest/tests/cellular_affinity_test.py b/modules/ducktests/tests/ignitetest/tests/cellular_affinity_test.py index eafc6f597499a..e6e2bed1a3f85 100644 --- a/modules/ducktests/tests/ignitetest/tests/cellular_affinity_test.py +++ b/modules/ducktests/tests/ignitetest/tests/cellular_affinity_test.py @@ -150,7 +150,7 @@ def test_latency(self, ignite_version, stop_type, discovery_type, prep_type): """ Tests Cellular switch tx latency. """ - cluster_size = len(self.test_context.cluster) + cluster_size = self.available_cluster_size cells_amount = math.floor((cluster_size - self.ZOOKEPER_CLUSTER_SIZE) / (self.NODES_PER_CELL + 1)) diff --git a/modules/ducktests/tests/ignitetest/tests/control_utility/consistency_test.py b/modules/ducktests/tests/ignitetest/tests/control_utility/consistency_test.py index 72e17e1906679..b18ce7eecaba2 100644 --- a/modules/ducktests/tests/ignitetest/tests/control_utility/consistency_test.py +++ b/modules/ducktests/tests/ignitetest/tests/control_utility/consistency_test.py @@ -32,6 +32,7 @@ from ignitetest.services.ignite_execution_exception import IgniteExecutionException from ignitetest.services.utils.control_utility import ControlUtility from ignitetest.services.utils.ignite_configuration import IgniteConfiguration +from ignitetest.services.utils.ignite_configuration.event_type import EventType from ignitetest.utils import cluster, ignite_versions from ignitetest.utils.ignite_test import IgniteTest from ignitetest.utils.version import DEV_BRANCH, IgniteVersion @@ -43,12 +44,6 @@ class ConsistencyTest(IgniteTest): """ CACHE_NAME = "TEST" - PROPERTIES = """ - - - - """ - @cluster(num_nodes=2) @ignite_versions(str(DEV_BRANCH)) def test_logging(self, ignite_version): @@ -62,7 +57,7 @@ def test_logging(self, ignite_version): IgniteConfiguration( version=IgniteVersion(ignite_version), cluster_state="INACTIVE", - properties=self.PROPERTIES, + include_event_types=[EventType.EVT_CONSISTENCY_VIOLATION], log4j_config=cfg_filename # default AI config (will be generated below) ), java_class_name="org.apache.ignite.internal.ducktest.tests.control_utility.InconsistentNodeApplication", @@ -73,7 +68,7 @@ def test_logging(self, ignite_version): "tx": False }, startup_timeout_sec=180, - num_nodes=len(self.test_context.cluster)) + num_nodes=self.available_cluster_size) for node in ignites.nodes: # copying default AI config with log path replacement ignites.init_persistent(node) diff --git a/modules/ducktests/tests/ignitetest/tests/discovery_test.py b/modules/ducktests/tests/ignitetest/tests/discovery_test.py index 52f80289f780c..80872c156e5e1 100644 --- a/modules/ducktests/tests/ignitetest/tests/discovery_test.py +++ b/modules/ducktests/tests/ignitetest/tests/discovery_test.py @@ -175,7 +175,7 @@ def test_2_nodes_fail_sequential_zk(self, ignite_version, load_type): def _perform_node_fail_scenario(self, test_config): failure_detection_timeout = self._global_int(self.GLOBAL_DETECTION_TIMEOUT, self.DEFAULT_DETECTION_TIMEOUT) - cluster_size = len(self.test_context.cluster) + cluster_size = self.available_cluster_size # One node is required to detect the failure. assert cluster_size >= 1 + test_config.nodes_to_kill + ( diff --git a/modules/ducktests/tests/ignitetest/tests/persistence_upgrade_test.py b/modules/ducktests/tests/ignitetest/tests/persistence_upgrade_test.py index ff6d1cd1c5cd6..91d35c114b072 100644 --- a/modules/ducktests/tests/ignitetest/tests/persistence_upgrade_test.py +++ b/modules/ducktests/tests/ignitetest/tests/persistence_upgrade_test.py @@ -22,7 +22,8 @@ from ignitetest.services.utils.control_utility import ControlUtility from ignitetest.services.utils.ignite_configuration import IgniteConfiguration, DataStorageConfiguration from ignitetest.services.utils.ignite_configuration.data_storage import DataRegionConfiguration -from ignitetest.utils import cluster +from ignitetest.services.utils.ssl.ssl_params import is_ssl_enabled +from ignitetest.utils import cluster, ignite_versions, ignore_if from ignitetest.utils.ignite_test import IgniteTest from ignitetest.utils.version import IgniteVersion, LATEST, DEV_BRANCH, OLDEST @@ -33,8 +34,10 @@ class PersistenceUpgradeTest(IgniteTest): """ @cluster(num_nodes=1) + @ignite_versions(str(OLDEST)) + @ignore_if(lambda _, globals: is_ssl_enabled(globals)) @parametrize(versions=[str(OLDEST), str(LATEST), str(DEV_BRANCH)]) - def upgrade_test(self, versions): + def upgrade_test(self, versions, ignite_version): """ Basic upgrade test. """ diff --git a/modules/ducktests/tests/ignitetest/tests/pme_free_switch_test.py b/modules/ducktests/tests/ignitetest/tests/pme_free_switch_test.py index 23c78c38cc480..a2cd1410f6877 100644 --- a/modules/ducktests/tests/ignitetest/tests/pme_free_switch_test.py +++ b/modules/ducktests/tests/ignitetest/tests/pme_free_switch_test.py @@ -75,7 +75,7 @@ def test(self, ignite_version, load_type): config = IgniteConfiguration(version=IgniteVersion(ignite_version), caches=caches, cluster_state="INACTIVE") - num_nodes = len(self.test_context.cluster) - 2 + num_nodes = self.available_cluster_size - 2 self.test_context.logger.info("Nodes amount calculated as %d." % num_nodes) diff --git a/modules/ducktests/tests/ignitetest/tests/rebalance/util.py b/modules/ducktests/tests/ignitetest/tests/rebalance/util.py index adf2635bd77e6..03f7eeefbdd75 100644 --- a/modules/ducktests/tests/ignitetest/tests/rebalance/util.py +++ b/modules/ducktests/tests/ignitetest/tests/rebalance/util.py @@ -97,7 +97,7 @@ def start_ignite(test_context, ignite_version: str, rebalance_params: RebalanceP :param rebalance_params: Rebalance parameters. :return: IgniteService. """ - node_count = len(test_context.cluster) - rebalance_params.preloaders + node_count = test_context.available_cluster_size - rebalance_params.preloaders if rebalance_params.persistent: data_storage = DataStorageConfiguration( diff --git a/modules/ducktests/tests/ignitetest/tests/snapshot_test.py b/modules/ducktests/tests/ignitetest/tests/snapshot_test.py index 8e1e9d96fe99a..711d2c7ef7984 100644 --- a/modules/ducktests/tests/ignitetest/tests/snapshot_test.py +++ b/modules/ducktests/tests/ignitetest/tests/snapshot_test.py @@ -17,8 +17,6 @@ Module contains snapshot test. """ -from ducktape.mark.resource import cluster - from ignitetest.services.ignite import IgniteService from ignitetest.services.ignite_app import IgniteApplicationService from ignitetest.services.utils.control_utility import ControlUtility @@ -28,6 +26,7 @@ from ignitetest.utils import ignite_versions from ignitetest.utils.ignite_test import IgniteTest from ignitetest.utils.version import IgniteVersion, LATEST, DEV_BRANCH +from ignitetest.utils import cluster class SnapshotTest(IgniteTest): @@ -52,7 +51,7 @@ def snapshot_test(self, ignite_version): metric_exporter='org.apache.ignite.spi.metric.jmx.JmxMetricExporterSpi' ) - nodes = IgniteService(self.test_context, ignite_config, num_nodes=len(self.test_context.cluster) - 1) + nodes = IgniteService(self.test_context, ignite_config, num_nodes=self.available_cluster_size - 1) nodes.start() control_utility = ControlUtility(nodes) diff --git a/modules/ducktests/tests/ignitetest/utils/_mark.py b/modules/ducktests/tests/ignitetest/utils/_mark.py index 28998be477f0f..9d0a06df4edc2 100644 --- a/modules/ducktests/tests/ignitetest/utils/_mark.py +++ b/modules/ducktests/tests/ignitetest/utils/_mark.py @@ -24,6 +24,7 @@ from ducktape.mark._mark import Ignore, Mark, _inject from ignitetest.utils.version import IgniteVersion +from ignitetest.utils.ignite_test import IgniteTestContext class IgnoreIf(Ignore): @@ -161,7 +162,7 @@ def apply(self, seed_context, context_list): if not ctx.cluster_use_metadata: ctx.cluster_use_metadata = self.metadata - return context_list + return list(map(lambda _ctx: IgniteTestContext.resolve(_ctx), context_list)) @staticmethod def _extract_cluster_size(seed_context): @@ -227,7 +228,15 @@ def cluster(**kwargs): - ``cluster_spec`` provide hint about how many nodes of each type the test will consume """ def cluster_use_metadata_adder(func): - Mark.mark(func, ParametrizableClusterMetadata(**kwargs)) - return func + def extended_test(self, *args, **kwargs): + self.test_context.before() + test_result = func(self, *args, **kwargs) + return self.test_context.after(test_result) + + extended_test.__dict__.update(**func.__dict__) + extended_test.__name__ = func.__name__ + + Mark.mark(extended_test, ParametrizableClusterMetadata(**kwargs)) + return extended_test return cluster_use_metadata_adder diff --git a/modules/ducktests/tests/ignitetest/utils/ignite_test.py b/modules/ducktests/tests/ignitetest/utils/ignite_test.py index b2b38cbfa5aa5..5eb7dd669fe59 100644 --- a/modules/ducktests/tests/ignitetest/utils/ignite_test.py +++ b/modules/ducktests/tests/ignitetest/utils/ignite_test.py @@ -16,15 +16,43 @@ """ This module contains basic ignite test. """ +import importlib from time import monotonic from ducktape.cluster.remoteaccount import RemoteCommandError -from ducktape.tests.test import Test +from ducktape.tests.test import Test, TestContext from ignitetest.services.utils.ducktests_service import DucktestsService # globals: JFR_ENABLED = "jfr_enabled" +IGNITE_TEST_CONTEXT_CLASS_KEY_NAME = "IgniteTestContext" + + +class IgniteTestContext(TestContext): + def __init__(self, test_context): + super().__init__() + self.__dict__.update(**test_context.__dict__) + + @property + def available_cluster_size(self): + return len(self.cluster) + + def before(self): + pass + + def after(self, test_result): + return test_result + + @staticmethod + def resolve(test_context): + if IGNITE_TEST_CONTEXT_CLASS_KEY_NAME in test_context.globals: + fqdn = test_context.globals[IGNITE_TEST_CONTEXT_CLASS_KEY_NAME] + (module, clazz) = fqdn.rsplit('.', 1) + module = importlib.import_module(module) + return getattr(module, clazz)(test_context) + else: + return IgniteTestContext(test_context) class IgniteTest(Test): @@ -32,8 +60,16 @@ class IgniteTest(Test): Basic ignite test. """ def __init__(self, test_context): + assert isinstance(test_context, IgniteTestContext),\ + "any IgniteTest MUST BE decorated with the @ignitetest.utils.cluster decorator" + super().__init__(test_context=test_context) + @property + def available_cluster_size(self): + # noinspection PyUnresolvedReferences + return self.test_context.available_cluster_size + @staticmethod def monotonic(): """