diff --git a/devstack/plugin.sh b/devstack/plugin.sh index 7d06c9a3bc..d19526d682 100644 --- a/devstack/plugin.sh +++ b/devstack/plugin.sh @@ -123,6 +123,7 @@ function configure_trove { setup_trove_logging $TROVE_TASKMANAGER_CONF # Increase default timeouts (required by the tests). + iniset $TROVE_TASKMANAGER_CONF DEFAULT agent_call_low_timeout 15 iniset $TROVE_TASKMANAGER_CONF DEFAULT agent_call_high_timeout 300 iniset $TROVE_TASKMANAGER_CONF DEFAULT usage_timeout 1200 fi diff --git a/trove/tests/scenario/groups/root_actions_group.py b/trove/tests/scenario/groups/root_actions_group.py index 0e053a819c..7b64ee2343 100644 --- a/trove/tests/scenario/groups/root_actions_group.py +++ b/trove/tests/scenario/groups/root_actions_group.py @@ -30,6 +30,8 @@ class RootActionsGroup(TestGroup): 'root_actions_runners', 'RootActionsRunner') self.backup_runner = self.get_runner( 'backup_runners', 'BackupRunner') + self.backup_runner2 = self.get_runner( + 'backup_runners', 'BackupRunner') @test def check_root_never_enabled(self): @@ -39,6 +41,7 @@ class RootActionsGroup(TestGroup): @test(depends_on=[check_root_never_enabled]) def disable_root_before_enabled(self): """Ensure disable fails if root was never enabled.""" + self.test_runner.check_root_disable_supported() self.test_runner.run_disable_root_before_enabled() @test(depends_on=[check_root_never_enabled], @@ -77,21 +80,36 @@ class RootActionsGroup(TestGroup): @test(depends_on=[enable_root_with_password]) def check_root_still_enabled(self): """Check the root is still enabled.""" - self.test_runner.run_check_root_still_enabled() + self.test_runner.run_check_root_enabled() @test(depends_on=[check_root_enabled], runs_after=[check_root_still_enabled]) def disable_root(self): """Disable root.""" + self.test_runner.check_root_disable_supported() self.test_runner.run_disable_root() @test(depends_on=[disable_root]) def check_root_still_enabled_after_disable(self): """Check the root is still marked as enabled after disable.""" + self.test_runner.check_root_disable_supported() self.test_runner.run_check_root_still_enabled_after_disable() + @test(depends_on=[check_root_still_enabled_after_disable]) + def backup_root_disabled_instance(self): + """Backup the root-disabled instance.""" + self.test_runner.check_root_disable_supported() + self.backup_runner2.run_backup_create() + self.backup_runner2.run_backup_create_completed() + + @test(depends_on=[backup_root_disabled_instance]) + def restore_root_disabled_instance(self): + """Restore the root-disabled instance.""" + self.test_runner.check_root_disable_supported() + self.backup_runner2.run_restore_from_backup() + @test(depends_on=[restore_root_enabled_instance], - runs_after=[check_root_still_enabled_after_disable]) + runs_after=[restore_root_disabled_instance]) def wait_for_restored_instance(self): """Wait until restoring a root-enabled instance completes.""" self.backup_runner.run_restore_from_backup_completed() @@ -100,10 +118,47 @@ class RootActionsGroup(TestGroup): def check_root_enabled_after_restore(self): """Check the root is also enabled on the restored instance.""" instance_id = self.backup_runner.restore_instance_id - self.test_runner.run_check_root_enabled_after_restore(instance_id) + root_creds = self.test_runner.restored_root_creds + self.test_runner.run_check_root_enabled_after_restore( + instance_id, root_creds) + + @test(depends_on=[restore_root_disabled_instance], + runs_after=[check_root_enabled_after_restore]) + def wait_for_restored_instance2(self): + """Wait until restoring a root-disabled instance completes.""" + self.test_runner.check_root_disable_supported() + self.backup_runner2.run_restore_from_backup_completed() + + @test(depends_on=[wait_for_restored_instance2]) + def check_root_enabled_after_restore2(self): + """Check the root is also enabled on the restored instance.""" + instance_id = self.backup_runner2.restore_instance_id + root_creds = self.test_runner.restored_root_creds2 + self.test_runner.run_check_root_enabled_after_restore2( + instance_id, root_creds) @test(depends_on=[wait_for_restored_instance], runs_after=[check_root_enabled_after_restore]) def delete_restored_instance(self): - """Delete root restored instances.""" + """Delete the restored root-enabled instance.""" self.backup_runner.run_delete_restored_instance() + + @test(depends_on=[backup_root_enabled_instance], + runs_after=[delete_restored_instance]) + def delete_instance_backup(self): + """Delete the root-enabled instance backup.""" + self.backup_runner.run_delete_backup() + + @test(depends_on=[wait_for_restored_instance2], + runs_after=[check_root_enabled_after_restore2]) + def delete_restored_instance2(self): + """Delete the restored root-disabled instance.""" + self.test_runner.check_root_disable_supported() + self.backup_runner2.run_delete_restored_instance() + + @test(depends_on=[backup_root_disabled_instance], + runs_after=[delete_restored_instance2]) + def delete_instance_backup2(self): + """Delete the root-disabled instance backup.""" + self.test_runner.check_root_disable_supported() + self.backup_runner2.run_delete_backup() diff --git a/trove/tests/scenario/helpers/cassandra_helper.py b/trove/tests/scenario/helpers/cassandra_helper.py index 7aad13a6c4..05de19ae6e 100644 --- a/trove/tests/scenario/helpers/cassandra_helper.py +++ b/trove/tests/scenario/helpers/cassandra_helper.py @@ -65,8 +65,10 @@ class CassandraHelper(TestHelper): def create_client(self, host, *args, **kwargs): user = self.get_helper_credentials() - return CassandraClient( - [host], user['name'], user['password'], user['database']) + username = kwargs.get('username', user['name']) + password = kwargs.get('password', user['password']) + database = kwargs.get('database', user['database']) + return CassandraClient([host], username, password, database) def add_actual_data(self, data_label, data_start, data_size, host, *args, **kwargs): @@ -131,6 +133,13 @@ class CassandraHelper(TestHelper): def get_helper_credentials(self): return {'name': 'lite', 'password': 'litepass', 'database': 'firstdb'} + def ping(self, host, *args, **kwargs): + try: + self.get_client(host, *args, **kwargs) + return True + except Exception: + return False + def get_valid_database_definitions(self): return [{"name": 'db1'}, {"name": 'db2'}, {"name": 'db3'}] diff --git a/trove/tests/scenario/helpers/postgresql_helper.py b/trove/tests/scenario/helpers/postgresql_helper.py index 12e029d1c2..87f3dff9e5 100644 --- a/trove/tests/scenario/helpers/postgresql_helper.py +++ b/trove/tests/scenario/helpers/postgresql_helper.py @@ -31,6 +31,9 @@ class PostgresqlHelper(SqlHelper): # for the user to be able to login. return {'name': 'lite', 'password': 'litepass', 'database': 'lite'} + def get_helper_credentials_root(self): + return {'name': 'postgres', 'password': 'rootpass'} + def get_valid_database_definitions(self): return [{'name': 'db1'}, {'name': 'db2'}, {'name': 'db3'}] diff --git a/trove/tests/scenario/helpers/redis_helper.py b/trove/tests/scenario/helpers/redis_helper.py index 7f0ea3b5e4..0c0fcbc01e 100644 --- a/trove/tests/scenario/helpers/redis_helper.py +++ b/trove/tests/scenario/helpers/redis_helper.py @@ -48,7 +48,8 @@ class RedisHelper(TestHelper): def create_client(self, host, *args, **kwargs): user = self.get_helper_credentials() - client = redis.StrictRedis(password=user['password'], host=host) + password = kwargs.get('password', user['password']) + client = redis.StrictRedis(password=password, host=host) return client # Add data overrides @@ -175,3 +176,10 @@ class RedisHelper(TestHelper): def get_invalid_groups(self): return [{'hz': 600}, {'databases': -1}, {'databases': 'string_value'}] + + def ping(self, host, *args, **kwargs): + try: + client = self.get_client(host, *args, **kwargs) + return client.ping() == 'PONG' + except Exception: + return False diff --git a/trove/tests/scenario/helpers/sql_helper.py b/trove/tests/scenario/helpers/sql_helper.py index 905d8bc8e6..03bc43af09 100644 --- a/trove/tests/scenario/helpers/sql_helper.py +++ b/trove/tests/scenario/helpers/sql_helper.py @@ -43,14 +43,12 @@ class SqlHelper(TestHelper): return self.credentials['database'] def create_client(self, host, *args, **kwargs): - username = kwargs.get("username") - password = kwargs.get("password") - if username and password: - creds = {"name": username, "password": password} - return sqlalchemy.create_engine( - self._build_connection_string(host, creds)) + username = kwargs.get('username', self.credentials['name']) + password = kwargs.get('password', self.credentials['password']) + database = kwargs.get('database', self.credentials['database']) + creds = {"name": username, "password": password, "database": database} return sqlalchemy.create_engine( - self._build_connection_string(host, self.credentials)) + self._build_connection_string(host, creds)) def _build_connection_string(self, host, creds): if self.port: @@ -136,8 +134,12 @@ class SqlHelper(TestHelper): return client.execute(data_table.select()).fetchall() def ping(self, host, *args, **kwargs): - root_client = self.get_client(host, *args, **kwargs) - root_client.execute("SELECT 1;") + try: + root_client = self.get_client(host, *args, **kwargs) + root_client.execute("SELECT 1;") + return True + except Exception: + return False def get_configuration_value(self, property_name, host, *args, **kwargs): client = self.get_client(host, *args, **kwargs) diff --git a/trove/tests/scenario/helpers/test_helper.py b/trove/tests/scenario/helpers/test_helper.py index 714cd04be8..bcf45b2597 100644 --- a/trove/tests/scenario/helpers/test_helper.py +++ b/trove/tests/scenario/helpers/test_helper.py @@ -158,6 +158,17 @@ class TestHelper(object): """ return {'name': None, 'password': None, 'database': None} + def ping(self, host, *args, **kwargs): + """Try to connect to a given host and perform a simple read-only + action. + + Return True on success or False otherwise. + """ + pass + + ############## + # Root related + ############## def get_helper_credentials_root(self): """Return the credentials that the client will be using to access the database as root. @@ -433,14 +444,6 @@ class TestHelper(object): """ return False - ############## - # Root related - ############## - def get_valid_root_password(self): - """Return a valid password that can be used by a 'root' user. - """ - return "RootTestPass" - ############## # Module related ############## diff --git a/trove/tests/scenario/runners/cluster_actions_runners.py b/trove/tests/scenario/runners/cluster_actions_runners.py index 8c94b674ab..46310368bd 100644 --- a/trove/tests/scenario/runners/cluster_actions_runners.py +++ b/trove/tests/scenario/runners/cluster_actions_runners.py @@ -133,11 +133,13 @@ class ClusterActionsRunner(TestRunner): root_enabled_test = self.auth_client.root.is_instance_root_enabled( instance['id']) self.assert_true(root_enabled_test.rootEnabled) - self.test_helper.ping( + + ping_response = self.test_helper.ping( cluster.ip[0], username=self.current_root_creds[0], password=self.current_root_creds[1] ) + self.assert_true(ping_response) def run_add_initial_cluster_data(self, data_type=DataType.tiny): self.assert_add_cluster_data(data_type, self.cluster_id) diff --git a/trove/tests/scenario/runners/root_actions_runners.py b/trove/tests/scenario/runners/root_actions_runners.py index 0fe6d81d63..fdcbb05f8d 100644 --- a/trove/tests/scenario/runners/root_actions_runners.py +++ b/trove/tests/scenario/runners/root_actions_runners.py @@ -23,6 +23,8 @@ class RootActionsRunner(TestRunner): def __init__(self): self.current_root_creds = None + self.restored_root_creds = None + self.restored_root_creds2 = None super(RootActionsRunner, self).__init__() def run_check_root_never_enabled(self, expected_http_code=200): @@ -53,20 +55,45 @@ class RootActionsRunner(TestRunner): self.auth_client.root.delete, instance_id) def run_enable_root_no_password(self, expected_http_code=200): + root_credentials = self.test_helper.get_helper_credentials_root() self.current_root_creds = self.assert_root_create( - self.instance_info.id, None, expected_http_code) + self.instance_info.id, None, root_credentials['name'], + expected_http_code) + self.restored_root_creds = list(self.current_root_creds) def assert_root_create(self, instance_id, root_password, - expected_http_code): - if root_password: + expected_root_name, expected_http_code): + if root_password is not None: root_creds = self.auth_client.root.create_instance_root( instance_id, root_password) + self.assert_equal(root_password, root_creds[1]) else: root_creds = self.auth_client.root.create(instance_id) + if expected_root_name is not None: + self.assert_equal(expected_root_name, root_creds[0]) + self.assert_instance_action(instance_id, None, expected_http_code) + self.assert_can_connect(instance_id, root_creds) + return root_creds + def assert_can_connect(self, instance_id, test_connect_creds): + self._assert_connect(instance_id, True, test_connect_creds) + + def _assert_connect( + self, instance_id, expected_response, test_connect_creds): + host = self.get_instance_host(instance_id=instance_id) + self.report.log("Pinging instance %s with credentials: %s" + % (instance_id, test_connect_creds)) + + ping_response = self.test_helper.ping( + host, + username=test_connect_creds[0], + password=test_connect_creds[1] + ) + self.assert_equal(expected_response, ping_response) + def run_check_root_enabled(self, expected_http_code=200): self.assert_root_enabled(self.instance_info.id, expected_http_code) @@ -76,19 +103,29 @@ class RootActionsRunner(TestRunner): "instance yet.") def run_enable_root_with_password(self, expected_http_code=200): - password = self.test_helper.get_valid_root_password() - self.current_root_creds = self.assert_root_create( - self.instance_info.id, password, expected_http_code) - - def run_check_root_still_enabled(self, expected_http_code=200): - self.assert_root_enabled(self.instance_info.id, expected_http_code) + root_credentials = self.test_helper.get_helper_credentials_root() + password = root_credentials['password'] + if password is not None: + self.current_root_creds = self.assert_root_create( + self.instance_info.id, + password, root_credentials['name'], + expected_http_code) + else: + raise SkipTest("No valid root password defined in %s." + % self.test_helper.get_class_name()) def run_disable_root(self, expected_http_code=200): + self.restored_root_creds2 = list(self.current_root_creds) self.assert_root_disable(self.instance_info.id, expected_http_code) def assert_root_disable(self, instance_id, expected_http_code): self.auth_client.root.delete(instance_id) self.assert_instance_action(instance_id, None, expected_http_code) + self.assert_cannot_connect(self.instance_info.id, + self.current_root_creds) + + def assert_cannot_connect(self, instance_id, test_connect_creds): + self._assert_connect(instance_id, False, test_connect_creds) def run_check_root_still_enabled_after_disable( self, expected_http_code=200): @@ -106,75 +143,64 @@ class RootActionsRunner(TestRunner): self.auth_client.users.delete, instance_id, root_user_name) - def run_check_root_enabled_after_restore(self, restored_instance_id, - expected_http_code=200): + def run_check_root_enabled_after_restore( + self, restored_instance_id, restored_creds, + expected_http_code=200): + self.assert_root_enabled_after_restore( + restored_instance_id, restored_creds, True, expected_http_code) + + def run_check_root_enabled_after_restore2( + self, restored_instance_id, restored_creds, + expected_http_code=200): + self.assert_root_enabled_after_restore( + restored_instance_id, restored_creds, False, expected_http_code) + + def assert_root_enabled_after_restore( + self, restored_instance_id, restored_creds, + expected_connect_response, expected_http_code): if restored_instance_id: self.assert_root_enabled(restored_instance_id, expected_http_code) + self._assert_connect(restored_instance_id, + expected_connect_response, restored_creds) else: - raise SkipTest("No instance with enabled root restored.") + raise SkipTest("No restored instance.") - -class MysqlRootActionsRunner(RootActionsRunner): - - def run_enable_root_with_password(self): - raise SkipTest("Operation is currently not supported.") + def check_root_disable_supported(self): + """Throw SkipTest if root-disable is not supported.""" + pass class PerconaRootActionsRunner(RootActionsRunner): - def run_disable_root_before_enabled(self): - raise SkipTest("Operation is currently not supported.") - - def run_enable_root_with_password(self): - raise SkipTest("Operation is currently not supported.") - - def run_disable_root(self): + def check_root_disable_supported(self): raise SkipTest("Operation is currently not supported.") class MariadbRootActionsRunner(RootActionsRunner): - def run_disable_root_before_enabled(self): - raise SkipTest("Operation is currently not supported.") - - def run_enable_root_with_password(self): - raise SkipTest("Operation is currently not supported.") - - def run_disable_root(self): - raise SkipTest("Operation is currently not supported.") - - -class PostgresqlRootActionsRunner(RootActionsRunner): - - def run_disable_root_before_enabled(self): - raise SkipTest("Operation is currently not supported.") - - def run_enable_root_with_password(self): - raise SkipTest("Operation is currently not supported.") - - def run_disable_root(self): - raise SkipTest("Operation is currently not supported.") - - -class CouchbaseRootActionsRunner(RootActionsRunner): - - def run_disable_root_before_enabled(self): - raise SkipTest("Operation is currently not supported.") - - def run_enable_root_with_password(self): - raise SkipTest("Operation is currently not supported.") - - def run_disable_root(self): + def check_root_disable_supported(self): raise SkipTest("Operation is currently not supported.") class PxcRootActionsRunner(RootActionsRunner): - def run_disable_root_before_enabled(self): + def check_root_disable_supported(self): raise SkipTest("Operation is currently not supported.") - def run_disable_root(self): + +class PostgresqlRootActionsRunner(RootActionsRunner): + + def check_root_disable_supported(self): raise SkipTest("Operation is currently not supported.") - def check_root_still_enabled_after_disable(self): + def run_enable_root_with_password(self): + raise SkipTest("Operation is currently not supported.") + + +class CouchbaseRootActionsRunner(RootActionsRunner): + + def check_root_disable_supported(self): + raise SkipTest("Operation is currently not supported.") + + def run_enable_root_with_password(self): raise SkipTest("Operation is currently not supported.")