Add root-actions int-tests

Add new scenario integration tests for root-related actions.

Closes-Bug: 1529965
Change-Id: Id317eacc5a028317d07a70c183173099d3125a43
This commit is contained in:
Petr Malik 2015-12-21 18:15:13 -05:00 committed by Peter Stachowski
parent fac6e76b54
commit d1bb391d30
7 changed files with 266 additions and 13 deletions

View File

@ -42,6 +42,7 @@ from trove.tests.scenario.groups import instance_create_group
from trove.tests.scenario.groups import instance_delete_group
from trove.tests.scenario.groups import negative_cluster_actions_group
from trove.tests.scenario.groups import replication_group
from trove.tests.scenario.groups import root_actions_group
from trove.tests.scenario.groups import user_actions_group
@ -157,6 +158,9 @@ instance_actions_groups.extend([instance_actions_group.GROUP])
replication_groups = list(instance_create_groups)
replication_groups.extend([replication_group.GROUP])
root_actions_groups = list(instance_create_groups)
root_actions_groups.extend([root_actions_group.GROUP])
user_actions_groups = list(instance_create_groups)
user_actions_groups.extend([user_actions_group.GROUP])
@ -173,6 +177,7 @@ register(["guest_log"], guest_log_groups)
register(["instance", "instance_actions"], instance_actions_groups)
register(["instance_create"], instance_create_groups)
register(["replication"], replication_groups)
register(["root"], root_actions_groups)
register(["user"], user_actions_groups)
# Register: Datastore based groups
@ -181,21 +186,22 @@ register(["db2_supported"], common_groups,
database_actions_groups, user_actions_groups)
register(["cassandra_supported"], common_groups,
backup_groups, configuration_groups)
register(["couchbase_supported"], common_groups, backup_groups)
register(["couchbase_supported"], common_groups, backup_groups,
root_actions_groups)
register(["couchdb_supported"], common_groups)
register(["postgresql_supported"], common_groups,
backup_groups, database_actions_groups, configuration_groups,
user_actions_groups)
root_actions_groups, user_actions_groups)
register(["mariadb_supported", "mysql_supported", "percona_supported"],
common_groups,
backup_groups, configuration_groups, database_actions_groups,
replication_groups, user_actions_groups)
replication_groups, root_actions_groups, user_actions_groups)
register(["mongodb_supported"], common_groups,
backup_groups, cluster_actions_groups, configuration_groups,
database_actions_groups, user_actions_groups)
database_actions_groups, root_actions_groups, user_actions_groups)
register(["pxc_supported"], common_groups,
cluster_actions_groups)
cluster_actions_groups, root_actions_groups)
register(["redis_supported"], common_groups,
backup_groups, replication_groups)
register(["vertica_supported"], common_groups,
cluster_actions_groups)
cluster_actions_groups, root_actions_groups)

View File

@ -21,6 +21,7 @@ from trove.tests.scenario.groups import database_actions_group
from trove.tests.scenario.groups import instance_actions_group
from trove.tests.scenario.groups import instance_create_group
from trove.tests.scenario.groups import replication_group
from trove.tests.scenario.groups import root_actions_group
from trove.tests.scenario.groups.test_group import TestGroup
from trove.tests.scenario.groups import user_actions_group
@ -35,6 +36,7 @@ GROUP = "scenario.instance_delete_group"
database_actions_group.GROUP,
instance_actions_group.GROUP,
replication_group.GROUP,
root_actions_group.GROUP,
user_actions_group.GROUP])
class InstanceDeleteGroup(TestGroup):

View File

@ -0,0 +1,103 @@
# Copyright 2015 Tesora Inc.
# All Rights Reserved.
#
# Licensed 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 proboscis import test
from trove.tests.scenario.groups import instance_create_group
from trove.tests.scenario.groups.test_group import TestGroup
GROUP = "scenario.root_actions_group"
@test(depends_on_groups=[instance_create_group.GROUP], groups=[GROUP])
class RootActionsGroup(TestGroup):
def __init__(self):
super(RootActionsGroup, self).__init__(
'root_actions_runners', 'RootActionsRunner')
self.backup_runner = self.get_runner(
'backup_runners', 'BackupRunner')
@test
def check_root_never_enabled(self):
"""Check the root has never been enabled on the instance."""
self.test_runner.run_check_root_never_enabled()
@test(depends_on=[check_root_never_enabled])
def disable_root_before_enabled(self):
"""Ensure disable fails if root was never enabled."""
self.test_runner.run_disable_root_before_enabled()
@test(depends_on=[check_root_never_enabled],
runs_after=[disable_root_before_enabled])
def enable_root_no_password(self):
"""Enable root (without specifying a password)."""
self.test_runner.run_enable_root_no_password()
@test(depends_on=[enable_root_no_password])
def check_root_enabled(self):
"""Check the root is now enabled."""
self.test_runner.run_check_root_enabled()
@test(depends_on=[check_root_enabled])
def backup_root_enabled_instance(self):
"""Backup the root-enabled instance."""
self.backup_runner.run_backup_create()
self.backup_runner.run_backup_create_completed()
@test(depends_on=[backup_root_enabled_instance])
def restore_root_enabled_instance(self):
"""Restore the root-enabled instance."""
self.backup_runner.run_restore_from_backup()
@test(depends_on=[check_root_enabled])
def delete_root(self):
"""Ensure an attempt to delete the root user fails."""
self.test_runner.run_delete_root()
@test(depends_on=[check_root_never_enabled],
runs_after=[delete_root])
def enable_root_with_password(self):
"""Enable root (with a given password)."""
self.test_runner.run_enable_root_with_password()
@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()
@test(depends_on=[check_root_enabled],
runs_after=[check_root_still_enabled])
def disable_root(self):
"""Disable root."""
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.run_check_root_still_enabled_after_disable()
@test(depends_on=[restore_root_enabled_instance],
runs_after=[check_root_still_enabled_after_disable])
def wait_for_restored_instance(self):
"""Wait until restoring a root-enabled instance completes."""
self.backup_runner.run_restore_from_backup_completed()
@test(depends_on=[wait_for_restored_instance])
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)

View File

@ -419,3 +419,11 @@ class TestHelper(object):
restart of the datastore.
"""
return False
##############
# Root related
##############
def get_valid_root_password(self):
"""Return a valid password that can be used by a 'root' user.
"""
return "RootTestPass"

View File

@ -77,6 +77,12 @@ class InstanceCreateRunner(TestRunner):
self, with_dbs=True, with_users=True, configuration_id=None,
expected_states=['BUILD', 'ACTIVE'], expected_http_code=200,
create_helper_user=True):
if self.is_using_existing_instance:
# The user requested to run the tests using an existing instance.
# We therefore skip any scenarios that involve creating new
# test instances.
raise SkipTest("Using an existing instance.")
name = self.instance_info.name + '_init'
flavor = self._get_instance_flavor()
trove_volume_size = CONFIG.get('trove_volume_size', 1)
@ -87,9 +93,6 @@ class InstanceCreateRunner(TestRunner):
if configuration_id:
self.init_config_group_id = configuration_id
if self.is_using_existing_instance:
raise SkipTest("Using existing instance.")
if (self.init_inst_dbs or self.init_inst_users or
self.init_config_group_id):
info = self.assert_instance_create(
@ -230,8 +233,6 @@ class InstanceCreateRunner(TestRunner):
instances = [self.instance_info.id]
if self.init_inst_id:
instances.append(self.init_inst_id)
if self.is_using_existing_instance:
expected_states = ['ACTIVE']
self.assert_all_instance_states(instances, expected_states)
def run_add_initialized_instance_data(self):

View File

@ -0,0 +1,132 @@
# Copyright 2015 Tesora Inc.
# All Rights Reserved.
#
# Licensed 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 proboscis import SkipTest
from trove.tests.scenario.runners.test_runners import TestRunner
from troveclient.compat import exceptions
class RootActionsRunner(TestRunner):
def __init__(self):
self.current_root_creds = None
super(RootActionsRunner, self).__init__()
def run_check_root_never_enabled(self, expected_http_code=200):
self.assert_root_disabled(self.instance_info.id, expected_http_code)
def assert_root_disabled(self, instance_id, expected_http_code):
self._assert_root_state(instance_id, False, expected_http_code,
"The root has already been enabled on the "
"instance.")
def _assert_root_state(self, instance_id, expected_state,
expected_http_code, message):
# The call returns a nameless user object with 'rootEnabled' attribute.
response = self.auth_client.root.is_root_enabled(instance_id)
self.assert_instance_action(instance_id, None, expected_http_code)
actual_state = getattr(response, 'rootEnabled', None)
self.assert_equal(expected_state, actual_state, message)
def run_disable_root_before_enabled(
self, expected_exception=exceptions.NotFound,
expected_http_code=404):
self.assert_root_disable_failure(
self.instance_info.id, expected_exception, expected_http_code)
def assert_root_disable_failure(self, instance_id, expected_exception,
expected_http_code):
self.assert_raises(expected_exception, expected_http_code,
self.auth_client.root.delete, instance_id)
def run_enable_root_no_password(self, expected_http_code=200):
self.current_root_creds = self.assert_root_create(
self.instance_info.id, None, expected_http_code)
def assert_root_create(self, instance_id, root_password,
expected_http_code):
if root_password:
root_creds = self.auth_client.root.create_instance_root(
instance_id, root_password)
else:
root_creds = self.auth_client.root.create(instance_id)
self.assert_instance_action(instance_id, None, expected_http_code)
return root_creds
def run_check_root_enabled(self, expected_http_code=200):
self.assert_root_enabled(self.instance_info.id, expected_http_code)
def assert_root_enabled(self, instance_id, expected_http_code):
self._assert_root_state(instance_id, True, expected_http_code,
"The root has not been enabled on the "
"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)
def run_disable_root(self, expected_http_code=200):
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)
def run_check_root_still_enabled_after_disable(
self, expected_http_code=200):
self.assert_root_enabled(self.instance_info.id, expected_http_code)
def run_delete_root(self, expected_exception=exceptions.BadRequest,
expected_http_code=400):
self.assert_root_delete_failure(
self.instance_info.id, expected_exception, expected_http_code)
def assert_root_delete_failure(self, instance_id, expected_exception,
expected_http_code):
root_user_name = self.current_root_creds[0]
self.assert_raises(expected_exception, expected_http_code,
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):
if restored_instance_id:
self.assert_root_enabled(restored_instance_id, expected_http_code)
else:
raise SkipTest("No instance with enabled root restored.")
class MysqlRootActionsRunner(RootActionsRunner):
def run_enable_root_with_password(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):
raise SkipTest("Operation is currently not supported.")

View File

@ -265,7 +265,7 @@ class TestRunner(object):
self.fail(str(task.poll_exception()))
def _assert_instance_states(self, instance_id, expected_states,
fast_fail_status='ERROR',
fast_fail_status=['ERROR', 'FAILED'],
require_all_states=False):
"""Keep polling for the expected instance states until the instance
acquires either the last or fast-fail state.
@ -357,10 +357,11 @@ class TestRunner(object):
sleep_time=sleep_time, time_out=time_out)
def _has_status(self, instance_id, status, fast_fail_status=None):
fast_fail_status = fast_fail_status or []
instance = self.get_instance(instance_id)
self.report.log("Polling instance '%s' for state '%s', was '%s'."
% (instance_id, status, instance.status))
if fast_fail_status and instance.status == fast_fail_status:
if instance.status in fast_fail_status:
raise RuntimeError("Instance '%s' acquired a fast-fail status: %s"
% (instance_id, instance.status))
return instance.status == status