diff --git a/trove/tests/unittests/cluster/test_vertica_cluster.py b/trove/tests/unittests/cluster/test_vertica_cluster.py index 816fd4b7c4..420306591c 100644 --- a/trove/tests/unittests/cluster/test_vertica_cluster.py +++ b/trove/tests/unittests/cluster/test_vertica_cluster.py @@ -15,6 +15,7 @@ import uuid from mock import Mock from mock import patch +from novaclient import exceptions as nova_exceptions from trove.cluster.models import Cluster from trove.cluster.models import ClusterTasks from trove.cluster.models import DBCluster @@ -31,6 +32,14 @@ from trove.tests.unittests import trove_testtools CONF = cfg.CONF +class FakeOptGroup(object): + def __init__(self, cluster_member_count=3, + volume_support=True, device_path='/dev/vdb'): + self.cluster_member_count = cluster_member_count + self.volume_support = volume_support + self.device_path = device_path + + class ClusterTest(trove_testtools.TestCase): def setUp(self): super(ClusterTest, self).setUp() @@ -58,13 +67,9 @@ class ClusterTest(trove_testtools.TestCase): self.instances = [{'volume_size': 1, 'flavor_id': '1234'}, {'volume_size': 1, 'flavor_id': '1234'}, {'volume_size': 1, 'flavor_id': '1234'}] - self.volume_support = CONF.get(self.dv.manager).volume_support - self.remote_nova = remote.create_nova_client def tearDown(self): super(ClusterTest, self).tearDown() - CONF.get(self.dv.manager).volume_support = self.volume_support - remote.create_nova_client = self.remote_nova def test_create_empty_instances(self): self.assertRaises(exception.ClusterNumInstancesNotSupported, @@ -88,6 +93,26 @@ class ClusterTest(trove_testtools.TestCase): instances ) + @patch.object(remote, 'create_nova_client') + def test_create_invalid_flavor_specified(self, + mock_client): + instances = [{'flavor_id': '1234'}, + {'flavor_id': '1234'}, + {'flavor_id': '1234'}] + + (mock_client.return_value.flavors.get) = Mock( + side_effect=nova_exceptions.NotFound( + 404, "Flavor id not found %s" % id)) + + self.assertRaises(exception.FlavorNotFound, + Cluster.create, + Mock(), + self.cluster_name, + self.datastore, + self.datastore_version, + instances + ) + @patch.object(remote, 'create_nova_client') def test_create_volume_no_specified(self, mock_client): @@ -105,9 +130,12 @@ class ClusterTest(trove_testtools.TestCase): ) @patch.object(remote, 'create_nova_client') + @patch.object(vertica_api, 'CONF') def test_create_storage_specified_with_no_volume_support(self, + mock_conf, mock_client): - CONF.get(self.dv.manager).volume_support = False + mock_conf.get = Mock( + return_value=FakeOptGroup(volume_support=False)) instances = self.instances instances[0]['volume_size'] = None flavors = Mock() @@ -122,7 +150,9 @@ class ClusterTest(trove_testtools.TestCase): ) @patch.object(remote, 'create_nova_client') + @patch.object(vertica_api, 'CONF') def test_create_storage_not_specified_and_no_ephemeral_flavor(self, + mock_conf, mock_client): class FakeFlavor: def __init__(self, flavor_id): @@ -138,7 +168,8 @@ class ClusterTest(trove_testtools.TestCase): instances = [{'flavor_id': '1234'}, {'flavor_id': '1234'}, {'flavor_id': '1234'}] - CONF.get(self.dv.manager).volume_support = False + mock_conf.get = Mock( + return_value=FakeOptGroup(volume_support=False)) (mock_client.return_value. flavors.get.return_value) = FakeFlavor('1234') self.assertRaises(exception.LocalStorageNotSpecified, @@ -150,6 +181,21 @@ class ClusterTest(trove_testtools.TestCase): instances ) + @patch.object(remote, 'create_nova_client') + def test_create_volume_not_equal(self, mock_client): + instances = self.instances + instances[0]['volume_size'] = 2 + flavors = Mock() + mock_client.return_value.flavors = flavors + self.assertRaises(exception.ClusterVolumeSizesNotEqual, + Cluster.create, + Mock(), + self.cluster_name, + self.datastore, + self.datastore_version, + instances + ) + @patch.object(inst_models.Instance, 'create') @patch.object(DBCluster, 'create') @patch.object(task_api, 'load') @@ -168,6 +214,41 @@ class ClusterTest(trove_testtools.TestCase): mock_task_api.create_cluster.assert_called self.assertEqual(3, mock_ins_create.call_count) + @patch.object(vertica_api, 'CONF') + @patch.object(inst_models.Instance, 'create') + @patch.object(DBCluster, 'create') + @patch.object(task_api, 'load') + @patch.object(QUOTAS, 'check_quotas') + @patch.object(remote, 'create_nova_client') + def test_create_with_ephemeral_flavor(self, mock_client, mock_check_quotas, + mock_task_api, mock_db_create, + mock_ins_create, mock_conf): + class FakeFlavor: + def __init__(self, flavor_id): + self.flavor_id = flavor_id + + @property + def id(self): + return self.flavor.id + + @property + def ephemeral(self): + return 1 + instances = [{'flavor_id': '1234'}, + {'flavor_id': '1234'}, + {'flavor_id': '1234'}] + mock_conf.get = Mock( + return_value=FakeOptGroup(volume_support=False)) + (mock_client.return_value. + flavors.get.return_value) = FakeFlavor('1234') + self.cluster.create(Mock(), + self.cluster_name, + self.datastore, + self.datastore_version, + instances) + mock_task_api.create_cluster.assert_called + self.assertEqual(3, mock_ins_create.call_count) + def test_delete_bad_task_status(self): self.cluster.db_info.task_status = ClusterTasks.BUILDING_INITIAL self.assertRaises(exception.UnprocessableEntity, diff --git a/trove/tests/unittests/guestagent/test_api.py b/trove/tests/unittests/guestagent/test_api.py index d7c096e6c1..24ffb8e8ba 100644 --- a/trove/tests/unittests/guestagent/test_api.py +++ b/trove/tests/unittests/guestagent/test_api.py @@ -20,6 +20,7 @@ from testtools.matchers import Is import trove.common.context as context from trove.common import exception +from trove.common.remote import guest_client from trove.guestagent import api from trove import rpc @@ -459,8 +460,14 @@ class ApiStrategyTest(testtools.TestCase): @mock.patch('trove.guestagent.api.API.__init__', mock.Mock(return_value=None)) - def test_guest_client(self): - from trove.common.remote import guest_client + def test_guest_client_mongodb(self): client = guest_client(mock.Mock(), mock.Mock(), 'mongodb') self.assertFalse(hasattr(client, 'add_config_servers2')) self.assertTrue(callable(client.add_config_servers)) + + @mock.patch('trove.guestagent.api.API.__init__', + mock.Mock(return_value=None)) + def test_guest_client_vertica(self): + client = guest_client(mock.Mock(), mock.Mock(), 'vertica') + self.assertFalse(hasattr(client, 'get_public_keys2')) + self.assertTrue(callable(client.get_public_keys)) diff --git a/trove/tests/unittests/guestagent/test_vertica_api.py b/trove/tests/unittests/guestagent/test_vertica_api.py new file mode 100644 index 0000000000..1abd494c3a --- /dev/null +++ b/trove/tests/unittests/guestagent/test_vertica_api.py @@ -0,0 +1,125 @@ +# Copyright 2015 Hewlett-Packard Development Company, L.P. +# +# 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 eventlet import Timeout +import mock + +import trove.common.context as context +from trove.common import exception +from trove.common.rpc.version import RPC_API_VERSION +from trove.common.strategies.cluster.experimental.vertica.guestagent import ( + VerticaGuestAgentAPI) +from trove.tests.unittests import trove_testtools + + +def _mock_call(cmd, timeout, version=None, user=None, + public_keys=None, members=None): + # To check get_public_keys, authorize_public_keys, + # install_cluster, cluster_complete in cmd. + if cmd in ('get_public_keys', 'authorize_public_keys', + 'install_cluster', 'cluster_complete'): + return True + else: + raise BaseException("Test Failed") + + +class ApiTest(trove_testtools.TestCase): + def setUp(self): + super(ApiTest, self).setUp() + self.context = context.TroveContext() + self.guest = VerticaGuestAgentAPI(self.context, 0) + self.guest._call = _mock_call + self.api = VerticaGuestAgentAPI(self.context, "instance-id-x23d2d") + self._mock_rpc_client() + + def test_get_routing_key(self): + self.assertEqual('guestagent.instance-id-x23d2d', + self.api._get_routing_key()) + + def test_api_cast_exception(self): + self.call_context.cast.side_effect = IOError('host down') + self.assertRaises(exception.GuestError, self.api.create_user, + 'test_user') + + def test_api_call_exception(self): + self.call_context.call.side_effect = IOError('host_down') + self.assertRaises(exception.GuestError, self.api.list_users) + + def test_api_call_timeout(self): + self.call_context.call.side_effect = Timeout() + self.assertRaises(exception.GuestTimeout, self.api.restart) + + def _verify_rpc_prepare_before_call(self): + self.api.client.prepare.assert_called_once_with( + version=RPC_API_VERSION, timeout=mock.ANY) + + def _verify_rpc_prepare_before_cast(self): + self.api.client.prepare.assert_called_once_with( + version=RPC_API_VERSION) + + def _verify_cast(self, *args, **kwargs): + self.call_context.cast.assert_called_once_with(self.context, *args, + **kwargs) + + def _verify_call(self, *args, **kwargs): + self.call_context.call.assert_called_once_with(self.context, *args, + **kwargs) + + def _mock_rpc_client(self): + self.call_context = mock.Mock() + self.api.client.prepare = mock.Mock(return_value=self.call_context) + self.call_context.call = mock.Mock() + self.call_context.cast = mock.Mock() + + def test_get_public_keys(self): + exp_resp = 'some_key' + self.call_context.call.return_value = exp_resp + + resp = self.api.get_public_keys(user='dummy') + + self._verify_rpc_prepare_before_call() + self._verify_call('get_public_keys', user='dummy') + self.assertEqual(exp_resp, resp) + + def test_authorize_public_keys(self): + exp_resp = None + self.call_context.call.return_value = exp_resp + + resp = self.api.authorize_public_keys(user='dummy', + public_keys='some_key') + + self._verify_rpc_prepare_before_call() + self._verify_call('authorize_public_keys', user='dummy', + public_keys='some_key') + self.assertEqual(exp_resp, resp) + + def test_install_cluster(self): + exp_resp = None + self.call_context.call.return_value = exp_resp + + resp = self.api.install_cluster(members=['10.0.0.1', '10.0.0.2']) + + self._verify_rpc_prepare_before_call() + self._verify_call('install_cluster', members=['10.0.0.1', '10.0.0.2']) + self.assertEqual(exp_resp, resp) + + def test_cluster_complete(self): + exp_resp = None + self.call_context.call.return_value = exp_resp + + resp = self.api.cluster_complete() + + self._verify_rpc_prepare_before_call() + self._verify_call('cluster_complete') + self.assertEqual(exp_resp, resp) diff --git a/trove/tests/unittests/taskmanager/test_vertica_clusters.py b/trove/tests/unittests/taskmanager/test_vertica_clusters.py index 6c74cdb812..15b165788b 100644 --- a/trove/tests/unittests/taskmanager/test_vertica_clusters.py +++ b/trove/tests/unittests/taskmanager/test_vertica_clusters.py @@ -18,14 +18,21 @@ from mock import patch from trove.cluster.models import ClusterTasks as ClusterTaskStatus from trove.cluster.models import DBCluster -from trove.common.strategies.cluster.experimental.vertica.taskmanager import \ - VerticaClusterTasks as ClusterTasks +import trove.common.context as context +from trove.common.exception import GuestError +from trove.common.strategies.cluster.experimental.vertica.taskmanager import ( + VerticaClusterTasks as ClusterTasks) +from trove.common.strategies.cluster.experimental.vertica.taskmanager import ( + VerticaTaskManagerAPI as task_api) +from trove.common.strategies.cluster.experimental.vertica.taskmanager import ( + VerticaTaskManagerStrategy as task_strategy) from trove.datastore import models as datastore_models from trove.instance.models import BaseInstance from trove.instance.models import DBInstance from trove.instance.models import Instance from trove.instance.models import InstanceServiceStatus from trove.instance.models import InstanceTasks +from trove import rpc from trove.taskmanager.models import ServiceStatuses from trove.tests.unittests import trove_testtools @@ -100,6 +107,23 @@ class VerticaClusterTasksTest(trove_testtools.TestCase): self.cluster_id) self.assertTrue(ret_val) + @patch.object(ClusterTasks, 'reset_task') + @patch.object(ClusterTasks, '_all_instances_ready', return_value=False) + @patch.object(Instance, 'load') + @patch.object(DBInstance, 'find_all') + @patch.object(datastore_models.Datastore, 'load') + @patch.object(datastore_models.DatastoreVersion, 'load_by_uuid') + def test_create_cluster_instance_not_ready(self, mock_dv, mock_ds, + mock_find_all, mock_load, + mock_ready, mock_reset_task): + mock_find_all.return_value.all.return_value = [self.dbinst1] + mock_load.return_value = BaseInstance(Mock(), + self.dbinst1, Mock(), + InstanceServiceStatus( + ServiceStatuses.NEW)) + self.clustertasks.create_cluster(Mock(), self.cluster_id) + mock_reset_task.assert_called() + @patch.object(ClusterTasks, 'reset_task') @patch.object(ClusterTasks, 'get_guest') @patch.object(ClusterTasks, 'get_ip') @@ -121,3 +145,62 @@ class VerticaClusterTasksTest(trove_testtools.TestCase): ) mock_reset_task.assert_called() mock_guest.return_value.cluster_complete.assert_called() + + @patch.object(ClusterTasks, 'update_statuses_on_failure') + @patch.object(ClusterTasks, 'reset_task') + @patch.object(ClusterTasks, 'get_ip') + @patch.object(ClusterTasks, '_all_instances_ready') + @patch.object(Instance, 'load') + @patch.object(DBInstance, 'find_all') + @patch.object(datastore_models.Datastore, 'load') + @patch.object(datastore_models.DatastoreVersion, 'load_by_uuid') + def test_create_cluster_fail(self, mock_dv, mock_ds, mock_find_all, + mock_load, mock_ready, mock_ip, + mock_reset_task, mock_update_status): + mock_find_all.return_value.all.return_value = [self.dbinst1] + mock_load.return_value = BaseInstance(Mock(), + self.dbinst1, Mock(), + InstanceServiceStatus( + ServiceStatuses.NEW)) + mock_ip.return_value = "10.0.0.2" + guest_client = Mock() + guest_client.install_cluster = Mock(side_effect=GuestError("Error")) + with patch.object(ClusterTasks, 'get_guest', + return_value=guest_client): + self.clustertasks.create_cluster(Mock(), self.cluster_id) + mock_update_status.assert_called() + mock_reset_task.assert_called() + + +class VerticaTaskManagerAPITest(trove_testtools.TestCase): + def setUp(self): + super(VerticaTaskManagerAPITest, self).setUp() + self.context = context.TroveContext() + self.api = task_api(self.context) + self.call_context = Mock() + self.api.client.prepare = Mock(return_value=self.call_context) + self.call_context.cast = Mock() + self.rpc_api_version = '1.0' + + @patch.object(rpc, 'get_client') + def test_task_manager_api__cast(self, mock_rpc_client): + self.api._cast(method_name='test_method', version=self.rpc_api_version) + mock_rpc_client.assert_called() + + +class VerticaTaskManagerStrategyTest(trove_testtools.TestCase): + + def test_task_manager_cluster_tasks_class(self): + vertica_strategy = task_strategy() + self.assertFalse( + hasattr(vertica_strategy.task_manager_cluster_tasks_class, + 'rebuild_cluster')) + self.assertTrue(callable( + vertica_strategy.task_manager_cluster_tasks_class.create_cluster)) + + def test_task_manager_api_class(self): + vertica_strategy = task_strategy() + self.assertFalse(hasattr(vertica_strategy.task_manager_api_class, + 'add_new_node')) + self.assertTrue( + callable(vertica_strategy.task_manager_api_class._cast))