Merge "Add support for configuration groups in int-tests"
This commit is contained in:
commit
45d1936e32
@ -34,6 +34,7 @@ from trove.tests.api import users
|
||||
from trove.tests.api import versions
|
||||
from trove.tests.scenario.groups import backup_group
|
||||
from trove.tests.scenario.groups import cluster_actions_group
|
||||
from trove.tests.scenario.groups import configuration_group
|
||||
from trove.tests.scenario.groups import database_actions_group
|
||||
from trove.tests.scenario.groups import guest_log_group
|
||||
from trove.tests.scenario.groups import instance_actions_group
|
||||
@ -120,6 +121,7 @@ proboscis.register(groups=["blackbox_mgmt"],
|
||||
#
|
||||
# Group designations for datastore agnostic int-tests
|
||||
#
|
||||
# Base groups for all other groups
|
||||
base_groups = [
|
||||
GROUP_SERVICES_INITIALIZE,
|
||||
flavors.GROUP,
|
||||
@ -127,12 +129,12 @@ base_groups = [
|
||||
GROUP_SETUP
|
||||
]
|
||||
|
||||
# cluster groups
|
||||
# Cluster-based groups
|
||||
cluster_actions_groups = list(base_groups)
|
||||
cluster_actions_groups.extend([cluster_actions_group.GROUP,
|
||||
negative_cluster_actions_group.GROUP])
|
||||
|
||||
# instance groups
|
||||
# Single-instance based groups
|
||||
instance_create_groups = list(base_groups)
|
||||
instance_create_groups.extend([instance_create_group.GROUP,
|
||||
instance_delete_group.GROUP])
|
||||
@ -140,8 +142,8 @@ instance_create_groups.extend([instance_create_group.GROUP,
|
||||
backup_groups = list(instance_create_groups)
|
||||
backup_groups.extend([backup_group.GROUP])
|
||||
|
||||
user_actions_groups = list(instance_create_groups)
|
||||
user_actions_groups.extend([user_actions_group.GROUP])
|
||||
configuration_groups = list(instance_create_groups)
|
||||
configuration_groups.extend([configuration_group.GROUP])
|
||||
|
||||
database_actions_groups = list(instance_create_groups)
|
||||
database_actions_groups.extend([database_actions_group.GROUP])
|
||||
@ -155,40 +157,45 @@ instance_actions_groups.extend([instance_actions_group.GROUP])
|
||||
replication_groups = list(instance_create_groups)
|
||||
replication_groups.extend([replication_group.GROUP])
|
||||
|
||||
user_actions_groups = list(instance_create_groups)
|
||||
user_actions_groups.extend([user_actions_group.GROUP])
|
||||
|
||||
# groups common to all datastores
|
||||
common_groups = list(instance_actions_groups)
|
||||
common_groups.extend([guest_log_groups])
|
||||
|
||||
# Module based groups
|
||||
# Register: Module based groups
|
||||
register(["backup"], backup_groups)
|
||||
register(["cluster"], cluster_actions_groups)
|
||||
register(["configuration"], configuration_groups)
|
||||
register(["database"], database_actions_groups)
|
||||
register(["guest_log"], guest_log_groups)
|
||||
register(["instance", "instance_actions"], instance_actions_groups)
|
||||
register(["instance_create"], instance_create_groups)
|
||||
register(["user"], user_actions_groups)
|
||||
register(["replication"], replication_groups)
|
||||
register(["user"], user_actions_groups)
|
||||
|
||||
# Datastore based groups - these should contain all functionality
|
||||
# currently supported by the datastore
|
||||
# Register: Datastore based groups
|
||||
# These should contain all functionality currently supported by the datastore
|
||||
register(["db2_supported"], common_groups,
|
||||
database_actions_groups, user_actions_groups)
|
||||
register(["cassandra_supported"], common_groups,
|
||||
backup_groups)
|
||||
register(["couchbase_supported"], common_groups)
|
||||
backup_groups, configuration_groups)
|
||||
register(["couchbase_supported"], common_groups, backup_groups)
|
||||
register(["couchdb_supported"], common_groups)
|
||||
register(["postgresql_supported"], common_groups,
|
||||
backup_groups, database_actions_groups, user_actions_groups)
|
||||
register(["mongodb_supported"], common_groups,
|
||||
backup_groups, cluster_actions_groups,
|
||||
database_actions_groups, user_actions_groups)
|
||||
register(["mysql_supported", "mariadb_supported", "percona_supported"],
|
||||
backup_groups, database_actions_groups, configuration_groups,
|
||||
user_actions_groups)
|
||||
register(["mariadb_supported", "mysql_supported", "percona_supported"],
|
||||
common_groups,
|
||||
backup_groups, database_actions_groups,
|
||||
backup_groups, configuration_groups, database_actions_groups,
|
||||
replication_groups, user_actions_groups)
|
||||
register(["mongodb_supported"], common_groups,
|
||||
backup_groups, cluster_actions_groups, configuration_groups,
|
||||
database_actions_groups, user_actions_groups)
|
||||
register(["pxc_supported"], common_groups,
|
||||
cluster_actions_groups)
|
||||
register(["redis_supported"], common_groups,
|
||||
backup_groups, replication_groups)
|
||||
register(["vertica_supported"], common_groups,
|
||||
cluster_actions_groups)
|
||||
register(["pxc_supported"], common_groups,
|
||||
cluster_actions_groups)
|
||||
register(["db2_supported"], common_groups,
|
||||
database_actions_groups, user_actions_groups)
|
||||
|
232
trove/tests/scenario/groups/configuration_group.py
Normal file
232
trove/tests/scenario/groups/configuration_group.py
Normal file
@ -0,0 +1,232 @@
|
||||
# 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.configuration_group"
|
||||
|
||||
|
||||
@test(depends_on_groups=[instance_create_group.GROUP], groups=[GROUP])
|
||||
class ConfigurationGroup(TestGroup):
|
||||
|
||||
def __init__(self):
|
||||
super(ConfigurationGroup, self).__init__(
|
||||
'configuration_runners', 'ConfigurationRunner')
|
||||
|
||||
@test
|
||||
def create_bad_group(self):
|
||||
"""Ensure a group with bad entries fails create."""
|
||||
self.test_runner.run_create_bad_group()
|
||||
|
||||
@test
|
||||
def create_invalid_groups(self):
|
||||
"""Ensure a group with invalid entries fails create."""
|
||||
self.test_runner.run_create_invalid_groups()
|
||||
|
||||
@test
|
||||
def delete_non_existent_group(self):
|
||||
"""Ensure delete non-existent group fails."""
|
||||
self.test_runner.run_delete_non_existent_group()
|
||||
|
||||
@test
|
||||
def delete_bad_group_id(self):
|
||||
"""Ensure delete bad group fails."""
|
||||
self.test_runner.run_delete_bad_group_id()
|
||||
|
||||
@test
|
||||
def attach_non_existent_group(self):
|
||||
"""Ensure attach non-existent group fails."""
|
||||
self.test_runner.run_attach_non_existent_group()
|
||||
|
||||
def attach_non_existent_group_to_non_existent_inst(self):
|
||||
"""Ensure attach non-existent group to non-existent inst fails."""
|
||||
self.test_runner.run_attach_non_existent_group_to_non_existent_inst()
|
||||
|
||||
@test
|
||||
def detach_group_with_none_attached(self):
|
||||
"""Test detach with none attached."""
|
||||
self.test_runner.run_detach_group_with_none_attached()
|
||||
|
||||
@test
|
||||
def create_dynamic_group(self):
|
||||
"""Create a group with only dynamic entries."""
|
||||
self.test_runner.run_create_dynamic_group()
|
||||
|
||||
@test
|
||||
def create_non_dynamic_group(self):
|
||||
"""Create a group with only non-dynamic entries."""
|
||||
self.test_runner.run_create_non_dynamic_group()
|
||||
|
||||
@test(depends_on=[create_dynamic_group])
|
||||
def attach_dynamic_group_to_non_existent_inst(self):
|
||||
"""Ensure attach dynamic group to non-existent inst fails."""
|
||||
self.test_runner.run_attach_dynamic_group_to_non_existent_inst()
|
||||
|
||||
@test(depends_on=[create_non_dynamic_group])
|
||||
def attach_non_dynamic_group_to_non_existent_inst(self):
|
||||
"""Ensure attach non-dynamic group to non-existent inst fails."""
|
||||
self.test_runner.run_attach_non_dynamic_group_to_non_existent_inst()
|
||||
|
||||
@test(depends_on=[create_dynamic_group, create_non_dynamic_group])
|
||||
def list_configuration_groups(self):
|
||||
"""Test list configuration groups."""
|
||||
self.test_runner.run_list_configuration_groups()
|
||||
|
||||
@test(depends_on=[create_dynamic_group])
|
||||
def dynamic_configuration_show(self):
|
||||
"""Test show on dynamic group."""
|
||||
self.test_runner.run_dynamic_configuration_show()
|
||||
|
||||
@test(depends_on=[create_non_dynamic_group])
|
||||
def non_dynamic_configuration_show(self):
|
||||
"""Test show on non-dynamic group."""
|
||||
self.test_runner.run_non_dynamic_configuration_show()
|
||||
|
||||
@test(depends_on=[create_dynamic_group])
|
||||
def dynamic_conf_get_unauthorized_user(self):
|
||||
"""Ensure show dynamic fails with unauthorized user."""
|
||||
self.test_runner.run_dynamic_conf_get_unauthorized_user()
|
||||
|
||||
@test(depends_on=[create_non_dynamic_group])
|
||||
def non_dynamic_conf_get_unauthorized_user(self):
|
||||
"""Ensure show non-dynamic fails with unauthorized user."""
|
||||
self.test_runner.run_non_dynamic_conf_get_unauthorized_user()
|
||||
|
||||
@test(depends_on=[create_dynamic_group],
|
||||
runs_after=[list_configuration_groups])
|
||||
def list_dynamic_inst_conf_groups_before(self):
|
||||
"""Count list instances for dynamic group before attach."""
|
||||
self.test_runner.run_list_dynamic_inst_conf_groups_before()
|
||||
|
||||
@test(depends_on=[create_dynamic_group],
|
||||
runs_after=[list_dynamic_inst_conf_groups_before,
|
||||
attach_non_existent_group,
|
||||
detach_group_with_none_attached])
|
||||
def attach_dynamic_group(self):
|
||||
"""Test attach dynamic group."""
|
||||
self.test_runner.run_attach_dynamic_group()
|
||||
|
||||
@test(depends_on=[attach_dynamic_group])
|
||||
def list_dynamic_inst_conf_groups_after(self):
|
||||
"""Test list instances for dynamic group after attach."""
|
||||
self.test_runner.run_list_dynamic_inst_conf_groups_after()
|
||||
|
||||
@test(depends_on=[attach_dynamic_group],
|
||||
runs_after=[list_dynamic_inst_conf_groups_after])
|
||||
def attach_dynamic_group_again(self):
|
||||
"""Ensure attaching dynamic group again fails."""
|
||||
self.test_runner.run_attach_dynamic_group_again()
|
||||
|
||||
@test(depends_on=[attach_dynamic_group],
|
||||
runs_after=[attach_dynamic_group_again])
|
||||
def delete_attached_dynamic_group(self):
|
||||
"""Ensure deleting attached dynamic group fails."""
|
||||
self.test_runner.run_delete_attached_dynamic_group()
|
||||
|
||||
@test(depends_on=[attach_dynamic_group],
|
||||
runs_after=[delete_attached_dynamic_group])
|
||||
def update_dynamic_group(self):
|
||||
"""Test update dynamic group."""
|
||||
self.test_runner.run_update_dynamic_group()
|
||||
|
||||
@test(depends_on=[create_dynamic_group],
|
||||
runs_after=[update_dynamic_group])
|
||||
def detach_dynamic_group(self):
|
||||
"""Test detach dynamic group."""
|
||||
self.test_runner.run_detach_dynamic_group()
|
||||
|
||||
@test(depends_on=[create_non_dynamic_group],
|
||||
runs_after=[detach_dynamic_group])
|
||||
def list_non_dynamic_inst_conf_groups_before(self):
|
||||
"""Count list instances for non-dynamic group before attach."""
|
||||
self.test_runner.run_list_non_dynamic_inst_conf_groups_before()
|
||||
|
||||
@test(depends_on=[create_non_dynamic_group],
|
||||
runs_after=[list_non_dynamic_inst_conf_groups_before,
|
||||
attach_non_existent_group])
|
||||
def attach_non_dynamic_group(self):
|
||||
"""Test attach non-dynamic group."""
|
||||
self.test_runner.run_attach_non_dynamic_group()
|
||||
|
||||
@test(depends_on=[attach_non_dynamic_group])
|
||||
def list_non_dynamic_inst_conf_groups_after(self):
|
||||
"""Test list instances for non-dynamic group after attach."""
|
||||
self.test_runner.run_list_non_dynamic_inst_conf_groups_after()
|
||||
|
||||
@test(depends_on=[attach_non_dynamic_group],
|
||||
runs_after=[list_non_dynamic_inst_conf_groups_after])
|
||||
def attach_non_dynamic_group_again(self):
|
||||
"""Ensure attaching non-dynamic group again fails."""
|
||||
self.test_runner.run_attach_non_dynamic_group_again()
|
||||
|
||||
@test(depends_on=[attach_non_dynamic_group],
|
||||
runs_after=[attach_non_dynamic_group_again])
|
||||
def delete_attached_non_dynamic_group(self):
|
||||
"""Ensure deleting attached non-dynamic group fails."""
|
||||
self.test_runner.run_delete_attached_non_dynamic_group()
|
||||
|
||||
@test(depends_on=[attach_non_dynamic_group],
|
||||
runs_after=[delete_attached_non_dynamic_group])
|
||||
def update_non_dynamic_group(self):
|
||||
"""Test update non-dynamic group."""
|
||||
self.test_runner.run_update_non_dynamic_group()
|
||||
|
||||
@test(depends_on=[attach_non_dynamic_group],
|
||||
runs_after=[update_non_dynamic_group])
|
||||
def detach_non_dynamic_group(self):
|
||||
"""Test detach non-dynamic group."""
|
||||
self.test_runner.run_detach_non_dynamic_group()
|
||||
|
||||
@test(runs_after=[create_dynamic_group, create_non_dynamic_group,
|
||||
update_dynamic_group, update_non_dynamic_group])
|
||||
def create_instance_with_conf(self):
|
||||
"""Test create instance with conf group."""
|
||||
self.test_runner.run_create_instance_with_conf()
|
||||
|
||||
@test(depends_on=[create_instance_with_conf],
|
||||
runs_after=[create_dynamic_group, create_non_dynamic_group,
|
||||
update_dynamic_group, update_non_dynamic_group])
|
||||
def wait_for_conf_instance(self):
|
||||
"""Test create instance with conf group completes."""
|
||||
self.test_runner.run_wait_for_conf_instance()
|
||||
|
||||
@test(depends_on=[wait_for_conf_instance])
|
||||
def delete_conf_instance(self):
|
||||
"""Test delete instance with conf group."""
|
||||
self.test_runner.run_delete_conf_instance()
|
||||
|
||||
@test(depends_on=[create_dynamic_group],
|
||||
runs_after=[list_configuration_groups, detach_dynamic_group,
|
||||
dynamic_configuration_show,
|
||||
dynamic_conf_get_unauthorized_user,
|
||||
attach_dynamic_group_to_non_existent_inst,
|
||||
delete_conf_instance])
|
||||
def delete_dynamic_group(self):
|
||||
"""Test delete dynamic group."""
|
||||
self.test_runner.run_delete_dynamic_group()
|
||||
|
||||
@test(depends_on=[create_non_dynamic_group],
|
||||
runs_after=[list_configuration_groups, detach_non_dynamic_group,
|
||||
non_dynamic_configuration_show,
|
||||
non_dynamic_conf_get_unauthorized_user,
|
||||
attach_non_dynamic_group_to_non_existent_inst,
|
||||
delete_conf_instance])
|
||||
def delete_non_dynamic_group(self):
|
||||
"""Test delete non-dynamic group."""
|
||||
self.test_runner.run_delete_non_dynamic_group()
|
@ -16,6 +16,7 @@
|
||||
from proboscis import test
|
||||
|
||||
from trove.tests.scenario.groups import backup_group
|
||||
from trove.tests.scenario.groups import configuration_group
|
||||
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
|
||||
@ -30,6 +31,7 @@ GROUP = "scenario.instance_delete_group"
|
||||
@test(depends_on_groups=[instance_create_group.GROUP],
|
||||
groups=[GROUP],
|
||||
runs_after_groups=[backup_group.GROUP_BACKUP,
|
||||
configuration_group.GROUP,
|
||||
database_actions_group.GROUP,
|
||||
instance_actions_group.GROUP,
|
||||
replication_group.GROUP,
|
||||
|
@ -58,22 +58,40 @@ class TestGroup(object):
|
||||
"""Try to load a datastore specific class if it exists; use the
|
||||
default otherwise.
|
||||
"""
|
||||
try:
|
||||
# This is for overridden Runner classes
|
||||
impl = self._build_class_path(module_name, class_prefix, base_name)
|
||||
return Strategy.get_strategy(impl, namespace)
|
||||
except ImportError:
|
||||
pass
|
||||
try:
|
||||
# This is for overridden Runner classes
|
||||
impl = self._build_class_path(module_name,
|
||||
class_prefix, base_name)
|
||||
cls = self._load_class('runner', impl, namespace)
|
||||
|
||||
if not cls:
|
||||
# This is for overridden Helper classes
|
||||
module = module_name.replace('test', class_prefix.lower())
|
||||
impl = self._build_class_path(module, class_prefix, base_name,
|
||||
strip_test=True)
|
||||
return Strategy.get_strategy(impl, namespace)
|
||||
except ImportError:
|
||||
cls = self._load_class('helper', impl, namespace)
|
||||
|
||||
if not cls:
|
||||
# Just import the base class
|
||||
impl = self._build_class_path(module_name, '', base_name)
|
||||
return Strategy.get_strategy(impl, namespace)
|
||||
cls = self._load_class(None, impl, namespace)
|
||||
|
||||
return cls
|
||||
|
||||
def _load_class(self, load_type, impl, namespace):
|
||||
cls = None
|
||||
if not load_type or load_type in impl.lower():
|
||||
try:
|
||||
cls = Strategy.get_strategy(impl, namespace)
|
||||
except ImportError as ie:
|
||||
# Only fail silently if it's something we expect,
|
||||
# such as a missing override class. Anything else
|
||||
# shouldn't be suppressed.
|
||||
l_msg = ie.message.lower()
|
||||
if load_type not in l_msg or (
|
||||
'no module named' not in l_msg and
|
||||
'cannot be found' not in l_msg):
|
||||
raise
|
||||
return cls
|
||||
|
||||
def _build_class_path(self, module_name, class_prefix, class_base,
|
||||
strip_test=False):
|
||||
|
@ -124,6 +124,18 @@ class TestHelper(object):
|
||||
|
||||
self._build_data_fns()
|
||||
|
||||
#################
|
||||
# Utility methods
|
||||
#################
|
||||
def get_class_name(self):
|
||||
"""Builds a string of the expected class name, plus the actual one
|
||||
being used if it's not the same.
|
||||
"""
|
||||
class_name_str = "'%s'" % self._expected_override_name
|
||||
if self._expected_override_name != self.__class__.__name__:
|
||||
class_name_str += ' (using %s)' % self.__class__.__name__
|
||||
return class_name_str
|
||||
|
||||
################
|
||||
# Client related
|
||||
################
|
||||
@ -135,7 +147,9 @@ class TestHelper(object):
|
||||
return self.create_client(host, *args, **kwargs)
|
||||
|
||||
def create_client(self, host, *args, **kwargs):
|
||||
"""Create a datastore client."""
|
||||
"""Create a datastore client. This is datastore specific, so this
|
||||
method should be overridden if datastore access is desired.
|
||||
"""
|
||||
raise SkipTest('No client defined')
|
||||
|
||||
def get_helper_credentials(self):
|
||||
@ -336,6 +350,7 @@ class TestHelper(object):
|
||||
|
||||
def get_invalid_groups(self):
|
||||
"""Return a list of configuration groups with invalid values.
|
||||
An empty list indicates that no 'invalid' tests should be run.
|
||||
"""
|
||||
return []
|
||||
|
||||
|
532
trove/tests/scenario/runners/configuration_runners.py
Normal file
532
trove/tests/scenario/runners/configuration_runners.py
Normal file
@ -0,0 +1,532 @@
|
||||
# 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 datetime import datetime
|
||||
import json
|
||||
from proboscis import SkipTest
|
||||
|
||||
from trove.common.utils import generate_uuid
|
||||
from trove.tests.config import CONFIG
|
||||
from trove.tests.scenario.runners.test_runners import TestRunner
|
||||
from trove.tests.util.check import CollectionCheck
|
||||
from trove.tests.util.check import TypeCheck
|
||||
from trove.tests.util import create_dbaas_client
|
||||
from trove.tests.util.users import Requirements
|
||||
from troveclient.compat import exceptions
|
||||
|
||||
|
||||
class ConfigurationRunner(TestRunner):
|
||||
|
||||
def __init__(self):
|
||||
super(ConfigurationRunner, self).__init__(sleep_time=10)
|
||||
self.dynamic_group_name = 'dynamic_test_group'
|
||||
self.dynamic_group_id = None
|
||||
self.dynamic_inst_count = 0
|
||||
self.non_dynamic_group_name = 'non_dynamic_test_group'
|
||||
self.non_dynamic_group_id = None
|
||||
self.non_dynamic_inst_count = 0
|
||||
self.initial_group_count = 0
|
||||
self.additional_group_count = 0
|
||||
self.other_client = None
|
||||
self.config_id_for_inst = None
|
||||
self.config_inst_id = None
|
||||
|
||||
def run_create_bad_group(self,
|
||||
expected_exception=exceptions.UnprocessableEntity,
|
||||
expected_http_code=422):
|
||||
bad_group = {'unknown_datastore_key': 'bad_value'}
|
||||
self.assert_action_on_conf_group_failure(
|
||||
bad_group, expected_exception, expected_http_code)
|
||||
|
||||
def assert_action_on_conf_group_failure(
|
||||
self, group_values, expected_exception, expected_http_code):
|
||||
json_def = json.dumps(group_values)
|
||||
self.assert_raises(
|
||||
expected_exception, expected_http_code,
|
||||
self.auth_client.configurations.create,
|
||||
'conf_group',
|
||||
json_def,
|
||||
'Group with Bad or Invalid entries',
|
||||
datastore=self.instance_info.dbaas_datastore,
|
||||
datastore_version=self.instance_info.dbaas_datastore_version)
|
||||
|
||||
def run_create_invalid_groups(
|
||||
self, expected_exception=exceptions.UnprocessableEntity,
|
||||
expected_http_code=422):
|
||||
invalid_groups = self.test_helper.get_invalid_groups()
|
||||
if invalid_groups:
|
||||
for invalid_group in invalid_groups:
|
||||
self.assert_action_on_conf_group_failure(
|
||||
invalid_group,
|
||||
expected_exception, expected_http_code)
|
||||
elif invalid_groups is None:
|
||||
raise SkipTest("No invalid configuration values defined in %s." %
|
||||
self.test_helper.get_class_name())
|
||||
else:
|
||||
raise SkipTest("Datastore has no invalid configuration values.")
|
||||
|
||||
def run_delete_non_existent_group(
|
||||
self, expected_exception=exceptions.NotFound,
|
||||
expected_http_code=404):
|
||||
self.assert_group_delete_failure(
|
||||
None, expected_exception, expected_http_code)
|
||||
|
||||
def run_delete_bad_group_id(
|
||||
self, expected_exception=exceptions.NotFound,
|
||||
expected_http_code=404):
|
||||
self.assert_group_delete_failure(
|
||||
generate_uuid(), expected_exception, expected_http_code)
|
||||
|
||||
def run_attach_non_existent_group(
|
||||
self, expected_exception=exceptions.NotFound,
|
||||
expected_http_code=404):
|
||||
self.assert_instance_modify_failure(
|
||||
self.instance_info.id, generate_uuid(),
|
||||
expected_exception, expected_http_code)
|
||||
|
||||
def run_attach_non_existent_group_to_non_existent_inst(
|
||||
self, expected_exception=exceptions.NotFound,
|
||||
expected_http_code=404):
|
||||
self.assert_instance_modify_failure(
|
||||
generate_uuid(), generate_uuid(),
|
||||
expected_exception, expected_http_code)
|
||||
|
||||
def run_detach_group_with_none_attached(self,
|
||||
expected_states=['ACTIVE'],
|
||||
expected_http_code=202):
|
||||
self.assert_instance_modify(
|
||||
self.instance_info.id, None,
|
||||
expected_states, expected_http_code)
|
||||
# run again, just to make sure
|
||||
self.assert_instance_modify(
|
||||
self.instance_info.id, None,
|
||||
expected_states, expected_http_code)
|
||||
|
||||
def run_create_dynamic_group(self, expected_http_code=200):
|
||||
self.initial_group_count = len(self.auth_client.configurations.list())
|
||||
values = self.test_helper.get_dynamic_group()
|
||||
if values:
|
||||
self.dynamic_group_id = self.assert_create_group(
|
||||
self.dynamic_group_name,
|
||||
'a fully dynamic group should not require restart',
|
||||
values, expected_http_code)
|
||||
self.additional_group_count += 1
|
||||
elif values is None:
|
||||
raise SkipTest("No dynamic group defined in %s." %
|
||||
self.test_helper.get_class_name())
|
||||
else:
|
||||
raise SkipTest("Datastore has no dynamic configuration values.")
|
||||
|
||||
def assert_create_group(self, name, description, values,
|
||||
expected_http_code):
|
||||
json_def = json.dumps(values)
|
||||
result = self.auth_client.configurations.create(
|
||||
name,
|
||||
json_def,
|
||||
description,
|
||||
datastore=self.instance_info.dbaas_datastore,
|
||||
datastore_version=self.instance_info.dbaas_datastore_version)
|
||||
self.assert_client_code(expected_http_code)
|
||||
|
||||
with TypeCheck('Configuration', result) as configuration:
|
||||
configuration.has_field('name', basestring)
|
||||
configuration.has_field('description', basestring)
|
||||
configuration.has_field('values', dict)
|
||||
configuration.has_field('datastore_name', basestring)
|
||||
configuration.has_field('datastore_version_id', unicode)
|
||||
configuration.has_field('datastore_version_name', basestring)
|
||||
|
||||
self.assert_equal(name, result.name)
|
||||
self.assert_equal(description, result.description)
|
||||
self.assert_equal(values, result.values)
|
||||
|
||||
return result.id
|
||||
|
||||
def run_create_non_dynamic_group(self, expected_http_code=200):
|
||||
values = self.test_helper.get_non_dynamic_group()
|
||||
if values:
|
||||
self.non_dynamic_group_id = self.assert_create_group(
|
||||
self.non_dynamic_group_name,
|
||||
'a group containing non-dynamic properties should always '
|
||||
'require restart',
|
||||
values, expected_http_code)
|
||||
self.additional_group_count += 1
|
||||
elif values is None:
|
||||
raise SkipTest("No non-dynamic group defined in %s." %
|
||||
self.test_helper.get_class_name())
|
||||
else:
|
||||
raise SkipTest("Datastore has no non-dynamic configuration "
|
||||
"values.")
|
||||
|
||||
def run_attach_dynamic_group_to_non_existent_inst(
|
||||
self, expected_exception=exceptions.NotFound,
|
||||
expected_http_code=404):
|
||||
if self.dynamic_group_id:
|
||||
self.assert_instance_modify_failure(
|
||||
generate_uuid(), self.dynamic_group_id,
|
||||
expected_exception, expected_http_code)
|
||||
|
||||
def run_attach_non_dynamic_group_to_non_existent_inst(
|
||||
self, expected_exception=exceptions.NotFound,
|
||||
expected_http_code=404):
|
||||
if self.non_dynamic_group_id:
|
||||
self.assert_instance_modify_failure(
|
||||
generate_uuid(), self.non_dynamic_group_id,
|
||||
expected_exception, expected_http_code)
|
||||
|
||||
def run_list_configuration_groups(self):
|
||||
configuration_list = self.auth_client.configurations.list()
|
||||
self.assert_configuration_list(
|
||||
configuration_list,
|
||||
self.initial_group_count + self.additional_group_count)
|
||||
|
||||
def assert_configuration_list(self, configuration_list, expected_count):
|
||||
self.assert_equal(expected_count, len(configuration_list),
|
||||
'Unexpected number of configurations found')
|
||||
if expected_count:
|
||||
configuration_names = [conf.name for conf in configuration_list]
|
||||
if self.dynamic_group_id:
|
||||
self.assert_true(
|
||||
self.dynamic_group_name in configuration_names)
|
||||
if self.non_dynamic_group_id:
|
||||
self.assert_true(
|
||||
self.non_dynamic_group_name in configuration_names)
|
||||
|
||||
def run_dynamic_configuration_show(self):
|
||||
if self.dynamic_group_id:
|
||||
self.assert_configuration_show(self.dynamic_group_id,
|
||||
self.dynamic_group_name)
|
||||
else:
|
||||
raise SkipTest("No dynamic group created.")
|
||||
|
||||
def assert_configuration_show(self, config_id, config_name):
|
||||
result = self.auth_client.configurations.get(config_id)
|
||||
self.assert_equal(config_id, result.id, "Unexpected config id")
|
||||
self.assert_equal(config_name, result.name, "Unexpected config name")
|
||||
|
||||
# check the result field types
|
||||
with TypeCheck("configuration", result) as check:
|
||||
check.has_field("id", basestring)
|
||||
check.has_field("name", basestring)
|
||||
check.has_field("description", basestring)
|
||||
check.has_field("values", dict)
|
||||
check.has_field("created", basestring)
|
||||
check.has_field("updated", basestring)
|
||||
check.has_field("instance_count", int)
|
||||
|
||||
# check for valid timestamps
|
||||
self.assert_true(self._is_valid_timestamp(result.created),
|
||||
'Created timestamp %s is invalid' % result.created)
|
||||
self.assert_true(self._is_valid_timestamp(result.updated),
|
||||
'Updated timestamp %s is invalid' % result.updated)
|
||||
|
||||
with CollectionCheck("configuration_values", result.values) as check:
|
||||
# check each item has the correct type according to the rules
|
||||
for (item_key, item_val) in result.values.iteritems():
|
||||
print("item_key: %s" % item_key)
|
||||
print("item_val: %s" % item_val)
|
||||
param = (
|
||||
self.auth_client.configuration_parameters.get_parameter(
|
||||
self.instance_info.dbaas_datastore,
|
||||
self.instance_info.dbaas_datastore_version,
|
||||
item_key))
|
||||
if param.type == 'integer':
|
||||
check.has_element(item_key, int)
|
||||
if param.type == 'string':
|
||||
check.has_element(item_key, basestring)
|
||||
if param.type == 'boolean':
|
||||
check.has_element(item_key, bool)
|
||||
|
||||
def _is_valid_timestamp(self, time_string):
|
||||
try:
|
||||
datetime.strptime(time_string, "%Y-%m-%dT%H:%M:%S")
|
||||
except ValueError:
|
||||
return False
|
||||
return True
|
||||
|
||||
def run_non_dynamic_configuration_show(self):
|
||||
if self.non_dynamic_group_id:
|
||||
self.assert_configuration_show(self.non_dynamic_group_id,
|
||||
self.non_dynamic_group_name)
|
||||
else:
|
||||
raise SkipTest("No non-dynamic group created.")
|
||||
|
||||
def run_dynamic_conf_get_unauthorized_user(
|
||||
self, expected_exception=exceptions.NotFound,
|
||||
expected_http_code=404):
|
||||
self.assert_conf_get_unauthorized_user(self.dynamic_group_id,
|
||||
expected_exception,
|
||||
expected_http_code)
|
||||
|
||||
def assert_conf_get_unauthorized_user(
|
||||
self, config_id, expected_exception=exceptions.NotFound,
|
||||
expected_http_code=404):
|
||||
self._create_other_client()
|
||||
self.assert_raises(
|
||||
expected_exception, None,
|
||||
self.other_client.configurations.get, config_id)
|
||||
# we're using a different client, so we'll check the return code
|
||||
# on it explicitly, instead of depending on 'assert_raises'
|
||||
self.assert_client_code(expected_http_code, client=self.other_client)
|
||||
|
||||
def _create_other_client(self):
|
||||
if not self.other_client:
|
||||
requirements = Requirements(is_admin=False)
|
||||
other_user = CONFIG.users.find_user(
|
||||
requirements, black_list=[self.instance_info.user.auth_user])
|
||||
self.other_client = create_dbaas_client(other_user)
|
||||
|
||||
def run_non_dynamic_conf_get_unauthorized_user(
|
||||
self, expected_exception=exceptions.NotFound,
|
||||
expected_http_code=404):
|
||||
self.assert_conf_get_unauthorized_user(self.dynamic_group_id,
|
||||
expected_exception,
|
||||
expected_http_code)
|
||||
|
||||
def run_list_dynamic_inst_conf_groups_before(self):
|
||||
if self.dynamic_group_id:
|
||||
self.dynamic_inst_count = len(
|
||||
self.auth_client.configurations.instances(
|
||||
self.dynamic_group_id))
|
||||
|
||||
def assert_conf_instance_list(self, group_id, expected_count):
|
||||
conf_instance_list = self.auth_client.configurations.instances(
|
||||
group_id)
|
||||
self.assert_equal(expected_count, len(conf_instance_list),
|
||||
'Unexpected number of configurations found')
|
||||
if expected_count:
|
||||
conf_instance_ids = [inst.id for inst in conf_instance_list]
|
||||
self.assert_true(
|
||||
self.instance_info.id in conf_instance_ids)
|
||||
|
||||
def run_attach_dynamic_group(
|
||||
self, expected_states=['ACTIVE'], expected_http_code=202):
|
||||
if self.dynamic_group_id:
|
||||
self.assert_instance_modify(
|
||||
self.instance_info.id, self.dynamic_group_id,
|
||||
expected_states, expected_http_code)
|
||||
|
||||
def run_list_dynamic_inst_conf_groups_after(self):
|
||||
if self.dynamic_group_id:
|
||||
self.assert_conf_instance_list(self.dynamic_group_id,
|
||||
self.dynamic_inst_count + 1)
|
||||
|
||||
def run_attach_dynamic_group_again(
|
||||
self, expected_exception=exceptions.BadRequest,
|
||||
expected_http_code=400):
|
||||
# The exception here should probably be UnprocessableEntity or
|
||||
# something else other than BadRequest as the request really is
|
||||
# valid.
|
||||
if self.dynamic_group_id:
|
||||
self.assert_instance_modify_failure(
|
||||
self.instance_info.id, self.dynamic_group_id,
|
||||
expected_exception, expected_http_code)
|
||||
|
||||
def run_delete_attached_dynamic_group(
|
||||
self, expected_exception=exceptions.BadRequest,
|
||||
expected_http_code=400):
|
||||
# The exception here should probably be UnprocessableEntity or
|
||||
# something else other than BadRequest as the request really is
|
||||
# valid.
|
||||
if self.dynamic_group_id:
|
||||
self.assert_group_delete_failure(
|
||||
self.dynamic_group_id, expected_exception, expected_http_code)
|
||||
|
||||
def run_update_dynamic_group(
|
||||
self, expected_states=['ACTIVE'], expected_http_code=202):
|
||||
if self.dynamic_group_id:
|
||||
values = json.dumps(self.test_helper.get_dynamic_group())
|
||||
self.assert_update_group(
|
||||
self.instance_info.id, self.dynamic_group_id, values,
|
||||
expected_states, expected_http_code)
|
||||
|
||||
def assert_update_group(
|
||||
self, instance_id, group_id, values,
|
||||
expected_states, expected_http_code, restart_inst=False):
|
||||
self.auth_client.configurations.update(group_id, values)
|
||||
self.assert_instance_action(
|
||||
instance_id, expected_states, expected_http_code)
|
||||
if restart_inst:
|
||||
self._restart_instance(instance_id)
|
||||
|
||||
def run_detach_dynamic_group(
|
||||
self, expected_states=['ACTIVE'], expected_http_code=202):
|
||||
if self.dynamic_group_id:
|
||||
self.assert_instance_modify(
|
||||
self.instance_info.id, None,
|
||||
expected_states, expected_http_code)
|
||||
|
||||
def run_list_non_dynamic_inst_conf_groups_before(self):
|
||||
if self.non_dynamic_group_id:
|
||||
self.non_dynamic_inst_count = len(
|
||||
self.auth_client.configurations.instances(
|
||||
self.non_dynamic_group_id))
|
||||
|
||||
def run_attach_non_dynamic_group(
|
||||
self, expected_states=['RESTART_REQUIRED'],
|
||||
expected_http_code=202):
|
||||
if self.non_dynamic_group_id:
|
||||
self.assert_instance_modify(
|
||||
self.instance_info.id, self.non_dynamic_group_id,
|
||||
expected_states, expected_http_code, restart_inst=True)
|
||||
|
||||
def run_list_non_dynamic_inst_conf_groups_after(self):
|
||||
if self.non_dynamic_group_id:
|
||||
self.assert_conf_instance_list(self.non_dynamic_group_id,
|
||||
self.non_dynamic_inst_count + 1)
|
||||
|
||||
def run_attach_non_dynamic_group_again(
|
||||
self, expected_exception=exceptions.BadRequest,
|
||||
expected_http_code=400):
|
||||
if self.non_dynamic_group_id:
|
||||
self.assert_instance_modify_failure(
|
||||
self.instance_info.id, self.non_dynamic_group_id,
|
||||
expected_exception, expected_http_code)
|
||||
|
||||
def run_delete_attached_non_dynamic_group(
|
||||
self, expected_exception=exceptions.BadRequest,
|
||||
expected_http_code=400):
|
||||
if self.non_dynamic_group_id:
|
||||
self.assert_group_delete_failure(
|
||||
self.non_dynamic_group_id, expected_exception,
|
||||
expected_http_code)
|
||||
|
||||
def run_update_non_dynamic_group(
|
||||
self, expected_states=['RESTART_REQUIRED'],
|
||||
expected_http_code=202):
|
||||
if self.non_dynamic_group_id:
|
||||
values = json.dumps(self.test_helper.get_non_dynamic_group())
|
||||
self.assert_update_group(
|
||||
self.instance_info.id, self.non_dynamic_group_id, values,
|
||||
expected_states, expected_http_code, restart_inst=True)
|
||||
|
||||
def run_detach_non_dynamic_group(
|
||||
self, expected_states=['RESTART_REQUIRED'],
|
||||
expected_http_code=202):
|
||||
if self.non_dynamic_group_id:
|
||||
self.assert_instance_modify(
|
||||
self.instance_info.id, None, expected_states,
|
||||
expected_http_code, restart_inst=True)
|
||||
|
||||
def assert_instance_modify(
|
||||
self, instance_id, group_id, expected_states, expected_http_code,
|
||||
restart_inst=False):
|
||||
self.auth_client.instances.modify(instance_id, configuration=group_id)
|
||||
self.assert_instance_action(
|
||||
instance_id, expected_states, expected_http_code)
|
||||
|
||||
# Verify the group has been attached.
|
||||
instance = self.get_instance(instance_id)
|
||||
if group_id:
|
||||
group = self.auth_client.configurations.get(group_id)
|
||||
self.assert_equal(
|
||||
group.id, instance.configuration['id'],
|
||||
"Attached group does not have the expected ID")
|
||||
self.assert_equal(
|
||||
group.name, instance.configuration['name'],
|
||||
"Attached group does not have the expected name")
|
||||
else:
|
||||
self.assert_false(
|
||||
hasattr(instance, 'configuration'),
|
||||
"The configuration group was not detached from the instance.")
|
||||
|
||||
if restart_inst:
|
||||
self._restart_instance(instance_id)
|
||||
|
||||
def assert_instance_modify_failure(
|
||||
self, instance_id, group_id, expected_exception,
|
||||
expected_http_code):
|
||||
self.assert_raises(
|
||||
expected_exception, expected_http_code,
|
||||
self.auth_client.instances.modify,
|
||||
instance_id, configuration=group_id)
|
||||
|
||||
def run_delete_dynamic_group(self, expected_http_code=202):
|
||||
if self.dynamic_group_id:
|
||||
self.assert_group_delete(self.dynamic_group_id,
|
||||
expected_http_code)
|
||||
|
||||
def assert_group_delete(self, group_id, expected_http_code):
|
||||
self.auth_client.configurations.delete(group_id)
|
||||
self.assert_client_code(expected_http_code)
|
||||
|
||||
def run_delete_non_dynamic_group(self, expected_http_code=202):
|
||||
if self.non_dynamic_group_id:
|
||||
self.assert_group_delete(self.non_dynamic_group_id,
|
||||
expected_http_code)
|
||||
|
||||
def assert_group_delete_failure(self, group_id, expected_exception,
|
||||
expected_http_code):
|
||||
self.assert_raises(
|
||||
expected_exception, expected_http_code,
|
||||
self.auth_client.configurations.delete, group_id)
|
||||
|
||||
def _restart_instance(
|
||||
self, instance_id, expected_states=['REBOOT', 'ACTIVE'],
|
||||
expected_http_code=202):
|
||||
self.auth_client.instances.restart(instance_id)
|
||||
self.assert_instance_action(instance_id, expected_states,
|
||||
expected_http_code)
|
||||
|
||||
def run_create_instance_with_conf(self):
|
||||
self.config_id_for_inst = (
|
||||
self.dynamic_group_id or self.non_dynamic_group_id)
|
||||
if self.config_id_for_inst:
|
||||
self.config_inst_id = self.assert_create_instance_with_conf(
|
||||
self.config_id_for_inst)
|
||||
else:
|
||||
raise SkipTest("No groups (dynamic or non-dynamic) defined in %s."
|
||||
% self.test_helper.get_class_name())
|
||||
|
||||
def assert_create_instance_with_conf(self, config_id):
|
||||
# test that a new instance will apply the configuration on create
|
||||
result = self.auth_client.instances.create(
|
||||
"TEST_" + str(datetime.now()) + "_config",
|
||||
self.instance_info.dbaas_flavor_href,
|
||||
self.instance_info.volume,
|
||||
[], [], availability_zone="nova",
|
||||
configuration=config_id)
|
||||
self.assert_client_code(200)
|
||||
self.assert_equal("BUILD", result.status, 'Unexpected inst status')
|
||||
return result.id
|
||||
|
||||
def run_wait_for_conf_instance(
|
||||
# we can't specify all the states here, as it may go active
|
||||
# before this test runs
|
||||
self, final_state=['ACTIVE'],
|
||||
expected_http_code=200):
|
||||
if self.config_inst_id:
|
||||
self.assert_instance_action(self.config_inst_id, final_state,
|
||||
expected_http_code)
|
||||
inst = self.auth_client.instances.get(self.config_inst_id)
|
||||
self.assert_equal(self.config_id_for_inst,
|
||||
inst.configuration['id'])
|
||||
else:
|
||||
raise SkipTest("No instance created with a configuration group.")
|
||||
|
||||
def run_delete_conf_instance(
|
||||
self, expected_states=['SHUTDOWN'],
|
||||
expected_http_code=202):
|
||||
if self.config_inst_id:
|
||||
self.assert_delete_conf_instance(
|
||||
self.config_inst_id, expected_states, expected_http_code)
|
||||
else:
|
||||
raise SkipTest("No instance created with a configuration group.")
|
||||
|
||||
def assert_delete_conf_instance(
|
||||
self, instance_id, expected_state, expected_http_code):
|
||||
self.auth_client.instances.delete(instance_id)
|
||||
self.assert_client_code(expected_http_code)
|
||||
self.assert_all_gone(instance_id, expected_state)
|
Loading…
x
Reference in New Issue
Block a user