diff options
Diffstat (limited to 'troveclient/tests')
| -rw-r--r-- | troveclient/tests/__init__.py | 0 | ||||
| -rw-r--r-- | troveclient/tests/test_accounts.py | 84 | ||||
| -rw-r--r-- | troveclient/tests/test_auth.py | 414 | ||||
| -rw-r--r-- | troveclient/tests/test_base.py | 447 | ||||
| -rw-r--r-- | troveclient/tests/test_client.py | 322 | ||||
| -rw-r--r-- | troveclient/tests/test_common.py | 395 | ||||
| -rw-r--r-- | troveclient/tests/test_instances.py | 176 | ||||
| -rw-r--r-- | troveclient/tests/test_limits.py | 79 | ||||
| -rw-r--r-- | troveclient/tests/test_management.py | 144 | ||||
| -rw-r--r-- | troveclient/tests/test_secgroups.py | 102 | ||||
| -rw-r--r-- | troveclient/tests/test_users.py | 126 | ||||
| -rw-r--r-- | troveclient/tests/test_utils.py | 41 | ||||
| -rw-r--r-- | troveclient/tests/test_xml.py | 241 |
13 files changed, 2571 insertions, 0 deletions
diff --git a/troveclient/tests/__init__.py b/troveclient/tests/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/troveclient/tests/__init__.py diff --git a/troveclient/tests/test_accounts.py b/troveclient/tests/test_accounts.py new file mode 100644 index 0000000..e2716fa --- /dev/null +++ b/troveclient/tests/test_accounts.py @@ -0,0 +1,84 @@ +from testtools import TestCase +from mock import Mock + +from troveclient import accounts +from troveclient import base + +""" +Unit tests for accounts.py +""" + + +class AccountTest(TestCase): + + def setUp(self): + super(AccountTest, self).setUp() + self.orig__init = accounts.Account.__init__ + accounts.Account.__init__ = Mock(return_value=None) + self.account = accounts.Account() + + def tearDown(self): + super(AccountTest, self).tearDown() + accounts.Account.__init__ = self.orig__init + + def test___repr__(self): + self.account.name = "account-1" + self.assertEqual('<Account: account-1>', self.account.__repr__()) + + +class AccountsTest(TestCase): + + def setUp(self): + super(AccountsTest, self).setUp() + self.orig__init = accounts.Accounts.__init__ + accounts.Accounts.__init__ = Mock(return_value=None) + self.accounts = accounts.Accounts() + self.accounts.api = Mock() + self.accounts.api.client = Mock() + + def tearDown(self): + super(AccountsTest, self).tearDown() + accounts.Accounts.__init__ = self.orig__init + + def test__list(self): + def side_effect_func(self, val): + return val + + self.accounts.resource_class = Mock(side_effect=side_effect_func) + key_ = 'key' + body_ = {key_: "test-value"} + self.accounts.api.client.get = Mock(return_value=('resp', body_)) + self.assertEqual("test-value", self.accounts._list('url', key_)) + + self.accounts.api.client.get = Mock(return_value=('resp', None)) + self.assertRaises(Exception, self.accounts._list, 'url', None) + + def test_index(self): + resp = Mock() + resp.status = 400 + body = {"Accounts": {}} + self.accounts.api.client.get = Mock(return_value=(resp, body)) + self.assertRaises(Exception, self.accounts.index) + resp.status = 200 + self.assertTrue(isinstance(self.accounts.index(), base.Resource)) + self.accounts.api.client.get = Mock(return_value=(resp, None)) + self.assertRaises(Exception, self.accounts.index) + + def test_show(self): + def side_effect_func(acct_name, acct): + return acct_name, acct + + account_ = Mock() + account_.name = "test-account" + self.accounts._list = Mock(side_effect=side_effect_func) + self.assertEqual(('/mgmt/accounts/test-account', 'account'), + self.accounts.show(account_)) + + def test__get_account_name(self): + account_ = 'account with no name' + self.assertEqual(account_, + accounts.Accounts._get_account_name(account_)) + account_ = Mock() + account_.name = "account-name" + self.assertEqual("account-name", + accounts.Accounts._get_account_name(account_)) diff --git a/troveclient/tests/test_auth.py b/troveclient/tests/test_auth.py new file mode 100644 index 0000000..28cecb9 --- /dev/null +++ b/troveclient/tests/test_auth.py @@ -0,0 +1,414 @@ +import contextlib + +from testtools import TestCase +from troveclient import auth +from mock import Mock + +from troveclient import exceptions + +""" +Unit tests for the classes and functions in auth.py. +""" + + +def check_url_none(test_case, auth_class): + # url is None, it must throw exception + authObj = auth_class(url=None, type=auth_class, client=None, + username=None, password=None, tenant=None) + try: + authObj.authenticate() + test_case.fail("AuthUrlNotGiven exception expected") + except exceptions.AuthUrlNotGiven: + pass + + +class AuthenticatorTest(TestCase): + + def setUp(self): + super(AuthenticatorTest, self).setUp() + self.orig_load = auth.ServiceCatalog._load + self.orig__init = auth.ServiceCatalog.__init__ + + def tearDown(self): + super(AuthenticatorTest, self).tearDown() + auth.ServiceCatalog._load = self.orig_load + auth.ServiceCatalog.__init__ = self.orig__init + + def test_get_authenticator_cls(self): + class_list = (auth.KeyStoneV2Authenticator, + auth.RaxAuthenticator, + auth.Auth1_1, + auth.FakeAuth) + + for c in class_list: + self.assertEqual(c, auth.get_authenticator_cls(c)) + + class_names = {"keystone": auth.KeyStoneV2Authenticator, + "rax": auth.RaxAuthenticator, + "auth1.1": auth.Auth1_1, + "fake": auth.FakeAuth} + + for cn in class_names.keys(): + self.assertEqual(class_names[cn], auth.get_authenticator_cls(cn)) + + cls_or_name = "_unknown_" + self.assertRaises(ValueError, auth.get_authenticator_cls, cls_or_name) + + def test__authenticate(self): + authObj = auth.Authenticator(Mock(), auth.KeyStoneV2Authenticator, + Mock(), Mock(), Mock(), Mock()) + # test response code 200 + resp = Mock() + resp.status = 200 + body = "test_body" + + auth.ServiceCatalog._load = Mock(return_value=1) + authObj.client._time_request = Mock(return_value=(resp, body)) + + sc = authObj._authenticate(Mock(), Mock()) + self.assertEqual(body, sc.catalog) + + # test AmbiguousEndpoints exception + auth.ServiceCatalog.__init__ = \ + Mock(side_effect=exceptions.AmbiguousEndpoints) + self.assertRaises(exceptions.AmbiguousEndpoints, + authObj._authenticate, Mock(), Mock()) + + # test handling KeyError and raising AuthorizationFailure exception + auth.ServiceCatalog.__init__ = Mock(side_effect=KeyError) + self.assertRaises(exceptions.AuthorizationFailure, + authObj._authenticate, Mock(), Mock()) + + # test EndpointNotFound exception + mock = Mock(side_effect=exceptions.EndpointNotFound) + auth.ServiceCatalog.__init__ = mock + self.assertRaises(exceptions.EndpointNotFound, + authObj._authenticate, Mock(), Mock()) + mock.side_effect = None + + # test response code 305 + resp.__getitem__ = Mock(return_value='loc') + resp.status = 305 + body = "test_body" + authObj.client._time_request = Mock(return_value=(resp, body)) + + l = authObj._authenticate(Mock(), Mock()) + self.assertEqual('loc', l) + + # test any response code other than 200 and 305 + resp.status = 404 + exceptions.from_response = Mock(side_effect=ValueError) + self.assertRaises(ValueError, authObj._authenticate, Mock(), Mock()) + + def test_authenticate(self): + authObj = auth.Authenticator(Mock(), auth.KeyStoneV2Authenticator, + Mock(), Mock(), Mock(), Mock()) + self.assertRaises(NotImplementedError, authObj.authenticate) + + +class KeyStoneV2AuthenticatorTest(TestCase): + + def test_authenticate(self): + # url is None + check_url_none(self, auth.KeyStoneV2Authenticator) + + # url is not None, so it must not throw exception + url = "test_url" + cls_type = auth.KeyStoneV2Authenticator + authObj = auth.KeyStoneV2Authenticator(url=url, type=cls_type, + client=None, username=None, + password=None, tenant=None) + + def side_effect_func(url): + return url + + mock = Mock() + mock.side_effect = side_effect_func + authObj._v2_auth = mock + r = authObj.authenticate() + self.assertEqual(url, r) + + def test__v2_auth(self): + username = "trove_user" + password = "trove_password" + tenant = "tenant" + cls_type = auth.KeyStoneV2Authenticator + authObj = auth.KeyStoneV2Authenticator(url=None, type=cls_type, + client=None, + username=username, + password=password, + tenant=tenant) + + def side_effect_func(url, body): + return body + mock = Mock() + mock.side_effect = side_effect_func + authObj._authenticate = mock + body = authObj._v2_auth(Mock()) + self.assertEqual(username, + body['auth']['passwordCredentials']['username']) + self.assertEqual(password, + body['auth']['passwordCredentials']['password']) + self.assertEqual(tenant, body['auth']['tenantName']) + + +class Auth1_1Test(TestCase): + + def test_authenticate(self): + # handle when url is None + check_url_none(self, auth.Auth1_1) + + # url is not none + username = "trove_user" + password = "trove_password" + url = "test_url" + authObj = auth.Auth1_1(url=url, + type=auth.Auth1_1, + client=None, username=username, + password=password, tenant=None) + + def side_effect_func(auth_url, body, root_key): + return auth_url, body, root_key + + mock = Mock() + mock.side_effect = side_effect_func + authObj._authenticate = mock + auth_url, body, root_key = authObj.authenticate() + + self.assertEqual(username, body['credentials']['username']) + self.assertEqual(password, body['credentials']['key']) + self.assertEqual(auth_url, url) + self.assertEqual('auth', root_key) + + +class RaxAuthenticatorTest(TestCase): + + def test_authenticate(self): + # url is None + check_url_none(self, auth.RaxAuthenticator) + + # url is not None, so it must not throw exception + url = "test_url" + authObj = auth.RaxAuthenticator(url=url, + type=auth.RaxAuthenticator, + client=None, username=None, + password=None, tenant=None) + + def side_effect_func(url): + return url + + mock = Mock() + mock.side_effect = side_effect_func + authObj._rax_auth = mock + r = authObj.authenticate() + self.assertEqual(url, r) + + def test__rax_auth(self): + username = "trove_user" + password = "trove_password" + tenant = "tenant" + authObj = auth.RaxAuthenticator(url=None, + type=auth.RaxAuthenticator, + client=None, username=username, + password=password, tenant=tenant) + + def side_effect_func(url, body): + return body + + mock = Mock() + mock.side_effect = side_effect_func + authObj._authenticate = mock + body = authObj._rax_auth(Mock()) + + v = body['auth']['RAX-KSKEY:apiKeyCredentials']['username'] + self.assertEqual(username, v) + + v = body['auth']['RAX-KSKEY:apiKeyCredentials']['apiKey'] + self.assertEqual(password, v) + + v = body['auth']['RAX-KSKEY:apiKeyCredentials']['tenantName'] + self.assertEqual(tenant, v) + + +class FakeAuthTest(TestCase): + + def test_authenticate(self): + tenant = "tenant" + authObj = auth.FakeAuth(url=None, + type=auth.FakeAuth, + client=None, username=None, + password=None, tenant=tenant) + + fc = authObj.authenticate() + public_url = "%s/%s" % ('http://localhost:8779/v1.0', tenant) + self.assertEqual(public_url, fc.get_public_url()) + self.assertEqual(tenant, fc.get_token()) + + +class ServiceCatalogTest(TestCase): + + def setUp(self): + super(ServiceCatalogTest, self).setUp() + self.orig_url_for = auth.ServiceCatalog._url_for + self.orig__init__ = auth.ServiceCatalog.__init__ + auth.ServiceCatalog.__init__ = Mock(return_value=None) + self.test_url = "http://localhost:1234/test" + + def tearDown(self): + super(ServiceCatalogTest, self).tearDown() + auth.ServiceCatalog._url_for = self.orig_url_for + auth.ServiceCatalog.__init__ = self.orig__init__ + + def test__load(self): + url = "random_url" + auth.ServiceCatalog._url_for = Mock(return_value=url) + + # when service_url is None + scObj = auth.ServiceCatalog() + scObj.region = None + scObj.service_url = None + scObj._load() + self.assertEqual(url, scObj.public_url) + self.assertEqual(url, scObj.management_url) + + # service url is not None + service_url = "service_url" + scObj = auth.ServiceCatalog() + scObj.region = None + scObj.service_url = service_url + scObj._load() + self.assertEqual(service_url, scObj.public_url) + self.assertEqual(service_url, scObj.management_url) + + def test_get_token(self): + test_id = "test_id" + scObj = auth.ServiceCatalog() + scObj.root_key = "root_key" + scObj.catalog = dict() + scObj.catalog[scObj.root_key] = dict() + scObj.catalog[scObj.root_key]['token'] = dict() + scObj.catalog[scObj.root_key]['token']['id'] = test_id + self.assertEqual(test_id, scObj.get_token()) + + def test_get_management_url(self): + test_mng_url = "test_management_url" + scObj = auth.ServiceCatalog() + scObj.management_url = test_mng_url + self.assertEqual(test_mng_url, scObj.get_management_url()) + + def test_get_public_url(self): + test_public_url = "test_public_url" + scObj = auth.ServiceCatalog() + scObj.public_url = test_public_url + self.assertEqual(test_public_url, scObj.get_public_url()) + + def test__url_for(self): + scObj = auth.ServiceCatalog() + + # case for no endpoint found + self.case_no_endpoint_match(scObj) + + # case for empty service catalog + self.case_endpoing_with_empty_catalog(scObj) + + # more than one matching endpoints + self.case_ambiguous_endpoint(scObj) + + # happy case + self.case_unique_endpoint(scObj) + + # testing if-statements in for-loop to iterate services in catalog + self.case_iterating_services_in_catalog(scObj) + + def case_no_endpoint_match(self, scObj): + # empty endpoint list + scObj.catalog = dict() + scObj.catalog['endpoints'] = list() + self.assertRaises(exceptions.EndpointNotFound, scObj._url_for) + + def side_effect_func_ep(attr): + return "test_attr_value" + + # simulating dict + endpoint = Mock() + mock = Mock() + mock.side_effect = side_effect_func_ep + endpoint.__getitem__ = mock + scObj.catalog['endpoints'].append(endpoint) + + # not-empty list but not matching endpoint + filter_value = "not_matching_value" + self.assertRaises(exceptions.EndpointNotFound, scObj._url_for, + attr="test_attr", filter_value=filter_value) + + filter_value = "test_attr_value" # so that we have an endpoint match + scObj.root_key = "access" + scObj.catalog[scObj.root_key] = dict() + self.assertRaises(exceptions.EndpointNotFound, scObj._url_for, + attr="test_attr", filter_value=filter_value) + + def case_endpoing_with_empty_catalog(self, scObj): + # first, test with empty catalog, this should pass since + # there is already enpoint added + scObj.catalog[scObj.root_key]['serviceCatalog'] = list() + + endpoint = scObj.catalog['endpoints'][0] + endpoint.get = Mock(return_value=self.test_url) + r_url = scObj._url_for(attr="test_attr", + filter_value="test_attr_value") + self.assertEqual(self.test_url, r_url) + + def case_ambiguous_endpoint(self, scObj): + scObj.service_type = "trove" + scObj.service_name = "test_service_name" + + def side_effect_func_service(key): + if key == "type": + return "trove" + elif key == "name": + return "test_service_name" + return None + + mock1 = Mock() + mock1.side_effect = side_effect_func_service + service1 = Mock() + service1.get = mock1 + + endpoint2 = {"test_attr": "test_attr_value"} + service1.__getitem__ = Mock(return_value=[endpoint2]) + scObj.catalog[scObj.root_key]['serviceCatalog'] = [service1] + self.assertRaises(exceptions.AmbiguousEndpoints, scObj._url_for, + attr="test_attr", filter_value="test_attr_value") + + def case_unique_endpoint(self, scObj): + # changing the endpoint2 attribute to pass the filter + service1 = scObj.catalog[scObj.root_key]['serviceCatalog'][0] + endpoint2 = service1[0][0] + endpoint2["test_attr"] = "new value not matching filter" + r_url = scObj._url_for(attr="test_attr", + filter_value="test_attr_value") + self.assertEqual(self.test_url, r_url) + + def case_iterating_services_in_catalog(self, scObj): + service1 = scObj.catalog[scObj.root_key]['serviceCatalog'][0] + + scObj.catalog = dict() + scObj.root_key = "access" + scObj.catalog[scObj.root_key] = dict() + scObj.service_type = "no_match" + + scObj.catalog[scObj.root_key]['serviceCatalog'] = [service1] + self.assertRaises(exceptions.EndpointNotFound, scObj._url_for) + + scObj.service_type = "database" + scObj.service_name = "no_match" + self.assertRaises(exceptions.EndpointNotFound, scObj._url_for) + + # no endpoints and no 'serviceCatalog' in catalog => raise exception + scObj = auth.ServiceCatalog() + scObj.catalog = dict() + scObj.root_key = "access" + scObj.catalog[scObj.root_key] = dict() + scObj.catalog[scObj.root_key]['serviceCatalog'] = [] + self.assertRaises(exceptions.EndpointNotFound, scObj._url_for, + attr="test_attr", filter_value="test_attr_value") diff --git a/troveclient/tests/test_base.py b/troveclient/tests/test_base.py new file mode 100644 index 0000000..ac7318b --- /dev/null +++ b/troveclient/tests/test_base.py @@ -0,0 +1,447 @@ +import contextlib +import os + +from testtools import TestCase +from mock import Mock + +from troveclient import base +from troveclient import exceptions +from troveclient import utils + +""" +Unit tests for base.py +""" + + +def obj_class(self, res, loaded=True): + return res + + +class BaseTest(TestCase): + + def test_getid(self): + obj = "test" + r = base.getid(obj) + self.assertEqual(obj, r) + + test_id = "test_id" + obj = Mock() + obj.id = test_id + r = base.getid(obj) + self.assertEqual(test_id, r) + + +class ManagerTest(TestCase): + + def setUp(self): + super(ManagerTest, self).setUp() + self.orig__init = base.Manager.__init__ + base.Manager.__init__ = Mock(return_value=None) + self.orig_os_makedirs = os.makedirs + + def tearDown(self): + super(ManagerTest, self).tearDown() + base.Manager.__init__ = self.orig__init + os.makedirs = self.orig_os_makedirs + + def test___init__(self): + api = Mock() + base.Manager.__init__ = self.orig__init + manager = base.Manager(api) + self.assertEqual(api, manager.api) + + def test_completion_cache(self): + manager = base.Manager() + + # handling exceptions + mode = "w" + cache_type = "unittest" + obj_class = Mock + with manager.completion_cache(cache_type, obj_class, mode): + pass + + os.makedirs = Mock(side_effect=OSError) + with manager.completion_cache(cache_type, obj_class, mode): + pass + + def test_write_to_completion_cache(self): + manager = base.Manager() + + # no cache object, nothing should happen + manager.write_to_completion_cache("non-exist", "val") + + def side_effect_func(val): + return val + + manager._mock_cache = Mock() + manager._mock_cache.write = Mock(return_value=None) + manager.write_to_completion_cache("mock", "val") + self.assertEqual(1, manager._mock_cache.write.call_count) + + def _get_mock(self): + manager = base.Manager() + manager.api = Mock() + manager.api.client = Mock() + + def side_effect_func(self, body, loaded=True): + return body + + manager.resource_class = Mock(side_effect=side_effect_func) + return manager + + def test__get_with_response_key_none(self): + manager = self._get_mock() + url_ = "test-url" + body_ = "test-body" + resp_ = "test-resp" + manager.api.client.get = Mock(return_value=(resp_, body_)) + r = manager._get(url=url_, response_key=None) + self.assertEqual(body_, r) + + def test__get_with_response_key(self): + manager = self._get_mock() + response_key = "response_key" + body_ = {response_key: "test-resp-key-body"} + url_ = "test_url_get" + manager.api.client.get = Mock(return_value=(url_, body_)) + r = manager._get(url=url_, response_key=response_key) + self.assertEqual(body_[response_key], r) + + def test__create(self): + manager = base.Manager() + manager.api = Mock() + manager.api.client = Mock() + + response_key = "response_key" + data_ = "test-data" + body_ = {response_key: data_} + url_ = "test_url_post" + manager.api.client.post = Mock(return_value=(url_, body_)) + + return_raw = True + r = manager._create(url_, body_, response_key, return_raw) + self.assertEqual(data_, r) + + return_raw = False + + @contextlib.contextmanager + def completion_cache_mock(*arg, **kwargs): + yield + + mock = Mock() + mock.side_effect = completion_cache_mock + manager.completion_cache = mock + + manager.resource_class = Mock(return_value="test-class") + r = manager._create(url_, body_, response_key, return_raw) + self.assertEqual("test-class", r) + + def get_mock_mng_api_client(self): + manager = base.Manager() + manager.api = Mock() + manager.api.client = Mock() + return manager + + def test__delete(self): + resp_ = "test-resp" + body_ = "test-body" + + manager = self.get_mock_mng_api_client() + manager.api.client.delete = Mock(return_value=(resp_, body_)) + # _delete just calls api.client.delete, and does nothing + # the correctness should be tested in api class + manager._delete("test-url") + pass + + def test__update(self): + resp_ = "test-resp" + body_ = "test-body" + + manager = self.get_mock_mng_api_client() + manager.api.client.put = Mock(return_value=(resp_, body_)) + body = manager._update("test-url", body_) + self.assertEqual(body_, body) + + +class ManagerListTest(ManagerTest): + + def setUp(self): + super(ManagerListTest, self).setUp() + + @contextlib.contextmanager + def completion_cache_mock(*arg, **kwargs): + yield + + self.manager = base.Manager() + self.manager.api = Mock() + self.manager.api.client = Mock() + + self.response_key = "response_key" + self.data_p = ["p1", "p2"] + self.body_p = {self.response_key: self.data_p} + self.url_p = "test_url_post" + self.manager.api.client.post = Mock(return_value=(self.url_p, + self.body_p)) + + self.data_g = ["g1", "g2", "g3"] + self.body_g = {self.response_key: self.data_g} + self.url_g = "test_url_get" + self.manager.api.client.get = Mock(return_value=(self.url_g, + self.body_g)) + + mock = Mock() + mock.side_effect = completion_cache_mock + self.manager.completion_cache = mock + + def tearDown(self): + super(ManagerListTest, self).tearDown() + + def obj_class(self, res, loaded=True): + return res + + def test_list_with_body_none(self): + body = None + l = self.manager._list("url", self.response_key, obj_class, body) + self.assertEqual(len(self.data_g), len(l)) + for i in range(0, len(l)): + self.assertEqual(self.data_g[i], l[i]) + + def test_list_body_not_none(self): + body = "something" + l = self.manager._list("url", self.response_key, obj_class, body) + self.assertEqual(len(self.data_p), len(l)) + for i in range(0, len(l)): + self.assertEqual(self.data_p[i], l[i]) + + def test_list_key_mapping(self): + data_ = {"values": ["p1", "p2"]} + body_ = {self.response_key: data_} + url_ = "test_url_post" + self.manager.api.client.post = Mock(return_value=(url_, body_)) + l = self.manager._list("url", self.response_key, + obj_class, "something") + data = data_["values"] + self.assertEqual(len(data), len(l)) + for i in range(0, len(l)): + self.assertEqual(data[i], l[i]) + + def test_list_without_key_mapping(self): + data_ = {"v1": "1", "v2": "2"} + body_ = {self.response_key: data_} + url_ = "test_url_post" + self.manager.api.client.post = Mock(return_value=(url_, body_)) + l = self.manager._list("url", self.response_key, + obj_class, "something") + self.assertEqual(len(data_), len(l)) + + +class ManagerWithFind(TestCase): + + def setUp(self): + super(ManagerWithFind, self).setUp() + self.orig__init = base.ManagerWithFind.__init__ + base.ManagerWithFind.__init__ = Mock(return_value=None) + self.manager = base.ManagerWithFind() + + def tearDown(self): + super(ManagerWithFind, self).tearDown() + base.ManagerWithFind.__init__ = self.orig__init + + def test_find(self): + obj1 = Mock() + obj1.attr1 = "v1" + obj1.attr2 = "v2" + obj1.attr3 = "v3" + + obj2 = Mock() + obj2.attr1 = "v1" + obj2.attr2 = "v2" + + self.manager.list = Mock(return_value=[obj1, obj2]) + self.manager.resource_class = Mock + + # exactly one match case + found = self.manager.find(attr1="v1", attr2="v2", attr3="v3") + self.assertEqual(obj1, found) + + # no match case + self.assertRaises(exceptions.NotFound, self.manager.find, + attr1="v2", attr2="v2", attr3="v3") + + # multiple matches case + obj2.attr3 = "v3" + self.assertRaises(exceptions.NoUniqueMatch, self.manager.find, + attr1="v1", attr2="v2", attr3="v3") + + def test_findall(self): + obj1 = Mock() + obj1.attr1 = "v1" + obj1.attr2 = "v2" + obj1.attr3 = "v3" + + obj2 = Mock() + obj2.attr1 = "v1" + obj2.attr2 = "v2" + + self.manager.list = Mock(return_value=[obj1, obj2]) + + found = self.manager.findall(attr1="v1", attr2="v2", attr3="v3") + self.assertEqual(1, len(found)) + self.assertEqual(obj1, found[0]) + + found = self.manager.findall(attr1="v2", attr2="v2", attr3="v3") + self.assertEqual(0, len(found)) + + found = self.manager.findall(attr7="v1", attr2="v2") + self.assertEqual(0, len(found)) + + def test_list(self): + # this method is not yet implemented, exception expected + self.assertRaises(NotImplementedError, self.manager.list) + + +class ResourceTest(TestCase): + + def setUp(self): + super(ResourceTest, self).setUp() + self.orig___init__ = base.Resource.__init__ + + def tearDown(self): + super(ResourceTest, self).tearDown() + base.Resource.__init__ = self.orig___init__ + + def test___init__(self): + manager = Mock() + manager.write_to_completion_cache = Mock(return_value=None) + + info_ = {} + robj = base.Resource(manager, info_) + self.assertEqual(0, manager.write_to_completion_cache.call_count) + + info_ = {"id": "id-with-less-than-36-char"} + robj = base.Resource(manager, info_) + self.assertEqual(info_["id"], robj.id) + self.assertEqual(0, manager.write_to_completion_cache.call_count) + + id_ = "id-with-36-char-" + for i in range(36 - len(id_)): + id_ = id_ + "-" + info_ = {"id": id_} + robj = base.Resource(manager, info_) + self.assertEqual(info_["id"], robj.id) + self.assertEqual(1, manager.write_to_completion_cache.call_count) + + info_["name"] = "test-human-id" + # Resource.HUMAN_ID is False + robj = base.Resource(manager, info_) + self.assertEqual(info_["id"], robj.id) + self.assertEqual(None, robj.human_id) + self.assertEqual(2, manager.write_to_completion_cache.call_count) + + # base.Resource.HUMAN_ID = True + info_["HUMAN_ID"] = True + robj = base.Resource(manager, info_) + self.assertEqual(info_["id"], robj.id) + self.assertEqual(info_["name"], robj.human_id) + self.assertEqual(4, manager.write_to_completion_cache.call_count) + + def test_human_id(self): + manager = Mock() + manager.write_to_completion_cache = Mock(return_value=None) + + info_ = {"name": "test-human-id"} + robj = base.Resource(manager, info_) + self.assertEqual(None, robj.human_id) + + info_["HUMAN_ID"] = True + robj = base.Resource(manager, info_) + self.assertEqual(info_["name"], robj.human_id) + robj.name = "new-human-id" + self.assertEqual("new-human-id", robj.human_id) + + def get_mock_resource_obj(self): + base.Resource.__init__ = Mock(return_value=None) + robj = base.Resource() + return robj + + def test__add_details(self): + robj = self.get_mock_resource_obj() + info_ = {"name": "test-human-id", "test_attr": 5} + robj._add_details(info_) + self.assertEqual(info_["name"], robj.name) + self.assertEqual(info_["test_attr"], robj.test_attr) + + def test___getattr__(self): + robj = self.get_mock_resource_obj() + info_ = {"name": "test-human-id", "test_attr": 5} + robj._add_details(info_) + self.assertEqual(info_["test_attr"], robj.__getattr__("test_attr")) + + # TODO: looks like causing infinite recursive calls + #robj.__getattr__("test_non_exist_attr") + + def test___repr__(self): + robj = self.get_mock_resource_obj() + info_ = {"name": "test-human-id", "test_attr": 5} + robj._add_details(info_) + + expected = "<Resource name=test-human-id, test_attr=5>" + self.assertEqual(expected, robj.__repr__()) + + def test_get(self): + robj = self.get_mock_resource_obj() + manager = Mock() + manager.get = None + + robj.manager = object() + robj.get() + + manager = Mock() + robj.manager = Mock() + + robj.id = "id" + new = Mock() + new._info = {"name": "test-human-id", "test_attr": 5} + robj.manager.get = Mock(return_value=new) + robj.get() + self.assertEqual("test-human-id", robj.name) + self.assertEqual(5, robj.test_attr) + + def tes___eq__(self): + robj = self.get_mock_resource_obj() + other = base.Resource() + + info_ = {"name": "test-human-id", "test_attr": 5} + robj._info = info_ + other._info = {} + self.assertNotTrue(robj.__eq__(other)) + + robj._info = info_ + self.assertTrue(robj.__eq__(other)) + + robj.id = "rid" + other.id = "oid" + self.assertNotTrue(robj.__eq__(other)) + + other.id = "rid" + self.assertTrue(robj.__eq__(other)) + + # not instance of the same class + other = Mock() + self.assertNotTrue(robj.__eq__(other)) + + def test_is_loaded(self): + robj = self.get_mock_resource_obj() + robj._loaded = True + self.assertTrue(robj.is_loaded()) + + robj._loaded = False + self.assertFalse(robj.is_loaded()) + + def test_set_loaded(self): + robj = self.get_mock_resource_obj() + robj.set_loaded(True) + self.assertTrue(robj._loaded) + + robj.set_loaded(False) + self.assertFalse(robj._loaded) diff --git a/troveclient/tests/test_client.py b/troveclient/tests/test_client.py new file mode 100644 index 0000000..263316b --- /dev/null +++ b/troveclient/tests/test_client.py @@ -0,0 +1,322 @@ +import contextlib +import os +import logging +import httplib2 +import time + +from testtools import TestCase +from mock import Mock + +from troveclient import client +from troveclient import exceptions +from troveclient import utils + +""" +Unit tests for client.py +""" + + +class ClientTest(TestCase): + + def test_log_to_streamhandler(self): + client.log_to_streamhandler() + self.assertTrue(client._logger.level == logging.DEBUG) + + +class TroveHTTPClientTest(TestCase): + + def setUp(self): + super(TroveHTTPClientTest, self).setUp() + self.orig__init = client.TroveHTTPClient.__init__ + client.TroveHTTPClient.__init__ = Mock(return_value=None) + self.hc = client.TroveHTTPClient() + self.hc.auth_token = "test-auth-token" + self.hc.service_url = "test-service-url/" + self.hc.tenant = "test-tenant" + + self.__debug_lines = list() + + self.orig_client__logger = client._logger + client._logger = Mock() + + self.orig_time = time.time + self.orig_htttp_request = httplib2.Http.request + + def tearDown(self): + super(TroveHTTPClientTest, self).tearDown() + client.TroveHTTPClient.__init__ = self.orig__init + client._logger = self.orig_client__logger + time.time = self.orig_time + httplib2.Http.request = self.orig_htttp_request + + def side_effect_func_for_moc_debug(self, s, *args): + self.__debug_lines.append(s) + + def test___init__(self): + client.TroveHTTPClient.__init__ = self.orig__init + + user = "test-user" + password = "test-password" + tenant = "test-tenant" + auth_url = "http://test-auth-url/" + service_name = None + + # when there is no auth_strategy provided + self.assertRaises(ValueError, client.TroveHTTPClient, user, + password, tenant, auth_url, service_name) + + hc = client.TroveHTTPClient(user, password, tenant, auth_url, + service_name, auth_strategy="fake") + self.assertEqual("http://test-auth-url", hc.auth_url) + + # auth_url is none + hc = client.TroveHTTPClient(user, password, tenant, None, + service_name, auth_strategy="fake") + self.assertEqual(None, hc.auth_url) + + def test_get_timings(self): + self.hc.times = ["item1", "item2"] + self.assertEqual(2, len(self.hc.get_timings())) + self.assertEqual("item1", self.hc.get_timings()[0]) + self.assertEqual("item2", self.hc.get_timings()[1]) + + def test_http_log(self): + self.hc.simple_log = Mock(return_value=None) + self.hc.pretty_log = Mock(return_value=None) + + client.RDC_PP = False + self.hc.http_log(None, None, None, None) + self.assertEqual(1, self.hc.simple_log.call_count) + + client.RDC_PP = True + self.hc.http_log(None, None, None, None) + self.assertEqual(1, self.hc.pretty_log.call_count) + + def test_simple_log(self): + client._logger.isEnabledFor = Mock(return_value=False) + self.hc.simple_log(None, None, None, None) + self.assertEqual(0, len(self.__debug_lines)) + + client._logger.isEnabledFor = Mock(return_value=True) + se = self.side_effect_func_for_moc_debug + client._logger.debug = Mock(side_effect=se) + self.hc.simple_log(['item1', 'GET', 'item3', 'POST', 'item5'], + {'headers': {'e1': 'e1-v', 'e2': 'e2-v'}, + 'body': 'body'}, None, None) + self.assertEqual(3, len(self.__debug_lines)) + self.assertTrue(self.__debug_lines[0].startswith('REQ: curl -i')) + self.assertTrue(self.__debug_lines[1].startswith('REQ BODY:')) + self.assertTrue(self.__debug_lines[2].startswith('RESP:')) + + def test_pretty_log(self): + client._logger.isEnabledFor = Mock(return_value=False) + self.hc.pretty_log(None, None, None, None) + self.assertEqual(0, len(self.__debug_lines)) + + client._logger.isEnabledFor = Mock(return_value=True) + se = self.side_effect_func_for_moc_debug + client._logger.debug = Mock(side_effect=se) + self.hc.pretty_log(['item1', 'GET', 'item3', 'POST', 'item5'], + {'headers': {'e1': 'e1-v', 'e2': 'e2-v'}, + 'body': 'body'}, None, None) + self.assertEqual(5, len(self.__debug_lines)) + self.assertTrue(self.__debug_lines[0].startswith('REQUEST:')) + self.assertTrue(self.__debug_lines[1].startswith('curl -i')) + self.assertTrue(self.__debug_lines[2].startswith('BODY:')) + self.assertTrue(self.__debug_lines[3].startswith('RESPONSE HEADERS:')) + self.assertTrue(self.__debug_lines[4].startswith('RESPONSE BODY')) + + # no body case + self.__debug_lines = list() + self.hc.pretty_log(['item1', 'GET', 'item3', 'POST', 'item5'], + {'headers': {'e1': 'e1-v', 'e2': 'e2-v'}}, + None, None) + self.assertEqual(4, len(self.__debug_lines)) + self.assertTrue(self.__debug_lines[0].startswith('REQUEST:')) + self.assertTrue(self.__debug_lines[1].startswith('curl -i')) + self.assertTrue(self.__debug_lines[2].startswith('RESPONSE HEADERS:')) + self.assertTrue(self.__debug_lines[3].startswith('RESPONSE BODY')) + + def test_request(self): + self.hc.USER_AGENT = "user-agent" + resp = Mock() + body = Mock() + resp.status = 200 + httplib2.Http.request = Mock(return_value=(resp, body)) + self.hc.morph_response_body = Mock(return_value=body) + r, b = self.hc.request() + self.assertEqual(resp, r) + self.assertEqual(body, b) + self.assertEqual((resp, body), self.hc.last_response) + + httplib2.Http.request = Mock(return_value=(resp, None)) + r, b = self.hc.request() + self.assertEqual(resp, r) + self.assertEqual(None, b) + + status_list = [400, 401, 403, 404, 408, 409, 413, 500, 501] + for status in status_list: + resp.status = status + self.assertRaises(Exception, self.hc.request) + + exception = exceptions.ResponseFormatError + self.hc.morph_response_body = Mock(side_effect=exception) + self.assertRaises(Exception, self.hc.request) + + def test_raise_error_from_status(self): + resp = Mock() + resp.status = 200 + self.hc.raise_error_from_status(resp, Mock()) + + status_list = [400, 401, 403, 404, 408, 409, 413, 500, 501] + for status in status_list: + resp.status = status + self.assertRaises(Exception, + self.hc.raise_error_from_status, resp, Mock()) + + def test_morph_request(self): + kwargs = dict() + kwargs['headers'] = dict() + kwargs['body'] = ['body', {'item1': 'value1'}] + self.hc.morph_request(kwargs) + expected = {'body': '["body", {"item1": "value1"}]', + 'headers': {'Content-Type': 'application/json', + 'Accept': 'application/json'}} + self.assertEqual(expected, kwargs) + + def test_morph_response_body(self): + body_string = '["body", {"item1": "value1"}]' + expected = ['body', {'item1': 'value1'}] + self.assertEqual(expected, self.hc.morph_response_body(body_string)) + body_string = '["body", {"item1": }]' + self.assertRaises(exceptions.ResponseFormatError, + self.hc.morph_response_body, body_string) + + def test__time_request(self): + self.__time = 0 + + def side_effect_func(): + self.__time = self.__time + 1 + return self.__time + + time.time = Mock(side_effect=side_effect_func) + self.hc.request = Mock(return_value=("mock-response", "mock-body")) + self.hc.times = list() + resp, body = self.hc._time_request("test-url", "Get") + self.assertEqual(("mock-response", "mock-body"), (resp, body)) + self.assertEqual([('Get test-url', 1, 2)], self.hc.times) + + def mock_time_request_func(self): + def side_effect_func(url, method, **kwargs): + return url, method + self.hc._time_request = Mock(side_effect=side_effect_func) + + def test__cs_request(self): + self.mock_time_request_func() + resp, body = self.hc._cs_request("test-url", "GET") + self.assertEqual(('test-service-url/test-url', 'GET'), (resp, body)) + + self.hc.authenticate = Mock(side_effect=ValueError) + self.hc.auth_token = None + self.hc.service_url = None + self.assertRaises(ValueError, self.hc._cs_request, "test-url", "GET") + + self.hc.authenticate = Mock(return_value=None) + self.hc.service_url = "test-service-url/" + + def side_effect_func_time_req(url, method, **kwargs): + raise exceptions.Unauthorized(None) + + self.hc._time_request = Mock(side_effect=side_effect_func_time_req) + self.assertRaises(exceptions.Unauthorized, + self.hc._cs_request, "test-url", "GET") + + def test_get(self): + self.mock_time_request_func() + resp, body = self.hc.get("test-url") + self.assertEqual(("test-service-url/test-url", "GET"), (resp, body)) + + def test_post(self): + self.mock_time_request_func() + resp, body = self.hc.post("test-url") + self.assertEqual(("test-service-url/test-url", "POST"), (resp, body)) + + def test_put(self): + self.mock_time_request_func() + resp, body = self.hc.put("test-url") + self.assertEqual(("test-service-url/test-url", "PUT"), (resp, body)) + + def test_delete(self): + self.mock_time_request_func() + resp, body = self.hc.delete("test-url") + self.assertEqual(("test-service-url/test-url", "DELETE"), (resp, body)) + + def test_authenticate(self): + self.hc.authenticator = Mock() + catalog = Mock() + catalog.get_public_url = Mock(return_value="public-url") + catalog.get_management_url = Mock(return_value="mng-url") + catalog.get_token = Mock(return_value="test-token") + + self.__auth_calls = [] + + def side_effect_func(token, url): + self.__auth_calls = [token, url] + + self.hc.authenticate_with_token = Mock(side_effect=side_effect_func) + self.hc.authenticator.authenticate = Mock(return_value=catalog) + self.hc.endpoint_type = "publicURL" + self.hc.authenticate() + self.assertEqual(["test-token", None], + self.__auth_calls) + + self.__auth_calls = [] + self.hc.service_url = None + self.hc.authenticate() + self.assertEqual(["test-token", "public-url"], self.__auth_calls) + + self.__auth_calls = [] + self.hc.endpoint_type = "adminURL" + self.hc.authenticate() + self.assertEqual(["test-token", "mng-url"], self.__auth_calls) + + def test_authenticate_with_token(self): + self.hc.service_url = None + self.assertRaises(exceptions.ServiceUrlNotGiven, + self.hc.authenticate_with_token, "token", None) + self.hc.authenticate_with_token("token", "test-url") + self.assertEqual("test-url", self.hc.service_url) + self.assertEqual("token", self.hc.auth_token) + + +class DbaasTest(TestCase): + + def setUp(self): + super(DbaasTest, self).setUp() + self.orig__init = client.TroveHTTPClient.__init__ + client.TroveHTTPClient.__init__ = Mock(return_value=None) + self.dbaas = client.Dbaas("user", "api-key") + + def tearDown(self): + super(DbaasTest, self).tearDown() + client.TroveHTTPClient.__init__ = self.orig__init + + def test___init__(self): + client.TroveHTTPClient.__init__ = Mock(return_value=None) + self.assertNotEqual(None, self.dbaas.mgmt) + + def test_set_management_url(self): + self.dbaas.set_management_url("test-management-url") + self.assertEqual("test-management-url", + self.dbaas.client.management_url) + + def test_get_timings(self): + __timings = {'start': 1, 'end': 2} + self.dbaas.client.get_timings = Mock(return_value=__timings) + self.assertEqual(__timings, self.dbaas.get_timings()) + + def test_authenticate(self): + mock_auth = Mock(return_value=None) + self.dbaas.client.authenticate = mock_auth + self.dbaas.authenticate() + self.assertEqual(1, mock_auth.call_count) diff --git a/troveclient/tests/test_common.py b/troveclient/tests/test_common.py new file mode 100644 index 0000000..e1b488a --- /dev/null +++ b/troveclient/tests/test_common.py @@ -0,0 +1,395 @@ +import sys +import optparse +import json +import collections + +from testtools import TestCase +from mock import Mock + +from troveclient import common +from troveclient import client + +""" + unit tests for common.py +""" + + +class CommonTest(TestCase): + + def setUp(self): + super(CommonTest, self).setUp() + self.orig_sys_exit = sys.exit + sys.exit = Mock(return_value=None) + + def tearDown(self): + super(CommonTest, self).tearDown() + sys.exit = self.orig_sys_exit + + def test_methods_of(self): + class DummyClass: + def dummyMethod(self): + print("just for test") + + obj = DummyClass() + result = common.methods_of(obj) + self.assertEqual(1, len(result)) + method = result['dummyMethod'] + self.assertIsNotNone(method) + + def test_check_for_exceptions(self): + status = [400, 422, 500] + for s in status: + resp = Mock() + resp.status = s + self.assertRaises(Exception, + common.check_for_exceptions, resp, "body") + + # a no-exception case + resp = Mock() + resp.status = 200 + common.check_for_exceptions(resp, "body") + + def test_print_actions(self): + cmd = "test-cmd" + actions = {"test": "test action", "help": "help action"} + common.print_actions(cmd, actions) + pass + + def test_print_commands(self): + commands = {"cmd-1": "cmd 1", "cmd-2": "cmd 2"} + common.print_commands(commands) + pass + + def test_limit_url(self): + url_ = "test-url" + limit_ = None + marker_ = None + self.assertEqual(url_, common.limit_url(url_)) + + limit_ = "test-limit" + marker_ = "test-marker" + expected = "test-url?marker=test-marker&limit=test-limit" + self.assertEqual(expected, + common.limit_url(url_, limit=limit_, marker=marker_)) + + +class CliOptionsTest(TestCase): + + def check_default_options(self, co): + self.assertEqual(None, co.username) + self.assertEqual(None, co.apikey) + self.assertEqual(None, co.tenant_id) + self.assertEqual(None, co.auth_url) + self.assertEqual('keystone', co.auth_type) + self.assertEqual('database', co.service_type) + self.assertEqual('trove', co.service_name) + self.assertEqual('RegionOne', co.region) + self.assertEqual(None, co.service_url) + self.assertFalse(co.insecure) + self.assertFalse(co.verbose) + self.assertFalse(co.debug) + self.assertEqual(None, co.token) + self.assertEqual(None, co.xml) + + def check_option(self, oparser, option_name): + option = oparser.get_option("--%s" % option_name) + self.assertNotEqual(None, option) + if option_name in common.CliOptions.DEFAULT_VALUES: + self.assertEqual(common.CliOptions.DEFAULT_VALUES[option_name], + option.default) + + def test___init__(self): + co = common.CliOptions() + self.check_default_options(co) + + def test_deafult(self): + co = common.CliOptions.default() + self.check_default_options(co) + + def test_load_from_file(self): + co = common.CliOptions.load_from_file() + self.check_default_options(co) + + def test_create_optparser(self): + option_names = ["verbose", "debug", "auth_url", "username", "apikey", + "tenant_id", "auth_type", "service_type", + "service_name", "service_type", "service_name", + "service_url", "region", "insecure", "token", + "xml", "secure", "json", "terse", "hide-debug"] + + oparser = common.CliOptions.create_optparser(True) + for option_name in option_names: + self.check_option(oparser, option_name) + + oparser = common.CliOptions.create_optparser(False) + for option_name in option_names: + self.check_option(oparser, option_name) + + +class ArgumentRequiredTest(TestCase): + + def setUp(self): + super(ArgumentRequiredTest, self).setUp() + self.param = "test-param" + self.arg_req = common.ArgumentRequired(self.param) + + def test___init__(self): + self.assertEqual(self.param, self.arg_req.param) + + def test___str__(self): + expected = 'Argument "--%s" required.' % self.param + self.assertEqual(expected, self.arg_req.__str__()) + + +class CommandsBaseTest(TestCase): + + def setUp(self): + super(CommandsBaseTest, self).setUp() + self.orig_sys_exit = sys.exit + sys.exit = Mock(return_value=None) + parser = common.CliOptions().create_optparser(False) + self.cmd_base = common.CommandsBase(parser) + + def tearDown(self): + super(CommandsBaseTest, self).tearDown() + sys.exit = self.orig_sys_exit + + def test___init__(self): + self.assertNotEqual(None, self.cmd_base) + + def test__get_client(self): + client.log_to_streamhandler = Mock(return_value=None) + expected = Mock() + client.Dbaas = Mock(return_value=expected) + + self.cmd_base.xml = Mock() + self.cmd_base.verbose = False + r = self.cmd_base._get_client() + self.assertEqual(expected, r) + + self.cmd_base.xml = None + self.cmd_base.verbose = True + r = self.cmd_base._get_client() + self.assertEqual(expected, r) + + # test debug true + self.cmd_base.debug = True + client.Dbaas = Mock(side_effect=ValueError) + self.assertRaises(ValueError, self.cmd_base._get_client) + + def test__safe_exec(self): + func = Mock(return_value="test") + self.cmd_base.debug = True + r = self.cmd_base._safe_exec(func) + self.assertEqual("test", r) + + self.cmd_base.debug = False + r = self.cmd_base._safe_exec(func) + self.assertEqual("test", r) + + func = Mock(side_effect=ValueError) # an arbitrary exception + r = self.cmd_base._safe_exec(func) + self.assertEqual(None, r) + + def test__prepare_parser(self): + parser = optparse.OptionParser() + common.CommandsBase.params = ["test_1", "test_2"] + self.cmd_base._prepare_parser(parser) + option = parser.get_option("--%s" % "test_1") + self.assertNotEqual(None, option) + option = parser.get_option("--%s" % "test_2") + self.assertNotEqual(None, option) + + def test__parse_options(self): + parser = optparse.OptionParser() + parser.add_option("--%s" % "test_1", default="test_1v") + parser.add_option("--%s" % "test_2", default="test_2v") + self.cmd_base._parse_options(parser) + self.assertEqual("test_1v", self.cmd_base.test_1) + self.assertEqual("test_2v", self.cmd_base.test_2) + + def test__require(self): + self.assertRaises(common.ArgumentRequired, + self.cmd_base._require, "attr_1") + self.cmd_base.attr_1 = None + self.assertRaises(common.ArgumentRequired, + self.cmd_base._require, "attr_1") + self.cmd_base.attr_1 = "attr_v1" + self.cmd_base._require("attr_1") + + def test__make_list(self): + self.assertRaises(AttributeError, self.cmd_base._make_list, "attr1") + self.cmd_base.attr1 = "v1,v2" + self.cmd_base._make_list("attr1") + self.assertEqual(["v1", "v2"], self.cmd_base.attr1) + self.cmd_base.attr1 = ["v3"] + self.cmd_base._make_list("attr1") + self.assertEqual(["v3"], self.cmd_base.attr1) + + def test__pretty_print(self): + func = Mock(return_value=None) + self.cmd_base.verbose = True + self.assertEqual(None, self.cmd_base._pretty_print(func)) + self.cmd_base.verbose = False + self.assertEqual(None, self.cmd_base._pretty_print(func)) + + def test__dumps(self): + json.dumps = Mock(return_value="test-dump") + self.assertEqual("test-dump", self.cmd_base._dumps("item")) + + def test__pretty_list(self): + func = Mock(return_value=None) + self.cmd_base.verbose = True + self.assertEqual(None, self.cmd_base._pretty_list(func)) + self.cmd_base.verbose = False + self.assertEqual(None, self.cmd_base._pretty_list(func)) + item = Mock(return_value="test") + item._info = "info" + func = Mock(return_value=[item]) + self.assertEqual(None, self.cmd_base._pretty_list(func)) + + def test__pretty_paged(self): + self.cmd_base.limit = "5" + func = Mock(return_value=None) + self.cmd_base.verbose = True + self.assertEqual(None, self.cmd_base._pretty_paged(func)) + + self.cmd_base.verbose = False + + class MockIterable(collections.Iterable): + links = ["item"] + count = 1 + + def __iter__(self): + return ["item1"] + + def __len__(self): + return count + + ret = MockIterable() + func = Mock(return_value=ret) + self.assertEqual(None, self.cmd_base._pretty_paged(func)) + + ret.count = 0 + self.assertEqual(None, self.cmd_base._pretty_paged(func)) + + func = Mock(side_effect=ValueError) + self.assertEqual(None, self.cmd_base._pretty_paged(func)) + self.cmd_base.debug = True + self.cmd_base.marker = Mock() + self.assertRaises(ValueError, self.cmd_base._pretty_paged, func) + + +class AuthTest(TestCase): + + def setUp(self): + super(AuthTest, self).setUp() + self.orig_sys_exit = sys.exit + sys.exit = Mock(return_value=None) + self.parser = common.CliOptions().create_optparser(False) + self.auth = common.Auth(self.parser) + + def tearDown(self): + super(AuthTest, self).tearDown() + sys.exit = self.orig_sys_exit + + def test___init__(self): + self.assertEqual(None, self.auth.dbaas) + self.assertEqual(None, self.auth.apikey) + + def test_login(self): + self.auth.username = "username" + self.auth.apikey = "apikey" + self.auth.tenant_id = "tenant_id" + self.auth.auth_url = "auth_url" + dbaas = Mock() + dbaas.authenticate = Mock(return_value=None) + dbaas.client = Mock() + dbaas.client.auth_token = Mock() + dbaas.client.service_url = Mock() + self.auth._get_client = Mock(return_value=dbaas) + self.auth.login() + + self.auth.debug = True + self.auth._get_client = Mock(side_effect=ValueError) + self.assertRaises(ValueError, self.auth.login) + + self.auth.debug = False + self.auth.login() + + +class AuthedCommandsBaseTest(TestCase): + + def setUp(self): + super(AuthedCommandsBaseTest, self).setUp() + self.orig_sys_exit = sys.exit + sys.exit = Mock(return_value=None) + + def tearDown(self): + super(AuthedCommandsBaseTest, self).tearDown() + sys.exit = self.orig_sys_exit + + def test___init__(self): + parser = common.CliOptions().create_optparser(False) + common.AuthedCommandsBase.debug = True + dbaas = Mock() + dbaas.authenticate = Mock(return_value=None) + dbaas.client = Mock() + dbaas.client.auth_token = Mock() + dbaas.client.service_url = Mock() + dbaas.client.authenticate_with_token = Mock() + common.AuthedCommandsBase._get_client = Mock(return_value=dbaas) + authed_cmd = common.AuthedCommandsBase(parser) + + +class PaginatedTest(TestCase): + + def setUp(self): + super(PaginatedTest, self).setUp() + self.items_ = ["item1", "item2"] + self.next_marker_ = "next-marker" + self.links_ = ["link1", "link2"] + self.pgn = common.Paginated(self.items_, self.next_marker_, + self.links_) + + def tearDown(self): + super(PaginatedTest, self).tearDown() + + def test___init__(self): + self.assertEqual(self.items_, self.pgn.items) + self.assertEqual(self.next_marker_, self.pgn.next) + self.assertEqual(self.links_, self.pgn.links) + + def test___len__(self): + self.assertEqual(len(self.items_), self.pgn.__len__()) + + def test___iter__(self): + itr_expected = self.items_.__iter__() + itr = self.pgn.__iter__() + self.assertEqual(itr_expected.next(), itr.next()) + self.assertEqual(itr_expected.next(), itr.next()) + self.assertRaises(StopIteration, itr_expected.next) + self.assertRaises(StopIteration, itr.next) + + def test___getitem__(self): + self.assertEqual(self.items_[0], self.pgn.__getitem__(0)) + + def test___setitem__(self): + self.pgn.__setitem__(0, "new-item") + self.assertEqual("new-item", self.pgn.items[0]) + + def test___delitem(self): + del self.pgn[0] + self.assertEqual(1, self.pgn.__len__()) + + def test___reversed__(self): + itr = self.pgn.__reversed__() + expected = ["item2", "item1"] + self.assertEqual("item2", itr.next()) + self.assertEqual("item1", itr.next()) + self.assertRaises(StopIteration, itr.next) + + def test___contains__(self): + self.assertTrue(self.pgn.__contains__("item1")) + self.assertTrue(self.pgn.__contains__("item2")) + self.assertFalse(self.pgn.__contains__("item3")) diff --git a/troveclient/tests/test_instances.py b/troveclient/tests/test_instances.py new file mode 100644 index 0000000..05e4019 --- /dev/null +++ b/troveclient/tests/test_instances.py @@ -0,0 +1,176 @@ +from testtools import TestCase +from mock import Mock + +from troveclient import instances +from troveclient import base + +""" +Unit tests for instances.py +""" + + +class InstanceTest(TestCase): + + def setUp(self): + super(InstanceTest, self).setUp() + self.orig__init = instances.Instance.__init__ + instances.Instance.__init__ = Mock(return_value=None) + self.instance = instances.Instance() + self.instance.manager = Mock() + + def tearDown(self): + super(InstanceTest, self).tearDown() + instances.Instance.__init__ = self.orig__init + + def test___repr__(self): + self.instance.name = "instance-1" + self.assertEqual('<Instance: instance-1>', self.instance.__repr__()) + + def test_list_databases(self): + db_list = ['database1', 'database2'] + self.instance.manager.databases = Mock() + self.instance.manager.databases.list = Mock(return_value=db_list) + self.assertEqual(db_list, self.instance.list_databases()) + + def test_delete(self): + db_delete_mock = Mock(return_value=None) + self.instance.manager.delete = db_delete_mock + self.instance.delete() + self.assertEqual(1, db_delete_mock.call_count) + + def test_restart(self): + db_restart_mock = Mock(return_value=None) + self.instance.manager.restart = db_restart_mock + self.instance.id = 1 + self.instance.restart() + self.assertEqual(1, db_restart_mock.call_count) + + +class InstancesTest(TestCase): + + def setUp(self): + super(InstancesTest, self).setUp() + self.orig__init = instances.Instances.__init__ + instances.Instances.__init__ = Mock(return_value=None) + self.instances = instances.Instances() + self.instances.api = Mock() + self.instances.api.client = Mock() + self.instances.resource_class = Mock(return_value="instance-1") + + self.orig_base_getid = base.getid + base.getid = Mock(return_value="instance1") + + def tearDown(self): + super(InstancesTest, self).tearDown() + instances.Instances.__init__ = self.orig__init + base.getid = self.orig_base_getid + + def test_create(self): + def side_effect_func(path, body, inst): + return path, body, inst + + self.instances._create = Mock(side_effect=side_effect_func) + p, b, i = self.instances.create("test-name", 103, "test-volume", + ['db1', 'db2'], ['u1', 'u2']) + self.assertEqual("/instances", p) + self.assertEqual("instance", i) + self.assertEqual(['db1', 'db2'], b["instance"]["databases"]) + self.assertEqual(['u1', 'u2'], b["instance"]["users"]) + self.assertEqual("test-name", b["instance"]["name"]) + self.assertEqual("test-volume", b["instance"]["volume"]) + self.assertEqual(103, b["instance"]["flavorRef"]) + + def test__list(self): + self.instances.api.client.get = Mock(return_value=('resp', None)) + self.assertRaises(Exception, self.instances._list, "url", None) + + body = Mock() + body.get = Mock(return_value=[{'href': 'http://test.net/test_file', + 'rel': 'next'}]) + body.__getitem__ = Mock(return_value='instance1') + #self.instances.resource_class = Mock(return_value="instance-1") + self.instances.api.client.get = Mock(return_value=('resp', body)) + _expected = [{'href': 'http://test.net/test_file', 'rel': 'next'}] + self.assertEqual(_expected, self.instances._list("url", None).links) + + def test_list(self): + def side_effect_func(path, inst, limit, marker): + return path, inst, limit, marker + + self.instances._list = Mock(side_effect=side_effect_func) + limit_ = "test-limit" + marker_ = "test-marker" + expected = ("/instances", "instances", limit_, marker_) + self.assertEqual(expected, self.instances.list(limit_, marker_)) + + def test_get(self): + def side_effect_func(path, inst): + return path, inst + + self.instances._get = Mock(side_effect=side_effect_func) + self.assertEqual(('/instances/instance1', 'instance'), + self.instances.get(1)) + + def test_delete(self): + resp = Mock() + resp.status = 200 + body = None + self.instances.api.client.delete = Mock(return_value=(resp, body)) + self.instances.delete('instance1') + resp.status = 500 + self.assertRaises(Exception, self.instances.delete, 'instance1') + + def test__action(self): + body = Mock() + resp = Mock() + resp.status = 200 + self.instances.api.client.post = Mock(return_value=(resp, body)) + self.assertEqual('instance-1', self.instances._action(1, body)) + + self.instances.api.client.post = Mock(return_value=(resp, None)) + self.assertEqual(None, self.instances._action(1, body)) + + def _set_action_mock(self): + def side_effect_func(instance_id, body): + self._instance_id = instance_id + self._body = body + + self._instance_id = None + self._body = None + self.instances._action = Mock(side_effect=side_effect_func) + + def test_resize_volume(self): + self._set_action_mock() + self.instances.resize_volume(152, 512) + self.assertEqual(152, self._instance_id) + self.assertEqual({"resize": {"volume": {"size": 512}}}, self._body) + + def test_resize_instance(self): + self._set_action_mock() + self.instances.resize_instance(4725, 103) + self.assertEqual(4725, self._instance_id) + self.assertEqual({"resize": {"flavorRef": 103}}, self._body) + + def test_restart(self): + self._set_action_mock() + self.instances.restart(253) + self.assertEqual(253, self._instance_id) + self.assertEqual({'restart': {}}, self._body) + + def test_reset_password(self): + self._set_action_mock() + self.instances.reset_password(634) + self.assertEqual(634, self._instance_id) + self.assertEqual({'reset-password': {}}, self._body) + + +class InstanceStatusTest(TestCase): + + def test_constants(self): + self.assertEqual("ACTIVE", instances.InstanceStatus.ACTIVE) + self.assertEqual("BLOCKED", instances.InstanceStatus.BLOCKED) + self.assertEqual("BUILD", instances.InstanceStatus.BUILD) + self.assertEqual("FAILED", instances.InstanceStatus.FAILED) + self.assertEqual("REBOOT", instances.InstanceStatus.REBOOT) + self.assertEqual("RESIZE", instances.InstanceStatus.RESIZE) + self.assertEqual("SHUTDOWN", instances.InstanceStatus.SHUTDOWN) diff --git a/troveclient/tests/test_limits.py b/troveclient/tests/test_limits.py new file mode 100644 index 0000000..d40b646 --- /dev/null +++ b/troveclient/tests/test_limits.py @@ -0,0 +1,79 @@ +from testtools import TestCase +from mock import Mock +from troveclient import limits + + +class LimitsTest(TestCase): + """ + This class tests the calling code for the Limits API + """ + + def setUp(self): + super(LimitsTest, self).setUp() + self.limits = limits.Limits(Mock()) + self.limits.api.client = Mock() + + def tearDown(self): + super(LimitsTest, self).tearDown() + + def test_list(self): + resp = Mock() + resp.status = 200 + body = {"limits": + [ + {'maxTotalInstances': 55, + 'verb': 'ABSOLUTE', + 'maxTotalVolumes': 100}, + {'regex': '.*', + 'nextAvailable': '2011-07-21T18:17:06Z', + 'uri': '*', + 'value': 10, + 'verb': 'POST', + 'remaining': 2, 'unit': 'MINUTE'}, + {'regex': '.*', + 'nextAvailable': '2011-07-21T18:17:06Z', + 'uri': '*', + 'value': 10, + 'verb': 'PUT', + 'remaining': 2, + 'unit': 'MINUTE'}, + {'regex': '.*', + 'nextAvailable': '2011-07-21T18:17:06Z', + 'uri': '*', + 'value': 10, + 'verb': 'DELETE', + 'remaining': 2, + 'unit': 'MINUTE'}, + {'regex': '.*', + 'nextAvailable': '2011-07-21T18:17:06Z', + 'uri': '*', + 'value': 10, + 'verb': 'GET', + 'remaining': 2, 'unit': 'MINUTE'}]} + response = (resp, body) + + mock_get = Mock(return_value=response) + self.limits.api.client.get = mock_get + self.assertIsNotNone(self.limits.list()) + mock_get.assert_called_once_with("/limits") + + def test_list_errors(self): + status_list = [400, 401, 403, 404, 408, 409, 413, 500, 501] + for status_code in status_list: + self._check_error_response(status_code) + + def _check_error_response(self, status_code): + RESPONSE_KEY = "limits" + + resp = Mock() + resp.status = status_code + body = {RESPONSE_KEY: { + 'absolute': {}, + 'rate': [ + {'limit': [] + }]}} + response = (resp, body) + + mock_get = Mock(return_value=response) + self.limits.api.client.get = mock_get + self.assertRaises(Exception, self.limits.list) diff --git a/troveclient/tests/test_management.py b/troveclient/tests/test_management.py new file mode 100644 index 0000000..c04e216 --- /dev/null +++ b/troveclient/tests/test_management.py @@ -0,0 +1,144 @@ +from testtools import TestCase +from mock import Mock + +from troveclient import management +from troveclient import base + +""" +Unit tests for management.py +""" + + +class RootHistoryTest(TestCase): + + def setUp(self): + super(RootHistoryTest, self).setUp() + self.orig__init = management.RootHistory.__init__ + management.RootHistory.__init__ = Mock(return_value=None) + + def tearDown(self): + super(RootHistoryTest, self).tearDown() + management.RootHistory.__init__ = self.orig__init + + def test___repr__(self): + root_history = management.RootHistory() + root_history.id = "1" + root_history.created = "ct" + root_history.user = "tu" + self.assertEqual('<Root History: Instance 1 enabled at ct by tu>', + root_history.__repr__()) + + +class ManagementTest(TestCase): + + def setUp(self): + super(ManagementTest, self).setUp() + self.orig__init = management.Management.__init__ + management.Management.__init__ = Mock(return_value=None) + self.management = management.Management() + self.management.api = Mock() + self.management.api.client = Mock() + + self.orig_hist__init = management.RootHistory.__init__ + self.orig_base_getid = base.getid + base.getid = Mock(return_value="instance1") + + def tearDown(self): + super(ManagementTest, self).tearDown() + management.Management.__init__ = self.orig__init + management.RootHistory.__init__ = self.orig_hist__init + base.getid = self.orig_base_getid + + def test__list(self): + self.management.api.client.get = Mock(return_value=('resp', None)) + self.assertRaises(Exception, self.management._list, "url", None) + + body = Mock() + body.get = Mock(return_value=[{'href': 'http://test.net/test_file', + 'rel': 'next'}]) + body.__getitem__ = Mock(return_value='instance1') + self.management.resource_class = Mock(return_value="instance-1") + self.management.api.client.get = Mock(return_value=('resp', body)) + _expected = [{'href': 'http://test.net/test_file', 'rel': 'next'}] + self.assertEqual(_expected, self.management._list("url", None).links) + + def test_show(self): + def side_effect_func(path, instance): + return path, instance + self.management._get = Mock(side_effect=side_effect_func) + p, i = self.management.show(1) + self.assertEqual(('/mgmt/instances/instance1', 'instance'), (p, i)) + + def test_index(self): + def side_effect_func(url, name, limit, marker): + return url + + self.management._list = Mock(side_effect=side_effect_func) + self.assertEqual('/mgmt/instances?deleted=true', + self.management.index(deleted=True)) + self.assertEqual('/mgmt/instances?deleted=false', + self.management.index(deleted=False)) + + def test_root_enabled_history(self): + self.management.api.client.get = Mock(return_value=('resp', None)) + self.assertRaises(Exception, + self.management.root_enabled_history, "instance") + body = {'root_history': 'rh'} + self.management.api.client.get = Mock(return_value=('resp', body)) + management.RootHistory.__init__ = Mock(return_value=None) + rh = self.management.root_enabled_history("instance") + self.assertTrue(isinstance(rh, management.RootHistory)) + + def test__action(self): + resp = Mock() + self.management.api.client.post = Mock(return_value=(resp, 'body')) + resp.status = 200 + self.management._action(1, 'body') + self.assertEqual(1, self.management.api.client.post.call_count) + resp.status = 400 + self.assertRaises(Exception, self.management._action, 1, 'body') + self.assertEqual(2, self.management.api.client.post.call_count) + + def _mock_action(self): + self.body_ = "" + + def side_effect_func(instance_id, body): + self.body_ = body + self.management._action = Mock(side_effect=side_effect_func) + + def test_stop(self): + self._mock_action() + self.management.stop(1) + self.assertEqual(1, self.management._action.call_count) + self.assertEqual({'stop': {}}, self.body_) + + def test_reboot(self): + self._mock_action() + self.management.reboot(1) + self.assertEqual(1, self.management._action.call_count) + self.assertEqual({'reboot': {}}, self.body_) + + def test_migrate(self): + self._mock_action() + self.management.migrate(1) + self.assertEqual(1, self.management._action.call_count) + self.assertEqual({'migrate': {}}, self.body_) + + def test_migrate_to_host(self): + hostname = 'hostname2' + self._mock_action() + self.management.migrate(1, host=hostname) + self.assertEqual(1, self.management._action.call_count) + self.assertEqual({'migrate': {'host': hostname}}, self.body_) + + def test_update(self): + self._mock_action() + self.management.update(1) + self.assertEqual(1, self.management._action.call_count) + self.assertEqual({'update': {}}, self.body_) + + def test_reset_task_status(self): + self._mock_action() + self.management.reset_task_status(1) + self.assertEqual(1, self.management._action.call_count) + self.assertEqual({'reset-task-status': {}}, self.body_) diff --git a/troveclient/tests/test_secgroups.py b/troveclient/tests/test_secgroups.py new file mode 100644 index 0000000..779d01e --- /dev/null +++ b/troveclient/tests/test_secgroups.py @@ -0,0 +1,102 @@ +from testtools import TestCase +from mock import Mock + +from troveclient import security_groups +from troveclient import base + +""" +Unit tests for security_groups.py +""" + + +class SecGroupTest(TestCase): + + def setUp(self): + super(SecGroupTest, self).setUp() + self.orig__init = security_groups.SecurityGroup.__init__ + security_groups.SecurityGroup.__init__ = Mock(return_value=None) + self.security_group = security_groups.SecurityGroup() + self.security_groups = security_groups.SecurityGroups(1) + + def tearDown(self): + super(SecGroupTest, self).tearDown() + security_groups.SecurityGroup.__init__ = self.orig__init + + def test___repr__(self): + self.security_group.name = "security_group-1" + self.assertEqual('<SecurityGroup: security_group-1>', + self.security_group.__repr__()) + + def test_list(self): + sec_group_list = ['secgroup1', 'secgroup2'] + self.security_groups.list = Mock(return_value=sec_group_list) + self.assertEqual(sec_group_list, self.security_groups.list()) + + def test_get(self): + def side_effect_func(path, inst): + return path, inst + + self.security_groups._get = Mock(side_effect=side_effect_func) + self.security_group.id = 1 + self.assertEqual(('/security-groups/1', 'security_group'), + self.security_groups.get(self.security_group)) + + +class SecGroupRuleTest(TestCase): + + def setUp(self): + super(SecGroupRuleTest, self).setUp() + self.orig__init = security_groups.SecurityGroupRule.__init__ + security_groups.SecurityGroupRule.__init__ = Mock(return_value=None) + security_groups.SecurityGroupRules.__init__ = Mock(return_value=None) + self.security_group_rule = security_groups.SecurityGroupRule() + self.security_group_rules = security_groups.SecurityGroupRules() + + def tearDown(self): + super(SecGroupRuleTest, self).tearDown() + security_groups.SecurityGroupRule.__init__ = self.orig__init + + def test___repr__(self): + self.security_group_rule.group_id = 1 + self.security_group_rule.protocol = "tcp" + self.security_group_rule.from_port = 80 + self.security_group_rule.to_port = 80 + self.security_group_rule.cidr = "0.0.0.0//0" + representation = \ + "<SecurityGroupRule: ( \ + Security Group id: %d, \ + Protocol: %s, \ + From_Port: %d, \ + To_Port: %d, \ + CIDR: %s )>" % (1, "tcp", 80, 80, "0.0.0.0//0") + + self.assertEqual(representation, + self.security_group_rule.__repr__()) + + def test_create(self): + def side_effect_func(path, body, inst): + return path, body, inst + + self.security_group_rules._create = Mock(side_effect=side_effect_func) + p, b, i = self.security_group_rules.create(1, "tcp", + 80, 80, "0.0.0.0//0") + self.assertEqual("/security-group-rules", p) + self.assertEqual("security_group_rule", i) + self.assertEqual(1, b["security_group_rule"]["group_id"]) + self.assertEqual("tcp", b["security_group_rule"]["protocol"]) + self.assertEqual(80, b["security_group_rule"]["from_port"]) + self.assertEqual(80, b["security_group_rule"]["to_port"]) + self.assertEqual("0.0.0.0//0", b["security_group_rule"]["cidr"]) + + def test_delete(self): + resp = Mock() + resp.status = 200 + body = None + self.security_group_rules.api = Mock() + self.security_group_rules.api.client = Mock() + self.security_group_rules.api.client.delete = \ + Mock(return_value=(resp, body)) + self.security_group_rules.delete(self.id) + resp.status = 500 + self.assertRaises(Exception, self.security_group_rules.delete, + self.id) diff --git a/troveclient/tests/test_users.py b/troveclient/tests/test_users.py new file mode 100644 index 0000000..0fc32f6 --- /dev/null +++ b/troveclient/tests/test_users.py @@ -0,0 +1,126 @@ +from testtools import TestCase +from mock import Mock + +from troveclient import users +from troveclient import base + +""" +Unit tests for users.py +""" + + +class UserTest(TestCase): + + def setUp(self): + super(UserTest, self).setUp() + self.orig__init = users.User.__init__ + users.User.__init__ = Mock(return_value=None) + self.user = users.User() + + def tearDown(self): + super(UserTest, self).tearDown() + users.User.__init__ = self.orig__init + + def test___repr__(self): + self.user.name = "user-1" + self.assertEqual('<User: user-1>', self.user.__repr__()) + + +class UsersTest(TestCase): + + def setUp(self): + super(UsersTest, self).setUp() + self.orig__init = users.Users.__init__ + users.Users.__init__ = Mock(return_value=None) + self.users = users.Users() + self.users.api = Mock() + self.users.api.client = Mock() + + self.orig_base_getid = base.getid + base.getid = Mock(return_value="instance1") + + def tearDown(self): + super(UsersTest, self).tearDown() + users.Users.__init__ = self.orig__init + base.getid = self.orig_base_getid + + def _get_mock_method(self): + self._resp = Mock() + self._body = None + self._url = None + + def side_effect_func(url, body=None): + self._body = body + self._url = url + return (self._resp, body) + + return Mock(side_effect=side_effect_func) + + def _build_fake_user(self, name, hostname=None, password=None, + databases=None): + return {'name': name, + 'password': password if password else 'password', + 'host': hostname, + 'databases': databases if databases else [], + } + + def test_create(self): + self.users.api.client.post = self._get_mock_method() + self._resp.status = 200 + user = self._build_fake_user('user1') + + self.users.create(23, [user]) + self.assertEqual('/instances/23/users', self._url) + self.assertEqual({"users": [user]}, self._body) + + # Even if host isn't supplied originally, + # the default is supplied. + del user['host'] + self.users.create(23, [user]) + self.assertEqual('/instances/23/users', self._url) + user['host'] = '%' + self.assertEqual({"users": [user]}, self._body) + + # If host is supplied, of course it's put into the body. + user['host'] = '127.0.0.1' + self.users.create(23, [user]) + self.assertEqual({"users": [user]}, self._body) + + # Make sure that response of 400 is recognized as an error. + user['host'] = '%' + self._resp.status = 400 + self.assertRaises(Exception, self.users.create, 12, [user]) + + def test_delete(self): + self.users.api.client.delete = self._get_mock_method() + self._resp.status = 200 + self.users.delete(27, 'user1') + self.assertEqual('/instances/27/users/user1', self._url) + self._resp.status = 400 + self.assertRaises(Exception, self.users.delete, 34, 'user1') + + def test__list(self): + def side_effect_func(self, val): + return val + + key = 'key' + body = Mock() + body.get = Mock(return_value=[{'href': 'http://test.net/test_file', + 'rel': 'next'}]) + body.__getitem__ = Mock(return_value=["test-value"]) + + resp = Mock() + resp.status = 200 + self.users.resource_class = Mock(side_effect=side_effect_func) + self.users.api.client.get = Mock(return_value=(resp, body)) + self.assertEqual(["test-value"], self.users._list('url', key).items) + + self.users.api.client.get = Mock(return_value=(resp, None)) + self.assertRaises(Exception, self.users._list, 'url', None) + + def test_list(self): + def side_effect_func(path, user, limit, marker): + return path + + self.users._list = Mock(side_effect=side_effect_func) + self.assertEqual('/instances/instance1/users', self.users.list(1)) diff --git a/troveclient/tests/test_utils.py b/troveclient/tests/test_utils.py new file mode 100644 index 0000000..12ee9d0 --- /dev/null +++ b/troveclient/tests/test_utils.py @@ -0,0 +1,41 @@ +import os +from testtools import TestCase +from troveclient import utils +from troveclient import versions + + +class UtilsTest(TestCase): + + def test_add_hookable_mixin(self): + def func(): + pass + + hook_type = "hook_type" + mixin = utils.HookableMixin() + mixin.add_hook(hook_type, func) + self.assertTrue(hook_type in mixin._hooks_map) + self.assertTrue(func in mixin._hooks_map[hook_type]) + + def test_run_hookable_mixin(self): + def func(): + pass + + hook_type = "hook_type" + mixin = utils.HookableMixin() + mixin.add_hook(hook_type, func) + mixin.run_hooks(hook_type) + + def test_environment(self): + self.assertEqual('', utils.env()) + self.assertEqual('passing', utils.env(default='passing')) + + os.environ['test_abc'] = 'passing' + self.assertEqual('passing', utils.env('test_abc')) + self.assertEqual('', utils.env('test_abcd')) + + def test_slugify(self): + import unicodedata + + self.assertEqual('not_unicode', utils.slugify('not_unicode')) + self.assertEqual('unicode', utils.slugify(unicode('unicode'))) + self.assertEqual('slugify-test', utils.slugify('SLUGIFY% test!')) diff --git a/troveclient/tests/test_xml.py b/troveclient/tests/test_xml.py new file mode 100644 index 0000000..96490ce --- /dev/null +++ b/troveclient/tests/test_xml.py @@ -0,0 +1,241 @@ +from testtools import TestCase +from lxml import etree +from troveclient import xml + + +class XmlTest(TestCase): + + ELEMENT = ''' + <instances> + <instance> + <flavor> + <links> + </links> + <value value="5"/> + </flavor> + </instance> + </instances> + ''' + ROOT = etree.fromstring(ELEMENT) + + JSON = {'instances': + {'instances': ['1', '2', '3']}, 'dummy': {'dict': True}} + + def test_element_ancestors_match_list(self): + # Test normal operation: + self.assertTrue(xml.element_ancestors_match_list(self.ROOT[0][0], + ['instance', + 'instances'])) + + # Test itr_elem is None: + self.assertTrue(xml.element_ancestors_match_list(self.ROOT, + ['instances'])) + + # Test that the first parent element does not match the first list + # element: + self.assertFalse(xml.element_ancestors_match_list(self.ROOT[0][0], + ['instances', + 'instance'])) + + def test_populate_element_from_dict(self): + # Test populate_element_from_dict with a None in the data + ele = ''' + <instance> + <volume> + <value size="5"/> + </volume> + </instance> + ''' + rt = etree.fromstring(ele) + + self.assertEqual(None, xml.populate_element_from_dict(rt, + {'size': None})) + + def test_element_must_be_list(self): + # Test for when name isn't in the dictionary + self.assertFalse(xml.element_must_be_list(self.ROOT, "not_in_list")) + + # Test when name is in the dictionary but list is empty + self.assertTrue(xml.element_must_be_list(self.ROOT, "accounts")) + + # Test when name is in the dictionary but list is not empty + self.assertTrue(xml.element_must_be_list(self.ROOT[0][0][0], "links")) + + def test_element_to_json(self): + # Test when element must be list: + self.assertEqual([{'flavor': {'links': [], 'value': {'value': '5'}}}], + xml.element_to_json("accounts", self.ROOT)) + + # Test when element must not be list: + exp = {'instance': {'flavor': {'links': [], 'value': {'value': '5'}}}} + self.assertEqual(exp, xml.element_to_json("not_in_list", self.ROOT)) + + def test_root_element_to_json(self): + # Test when element must be list: + exp = ([{'flavor': {'links': [], 'value': {'value': '5'}}}], None) + self.assertEqual(exp, xml.root_element_to_json("accounts", self.ROOT)) + + # Test when element must not be list: + exp = {'instance': {'flavor': {'links': [], 'value': {'value': '5'}}}} + self.assertEqual((exp, None), + xml.root_element_to_json("not_in_list", self.ROOT)) + + # Test rootEnabled True: + t_element = etree.fromstring('''<rootEnabled> True </rootEnabled>''') + self.assertEqual((True, None), + xml.root_element_to_json("rootEnabled", t_element)) + + # Test rootEnabled False: + f_element = etree.fromstring('''<rootEnabled> False </rootEnabled>''') + self.assertEqual((False, None), + xml.root_element_to_json("rootEnabled", f_element)) + + def test_element_to_list(self): + # Test w/ no child elements + self.assertEqual([], xml.element_to_list(self.ROOT[0][0][0])) + + # Test w/ no child elements and check_for_links = True + self.assertEqual(([], None), + xml.element_to_list(self.ROOT[0][0][0], + check_for_links=True)) + + # Test w/ child elements + self.assertEqual([{}, {'value': '5'}], + xml.element_to_list(self.ROOT[0][0])) + + # Test w/ child elements and check_for_links = True + self.assertEqual(([{'value': '5'}], []), + xml.element_to_list(self.ROOT[0][0], + check_for_links=True)) + + def test_element_to_dict(self): + # Test when there is not a None + exp = {'instance': {'flavor': {'links': [], 'value': {'value': '5'}}}} + self.assertEqual(exp, xml.element_to_dict(self.ROOT)) + + # Test when there is a None + element = ''' + <server> + None + </server> + ''' + rt = etree.fromstring(element) + self.assertEqual(None, xml.element_to_dict(rt)) + + def test_standarize_json(self): + xml.standardize_json_lists(self.JSON) + self.assertEqual({'instances': ['1', '2', '3'], + 'dummy': {'dict': True}}, self.JSON) + + def test_normalize_tag(self): + ELEMENT_NS = ''' + <instances xmlns="http://www.w3.org/1999/xhtml"> + <instance> + <flavor> + <links> + </links> + <value value="5"/> + </flavor> + </instance> + </instances> + ''' + ROOT_NS = etree.fromstring(ELEMENT_NS) + + # Test normalizing without namespace info + self.assertEqual('instances', xml.normalize_tag(self.ROOT)) + + # Test normalizing with namespace info + self.assertEqual('instances', xml.normalize_tag(ROOT_NS)) + + def test_create_root_xml_element(self): + # Test creating when name is not in REQUEST_AS_LIST + element = xml.create_root_xml_element("root", {"root": "value"}) + exp = '<root xmlns="http://docs.openstack.org/database/api/v1.0" ' \ + 'root="value"/>' + self.assertEqual(exp, etree.tostring(element)) + + # Test creating when name is in REQUEST_AS_LIST + element = xml.create_root_xml_element("users", []) + exp = '<users xmlns="http://docs.openstack.org/database/api/v1.0"/>' + self.assertEqual(exp, etree.tostring(element)) + + def test_creating_subelements(self): + # Test creating a subelement as a dictionary + element = xml.create_root_xml_element("root", {"root": 5}) + xml.create_subelement(element, "subelement", {"subelement": "value"}) + exp = '<root xmlns="http://docs.openstack.org/database/api/v1.0" ' \ + 'root="5"><subelement subelement="value"/></root>' + self.assertEqual(exp, etree.tostring(element)) + + # Test creating a subelement as a list + element = xml.create_root_xml_element("root", + {"root": {"value": "nested"}}) + xml.create_subelement(element, "subelement", [{"subelement": "value"}]) + exp = '<root xmlns="http://docs.openstack.org/database/api/v1.0">' \ + '<root value="nested"/><subelement><subelement subelement=' \ + '"value"/></subelement></root>' + self.assertEqual(exp, etree.tostring(element)) + + # Test creating a subelement as a string (should raise TypeError) + element = xml.create_root_xml_element("root", {"root": "value"}) + try: + xml.create_subelement(element, "subelement", ["value"]) + self.fail("TypeError exception expected") + except TypeError: + pass + + def test_modify_response_types(self): + TYPE_MAP = { + "Int": int, + "Bool": bool + } + #Is a string True + self.assertEqual(True, xml.modify_response_types('True', TYPE_MAP)) + + #Is a string False + self.assertEqual(False, xml.modify_response_types('False', TYPE_MAP)) + + #Is a dict + test_dict = {"Int": "5"} + test_dict = xml.modify_response_types(test_dict, TYPE_MAP) + self.assertEqual(int, test_dict["Int"].__class__) + + #Is a list + test_list = {"a_list": [{"Int": "5"}, {"Str": "A"}]} + test_list = xml.modify_response_types(test_list["a_list"], TYPE_MAP) + self.assertEqual([{'Int': 5}, {'Str': 'A'}], test_list) + + def test_trovexmlclient(self): + from troveclient import exceptions + + client = xml.TroveXmlClient("user", "password", "tenant", + "auth_url", "service_name", + auth_strategy="fake") + request = {'headers': {}} + + # Test morph_request, no body + client.morph_request(request) + self.assertEqual('application/xml', request['headers']['Accept']) + self.assertEqual('application/xml', request['headers']['Content-Type']) + + # Test morph_request, with body + request['body'] = {'root': {'test': 'test'}} + client.morph_request(request) + body = '<root xmlns="http://docs.openstack.org/database/api/v1.0" ' \ + 'test="test"/>\n' + exp = {'body': body, + 'headers': {'Content-Type': 'application/xml', + 'Accept': 'application/xml'}} + self.assertEqual(exp, request) + + # Test morph_response_body + request = "<users><links><user href='value'/></links></users>" + result = client.morph_response_body(request) + self.assertEqual({'users': [], 'links': [{'href': 'value'}]}, result) + + # Test morph_response_body with improper input + try: + client.morph_response_body("value") + self.fail("ResponseFormatError exception expected") + except exceptions.ResponseFormatError: + pass |
