# Copyright 2011 OpenStack Foundation # # 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.asserts import assert_equal from proboscis.asserts import assert_raises from proboscis import before_class from proboscis.check import Check from proboscis import SkipTest from proboscis import test import six from troveclient.compat import exceptions from trove.common.utils import poll_until from trove.tests.api.instances import CreateInstance from trove.tests.api.instances import GROUP_START from trove.tests.api.instances import GROUP_TEST from trove.tests.api.instances import instance_info from trove.tests.config import CONFIG from trove.tests.util.check import CollectionCheck from trove.tests.util.check import TypeCheck from trove.tests.util import create_client from trove.tests.util import create_dbaas_client from trove.tests.util.users import Requirements GROUP = "dbaas.api.mgmt.instances" @test(groups=[GROUP]) def mgmt_index_requires_admin_account(): """Verify that an admin context is required to call this function.""" client = create_client(is_admin=False) assert_raises(exceptions.Unauthorized, client.management.index) # These functions check some dictionaries in the returned response. def flavor_check(flavor): with CollectionCheck("flavor", flavor) as check: check.has_element("id", six.string_types) check.has_element("links", list) def datastore_check(datastore): with CollectionCheck("datastore", datastore) as check: check.has_element("type", six.string_types) check.has_element("version", six.string_types) def guest_status_check(guest_status): with CollectionCheck("guest_status", guest_status) as check: check.has_element("state_description", six.string_types) def volume_check(volume): with CollectionCheck("volume", volume) as check: check.has_element("id", six.string_types) check.has_element("size", int) check.has_element("used", float) check.has_element("total", float) @test(depends_on_groups=[GROUP_START], groups=[GROUP, GROUP_TEST]) def mgmt_instance_get(): """Tests the mgmt instances index method.""" reqs = Requirements(is_admin=True) user = CONFIG.users.find_user(reqs) client = create_dbaas_client(user) mgmt = client.management # Grab the info.id created by the main instance test which is stored in # a global. id = instance_info.id api_instance = mgmt.show(id) datastore = getattr(api_instance, 'datastore') datastore_type = datastore.get('type') # Print out all fields for extra info if the test fails. for name in dir(api_instance): print(str(name) + "=" + str(getattr(api_instance, name))) with TypeCheck("instance", api_instance) as instance: instance.has_field('created', six.string_types) instance.has_field('deleted', bool) # If the instance hasn't been deleted, this should be false... but # lets avoid creating more ordering work. instance.has_field('deleted_at', (six.string_types, None)) instance.has_field('flavor', dict, flavor_check) instance.has_field('datastore', dict, datastore_check) instance.has_field('guest_status', dict, guest_status_check) instance.has_field('id', six.string_types) instance.has_field('links', list) instance.has_field('name', six.string_types) # instance.has_field('server_status', six.string_types) instance.has_field('status', six.string_types) instance.has_field('tenant_id', six.string_types) instance.has_field('updated', six.string_types) # Can be None if no volume is given on this instance. volume_support = CONFIG.get(datastore_type, 'mysql')['volume_support'] if volume_support: instance.has_field('volume', dict, volume_check) else: instance.has_field('volume', None) # TODO(tim-simpson): Validate additional fields, assert # no extra fields exist. if api_instance.server is not None: print("the real content of server: %s" % dir(api_instance.server)) print("the type of server: %s" % type(api_instance.server)) print("the real content of api_instance: %s" % dir(api_instance)) print("the type of api_instance: %s" % type(api_instance)) print(hasattr(api_instance, "server")) with CollectionCheck("server", api_instance.server) as server: server.has_element("addresses", dict) server.has_element("deleted", bool) server.has_element("deleted_at", (six.string_types, None)) server.has_element("host", six.string_types) server.has_element("id", six.string_types) server.has_element("local_id", int) server.has_element("name", six.string_types) server.has_element("status", six.string_types) server.has_element("tenant_id", six.string_types) if (volume_support and CONFIG.trove_main_instance_has_volume): with CollectionCheck("volume", api_instance.volume) as volume: volume.has_element("attachments", list) volume.has_element("availability_zone", six.string_types) volume.has_element("created_at", (six.string_types, None)) volume.has_element("id", six.string_types) volume.has_element("size", int) volume.has_element("status", six.string_types) @test(groups=["fake." + GROUP]) class WhenMgmtInstanceGetIsCalledButServerIsNotReady(object): @before_class def set_up(self): """Create client for mgmt instance test (2).""" if not CONFIG.fake_mode: raise SkipTest("This test only works in fake mode.") self.client = create_client(is_admin=True) self.mgmt = self.client.management # Fake nova will fail a server ending with 'test_SERVER_ERROR'." # Fake volume will fail if the size is 13. # TODO(tim.simpson): This would be a lot nicer looking if we used a # traditional mock framework. datastore = {'type': 'mysql', 'version': '5.5'} body = {'datastore': datastore} vol_support = CONFIG.get(datastore['type'], 'mysql')['volume_support'] if vol_support: body.update({'size': 13}) response = self.client.instances.create( 'test_SERVER_ERROR', instance_info.dbaas_flavor_href, body, []) poll_until(lambda: self.client.instances.get(response.id), lambda instance: instance.status == 'ERROR', time_out=10) self.id = response.id @test def mgmt_instance_get(self): """Tests the mgmt get call works when the Nova server isn't ready.""" api_instance = self.mgmt.show(self.id) # Print out all fields for extra info if the test fails. for name in dir(api_instance): print(str(name) + "=" + str(getattr(api_instance, name))) # Print out all fields for extra info if the test fails. for name in dir(api_instance): print(str(name) + "=" + str(getattr(api_instance, name))) with TypeCheck("instance", api_instance) as instance: instance.has_field('created', six.string_types) instance.has_field('deleted', bool) # If the instance hasn't been deleted, this should be false... but # lets avoid creating more ordering work. instance.has_field('deleted_at', (six.string_types, None)) instance.has_field('flavor', dict, flavor_check) instance.has_field('datastore', dict, datastore_check) instance.has_field('guest_status', dict, guest_status_check) instance.has_field('id', six.string_types) instance.has_field('links', list) instance.has_field('name', six.string_types) # instance.has_field('server_status', six.string_types) instance.has_field('status', six.string_types) instance.has_field('tenant_id', six.string_types) instance.has_field('updated', six.string_types) # Can be None if no volume is given on this instance. instance.has_field('server', None) instance.has_field('volume', None) # TODO(tim-simpson): Validate additional fields, # assert no extra fields exist. @test(depends_on_classes=[CreateInstance], groups=[GROUP]) class MgmtInstancesIndex(object): """Tests the mgmt instances index method.""" @before_class def setUp(self): """Create client for mgmt instance test.""" reqs = Requirements(is_admin=True) self.user = CONFIG.users.find_user(reqs) self.client = create_dbaas_client(self.user) @test def test_mgmt_instance_index_fields_present(self): """ Verify that all the expected fields are returned by the index method. """ expected_fields = [ 'created', 'deleted', 'deleted_at', 'flavor', 'datastore', 'id', 'links', 'name', 'server', 'status', 'task_description', 'tenant_id', 'updated', ] if CONFIG.trove_volume_support: expected_fields.append('volume') index = self.client.management.index() if not hasattr(index, "deleted"): raise SkipTest("instance index must have a " "deleted label for this test") for instance in index: with Check() as check: for field in expected_fields: check.true(hasattr(instance, field), "Index lacks field %s" % field) @test def test_mgmt_instance_index_check_filter(self): """ Make sure that the deleted= filter works as expected, and no instances are excluded. """ if not hasattr(self.client.management.index, 'deleted'): raise SkipTest("instance index must have a deleted " "label for this test") instance_counts = [] for deleted_filter in (True, False): filtered_index = self.client.management.index( deleted=deleted_filter) instance_counts.append(len(filtered_index)) for instance in filtered_index: # Every instance listed here should have the proper value # for 'deleted'. assert_equal(deleted_filter, instance.deleted) full_index = self.client.management.index() # There should be no instances that are neither deleted or not-deleted. assert_equal(len(full_index), sum(instance_counts))