summaryrefslogtreecommitdiff
path: root/openstackclient/tests/unit
diff options
context:
space:
mode:
authorSteve Martinelli <s.martinelli@gmail.com>2016-09-05 22:14:33 -0700
committerSteve Martinelli <s.martinelli@gmail.com>2016-09-08 15:19:50 -0700
commit39839def2e356e8d145be89380c73a71423cf06d (patch)
treef53c090b7ded46554866436e9d687492d2cef487 /openstackclient/tests/unit
parent7d1a5d0854c732681a130255ddc6abb2e9721a7a (diff)
downloadpython-openstackclient-39839def2e356e8d145be89380c73a71423cf06d.tar.gz
move unit tests to new "unit" test module
this will better isolate the unit tests from the functional tests. unfortunately, the "integration" tests had to be lumped into the "unit" tests since we need the separation in testr.conf Change-Id: Ifd12198c1f90e4e3c951c73bfa1884ab300d8ded
Diffstat (limited to 'openstackclient/tests/unit')
-rw-r--r--openstackclient/tests/unit/__init__.py0
-rw-r--r--openstackclient/tests/unit/api/__init__.py0
-rw-r--r--openstackclient/tests/unit/api/fakes.py56
-rw-r--r--openstackclient/tests/unit/api/test_api.py326
-rw-r--r--openstackclient/tests/unit/api/test_image_v1.py98
-rw-r--r--openstackclient/tests/unit/api/test_image_v2.py98
-rw-r--r--openstackclient/tests/unit/api/test_object_store_v1.py337
-rw-r--r--openstackclient/tests/unit/api/test_utils.py115
-rw-r--r--openstackclient/tests/unit/common/__init__.py0
-rw-r--r--openstackclient/tests/unit/common/test_availability_zone.py268
-rw-r--r--openstackclient/tests/unit/common/test_clientmanager.py69
-rw-r--r--openstackclient/tests/unit/common/test_command.py49
-rw-r--r--openstackclient/tests/unit/common/test_commandmanager.py107
-rw-r--r--openstackclient/tests/unit/common/test_configuration.py85
-rw-r--r--openstackclient/tests/unit/common/test_extension.py244
-rw-r--r--openstackclient/tests/unit/common/test_logs.py207
-rw-r--r--openstackclient/tests/unit/common/test_module.py130
-rw-r--r--openstackclient/tests/unit/common/test_parseractions.py221
-rw-r--r--openstackclient/tests/unit/common/test_quota.py381
-rw-r--r--openstackclient/tests/unit/compute/__init__.py0
-rw-r--r--openstackclient/tests/unit/compute/v2/__init__.py0
-rw-r--r--openstackclient/tests/unit/compute/v2/fakes.py1249
-rw-r--r--openstackclient/tests/unit/compute/v2/test_agent.py320
-rw-r--r--openstackclient/tests/unit/compute/v2/test_aggregate.py447
-rw-r--r--openstackclient/tests/unit/compute/v2/test_console.py196
-rw-r--r--openstackclient/tests/unit/compute/v2/test_flavor.py825
-rw-r--r--openstackclient/tests/unit/compute/v2/test_host.py179
-rw-r--r--openstackclient/tests/unit/compute/v2/test_hypervisor.py221
-rw-r--r--openstackclient/tests/unit/compute/v2/test_hypervisor_stats.py79
-rw-r--r--openstackclient/tests/unit/compute/v2/test_keypair.py312
-rw-r--r--openstackclient/tests/unit/compute/v2/test_server.py1844
-rw-r--r--openstackclient/tests/unit/compute/v2/test_server_backup.py271
-rw-r--r--openstackclient/tests/unit/compute/v2/test_server_group.py284
-rw-r--r--openstackclient/tests/unit/compute/v2/test_server_image.py228
-rw-r--r--openstackclient/tests/unit/compute/v2/test_service.py410
-rw-r--r--openstackclient/tests/unit/fakes.py242
-rw-r--r--openstackclient/tests/unit/identity/__init__.py0
-rw-r--r--openstackclient/tests/unit/identity/v2_0/__init__.py0
-rw-r--r--openstackclient/tests/unit/identity/v2_0/fakes.py515
-rw-r--r--openstackclient/tests/unit/identity/v2_0/test_catalog.py176
-rw-r--r--openstackclient/tests/unit/identity/v2_0/test_endpoint.py239
-rw-r--r--openstackclient/tests/unit/identity/v2_0/test_project.py635
-rw-r--r--openstackclient/tests/unit/identity/v2_0/test_role.py480
-rw-r--r--openstackclient/tests/unit/identity/v2_0/test_role_assignment.py271
-rw-r--r--openstackclient/tests/unit/identity/v2_0/test_service.py316
-rw-r--r--openstackclient/tests/unit/identity/v2_0/test_token.py115
-rw-r--r--openstackclient/tests/unit/identity/v2_0/test_user.py793
-rw-r--r--openstackclient/tests/unit/identity/v3/__init__.py0
-rw-r--r--openstackclient/tests/unit/identity/v3/fakes.py914
-rw-r--r--openstackclient/tests/unit/identity/v3/test_catalog.py142
-rw-r--r--openstackclient/tests/unit/identity/v3/test_consumer.py219
-rw-r--r--openstackclient/tests/unit/identity/v3/test_credential.py357
-rw-r--r--openstackclient/tests/unit/identity/v3/test_domain.py401
-rw-r--r--openstackclient/tests/unit/identity/v3/test_endpoint.py750
-rw-r--r--openstackclient/tests/unit/identity/v3/test_group.py569
-rw-r--r--openstackclient/tests/unit/identity/v3/test_identity_provider.py593
-rw-r--r--openstackclient/tests/unit/identity/v3/test_mappings.py244
-rw-r--r--openstackclient/tests/unit/identity/v3/test_oauth.py173
-rw-r--r--openstackclient/tests/unit/identity/v3/test_project.py978
-rw-r--r--openstackclient/tests/unit/identity/v3/test_protocol.py188
-rw-r--r--openstackclient/tests/unit/identity/v3/test_region.py348
-rw-r--r--openstackclient/tests/unit/identity/v3/test_role.py1105
-rw-r--r--openstackclient/tests/unit/identity/v3/test_role_assignment.py683
-rw-r--r--openstackclient/tests/unit/identity/v3/test_service.py504
-rw-r--r--openstackclient/tests/unit/identity/v3/test_service_provider.py408
-rw-r--r--openstackclient/tests/unit/identity/v3/test_token.py138
-rw-r--r--openstackclient/tests/unit/identity/v3/test_trust.py236
-rw-r--r--openstackclient/tests/unit/identity/v3/test_unscoped_saml.py133
-rw-r--r--openstackclient/tests/unit/identity/v3/test_user.py1063
-rw-r--r--openstackclient/tests/unit/image/__init__.py0
-rw-r--r--openstackclient/tests/unit/image/v1/__init__.py0
-rw-r--r--openstackclient/tests/unit/image/v1/fakes.py76
-rw-r--r--openstackclient/tests/unit/image/v1/test_image.py701
-rw-r--r--openstackclient/tests/unit/image/v2/__init__.py0
-rw-r--r--openstackclient/tests/unit/image/v2/fakes.py309
-rw-r--r--openstackclient/tests/unit/image/v2/test_image.py1316
-rw-r--r--openstackclient/tests/unit/integ/__init__.py0
-rw-r--r--openstackclient/tests/unit/integ/base.py121
-rw-r--r--openstackclient/tests/unit/integ/cli/__init__.py0
-rw-r--r--openstackclient/tests/unit/integ/cli/test_project.py257
-rw-r--r--openstackclient/tests/unit/integ/cli/test_shell.py506
-rw-r--r--openstackclient/tests/unit/network/__init__.py0
-rw-r--r--openstackclient/tests/unit/network/test_common.py174
-rw-r--r--openstackclient/tests/unit/network/v2/__init__.py0
-rw-r--r--openstackclient/tests/unit/network/v2/fakes.py1100
-rw-r--r--openstackclient/tests/unit/network/v2/test_address_scope.py399
-rw-r--r--openstackclient/tests/unit/network/v2/test_floating_ip.py565
-rw-r--r--openstackclient/tests/unit/network/v2/test_floating_ip_pool.py97
-rw-r--r--openstackclient/tests/unit/network/v2/test_ip_availability.py172
-rw-r--r--openstackclient/tests/unit/network/v2/test_network.py1059
-rw-r--r--openstackclient/tests/unit/network/v2/test_network_agent.py294
-rw-r--r--openstackclient/tests/unit/network/v2/test_network_rbac.py430
-rw-r--r--openstackclient/tests/unit/network/v2/test_network_segment.py200
-rw-r--r--openstackclient/tests/unit/network/v2/test_port.py696
-rw-r--r--openstackclient/tests/unit/network/v2/test_router.py751
-rw-r--r--openstackclient/tests/unit/network/v2/test_security_group.py770
-rw-r--r--openstackclient/tests/unit/network/v2/test_security_group_rule.py1177
-rw-r--r--openstackclient/tests/unit/network/v2/test_subnet.py978
-rw-r--r--openstackclient/tests/unit/network/v2/test_subnet_pool.py722
-rw-r--r--openstackclient/tests/unit/object/__init__.py0
-rw-r--r--openstackclient/tests/unit/object/v1/__init__.py0
-rw-r--r--openstackclient/tests/unit/object/v1/fakes.py88
-rw-r--r--openstackclient/tests/unit/object/v1/test_container.py407
-rw-r--r--openstackclient/tests/unit/object/v1/test_container_all.py345
-rw-r--r--openstackclient/tests/unit/object/v1/test_object.py382
-rw-r--r--openstackclient/tests/unit/object/v1/test_object_all.py182
-rw-r--r--openstackclient/tests/unit/test_shell.py442
-rw-r--r--openstackclient/tests/unit/utils.py75
-rw-r--r--openstackclient/tests/unit/volume/__init__.py0
-rw-r--r--openstackclient/tests/unit/volume/test_find_resource.py83
-rw-r--r--openstackclient/tests/unit/volume/v1/__init__.py0
-rw-r--r--openstackclient/tests/unit/volume/v1/fakes.py280
-rw-r--r--openstackclient/tests/unit/volume/v1/test_qos_specs.py472
-rw-r--r--openstackclient/tests/unit/volume/v1/test_service.py286
-rw-r--r--openstackclient/tests/unit/volume/v1/test_transfer_request.py114
-rw-r--r--openstackclient/tests/unit/volume/v1/test_volume.py716
-rw-r--r--openstackclient/tests/unit/volume/v2/__init__.py0
-rw-r--r--openstackclient/tests/unit/volume/v2/fakes.py696
-rw-r--r--openstackclient/tests/unit/volume/v2/test_backup.py388
-rw-r--r--openstackclient/tests/unit/volume/v2/test_qos_specs.py453
-rw-r--r--openstackclient/tests/unit/volume/v2/test_service.py286
-rw-r--r--openstackclient/tests/unit/volume/v2/test_snapshot.py458
-rw-r--r--openstackclient/tests/unit/volume/v2/test_transfer_request.py114
-rw-r--r--openstackclient/tests/unit/volume/v2/test_type.py575
-rw-r--r--openstackclient/tests/unit/volume/v2/test_volume.py966
125 files changed, 44262 insertions, 0 deletions
diff --git a/openstackclient/tests/unit/__init__.py b/openstackclient/tests/unit/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/unit/__init__.py
diff --git a/openstackclient/tests/unit/api/__init__.py b/openstackclient/tests/unit/api/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/unit/api/__init__.py
diff --git a/openstackclient/tests/unit/api/fakes.py b/openstackclient/tests/unit/api/fakes.py
new file mode 100644
index 00000000..26213a2f
--- /dev/null
+++ b/openstackclient/tests/unit/api/fakes.py
@@ -0,0 +1,56 @@
+# 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.
+#
+
+"""API Test Fakes"""
+
+from keystoneauth1 import session
+from requests_mock.contrib import fixture
+
+from openstackclient.tests.unit import utils
+
+
+RESP_ITEM_1 = {
+ 'id': '1',
+ 'name': 'alpha',
+ 'status': 'UP',
+ 'props': {'a': 1, 'b': 2},
+}
+RESP_ITEM_2 = {
+ 'id': '2',
+ 'name': 'beta',
+ 'status': 'DOWN',
+ 'props': {'a': 2, 'b': 2},
+}
+RESP_ITEM_3 = {
+ 'id': '3',
+ 'name': 'delta',
+ 'status': 'UP',
+ 'props': {'a': 3, 'b': 1},
+}
+
+LIST_RESP = [RESP_ITEM_1, RESP_ITEM_2]
+
+LIST_BODY = {
+ 'p1': 'xxx',
+ 'p2': 'yyy',
+}
+
+
+class TestSession(utils.TestCase):
+
+ BASE_URL = 'https://api.example.com:1234/vX'
+
+ def setUp(self):
+ super(TestSession, self).setUp()
+ self.sess = session.Session()
+ self.requests_mock = self.useFixture(fixture.Fixture())
diff --git a/openstackclient/tests/unit/api/test_api.py b/openstackclient/tests/unit/api/test_api.py
new file mode 100644
index 00000000..5f4a0c1a
--- /dev/null
+++ b/openstackclient/tests/unit/api/test_api.py
@@ -0,0 +1,326 @@
+# 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.
+#
+
+"""Base API Library Tests"""
+
+from osc_lib import exceptions
+
+from openstackclient.api import api
+from openstackclient.tests.unit.api import fakes as api_fakes
+
+
+class TestKeystoneSession(api_fakes.TestSession):
+
+ def setUp(self):
+ super(TestKeystoneSession, self).setUp()
+ self.api = api.KeystoneSession(
+ session=self.sess,
+ endpoint=self.BASE_URL,
+ )
+
+ def test_session_request(self):
+ self.requests_mock.register_uri(
+ 'GET',
+ self.BASE_URL + '/qaz',
+ json=api_fakes.RESP_ITEM_1,
+ status_code=200,
+ )
+ ret = self.api._request('GET', '/qaz')
+ self.assertEqual(api_fakes.RESP_ITEM_1, ret.json())
+
+
+class TestBaseAPI(api_fakes.TestSession):
+
+ def setUp(self):
+ super(TestBaseAPI, self).setUp()
+ self.api = api.BaseAPI(
+ session=self.sess,
+ endpoint=self.BASE_URL,
+ )
+
+ def test_create_post(self):
+ self.requests_mock.register_uri(
+ 'POST',
+ self.BASE_URL + '/qaz',
+ json=api_fakes.RESP_ITEM_1,
+ status_code=202,
+ )
+ ret = self.api.create('qaz')
+ self.assertEqual(api_fakes.RESP_ITEM_1, ret)
+
+ def test_create_put(self):
+ self.requests_mock.register_uri(
+ 'PUT',
+ self.BASE_URL + '/qaz',
+ json=api_fakes.RESP_ITEM_1,
+ status_code=202,
+ )
+ ret = self.api.create('qaz', method='PUT')
+ self.assertEqual(api_fakes.RESP_ITEM_1, ret)
+
+ def test_delete(self):
+ self.requests_mock.register_uri(
+ 'DELETE',
+ self.BASE_URL + '/qaz',
+ status_code=204,
+ )
+ ret = self.api.delete('qaz')
+ self.assertEqual(204, ret.status_code)
+
+ # find tests
+
+ def test_find_attr_by_id(self):
+
+ # All first requests (by name) will fail in this test
+ self.requests_mock.register_uri(
+ 'GET',
+ self.BASE_URL + '/qaz?name=1',
+ json={'qaz': []},
+ status_code=200,
+ )
+ self.requests_mock.register_uri(
+ 'GET',
+ self.BASE_URL + '/qaz?id=1',
+ json={'qaz': [api_fakes.RESP_ITEM_1]},
+ status_code=200,
+ )
+ ret = self.api.find_attr('qaz', '1')
+ self.assertEqual(api_fakes.RESP_ITEM_1, ret)
+
+ # value not found
+ self.requests_mock.register_uri(
+ 'GET',
+ self.BASE_URL + '/qaz?name=0',
+ json={'qaz': []},
+ status_code=200,
+ )
+ self.requests_mock.register_uri(
+ 'GET',
+ self.BASE_URL + '/qaz?id=0',
+ json={'qaz': []},
+ status_code=200,
+ )
+ self.assertRaises(
+ exceptions.CommandError,
+ self.api.find_attr,
+ 'qaz',
+ '0',
+ )
+
+ # Attribute other than 'name'
+ self.requests_mock.register_uri(
+ 'GET',
+ self.BASE_URL + '/qaz?status=UP',
+ json={'qaz': [api_fakes.RESP_ITEM_1]},
+ status_code=200,
+ )
+ ret = self.api.find_attr('qaz', 'UP', attr='status')
+ self.assertEqual(api_fakes.RESP_ITEM_1, ret)
+ ret = self.api.find_attr('qaz', value='UP', attr='status')
+ self.assertEqual(api_fakes.RESP_ITEM_1, ret)
+
+ def test_find_attr_by_name(self):
+ self.requests_mock.register_uri(
+ 'GET',
+ self.BASE_URL + '/qaz?name=alpha',
+ json={'qaz': [api_fakes.RESP_ITEM_1]},
+ status_code=200,
+ )
+ ret = self.api.find_attr('qaz', 'alpha')
+ self.assertEqual(api_fakes.RESP_ITEM_1, ret)
+
+ # value not found
+ self.requests_mock.register_uri(
+ 'GET',
+ self.BASE_URL + '/qaz?name=0',
+ json={'qaz': []},
+ status_code=200,
+ )
+ self.requests_mock.register_uri(
+ 'GET',
+ self.BASE_URL + '/qaz?id=0',
+ json={'qaz': []},
+ status_code=200,
+ )
+ self.assertRaises(
+ exceptions.CommandError,
+ self.api.find_attr,
+ 'qaz',
+ '0',
+ )
+
+ # Attribute other than 'name'
+ self.requests_mock.register_uri(
+ 'GET',
+ self.BASE_URL + '/qaz?status=UP',
+ json={'qaz': [api_fakes.RESP_ITEM_1]},
+ status_code=200,
+ )
+ ret = self.api.find_attr('qaz', 'UP', attr='status')
+ self.assertEqual(api_fakes.RESP_ITEM_1, ret)
+ ret = self.api.find_attr('qaz', value='UP', attr='status')
+ self.assertEqual(api_fakes.RESP_ITEM_1, ret)
+
+ def test_find_attr_path_resource(self):
+
+ # Test resource different than path
+ self.requests_mock.register_uri(
+ 'GET',
+ self.BASE_URL + '/wsx?name=1',
+ json={'qaz': []},
+ status_code=200,
+ )
+ self.requests_mock.register_uri(
+ 'GET',
+ self.BASE_URL + '/wsx?id=1',
+ json={'qaz': [api_fakes.RESP_ITEM_1]},
+ status_code=200,
+ )
+ ret = self.api.find_attr('wsx', '1', resource='qaz')
+ self.assertEqual(api_fakes.RESP_ITEM_1, ret)
+
+ def test_find_bulk_none(self):
+ self.requests_mock.register_uri(
+ 'GET',
+ self.BASE_URL + '/qaz',
+ json=api_fakes.LIST_RESP,
+ status_code=200,
+ )
+ ret = self.api.find_bulk('qaz')
+ self.assertEqual(api_fakes.LIST_RESP, ret)
+
+ def test_find_bulk_one(self):
+ self.requests_mock.register_uri(
+ 'GET',
+ self.BASE_URL + '/qaz',
+ json=api_fakes.LIST_RESP,
+ status_code=200,
+ )
+ ret = self.api.find_bulk('qaz', id='1')
+ self.assertEqual([api_fakes.LIST_RESP[0]], ret)
+
+ ret = self.api.find_bulk('qaz', id='0')
+ self.assertEqual([], ret)
+
+ ret = self.api.find_bulk('qaz', name='beta')
+ self.assertEqual([api_fakes.LIST_RESP[1]], ret)
+
+ ret = self.api.find_bulk('qaz', error='bogus')
+ self.assertEqual([], ret)
+
+ def test_find_bulk_two(self):
+ self.requests_mock.register_uri(
+ 'GET',
+ self.BASE_URL + '/qaz',
+ json=api_fakes.LIST_RESP,
+ status_code=200,
+ )
+ ret = self.api.find_bulk('qaz', id='1', name='alpha')
+ self.assertEqual([api_fakes.LIST_RESP[0]], ret)
+
+ ret = self.api.find_bulk('qaz', id='1', name='beta')
+ self.assertEqual([], ret)
+
+ ret = self.api.find_bulk('qaz', id='1', error='beta')
+ self.assertEqual([], ret)
+
+ def test_find_bulk_dict(self):
+ self.requests_mock.register_uri(
+ 'GET',
+ self.BASE_URL + '/qaz',
+ json={'qaz': api_fakes.LIST_RESP},
+ status_code=200,
+ )
+ ret = self.api.find_bulk('qaz', id='1')
+ self.assertEqual([api_fakes.LIST_RESP[0]], ret)
+
+ # list tests
+
+ def test_list_no_body(self):
+ self.requests_mock.register_uri(
+ 'GET',
+ self.BASE_URL,
+ json=api_fakes.LIST_RESP,
+ status_code=200,
+ )
+ ret = self.api.list('')
+ self.assertEqual(api_fakes.LIST_RESP, ret)
+
+ self.requests_mock.register_uri(
+ 'GET',
+ self.BASE_URL + '/qaz',
+ json=api_fakes.LIST_RESP,
+ status_code=200,
+ )
+ ret = self.api.list('qaz')
+ self.assertEqual(api_fakes.LIST_RESP, ret)
+
+ def test_list_params(self):
+ params = {'format': 'json'}
+ self.requests_mock.register_uri(
+ 'GET',
+ self.BASE_URL + '?format=json',
+ json=api_fakes.LIST_RESP,
+ status_code=200,
+ )
+ ret = self.api.list('', **params)
+ self.assertEqual(api_fakes.LIST_RESP, ret)
+
+ self.requests_mock.register_uri(
+ 'GET',
+ self.BASE_URL + '/qaz?format=json',
+ json=api_fakes.LIST_RESP,
+ status_code=200,
+ )
+ ret = self.api.list('qaz', **params)
+ self.assertEqual(api_fakes.LIST_RESP, ret)
+
+ def test_list_body(self):
+ self.requests_mock.register_uri(
+ 'POST',
+ self.BASE_URL + '/qaz',
+ json=api_fakes.LIST_RESP,
+ status_code=200,
+ )
+ ret = self.api.list('qaz', body=api_fakes.LIST_BODY)
+ self.assertEqual(api_fakes.LIST_RESP, ret)
+
+ def test_list_detailed(self):
+ self.requests_mock.register_uri(
+ 'GET',
+ self.BASE_URL + '/qaz/details',
+ json=api_fakes.LIST_RESP,
+ status_code=200,
+ )
+ ret = self.api.list('qaz', detailed=True)
+ self.assertEqual(api_fakes.LIST_RESP, ret)
+
+ def test_list_filtered(self):
+ self.requests_mock.register_uri(
+ 'GET',
+ self.BASE_URL + '/qaz?attr=value',
+ json=api_fakes.LIST_RESP,
+ status_code=200,
+ )
+ ret = self.api.list('qaz', attr='value')
+ self.assertEqual(api_fakes.LIST_RESP, ret)
+
+ def test_list_wrapped(self):
+ self.requests_mock.register_uri(
+ 'GET',
+ self.BASE_URL + '/qaz?attr=value',
+ json={'responses': api_fakes.LIST_RESP},
+ status_code=200,
+ )
+ ret = self.api.list('qaz', attr='value')
+ self.assertEqual({'responses': api_fakes.LIST_RESP}, ret)
diff --git a/openstackclient/tests/unit/api/test_image_v1.py b/openstackclient/tests/unit/api/test_image_v1.py
new file mode 100644
index 00000000..e02ef381
--- /dev/null
+++ b/openstackclient/tests/unit/api/test_image_v1.py
@@ -0,0 +1,98 @@
+# 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.
+#
+
+"""Image v1 API Library Tests"""
+
+from keystoneauth1 import session
+from requests_mock.contrib import fixture
+
+from openstackclient.api import image_v1
+from openstackclient.tests.unit import utils
+
+
+FAKE_PROJECT = 'xyzpdq'
+FAKE_URL = 'http://gopher.com'
+
+
+class TestImageAPIv1(utils.TestCase):
+
+ def setUp(self):
+ super(TestImageAPIv1, self).setUp()
+
+ sess = session.Session()
+ self.api = image_v1.APIv1(session=sess, endpoint=FAKE_URL)
+ self.requests_mock = self.useFixture(fixture.Fixture())
+
+
+class TestImage(TestImageAPIv1):
+
+ PUB_PROT = {
+ 'id': '1',
+ 'name': 'pub1',
+ 'is_public': True,
+ 'protected': True,
+ }
+ PUB_NOPROT = {
+ 'id': '2',
+ 'name': 'pub2-noprot',
+ 'is_public': True,
+ 'protected': False,
+ }
+ NOPUB_PROT = {
+ 'id': '3',
+ 'name': 'priv3',
+ 'is_public': False,
+ 'protected': True,
+ }
+ NOPUB_NOPROT = {
+ 'id': '4',
+ 'name': 'priv4-noprot',
+ 'is_public': False,
+ 'protected': False,
+ }
+ LIST_IMAGE_RESP = [
+ PUB_PROT,
+ PUB_NOPROT,
+ NOPUB_PROT,
+ NOPUB_NOPROT,
+ ]
+
+ def test_image_list_no_options(self):
+ self.requests_mock.register_uri(
+ 'GET',
+ FAKE_URL + '/v1/images',
+ json={'images': self.LIST_IMAGE_RESP},
+ status_code=200,
+ )
+ ret = self.api.image_list()
+ self.assertEqual(self.LIST_IMAGE_RESP, ret)
+
+ def test_image_list_public(self):
+ self.requests_mock.register_uri(
+ 'GET',
+ FAKE_URL + '/v1/images/detail',
+ json={'images': self.LIST_IMAGE_RESP},
+ status_code=200,
+ )
+ ret = self.api.image_list(public=True)
+ self.assertEqual([self.PUB_PROT, self.PUB_NOPROT], ret)
+
+ def test_image_list_private(self):
+ self.requests_mock.register_uri(
+ 'GET',
+ FAKE_URL + '/v1/images/detail',
+ json={'images': self.LIST_IMAGE_RESP},
+ status_code=200,
+ )
+ ret = self.api.image_list(private=True)
+ self.assertEqual([self.NOPUB_PROT, self.NOPUB_NOPROT], ret)
diff --git a/openstackclient/tests/unit/api/test_image_v2.py b/openstackclient/tests/unit/api/test_image_v2.py
new file mode 100644
index 00000000..5dbb51e0
--- /dev/null
+++ b/openstackclient/tests/unit/api/test_image_v2.py
@@ -0,0 +1,98 @@
+# 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.
+#
+
+"""Image v2 API Library Tests"""
+
+from keystoneauth1 import session
+from requests_mock.contrib import fixture
+
+from openstackclient.api import image_v2
+from openstackclient.tests.unit import utils
+
+
+FAKE_PROJECT = 'xyzpdq'
+FAKE_URL = 'http://gopher.com'
+
+
+class TestImageAPIv2(utils.TestCase):
+
+ def setUp(self):
+ super(TestImageAPIv2, self).setUp()
+
+ sess = session.Session()
+ self.api = image_v2.APIv2(session=sess, endpoint=FAKE_URL)
+ self.requests_mock = self.useFixture(fixture.Fixture())
+
+
+class TestImage(TestImageAPIv2):
+
+ PUB_PROT = {
+ 'id': '1',
+ 'name': 'pub1',
+ 'visibility': 'public',
+ 'protected': True,
+ }
+ PUB_NOPROT = {
+ 'id': '2',
+ 'name': 'pub2-noprot',
+ 'visibility': 'public',
+ 'protected': False,
+ }
+ NOPUB_PROT = {
+ 'id': '3',
+ 'name': 'priv3',
+ 'visibility': 'private',
+ 'protected': True,
+ }
+ NOPUB_NOPROT = {
+ 'id': '4',
+ 'name': 'priv4-noprot',
+ 'visibility': 'private',
+ 'protected': False,
+ }
+ LIST_IMAGE_RESP = [
+ PUB_PROT,
+ PUB_NOPROT,
+ NOPUB_PROT,
+ NOPUB_NOPROT,
+ ]
+
+ def test_image_list_no_options(self):
+ self.requests_mock.register_uri(
+ 'GET',
+ FAKE_URL + '/v2/images',
+ json={'images': self.LIST_IMAGE_RESP},
+ status_code=200,
+ )
+ ret = self.api.image_list()
+ self.assertEqual(self.LIST_IMAGE_RESP, ret)
+
+ def test_image_list_public(self):
+ self.requests_mock.register_uri(
+ 'GET',
+ FAKE_URL + '/v2/images',
+ json={'images': [self.PUB_PROT, self.PUB_NOPROT]},
+ status_code=200,
+ )
+ ret = self.api.image_list(public=True)
+ self.assertEqual([self.PUB_PROT, self.PUB_NOPROT], ret)
+
+ def test_image_list_private(self):
+ self.requests_mock.register_uri(
+ 'GET',
+ FAKE_URL + '/v2/images',
+ json={'images': [self.NOPUB_PROT, self.NOPUB_NOPROT]},
+ status_code=200,
+ )
+ ret = self.api.image_list(public=True)
+ self.assertEqual([self.NOPUB_PROT, self.NOPUB_NOPROT], ret)
diff --git a/openstackclient/tests/unit/api/test_object_store_v1.py b/openstackclient/tests/unit/api/test_object_store_v1.py
new file mode 100644
index 00000000..acf95550
--- /dev/null
+++ b/openstackclient/tests/unit/api/test_object_store_v1.py
@@ -0,0 +1,337 @@
+# 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.
+#
+
+"""Object Store v1 API Library Tests"""
+
+import mock
+
+from keystoneauth1 import session
+from requests_mock.contrib import fixture
+
+from openstackclient.api import object_store_v1 as object_store
+from openstackclient.tests.unit import utils
+
+
+FAKE_ACCOUNT = 'q12we34r'
+FAKE_AUTH = '11223344556677889900'
+FAKE_URL = 'http://gopher.com/v1/' + FAKE_ACCOUNT
+
+FAKE_CONTAINER = 'rainbarrel'
+FAKE_OBJECT = 'spigot'
+
+LIST_CONTAINER_RESP = [
+ 'qaz',
+ 'fred',
+]
+
+LIST_OBJECT_RESP = [
+ {'name': 'fred', 'bytes': 1234, 'content_type': 'text'},
+ {'name': 'wilma', 'bytes': 5678, 'content_type': 'text'},
+]
+
+
+class TestObjectAPIv1(utils.TestCase):
+
+ def setUp(self):
+ super(TestObjectAPIv1, self).setUp()
+ sess = session.Session()
+ self.api = object_store.APIv1(session=sess, endpoint=FAKE_URL)
+ self.requests_mock = self.useFixture(fixture.Fixture())
+
+
+class TestContainer(TestObjectAPIv1):
+
+ def setUp(self):
+ super(TestContainer, self).setUp()
+
+ def test_container_create(self):
+ headers = {
+ 'x-trans-id': '1qaz2wsx',
+ }
+ self.requests_mock.register_uri(
+ 'PUT',
+ FAKE_URL + '/qaz',
+ headers=headers,
+ status_code=201,
+ )
+ ret = self.api.container_create(container='qaz')
+ data = {
+ 'account': FAKE_ACCOUNT,
+ 'container': 'qaz',
+ 'x-trans-id': '1qaz2wsx',
+ }
+ self.assertEqual(data, ret)
+
+ def test_container_delete(self):
+ self.requests_mock.register_uri(
+ 'DELETE',
+ FAKE_URL + '/qaz',
+ status_code=204,
+ )
+ ret = self.api.container_delete(container='qaz')
+ self.assertIsNone(ret)
+
+ def test_container_list_no_options(self):
+ self.requests_mock.register_uri(
+ 'GET',
+ FAKE_URL,
+ json=LIST_CONTAINER_RESP,
+ status_code=200,
+ )
+ ret = self.api.container_list()
+ self.assertEqual(LIST_CONTAINER_RESP, ret)
+
+ def test_container_list_prefix(self):
+ self.requests_mock.register_uri(
+ 'GET',
+ FAKE_URL + '?prefix=foo%2f&format=json',
+ json=LIST_CONTAINER_RESP,
+ status_code=200,
+ )
+ ret = self.api.container_list(
+ prefix='foo/',
+ )
+ self.assertEqual(LIST_CONTAINER_RESP, ret)
+
+ def test_container_list_marker_limit_end(self):
+ self.requests_mock.register_uri(
+ 'GET',
+ FAKE_URL + '?marker=next&limit=2&end_marker=stop&format=json',
+ json=LIST_CONTAINER_RESP,
+ status_code=200,
+ )
+ ret = self.api.container_list(
+ marker='next',
+ limit=2,
+ end_marker='stop',
+ )
+ self.assertEqual(LIST_CONTAINER_RESP, ret)
+
+# def test_container_list_full_listing(self):
+# sess = self.app.client_manager.session
+#
+# def side_effect(*args, **kwargs):
+# rv = sess.get().json.return_value
+# sess.get().json.return_value = []
+# sess.get().json.side_effect = None
+# return rv
+#
+# resp = [{'name': 'is-name'}]
+# sess.get().json.return_value = resp
+# sess.get().json.side_effect = side_effect
+#
+# data = lib_container.list_containers(
+# self.app.client_manager.session,
+# fake_url,
+# full_listing=True,
+# )
+#
+# # Check expected values
+# sess.get.assert_called_with(
+# fake_url,
+# params={
+# 'format': 'json',
+# 'marker': 'is-name',
+# }
+# )
+# self.assertEqual(resp, data)
+
+ def test_container_show(self):
+ headers = {
+ 'X-Container-Meta-Owner': FAKE_ACCOUNT,
+ 'x-container-object-count': '1',
+ 'x-container-bytes-used': '577',
+ }
+ resp = {
+ 'account': FAKE_ACCOUNT,
+ 'container': 'qaz',
+ 'object_count': '1',
+ 'bytes_used': '577',
+ 'properties': {'Owner': FAKE_ACCOUNT},
+ }
+ self.requests_mock.register_uri(
+ 'HEAD',
+ FAKE_URL + '/qaz',
+ headers=headers,
+ status_code=204,
+ )
+ ret = self.api.container_show(container='qaz')
+ self.assertEqual(resp, ret)
+
+
+class TestObject(TestObjectAPIv1):
+
+ def setUp(self):
+ super(TestObject, self).setUp()
+
+ @mock.patch('openstackclient.api.object_store_v1.io.open')
+ def base_object_create(self, file_contents, mock_open):
+ mock_open.read.return_value = file_contents
+
+ headers = {
+ 'etag': 'youreit',
+ 'x-trans-id': '1qaz2wsx',
+ }
+ # TODO(dtroyer): When requests_mock gains the ability to
+ # match against request.body add this check
+ # https://review.openstack.org/127316
+ self.requests_mock.register_uri(
+ 'PUT',
+ FAKE_URL + '/qaz/counter.txt',
+ headers=headers,
+ # body=file_contents,
+ status_code=201,
+ )
+ ret = self.api.object_create(
+ container='qaz',
+ object='counter.txt',
+ )
+ data = {
+ 'account': FAKE_ACCOUNT,
+ 'container': 'qaz',
+ 'object': 'counter.txt',
+ 'etag': 'youreit',
+ 'x-trans-id': '1qaz2wsx',
+ }
+ self.assertEqual(data, ret)
+
+ def test_object_create(self):
+ self.base_object_create('111\n222\n333\n')
+ self.base_object_create(bytes([0x31, 0x00, 0x0d, 0x0a, 0x7f, 0xff]))
+
+ def test_object_delete(self):
+ self.requests_mock.register_uri(
+ 'DELETE',
+ FAKE_URL + '/qaz/wsx',
+ status_code=204,
+ )
+ ret = self.api.object_delete(
+ container='qaz',
+ object='wsx',
+ )
+ self.assertIsNone(ret)
+
+ def test_object_list_no_options(self):
+ self.requests_mock.register_uri(
+ 'GET',
+ FAKE_URL + '/qaz',
+ json=LIST_OBJECT_RESP,
+ status_code=200,
+ )
+ ret = self.api.object_list(container='qaz')
+ self.assertEqual(LIST_OBJECT_RESP, ret)
+
+ def test_object_list_delimiter(self):
+ self.requests_mock.register_uri(
+ 'GET',
+ FAKE_URL + '/qaz?delimiter=%7C',
+ json=LIST_OBJECT_RESP,
+ status_code=200,
+ )
+ ret = self.api.object_list(
+ container='qaz',
+ delimiter='|',
+ )
+ self.assertEqual(LIST_OBJECT_RESP, ret)
+
+ def test_object_list_prefix(self):
+ self.requests_mock.register_uri(
+ 'GET',
+ FAKE_URL + '/qaz?prefix=foo%2f',
+ json=LIST_OBJECT_RESP,
+ status_code=200,
+ )
+ ret = self.api.object_list(
+ container='qaz',
+ prefix='foo/',
+ )
+ self.assertEqual(LIST_OBJECT_RESP, ret)
+
+ def test_object_list_marker_limit_end(self):
+ self.requests_mock.register_uri(
+ 'GET',
+ FAKE_URL + '/qaz?marker=next&limit=2&end_marker=stop',
+ json=LIST_CONTAINER_RESP,
+ status_code=200,
+ )
+ ret = self.api.object_list(
+ container='qaz',
+ marker='next',
+ limit=2,
+ end_marker='stop',
+ )
+ self.assertEqual(LIST_CONTAINER_RESP, ret)
+
+# def test_list_objects_full_listing(self):
+# sess = self.app.client_manager.session
+#
+# def side_effect(*args, **kwargs):
+# rv = sess.get().json.return_value
+# sess.get().json.return_value = []
+# sess.get().json.side_effect = None
+# return rv
+#
+# resp = [{'name': 'is-name'}]
+# sess.get().json.return_value = resp
+# sess.get().json.side_effect = side_effect
+#
+# data = lib_object.list_objects(
+# sess,
+# fake_url,
+# fake_container,
+# full_listing=True,
+# )
+#
+# # Check expected values
+# sess.get.assert_called_with(
+# fake_url + '/' + fake_container,
+# params={
+# 'format': 'json',
+# 'marker': 'is-name',
+# }
+# )
+# self.assertEqual(resp, data)
+
+ def test_object_show(self):
+ headers = {
+ 'content-type': 'text/alpha',
+ 'content-length': '577',
+ 'last-modified': '20130101',
+ 'etag': 'qaz',
+ 'x-container-meta-owner': FAKE_ACCOUNT,
+ 'x-object-meta-wife': 'Wilma',
+ 'x-object-meta-Husband': 'fred',
+ 'x-tra-header': 'yabba-dabba-do',
+ }
+ resp = {
+ 'account': FAKE_ACCOUNT,
+ 'container': 'qaz',
+ 'object': FAKE_OBJECT,
+ 'content-type': 'text/alpha',
+ 'content-length': '577',
+ 'last-modified': '20130101',
+ 'etag': 'qaz',
+ 'properties': {'wife': 'Wilma',
+ 'Husband': 'fred'},
+ }
+ self.requests_mock.register_uri(
+ 'HEAD',
+ FAKE_URL + '/qaz/' + FAKE_OBJECT,
+ headers=headers,
+ status_code=204,
+ )
+ ret = self.api.object_show(
+ container='qaz',
+ object=FAKE_OBJECT,
+ )
+ self.assertEqual(resp, ret)
diff --git a/openstackclient/tests/unit/api/test_utils.py b/openstackclient/tests/unit/api/test_utils.py
new file mode 100644
index 00000000..1f528558
--- /dev/null
+++ b/openstackclient/tests/unit/api/test_utils.py
@@ -0,0 +1,115 @@
+# 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.
+#
+
+"""API Utilities Library Tests"""
+
+import copy
+
+from openstackclient.api import api
+from openstackclient.api import utils as api_utils
+from openstackclient.tests.unit.api import fakes as api_fakes
+
+
+class TestBaseAPIFilter(api_fakes.TestSession):
+ """The filters can be tested independently"""
+
+ def setUp(self):
+ super(TestBaseAPIFilter, self).setUp()
+ self.api = api.BaseAPI(
+ session=self.sess,
+ endpoint=self.BASE_URL,
+ )
+
+ self.input_list = [
+ api_fakes.RESP_ITEM_1,
+ api_fakes.RESP_ITEM_2,
+ api_fakes.RESP_ITEM_3,
+ ]
+
+ def test_simple_filter_none(self):
+ output = api_utils.simple_filter(
+ )
+ self.assertIsNone(output)
+
+ def test_simple_filter_no_attr(self):
+ output = api_utils.simple_filter(
+ copy.deepcopy(self.input_list),
+ )
+ self.assertEqual(self.input_list, output)
+
+ def test_simple_filter_attr_only(self):
+ output = api_utils.simple_filter(
+ copy.deepcopy(self.input_list),
+ attr='status',
+ )
+ self.assertEqual(self.input_list, output)
+
+ def test_simple_filter_attr_value(self):
+ output = api_utils.simple_filter(
+ copy.deepcopy(self.input_list),
+ attr='status',
+ value='',
+ )
+ self.assertEqual([], output)
+
+ output = api_utils.simple_filter(
+ copy.deepcopy(self.input_list),
+ attr='status',
+ value='UP',
+ )
+ self.assertEqual(
+ [api_fakes.RESP_ITEM_1, api_fakes.RESP_ITEM_3],
+ output,
+ )
+
+ output = api_utils.simple_filter(
+ copy.deepcopy(self.input_list),
+ attr='fred',
+ value='UP',
+ )
+ self.assertEqual([], output)
+
+ def test_simple_filter_prop_attr_only(self):
+ output = api_utils.simple_filter(
+ copy.deepcopy(self.input_list),
+ attr='b',
+ property_field='props',
+ )
+ self.assertEqual(self.input_list, output)
+
+ output = api_utils.simple_filter(
+ copy.deepcopy(self.input_list),
+ attr='status',
+ property_field='props',
+ )
+ self.assertEqual(self.input_list, output)
+
+ def test_simple_filter_prop_attr_value(self):
+ output = api_utils.simple_filter(
+ copy.deepcopy(self.input_list),
+ attr='b',
+ value=2,
+ property_field='props',
+ )
+ self.assertEqual(
+ [api_fakes.RESP_ITEM_1, api_fakes.RESP_ITEM_2],
+ output,
+ )
+
+ output = api_utils.simple_filter(
+ copy.deepcopy(self.input_list),
+ attr='b',
+ value=9,
+ property_field='props',
+ )
+ self.assertEqual([], output)
diff --git a/openstackclient/tests/unit/common/__init__.py b/openstackclient/tests/unit/common/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/unit/common/__init__.py
diff --git a/openstackclient/tests/unit/common/test_availability_zone.py b/openstackclient/tests/unit/common/test_availability_zone.py
new file mode 100644
index 00000000..6c7adc43
--- /dev/null
+++ b/openstackclient/tests/unit/common/test_availability_zone.py
@@ -0,0 +1,268 @@
+# 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.
+#
+
+import mock
+
+import six
+
+from openstackclient.common import availability_zone
+from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit.network.v2 import fakes as network_fakes
+from openstackclient.tests.unit import utils
+from openstackclient.tests.unit.volume.v2 import fakes as volume_fakes
+
+
+def _build_compute_az_datalist(compute_az, long_datalist=False):
+ datalist = ()
+ if not long_datalist:
+ datalist = (
+ compute_az.zoneName,
+ 'available',
+ )
+ else:
+ for host, services in six.iteritems(compute_az.hosts):
+ for service, state in six.iteritems(services):
+ datalist += (
+ compute_az.zoneName,
+ 'available',
+ '',
+ host,
+ service,
+ 'enabled :-) ' + state['updated_at'],
+ )
+ return (datalist,)
+
+
+def _build_volume_az_datalist(volume_az, long_datalist=False):
+ datalist = ()
+ if not long_datalist:
+ datalist = (
+ volume_az.zoneName,
+ 'available',
+ )
+ else:
+ datalist = (
+ volume_az.zoneName,
+ 'available',
+ '', '', '', '',
+ )
+ return (datalist,)
+
+
+def _build_network_az_datalist(network_az, long_datalist=False):
+ datalist = ()
+ if not long_datalist:
+ datalist = (
+ network_az.name,
+ network_az.state,
+ )
+ else:
+ datalist = (
+ network_az.name,
+ network_az.state,
+ network_az.resource,
+ '', '', '',
+ )
+ return (datalist,)
+
+
+class TestAvailabilityZone(utils.TestCommand):
+
+ def setUp(self):
+ super(TestAvailabilityZone, self).setUp()
+
+ compute_client = compute_fakes.FakeComputev2Client(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN,
+ )
+ self.app.client_manager.compute = compute_client
+
+ self.compute_azs_mock = compute_client.availability_zones
+ self.compute_azs_mock.reset_mock()
+
+ volume_client = volume_fakes.FakeVolumeClient(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN,
+ )
+ self.app.client_manager.volume = volume_client
+
+ self.volume_azs_mock = volume_client.availability_zones
+ self.volume_azs_mock.reset_mock()
+
+ network_client = network_fakes.FakeNetworkV2Client(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN,
+ )
+ self.app.client_manager.network = network_client
+
+ network_client.availability_zones = mock.Mock()
+ network_client.find_extension = mock.Mock()
+ self.network_azs_mock = network_client.availability_zones
+
+
+class TestAvailabilityZoneList(TestAvailabilityZone):
+
+ compute_azs = \
+ compute_fakes.FakeAvailabilityZone.create_availability_zones()
+ volume_azs = \
+ volume_fakes.FakeAvailabilityZone.create_availability_zones(count=1)
+ network_azs = \
+ network_fakes.FakeAvailabilityZone.create_availability_zones()
+
+ short_columnslist = ('Zone Name', 'Zone Status')
+ long_columnslist = (
+ 'Zone Name',
+ 'Zone Status',
+ 'Zone Resource',
+ 'Host Name',
+ 'Service Name',
+ 'Service Status',
+ )
+
+ def setUp(self):
+ super(TestAvailabilityZoneList, self).setUp()
+
+ self.compute_azs_mock.list.return_value = self.compute_azs
+ self.volume_azs_mock.list.return_value = self.volume_azs
+ self.network_azs_mock.return_value = self.network_azs
+
+ # Get the command object to test
+ self.cmd = availability_zone.ListAvailabilityZone(self.app, None)
+
+ def test_availability_zone_list_no_options(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.compute_azs_mock.list.assert_called_with()
+ self.volume_azs_mock.list.assert_called_with()
+ self.network_azs_mock.assert_called_with()
+
+ self.assertEqual(self.short_columnslist, columns)
+ datalist = ()
+ for compute_az in self.compute_azs:
+ datalist += _build_compute_az_datalist(compute_az)
+ for volume_az in self.volume_azs:
+ datalist += _build_volume_az_datalist(volume_az)
+ for network_az in self.network_azs:
+ datalist += _build_network_az_datalist(network_az)
+ self.assertEqual(datalist, tuple(data))
+
+ def test_availability_zone_list_long(self):
+ arglist = [
+ '--long',
+ ]
+ verifylist = [
+ ('long', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.compute_azs_mock.list.assert_called_with()
+ self.volume_azs_mock.list.assert_called_with()
+ self.network_azs_mock.assert_called_with()
+
+ self.assertEqual(self.long_columnslist, columns)
+ datalist = ()
+ for compute_az in self.compute_azs:
+ datalist += _build_compute_az_datalist(compute_az,
+ long_datalist=True)
+ for volume_az in self.volume_azs:
+ datalist += _build_volume_az_datalist(volume_az,
+ long_datalist=True)
+ for network_az in self.network_azs:
+ datalist += _build_network_az_datalist(network_az,
+ long_datalist=True)
+ self.assertEqual(datalist, tuple(data))
+
+ def test_availability_zone_list_compute(self):
+ arglist = [
+ '--compute',
+ ]
+ verifylist = [
+ ('compute', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.compute_azs_mock.list.assert_called_with()
+ self.volume_azs_mock.list.assert_not_called()
+ self.network_azs_mock.assert_not_called()
+
+ self.assertEqual(self.short_columnslist, columns)
+ datalist = ()
+ for compute_az in self.compute_azs:
+ datalist += _build_compute_az_datalist(compute_az)
+ self.assertEqual(datalist, tuple(data))
+
+ def test_availability_zone_list_volume(self):
+ arglist = [
+ '--volume',
+ ]
+ verifylist = [
+ ('volume', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.compute_azs_mock.list.assert_not_called()
+ self.volume_azs_mock.list.assert_called_with()
+ self.network_azs_mock.assert_not_called()
+
+ self.assertEqual(self.short_columnslist, columns)
+ datalist = ()
+ for volume_az in self.volume_azs:
+ datalist += _build_volume_az_datalist(volume_az)
+ self.assertEqual(datalist, tuple(data))
+
+ def test_availability_zone_list_network(self):
+ arglist = [
+ '--network',
+ ]
+ verifylist = [
+ ('network', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.compute_azs_mock.list.assert_not_called()
+ self.volume_azs_mock.list.assert_not_called()
+ self.network_azs_mock.assert_called_with()
+
+ self.assertEqual(self.short_columnslist, columns)
+ datalist = ()
+ for network_az in self.network_azs:
+ datalist += _build_network_az_datalist(network_az)
+ self.assertEqual(datalist, tuple(data))
diff --git a/openstackclient/tests/unit/common/test_clientmanager.py b/openstackclient/tests/unit/common/test_clientmanager.py
new file mode 100644
index 00000000..7f82c35d
--- /dev/null
+++ b/openstackclient/tests/unit/common/test_clientmanager.py
@@ -0,0 +1,69 @@
+# Copyright 2012-2013 OpenStack Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+import copy
+
+from keystoneauth1 import token_endpoint
+from osc_lib.tests import utils as osc_lib_test_utils
+
+from openstackclient.common import clientmanager
+from openstackclient.tests.unit import fakes
+
+
+class TestClientManager(osc_lib_test_utils.TestClientManager):
+
+ def _clientmanager_class(self):
+ """Allow subclasses to override the ClientManager class"""
+ return clientmanager.ClientManager
+
+ def test_client_manager_token_endpoint(self):
+ token_auth = {
+ 'url': fakes.AUTH_URL,
+ 'token': fakes.AUTH_TOKEN,
+ }
+ client_manager = self._make_clientmanager(
+ auth_args=token_auth,
+ auth_plugin_name='token_endpoint',
+ )
+
+ self.assertEqual(
+ fakes.AUTH_URL,
+ client_manager._cli_options.config['auth']['url'],
+ )
+ self.assertEqual(
+ fakes.AUTH_TOKEN,
+ client_manager.auth.get_token(None),
+ )
+ self.assertIsInstance(
+ client_manager.auth,
+ token_endpoint.Token,
+ )
+ self.assertTrue(client_manager.is_network_endpoint_enabled())
+
+ def test_client_manager_network_endpoint_disabled(self):
+ auth_args = copy.deepcopy(self.default_password_auth)
+ auth_args.update({
+ 'user_domain_name': 'default',
+ 'project_domain_name': 'default',
+ })
+ # v3 fake doesn't have network endpoint
+ client_manager = self._make_clientmanager(
+ auth_args=auth_args,
+ identity_api_version='3',
+ auth_plugin_name='v3password',
+ )
+
+ self.assertFalse(client_manager.is_service_available('network'))
+ self.assertFalse(client_manager.is_network_endpoint_enabled())
diff --git a/openstackclient/tests/unit/common/test_command.py b/openstackclient/tests/unit/common/test_command.py
new file mode 100644
index 00000000..f24b290b
--- /dev/null
+++ b/openstackclient/tests/unit/common/test_command.py
@@ -0,0 +1,49 @@
+# Copyright 2016 NEC Corporation
+#
+# 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.
+
+import mock
+
+from osc_lib import exceptions
+
+from openstackclient.common import command
+from openstackclient.tests.unit import fakes as test_fakes
+from openstackclient.tests.unit import utils as test_utils
+
+
+class FakeCommand(command.Command):
+
+ def take_action(self, parsed_args):
+ pass
+
+
+class TestCommand(test_utils.TestCase):
+
+ def test_command_has_logger(self):
+ cmd = FakeCommand(mock.Mock(), mock.Mock())
+ self.assertTrue(hasattr(cmd, 'log'))
+ self.assertEqual('openstackclient.tests.unit.common.test_command.'
+ 'FakeCommand', cmd.log.name)
+
+ def test_validate_os_beta_command_enabled(self):
+ cmd = FakeCommand(mock.Mock(), mock.Mock())
+ cmd.app = mock.Mock()
+ cmd.app.options = test_fakes.FakeOptions()
+
+ # No exception is raised when enabled.
+ cmd.app.options.os_beta_command = True
+ cmd.validate_os_beta_command_enabled()
+
+ cmd.app.options.os_beta_command = False
+ self.assertRaises(exceptions.CommandError,
+ cmd.validate_os_beta_command_enabled)
diff --git a/openstackclient/tests/unit/common/test_commandmanager.py b/openstackclient/tests/unit/common/test_commandmanager.py
new file mode 100644
index 00000000..0c6c99c0
--- /dev/null
+++ b/openstackclient/tests/unit/common/test_commandmanager.py
@@ -0,0 +1,107 @@
+# Copyright 2012-2013 OpenStack Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+import mock
+
+from openstackclient.common import commandmanager
+from openstackclient.tests.unit import utils
+
+
+class FakeCommand(object):
+
+ @classmethod
+ def load(cls):
+ return cls
+
+ def __init__(self):
+ return
+
+FAKE_CMD_ONE = FakeCommand
+FAKE_CMD_TWO = FakeCommand
+FAKE_CMD_ALPHA = FakeCommand
+FAKE_CMD_BETA = FakeCommand
+
+
+class FakeCommandManager(commandmanager.CommandManager):
+ commands = {}
+
+ def load_commands(self, namespace):
+ if namespace == 'test':
+ self.commands['one'] = FAKE_CMD_ONE
+ self.commands['two'] = FAKE_CMD_TWO
+ self.group_list.append(namespace)
+ elif namespace == 'greek':
+ self.commands['alpha'] = FAKE_CMD_ALPHA
+ self.commands['beta'] = FAKE_CMD_BETA
+ self.group_list.append(namespace)
+
+
+class TestCommandManager(utils.TestCase):
+
+ def test_add_command_group(self):
+ mgr = FakeCommandManager('test')
+
+ # Make sure add_command() still functions
+ mock_cmd_one = mock.Mock()
+ mgr.add_command('mock', mock_cmd_one)
+ cmd_mock, name, args = mgr.find_command(['mock'])
+ self.assertEqual(mock_cmd_one, cmd_mock)
+
+ # Find a command added in initialization
+ cmd_one, name, args = mgr.find_command(['one'])
+ self.assertEqual(FAKE_CMD_ONE, cmd_one)
+
+ # Load another command group
+ mgr.add_command_group('greek')
+
+ # Find a new command
+ cmd_alpha, name, args = mgr.find_command(['alpha'])
+ self.assertEqual(FAKE_CMD_ALPHA, cmd_alpha)
+
+ # Ensure that the original commands were not overwritten
+ cmd_two, name, args = mgr.find_command(['two'])
+ self.assertEqual(FAKE_CMD_TWO, cmd_two)
+
+ def test_get_command_groups(self):
+ mgr = FakeCommandManager('test')
+
+ # Make sure add_command() still functions
+ mock_cmd_one = mock.Mock()
+ mgr.add_command('mock', mock_cmd_one)
+ cmd_mock, name, args = mgr.find_command(['mock'])
+ self.assertEqual(mock_cmd_one, cmd_mock)
+
+ # Load another command group
+ mgr.add_command_group('greek')
+
+ gl = mgr.get_command_groups()
+ self.assertEqual(['test', 'greek'], gl)
+
+ def test_get_command_names(self):
+ mock_cmd_one = mock.Mock()
+ mock_cmd_one.name = 'one'
+ mock_cmd_two = mock.Mock()
+ mock_cmd_two.name = 'cmd two'
+ mock_pkg_resources = mock.Mock(
+ return_value=[mock_cmd_one, mock_cmd_two],
+ )
+ with mock.patch(
+ 'pkg_resources.iter_entry_points',
+ mock_pkg_resources,
+ ) as iter_entry_points:
+ mgr = commandmanager.CommandManager('test')
+ iter_entry_points.assert_called_once_with('test')
+ cmds = mgr.get_command_names('test')
+ self.assertEqual(['one', 'cmd two'], cmds)
diff --git a/openstackclient/tests/unit/common/test_configuration.py b/openstackclient/tests/unit/common/test_configuration.py
new file mode 100644
index 00000000..e10522b9
--- /dev/null
+++ b/openstackclient/tests/unit/common/test_configuration.py
@@ -0,0 +1,85 @@
+# 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.
+#
+
+import mock
+
+from openstackclient.common import configuration
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit import utils
+
+
+class TestConfiguration(utils.TestCommand):
+
+ columns = (
+ 'auth.password',
+ 'auth.token',
+ 'auth.username',
+ 'identity_api_version',
+ 'region',
+ )
+ datalist = (
+ configuration.REDACTED,
+ configuration.REDACTED,
+ fakes.USERNAME,
+ fakes.VERSION,
+ fakes.REGION_NAME,
+ )
+
+ opts = [mock.Mock(secret=True, dest="password"),
+ mock.Mock(secret=True, dest="token")]
+
+ @mock.patch("keystoneauth1.loading.base.get_plugin_options",
+ return_value=opts)
+ def test_show(self, m_get_plugin_opts):
+ arglist = []
+ verifylist = [('mask', True)]
+ cmd = configuration.ShowConfiguration(self.app, None)
+ parsed_args = self.check_parser(cmd, arglist, verifylist)
+
+ columns, data = cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ @mock.patch("keystoneauth1.loading.base.get_plugin_options",
+ return_value=opts)
+ def test_show_unmask(self, m_get_plugin_opts):
+ arglist = ['--unmask']
+ verifylist = [('mask', False)]
+ cmd = configuration.ShowConfiguration(self.app, None)
+ parsed_args = self.check_parser(cmd, arglist, verifylist)
+
+ columns, data = cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+ datalist = (
+ fakes.PASSWORD,
+ fakes.AUTH_TOKEN,
+ fakes.USERNAME,
+ fakes.VERSION,
+ fakes.REGION_NAME,
+ )
+ self.assertEqual(datalist, data)
+
+ @mock.patch("keystoneauth1.loading.base.get_plugin_options",
+ return_value=opts)
+ def test_show_mask(self, m_get_plugin_opts):
+ arglist = ['--mask']
+ verifylist = [('mask', True)]
+ cmd = configuration.ShowConfiguration(self.app, None)
+ parsed_args = self.check_parser(cmd, arglist, verifylist)
+
+ columns, data = cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
diff --git a/openstackclient/tests/unit/common/test_extension.py b/openstackclient/tests/unit/common/test_extension.py
new file mode 100644
index 00000000..bf856ed1
--- /dev/null
+++ b/openstackclient/tests/unit/common/test_extension.py
@@ -0,0 +1,244 @@
+# 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.
+#
+
+import mock
+
+from openstackclient.common import extension
+from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit.identity.v2_0 import fakes as identity_fakes
+from openstackclient.tests.unit.network.v2 import fakes as network_fakes
+from openstackclient.tests.unit import utils
+from openstackclient.tests.unit.volume.v2 import fakes as volume_fakes
+
+
+class TestExtension(utils.TestCommand):
+
+ def setUp(self):
+ super(TestExtension, self).setUp()
+
+ identity_client = identity_fakes.FakeIdentityv2Client(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN,
+ )
+ self.app.client_manager.identity = identity_client
+ self.identity_extensions_mock = identity_client.extensions
+ self.identity_extensions_mock.reset_mock()
+
+ compute_client = compute_fakes.FakeComputev2Client(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN,
+ )
+ self.app.client_manager.compute = compute_client
+ compute_client.list_extensions = mock.Mock()
+ self.compute_extensions_mock = compute_client.list_extensions
+ self.compute_extensions_mock.reset_mock()
+
+ volume_client = volume_fakes.FakeVolumeClient(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN,
+ )
+ self.app.client_manager.volume = volume_client
+ volume_client.list_extensions = mock.Mock()
+ self.volume_extensions_mock = volume_client.list_extensions
+ self.volume_extensions_mock.reset_mock()
+
+ network_client = network_fakes.FakeNetworkV2Client(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN,
+ )
+ self.app.client_manager.network = network_client
+ network_client.extensions = mock.Mock()
+ self.network_extensions_mock = network_client.extensions
+ self.network_extensions_mock.reset_mock()
+
+
+class TestExtensionList(TestExtension):
+
+ columns = ('Name', 'Alias', 'Description')
+ long_columns = ('Name', 'Namespace', 'Description', 'Alias', 'Updated',
+ 'Links')
+
+ volume_extension = volume_fakes.FakeExtension.create_one_extension()
+ identity_extension = identity_fakes.FakeExtension.create_one_extension()
+ compute_extension = compute_fakes.FakeExtension.create_one_extension()
+ network_extension = network_fakes.FakeExtension.create_one_extension()
+
+ def setUp(self):
+ super(TestExtensionList, self).setUp()
+
+ self.identity_extensions_mock.list.return_value = [
+ self.identity_extension]
+ self.compute_extensions_mock.show_all.return_value = [
+ self.compute_extension]
+ self.volume_extensions_mock.show_all.return_value = [
+ self.volume_extension]
+ self.network_extensions_mock.return_value = [self.network_extension]
+
+ # Get the command object to test
+ self.cmd = extension.ListExtension(self.app, None)
+
+ def _test_extension_list_helper(self, arglist, verifylist,
+ expected_data, long=False):
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ if long:
+ self.assertEqual(self.long_columns, columns)
+ else:
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(expected_data, tuple(data))
+
+ def test_extension_list_no_options(self):
+ arglist = []
+ verifylist = []
+ datalist = (
+ (
+ self.identity_extension.name,
+ self.identity_extension.alias,
+ self.identity_extension.description,
+ ),
+ (
+ self.compute_extension.name,
+ self.compute_extension.alias,
+ self.compute_extension.description,
+ ),
+ (
+ self.volume_extension.name,
+ self.volume_extension.alias,
+ self.volume_extension.description,
+ ),
+ (
+ self.network_extension.name,
+ self.network_extension.alias,
+ self.network_extension.description,
+ ),
+ )
+ self._test_extension_list_helper(arglist, verifylist, datalist)
+ self.identity_extensions_mock.list.assert_called_with()
+ self.compute_extensions_mock.show_all.assert_called_with()
+ self.volume_extensions_mock.show_all.assert_called_with()
+ self.network_extensions_mock.assert_called_with()
+
+ def test_extension_list_long(self):
+ arglist = [
+ '--long',
+ ]
+ verifylist = [
+ ('long', True),
+ ]
+ datalist = (
+ (
+ self.identity_extension.name,
+ self.identity_extension.namespace,
+ self.identity_extension.description,
+ self.identity_extension.alias,
+ self.identity_extension.updated,
+ self.identity_extension.links,
+ ),
+ (
+ self.compute_extension.name,
+ self.compute_extension.namespace,
+ self.compute_extension.description,
+ self.compute_extension.alias,
+ self.compute_extension.updated,
+ self.compute_extension.links,
+ ),
+ (
+ self.volume_extension.name,
+ self.volume_extension.namespace,
+ self.volume_extension.description,
+ self.volume_extension.alias,
+ self.volume_extension.updated,
+ self.volume_extension.links,
+ ),
+ (
+ self.network_extension.name,
+ self.network_extension.namespace,
+ self.network_extension.description,
+ self.network_extension.alias,
+ self.network_extension.updated,
+ self.network_extension.links,
+ ),
+ )
+ self._test_extension_list_helper(arglist, verifylist, datalist, True)
+ self.identity_extensions_mock.list.assert_called_with()
+ self.compute_extensions_mock.show_all.assert_called_with()
+ self.volume_extensions_mock.show_all.assert_called_with()
+ self.network_extensions_mock.assert_called_with()
+
+ def test_extension_list_identity(self):
+ arglist = [
+ '--identity',
+ ]
+ verifylist = [
+ ('identity', True),
+ ]
+ datalist = ((
+ self.identity_extension.name,
+ self.identity_extension.alias,
+ self.identity_extension.description,
+ ), )
+ self._test_extension_list_helper(arglist, verifylist, datalist)
+ self.identity_extensions_mock.list.assert_called_with()
+
+ def test_extension_list_network(self):
+ arglist = [
+ '--network',
+ ]
+ verifylist = [
+ ('network', True),
+ ]
+ datalist = (
+ (
+ self.network_extension.name,
+ self.network_extension.alias,
+ self.network_extension.description,
+ ),
+ )
+ self._test_extension_list_helper(arglist, verifylist, datalist)
+ self.network_extensions_mock.assert_called_with()
+
+ def test_extension_list_compute(self):
+ arglist = [
+ '--compute',
+ ]
+ verifylist = [
+ ('compute', True),
+ ]
+ datalist = ((
+ self.compute_extension.name,
+ self.compute_extension.alias,
+ self.compute_extension.description,
+ ), )
+ self._test_extension_list_helper(arglist, verifylist, datalist)
+ self.compute_extensions_mock.show_all.assert_called_with()
+
+ def test_extension_list_volume(self):
+ arglist = [
+ '--volume',
+ ]
+ verifylist = [
+ ('volume', True),
+ ]
+ datalist = ((
+ self.volume_extension.name,
+ self.volume_extension.alias,
+ self.volume_extension.description,
+ ), )
+ self._test_extension_list_helper(arglist, verifylist, datalist)
+ self.volume_extensions_mock.show_all.assert_called_with()
diff --git a/openstackclient/tests/unit/common/test_logs.py b/openstackclient/tests/unit/common/test_logs.py
new file mode 100644
index 00000000..4842c8d4
--- /dev/null
+++ b/openstackclient/tests/unit/common/test_logs.py
@@ -0,0 +1,207 @@
+# 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.
+#
+
+# NOTE(dtroyer): This file is deprecated in Jun 2016, remove after 4.x release
+# or Jun 2017.
+
+import logging
+import mock
+
+from openstackclient.common import logs
+from openstackclient.tests.unit import utils
+
+
+class TestContext(utils.TestCase):
+
+ def test_log_level_from_options(self):
+ opts = mock.Mock()
+ opts.verbose_level = 0
+ self.assertEqual(logging.ERROR, logs.log_level_from_options(opts))
+ opts.verbose_level = 1
+ self.assertEqual(logging.WARNING, logs.log_level_from_options(opts))
+ opts.verbose_level = 2
+ self.assertEqual(logging.INFO, logs.log_level_from_options(opts))
+ opts.verbose_level = 3
+ self.assertEqual(logging.DEBUG, logs.log_level_from_options(opts))
+
+ def test_log_level_from_config(self):
+ cfg = {'verbose_level': 0}
+ self.assertEqual(logging.ERROR, logs.log_level_from_config(cfg))
+ cfg = {'verbose_level': 1}
+ self.assertEqual(logging.WARNING, logs.log_level_from_config(cfg))
+ cfg = {'verbose_level': 2}
+ self.assertEqual(logging.INFO, logs.log_level_from_config(cfg))
+ cfg = {'verbose_level': 3}
+ self.assertEqual(logging.DEBUG, logs.log_level_from_config(cfg))
+ cfg = {'verbose_level': 1, 'log_level': 'critical'}
+ self.assertEqual(logging.CRITICAL, logs.log_level_from_config(cfg))
+ cfg = {'verbose_level': 1, 'log_level': 'error'}
+ self.assertEqual(logging.ERROR, logs.log_level_from_config(cfg))
+ cfg = {'verbose_level': 1, 'log_level': 'warning'}
+ self.assertEqual(logging.WARNING, logs.log_level_from_config(cfg))
+ cfg = {'verbose_level': 1, 'log_level': 'info'}
+ self.assertEqual(logging.INFO, logs.log_level_from_config(cfg))
+ cfg = {'verbose_level': 1, 'log_level': 'debug'}
+ self.assertEqual(logging.DEBUG, logs.log_level_from_config(cfg))
+ cfg = {'verbose_level': 1, 'log_level': 'bogus'}
+ self.assertEqual(logging.WARNING, logs.log_level_from_config(cfg))
+ cfg = {'verbose_level': 1, 'log_level': 'info', 'debug': True}
+ self.assertEqual(logging.DEBUG, logs.log_level_from_config(cfg))
+
+ @mock.patch('warnings.simplefilter')
+ def test_set_warning_filter(self, simplefilter):
+ logs.set_warning_filter(logging.ERROR)
+ simplefilter.assert_called_with("ignore")
+ logs.set_warning_filter(logging.WARNING)
+ simplefilter.assert_called_with("ignore")
+ logs.set_warning_filter(logging.INFO)
+ simplefilter.assert_called_with("once")
+
+
+class TestFileFormatter(utils.TestCase):
+
+ def test_nothing(self):
+ formatter = logs._FileFormatter()
+ self.assertEqual(('%(asctime)s.%(msecs)03d %(process)d %(levelname)s '
+ '%(name)s %(message)s'), formatter.fmt)
+
+ def test_options(self):
+ class Opts(object):
+ cloud = 'cloudy'
+ os_project_name = 'projecty'
+ username = 'usernamey'
+ options = Opts()
+ formatter = logs._FileFormatter(options=options)
+ self.assertEqual(('%(asctime)s.%(msecs)03d %(process)d %(levelname)s '
+ '%(name)s [cloudy usernamey projecty] %(message)s'),
+ formatter.fmt)
+
+ def test_config(self):
+ config = mock.Mock()
+ config.config = {'cloud': 'cloudy'}
+ config.auth = {'project_name': 'projecty', 'username': 'usernamey'}
+ formatter = logs._FileFormatter(config=config)
+ self.assertEqual(('%(asctime)s.%(msecs)03d %(process)d %(levelname)s '
+ '%(name)s [cloudy usernamey projecty] %(message)s'),
+ formatter.fmt)
+
+
+class TestLogConfigurator(utils.TestCase):
+
+ def setUp(self):
+ super(TestLogConfigurator, self).setUp()
+ self.options = mock.Mock()
+ self.options.verbose_level = 1
+ self.options.log_file = None
+ self.options.debug = False
+ self.root_logger = mock.Mock()
+ self.root_logger.setLevel = mock.Mock()
+ self.root_logger.addHandler = mock.Mock()
+ self.requests_log = mock.Mock()
+ self.requests_log.setLevel = mock.Mock()
+ self.cliff_log = mock.Mock()
+ self.cliff_log.setLevel = mock.Mock()
+ self.stevedore_log = mock.Mock()
+ self.stevedore_log.setLevel = mock.Mock()
+ self.iso8601_log = mock.Mock()
+ self.iso8601_log.setLevel = mock.Mock()
+ self.loggers = [
+ self.root_logger,
+ self.requests_log,
+ self.cliff_log,
+ self.stevedore_log,
+ self.iso8601_log]
+
+ @mock.patch('logging.StreamHandler')
+ @mock.patch('logging.getLogger')
+ @mock.patch('osc_lib.logs.set_warning_filter')
+ def test_init(self, warning_filter, getLogger, handle):
+ getLogger.side_effect = self.loggers
+ console_logger = mock.Mock()
+ console_logger.setFormatter = mock.Mock()
+ console_logger.setLevel = mock.Mock()
+ handle.return_value = console_logger
+
+ configurator = logs.LogConfigurator(self.options)
+
+ getLogger.assert_called_with('iso8601') # last call
+ warning_filter.assert_called_with(logging.WARNING)
+ self.root_logger.setLevel.assert_called_with(logging.DEBUG)
+ self.root_logger.addHandler.assert_called_with(console_logger)
+ self.requests_log.setLevel.assert_called_with(logging.ERROR)
+ self.cliff_log.setLevel.assert_called_with(logging.ERROR)
+ self.stevedore_log.setLevel.assert_called_with(logging.ERROR)
+ self.iso8601_log.setLevel.assert_called_with(logging.ERROR)
+ self.assertFalse(configurator.dump_trace)
+
+ @mock.patch('logging.getLogger')
+ @mock.patch('osc_lib.logs.set_warning_filter')
+ def test_init_no_debug(self, warning_filter, getLogger):
+ getLogger.side_effect = self.loggers
+ self.options.debug = True
+
+ configurator = logs.LogConfigurator(self.options)
+
+ warning_filter.assert_called_with(logging.DEBUG)
+ self.requests_log.setLevel.assert_called_with(logging.DEBUG)
+ self.assertTrue(configurator.dump_trace)
+
+ @mock.patch('logging.FileHandler')
+ @mock.patch('logging.getLogger')
+ @mock.patch('osc_lib.logs.set_warning_filter')
+ @mock.patch('osc_lib.logs._FileFormatter')
+ def test_init_log_file(self, formatter, warning_filter, getLogger, handle):
+ getLogger.side_effect = self.loggers
+ self.options.log_file = '/tmp/log_file'
+ file_logger = mock.Mock()
+ file_logger.setFormatter = mock.Mock()
+ file_logger.setLevel = mock.Mock()
+ handle.return_value = file_logger
+ mock_formatter = mock.Mock()
+ formatter.return_value = mock_formatter
+
+ logs.LogConfigurator(self.options)
+
+ handle.assert_called_with(filename=self.options.log_file)
+ self.root_logger.addHandler.assert_called_with(file_logger)
+ file_logger.setFormatter.assert_called_with(mock_formatter)
+ file_logger.setLevel.assert_called_with(logging.WARNING)
+
+ @mock.patch('logging.FileHandler')
+ @mock.patch('logging.getLogger')
+ @mock.patch('osc_lib.logs.set_warning_filter')
+ @mock.patch('osc_lib.logs._FileFormatter')
+ def test_configure(self, formatter, warning_filter, getLogger, handle):
+ getLogger.side_effect = self.loggers
+ configurator = logs.LogConfigurator(self.options)
+ cloud_config = mock.Mock()
+ config_log = '/tmp/config_log'
+ cloud_config.config = {
+ 'log_file': config_log,
+ 'verbose_level': 1,
+ 'log_level': 'info'}
+ file_logger = mock.Mock()
+ file_logger.setFormatter = mock.Mock()
+ file_logger.setLevel = mock.Mock()
+ handle.return_value = file_logger
+ mock_formatter = mock.Mock()
+ formatter.return_value = mock_formatter
+
+ configurator.configure(cloud_config)
+
+ warning_filter.assert_called_with(logging.INFO)
+ handle.assert_called_with(filename=config_log)
+ self.root_logger.addHandler.assert_called_with(file_logger)
+ file_logger.setFormatter.assert_called_with(mock_formatter)
+ file_logger.setLevel.assert_called_with(logging.INFO)
+ self.assertFalse(configurator.dump_trace)
diff --git a/openstackclient/tests/unit/common/test_module.py b/openstackclient/tests/unit/common/test_module.py
new file mode 100644
index 00000000..eb54dbe0
--- /dev/null
+++ b/openstackclient/tests/unit/common/test_module.py
@@ -0,0 +1,130 @@
+# Copyright 2013 Nebula Inc.
+#
+# 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.
+#
+
+"""Test module module"""
+
+import mock
+
+from openstackclient.common import module as osc_module
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit import utils
+
+
+# NOTE(dtroyer): module_1 must match the version list filter (not --all)
+# currently == '*client*'
+module_name_1 = 'fakeclient'
+module_version_1 = '0.1.2'
+MODULE_1 = {
+ '__version__': module_version_1,
+}
+
+module_name_2 = 'zlib'
+module_version_2 = '1.1'
+MODULE_2 = {
+ '__version__': module_version_2,
+}
+
+MODULES = {
+ module_name_1: fakes.FakeModule(module_name_1, module_version_1),
+ module_name_2: fakes.FakeModule(module_name_2, module_version_2),
+}
+
+
+class TestCommandList(utils.TestCommand):
+
+ def setUp(self):
+ super(TestCommandList, self).setUp()
+
+ self.app.command_manager = mock.Mock()
+ self.app.command_manager.get_command_groups.return_value = [
+ 'openstack.common'
+ ]
+ self.app.command_manager.get_command_names.return_value = [
+ 'limits show\nextension list'
+ ]
+
+ # Get the command object to test
+ self.cmd = osc_module.ListCommand(self.app, None)
+
+ def test_command_list_no_options(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # TODO(bapalm): Adjust this when cliff properly supports
+ # handling the detection rather than using the hard-code below.
+ collist = ('Command Group', 'Commands')
+ self.assertEqual(collist, columns)
+ datalist = ((
+ 'openstack.common',
+ 'limits show\nextension list'
+ ),)
+
+ self.assertEqual(datalist, tuple(data))
+
+
+@mock.patch.dict(
+ 'openstackclient.common.module.sys.modules',
+ values=MODULES,
+ clear=True,
+)
+class TestModuleList(utils.TestCommand):
+
+ def setUp(self):
+ super(TestModuleList, self).setUp()
+
+ # Get the command object to test
+ self.cmd = osc_module.ListModule(self.app, None)
+
+ def test_module_list_no_options(self):
+ arglist = []
+ verifylist = [
+ ('all', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Additional modules may be present, just check our additions
+ self.assertIn(module_name_1, columns)
+ self.assertIn(module_version_1, data)
+
+ def test_module_list_all(self):
+ arglist = [
+ '--all',
+ ]
+ verifylist = [
+ ('all', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Additional modules may be present, just check our additions
+ self.assertIn(module_name_1, columns)
+ self.assertIn(module_name_2, columns)
+ self.assertIn(module_version_1, data)
+ self.assertIn(module_version_2, data)
diff --git a/openstackclient/tests/unit/common/test_parseractions.py b/openstackclient/tests/unit/common/test_parseractions.py
new file mode 100644
index 00000000..1212ad23
--- /dev/null
+++ b/openstackclient/tests/unit/common/test_parseractions.py
@@ -0,0 +1,221 @@
+# Copyright 2012-2013 OpenStack Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+# NOTE(dtroyer): This file is deprecated in Jun 2016, remove after 4.x release
+# or Jun 2017.
+
+import argparse
+
+from openstackclient.common import parseractions
+from openstackclient.tests.unit import utils
+
+
+class TestKeyValueAction(utils.TestCase):
+
+ def setUp(self):
+ super(TestKeyValueAction, self).setUp()
+
+ self.parser = argparse.ArgumentParser()
+
+ # Set up our typical usage
+ self.parser.add_argument(
+ '--property',
+ metavar='<key=value>',
+ action=parseractions.KeyValueAction,
+ default={'green': '20%', 'format': '#rgb'},
+ help='Property to store for this volume '
+ '(repeat option to set multiple properties)',
+ )
+
+ def test_good_values(self):
+ results = self.parser.parse_args([
+ '--property', 'red=',
+ '--property', 'green=100%',
+ '--property', 'blue=50%',
+ ])
+
+ actual = getattr(results, 'property', {})
+ # All should pass through unmolested
+ expect = {'red': '', 'green': '100%', 'blue': '50%', 'format': '#rgb'}
+ self.assertEqual(expect, actual)
+
+ def test_error_values(self):
+ self.assertRaises(
+ argparse.ArgumentTypeError,
+ self.parser.parse_args,
+ [
+ '--property', 'red',
+ ]
+ )
+
+
+class TestMultiKeyValueAction(utils.TestCase):
+
+ def setUp(self):
+ super(TestMultiKeyValueAction, self).setUp()
+
+ self.parser = argparse.ArgumentParser()
+
+ # Set up our typical usage
+ self.parser.add_argument(
+ '--test',
+ metavar='req1=xxx,req2=yyy',
+ action=parseractions.MultiKeyValueAction,
+ dest='test',
+ default=None,
+ required_keys=['req1', 'req2'],
+ optional_keys=['opt1', 'opt2'],
+ help='Test'
+ )
+
+ def test_good_values(self):
+ results = self.parser.parse_args([
+ '--test', 'req1=aaa,req2=bbb',
+ '--test', 'req1=,req2=',
+ ])
+
+ actual = getattr(results, 'test', [])
+ expect = [
+ {'req1': 'aaa', 'req2': 'bbb'},
+ {'req1': '', 'req2': ''},
+ ]
+ self.assertItemsEqual(expect, actual)
+
+ def test_empty_required_optional(self):
+ self.parser.add_argument(
+ '--test-empty',
+ metavar='req1=xxx,req2=yyy',
+ action=parseractions.MultiKeyValueAction,
+ dest='test_empty',
+ default=None,
+ required_keys=[],
+ optional_keys=[],
+ help='Test'
+ )
+
+ results = self.parser.parse_args([
+ '--test-empty', 'req1=aaa,req2=bbb',
+ '--test-empty', 'req1=,req2=',
+ ])
+
+ actual = getattr(results, 'test_empty', [])
+ expect = [
+ {'req1': 'aaa', 'req2': 'bbb'},
+ {'req1': '', 'req2': ''},
+ ]
+ self.assertItemsEqual(expect, actual)
+
+ def test_error_values_with_comma(self):
+ self.assertRaises(
+ argparse.ArgumentTypeError,
+ self.parser.parse_args,
+ [
+ '--test', 'mmm,nnn=zzz',
+ ]
+ )
+
+ def test_error_values_without_comma(self):
+ self.assertRaises(
+ argparse.ArgumentTypeError,
+ self.parser.parse_args,
+ [
+ '--test', 'mmmnnn',
+ ]
+ )
+
+ def test_missing_key(self):
+ self.assertRaises(
+ argparse.ArgumentTypeError,
+ self.parser.parse_args,
+ [
+ '--test', 'req2=ddd',
+ ]
+ )
+
+ def test_invalid_key(self):
+ self.assertRaises(
+ argparse.ArgumentTypeError,
+ self.parser.parse_args,
+ [
+ '--test', 'req1=aaa,req2=bbb,aaa=req1',
+ ]
+ )
+
+ def test_required_keys_not_list(self):
+ self.assertRaises(
+ TypeError,
+ self.parser.add_argument,
+ '--test-required-dict',
+ metavar='req1=xxx,req2=yyy',
+ action=parseractions.MultiKeyValueAction,
+ dest='test_required_dict',
+ default=None,
+ required_keys={'aaa': 'bbb'},
+ optional_keys=['opt1', 'opt2'],
+ help='Test'
+ )
+
+ def test_optional_keys_not_list(self):
+ self.assertRaises(
+ TypeError,
+ self.parser.add_argument,
+ '--test-optional-dict',
+ metavar='req1=xxx,req2=yyy',
+ action=parseractions.MultiKeyValueAction,
+ dest='test_optional_dict',
+ default=None,
+ required_keys=['req1', 'req2'],
+ optional_keys={'aaa': 'bbb'},
+ help='Test'
+ )
+
+
+class TestNonNegativeAction(utils.TestCase):
+
+ def setUp(self):
+ super(TestNonNegativeAction, self).setUp()
+
+ self.parser = argparse.ArgumentParser()
+
+ # Set up our typical usage
+ self.parser.add_argument(
+ '--foo',
+ metavar='<foo>',
+ type=int,
+ action=parseractions.NonNegativeAction,
+ )
+
+ def test_negative_values(self):
+ self.assertRaises(
+ argparse.ArgumentTypeError,
+ self.parser.parse_args,
+ "--foo -1".split()
+ )
+
+ def test_zero_values(self):
+ results = self.parser.parse_args(
+ '--foo 0'.split()
+ )
+
+ actual = getattr(results, 'foo', None)
+ self.assertEqual(actual, 0)
+
+ def test_positive_values(self):
+ results = self.parser.parse_args(
+ '--foo 1'.split()
+ )
+
+ actual = getattr(results, 'foo', None)
+ self.assertEqual(actual, 1)
diff --git a/openstackclient/tests/unit/common/test_quota.py b/openstackclient/tests/unit/common/test_quota.py
new file mode 100644
index 00000000..4a80a2b2
--- /dev/null
+++ b/openstackclient/tests/unit/common/test_quota.py
@@ -0,0 +1,381 @@
+# 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.
+
+import copy
+import mock
+
+from openstackclient.common import quota
+from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit.identity.v2_0 import fakes as identity_fakes
+from openstackclient.tests.unit.network.v2 import fakes as network_fakes
+
+
+class FakeQuotaResource(fakes.FakeResource):
+
+ _keys = {'property': 'value'}
+
+ def set_keys(self, args):
+ self._keys.update(args)
+
+ def unset_keys(self, keys):
+ for key in keys:
+ self._keys.pop(key, None)
+
+ def get_keys(self):
+ return self._keys
+
+
+class TestQuota(compute_fakes.TestComputev2):
+
+ def setUp(self):
+ super(TestQuota, self).setUp()
+ self.quotas_mock = self.app.client_manager.compute.quotas
+ self.quotas_mock.reset_mock()
+ self.quotas_class_mock = self.app.client_manager.compute.quota_classes
+ self.quotas_class_mock.reset_mock()
+ volume_mock = mock.Mock()
+ volume_mock.quotas = mock.Mock()
+ self.app.client_manager.volume = volume_mock
+ self.volume_quotas_mock = volume_mock.quotas
+ self.volume_quotas_mock.reset_mock()
+ self.volume_quotas_class_mock = \
+ self.app.client_manager.volume.quota_classes
+ self.volume_quotas_class_mock.reset_mock()
+ self.projects_mock = self.app.client_manager.identity.projects
+ self.projects_mock.reset_mock()
+ self.app.client_manager.auth_ref = mock.Mock()
+ self.app.client_manager.auth_ref.service_catalog = mock.Mock()
+ self.service_catalog_mock = \
+ self.app.client_manager.auth_ref.service_catalog
+ self.service_catalog_mock.reset_mock()
+ self.app.client_manager.auth_ref.project_id = identity_fakes.project_id
+
+
+class TestQuotaSet(TestQuota):
+
+ def setUp(self):
+ super(TestQuotaSet, self).setUp()
+
+ self.quotas_mock.find.return_value = FakeQuotaResource(
+ None,
+ copy.deepcopy(compute_fakes.QUOTA),
+ loaded=True,
+ )
+
+ self.quotas_mock.update.return_value = FakeQuotaResource(
+ None,
+ copy.deepcopy(compute_fakes.QUOTA),
+ loaded=True,
+ )
+
+ self.volume_quotas_mock.find.return_value = FakeQuotaResource(
+ None,
+ copy.deepcopy(compute_fakes.QUOTA),
+ loaded=True,
+ )
+
+ self.volume_quotas_mock.update.return_value = FakeQuotaResource(
+ None,
+ copy.deepcopy(compute_fakes.QUOTA),
+ loaded=True,
+ )
+
+ self.projects_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.PROJECT),
+ loaded=True,
+ )
+
+ self.network_mock = self.app.client_manager.network
+ self.network_mock.update_quota = mock.Mock()
+
+ self.cmd = quota.SetQuota(self.app, None)
+
+ def test_quota_set(self):
+ arglist = [
+ '--floating-ips', str(compute_fakes.floating_ip_num),
+ '--fixed-ips', str(compute_fakes.fix_ip_num),
+ '--injected-files', str(compute_fakes.injected_file_num),
+ '--injected-file-size', str(compute_fakes.injected_file_size_num),
+ '--injected-path-size', str(compute_fakes.injected_path_size_num),
+ '--key-pairs', str(compute_fakes.key_pair_num),
+ '--cores', str(compute_fakes.core_num),
+ '--ram', str(compute_fakes.ram_num),
+ '--instances', str(compute_fakes.instance_num),
+ '--properties', str(compute_fakes.property_num),
+ '--secgroup-rules', str(compute_fakes.secgroup_rule_num),
+ '--secgroups', str(compute_fakes.secgroup_num),
+ '--server-groups', str(compute_fakes.servgroup_num),
+ '--server-group-members', str(compute_fakes.servgroup_members_num),
+ identity_fakes.project_name,
+ ]
+ verifylist = [
+ ('floating_ips', compute_fakes.floating_ip_num),
+ ('fixed_ips', compute_fakes.fix_ip_num),
+ ('injected_files', compute_fakes.injected_file_num),
+ ('injected_file_content_bytes',
+ compute_fakes.injected_file_size_num),
+ ('injected_file_path_bytes', compute_fakes.injected_path_size_num),
+ ('key_pairs', compute_fakes.key_pair_num),
+ ('cores', compute_fakes.core_num),
+ ('ram', compute_fakes.ram_num),
+ ('instances', compute_fakes.instance_num),
+ ('metadata_items', compute_fakes.property_num),
+ ('security_group_rules', compute_fakes.secgroup_rule_num),
+ ('security_groups', compute_fakes.secgroup_num),
+ ('server_groups', compute_fakes.servgroup_num),
+ ('server_group_members', compute_fakes.servgroup_members_num),
+ ('project', identity_fakes.project_name),
+ ]
+
+ self.app.client_manager.network_endpoint_enabled = False
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+
+ kwargs = {
+ 'floating_ips': compute_fakes.floating_ip_num,
+ 'fixed_ips': compute_fakes.fix_ip_num,
+ 'injected_files': compute_fakes.injected_file_num,
+ 'injected_file_content_bytes':
+ compute_fakes.injected_file_size_num,
+ 'injected_file_path_bytes': compute_fakes.injected_path_size_num,
+ 'key_pairs': compute_fakes.key_pair_num,
+ 'cores': compute_fakes.core_num,
+ 'ram': compute_fakes.ram_num,
+ 'instances': compute_fakes.instance_num,
+ 'metadata_items': compute_fakes.property_num,
+ 'security_group_rules': compute_fakes.secgroup_rule_num,
+ 'security_groups': compute_fakes.secgroup_num,
+ 'server_groups': compute_fakes.servgroup_num,
+ 'server_group_members': compute_fakes.servgroup_members_num,
+ }
+
+ self.quotas_mock.update.assert_called_with(
+ identity_fakes.project_id,
+ **kwargs
+ )
+
+ def test_quota_set_volume(self):
+ arglist = [
+ '--gigabytes', str(compute_fakes.floating_ip_num),
+ '--snapshots', str(compute_fakes.fix_ip_num),
+ '--volumes', str(compute_fakes.injected_file_num),
+ identity_fakes.project_name,
+ ]
+ verifylist = [
+ ('gigabytes', compute_fakes.floating_ip_num),
+ ('snapshots', compute_fakes.fix_ip_num),
+ ('volumes', compute_fakes.injected_file_num),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+
+ kwargs = {
+ 'gigabytes': compute_fakes.floating_ip_num,
+ 'snapshots': compute_fakes.fix_ip_num,
+ 'volumes': compute_fakes.injected_file_num,
+ }
+
+ self.volume_quotas_mock.update.assert_called_with(
+ identity_fakes.project_id,
+ **kwargs
+ )
+
+ def test_quota_set_network(self):
+ arglist = [
+ '--subnets', str(network_fakes.QUOTA['subnet']),
+ '--networks', str(network_fakes.QUOTA['network']),
+ '--floating-ips', str(network_fakes.QUOTA['floatingip']),
+ '--subnetpools', str(network_fakes.QUOTA['subnetpool']),
+ '--secgroup-rules',
+ str(network_fakes.QUOTA['security_group_rule']),
+ '--secgroups', str(network_fakes.QUOTA['security_group']),
+ '--routers', str(network_fakes.QUOTA['router']),
+ '--rbac-policies', str(network_fakes.QUOTA['rbac_policy']),
+ '--ports', str(network_fakes.QUOTA['port']),
+ '--vips', str(network_fakes.QUOTA['vip']),
+ '--members', str(network_fakes.QUOTA['member']),
+ '--health-monitors', str(network_fakes.QUOTA['health_monitor']),
+ identity_fakes.project_name,
+ ]
+ verifylist = [
+ ('subnet', network_fakes.QUOTA['subnet']),
+ ('network', network_fakes.QUOTA['network']),
+ ('floatingip', network_fakes.QUOTA['floatingip']),
+ ('subnetpool', network_fakes.QUOTA['subnetpool']),
+ ('security_group_rule',
+ network_fakes.QUOTA['security_group_rule']),
+ ('security_group', network_fakes.QUOTA['security_group']),
+ ('router', network_fakes.QUOTA['router']),
+ ('rbac_policy', network_fakes.QUOTA['rbac_policy']),
+ ('port', network_fakes.QUOTA['port']),
+ ('vip', network_fakes.QUOTA['vip']),
+ ('member', network_fakes.QUOTA['member']),
+ ('health_monitor', network_fakes.QUOTA['health_monitor']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+ kwargs = {
+ 'subnet': network_fakes.QUOTA['subnet'],
+ 'network': network_fakes.QUOTA['network'],
+ 'floatingip': network_fakes.QUOTA['floatingip'],
+ 'subnetpool': network_fakes.QUOTA['subnetpool'],
+ 'security_group_rule':
+ network_fakes.QUOTA['security_group_rule'],
+ 'security_group': network_fakes.QUOTA['security_group'],
+ 'router': network_fakes.QUOTA['router'],
+ 'rbac_policy': network_fakes.QUOTA['rbac_policy'],
+ 'port': network_fakes.QUOTA['port'],
+ 'vip': network_fakes.QUOTA['vip'],
+ 'member': network_fakes.QUOTA['member'],
+ 'health_monitor': network_fakes.QUOTA['health_monitor'],
+ }
+ self.network_mock.update_quota.assert_called_with(
+ identity_fakes.project_id,
+ **kwargs
+ )
+
+
+class TestQuotaShow(TestQuota):
+
+ def setUp(self):
+ super(TestQuotaShow, self).setUp()
+
+ self.quotas_mock.get.return_value = FakeQuotaResource(
+ None,
+ copy.deepcopy(compute_fakes.QUOTA),
+ loaded=True,
+ )
+
+ self.quotas_mock.defaults.return_value = FakeQuotaResource(
+ None,
+ copy.deepcopy(compute_fakes.QUOTA),
+ loaded=True,
+ )
+
+ self.volume_quotas_mock.get.return_value = FakeQuotaResource(
+ None,
+ copy.deepcopy(compute_fakes.QUOTA),
+ loaded=True,
+ )
+
+ self.volume_quotas_mock.defaults.return_value = FakeQuotaResource(
+ None,
+ copy.deepcopy(compute_fakes.QUOTA),
+ loaded=True,
+ )
+
+ fake_network_endpoint = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.ENDPOINT),
+ loaded=True,
+ )
+
+ self.service_catalog_mock.get_endpoints.return_value = {
+ 'network': fake_network_endpoint
+ }
+
+ self.quotas_class_mock.get.return_value = FakeQuotaResource(
+ None,
+ copy.deepcopy(compute_fakes.QUOTA),
+ loaded=True,
+ )
+
+ self.volume_quotas_class_mock.get.return_value = FakeQuotaResource(
+ None,
+ copy.deepcopy(compute_fakes.QUOTA),
+ loaded=True,
+ )
+
+ self.projects_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.PROJECT),
+ loaded=True,
+ )
+
+ self.app.client_manager.network = network_fakes.FakeNetworkV2Client(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN,
+ )
+ self.network = self.app.client_manager.network
+ self.network.get_quota = mock.Mock(return_value=network_fakes.QUOTA)
+
+ self.cmd = quota.ShowQuota(self.app, None)
+
+ def test_quota_show(self):
+ arglist = [
+ identity_fakes.project_name,
+ ]
+ verifylist = [
+ ('project', identity_fakes.project_name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+
+ self.quotas_mock.get.assert_called_with(identity_fakes.project_id)
+ self.volume_quotas_mock.get.assert_called_with(
+ identity_fakes.project_id)
+ self.network.get_quota.assert_called_with(identity_fakes.project_id)
+
+ def test_quota_show_with_default(self):
+ arglist = [
+ '--default',
+ identity_fakes.project_name,
+ ]
+ verifylist = [
+ ('default', True),
+ ('project', identity_fakes.project_name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+
+ self.quotas_mock.defaults.assert_called_with(identity_fakes.project_id)
+ self.volume_quotas_mock.defaults.assert_called_with(
+ identity_fakes.project_id)
+
+ def test_quota_show_with_class(self):
+ arglist = [
+ '--class',
+ identity_fakes.project_name,
+ ]
+ verifylist = [
+ ('quota_class', True),
+ ('project', identity_fakes.project_name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+
+ self.quotas_class_mock.get.assert_called_with(
+ identity_fakes.project_id)
+ self.volume_quotas_class_mock.get.assert_called_with(
+ identity_fakes.project_id)
+
+ def test_quota_show_no_project(self):
+ parsed_args = self.check_parser(self.cmd, [], [])
+
+ self.cmd.take_action(parsed_args)
+
+ self.quotas_mock.get.assert_called_with(identity_fakes.project_id)
+ self.volume_quotas_mock.get.assert_called_with(
+ identity_fakes.project_id)
+ self.network.get_quota.assert_called_with(identity_fakes.project_id)
diff --git a/openstackclient/tests/unit/compute/__init__.py b/openstackclient/tests/unit/compute/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/unit/compute/__init__.py
diff --git a/openstackclient/tests/unit/compute/v2/__init__.py b/openstackclient/tests/unit/compute/v2/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/unit/compute/v2/__init__.py
diff --git a/openstackclient/tests/unit/compute/v2/fakes.py b/openstackclient/tests/unit/compute/v2/fakes.py
new file mode 100644
index 00000000..0e3d47ba
--- /dev/null
+++ b/openstackclient/tests/unit/compute/v2/fakes.py
@@ -0,0 +1,1249 @@
+# Copyright 2013 Nebula Inc.
+#
+# 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.
+#
+
+import copy
+import mock
+import uuid
+
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit.identity.v2_0 import fakes as identity_fakes
+from openstackclient.tests.unit.image.v2 import fakes as image_fakes
+from openstackclient.tests.unit.network.v2 import fakes as network_fakes
+from openstackclient.tests.unit import utils
+from openstackclient.tests.unit.volume.v2 import fakes as volume_fakes
+
+floating_ip_num = 100
+fix_ip_num = 100
+injected_file_num = 100
+injected_file_size_num = 10240
+injected_path_size_num = 255
+key_pair_num = 100
+core_num = 20
+ram_num = 51200
+instance_num = 10
+property_num = 128
+secgroup_rule_num = 20
+secgroup_num = 10
+servgroup_num = 10
+servgroup_members_num = 10
+project_name = 'project_test'
+QUOTA = {
+ 'project': project_name,
+ 'floating-ips': floating_ip_num,
+ 'fix-ips': fix_ip_num,
+ 'injected-files': injected_file_num,
+ 'injected-file-size': injected_file_size_num,
+ 'injected-path-size': injected_path_size_num,
+ 'key-pairs': key_pair_num,
+ 'cores': core_num,
+ 'ram': ram_num,
+ 'instances': instance_num,
+ 'properties': property_num,
+ 'secgroup_rules': secgroup_rule_num,
+ 'secgroups': secgroup_num,
+ 'server-groups': servgroup_num,
+ 'server-group-members': servgroup_members_num
+}
+
+QUOTA_columns = tuple(sorted(QUOTA))
+QUOTA_data = tuple(QUOTA[x] for x in sorted(QUOTA))
+
+
+class FakeAggregate(object):
+ """Fake one aggregate."""
+
+ @staticmethod
+ def create_one_aggregate(attrs=None):
+ """Create a fake aggregate.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id and other attributes
+ """
+ attrs = attrs or {}
+
+ # Set default attribute
+ aggregate_info = {
+ "name": "aggregate-name-" + uuid.uuid4().hex,
+ "availability_zone": "ag_zone",
+ "hosts": [],
+ "id": "aggregate-id-" + uuid.uuid4().hex,
+ "metadata": {
+ "availability_zone": "ag_zone",
+ }
+ }
+
+ # Overwrite default attributes.
+ aggregate_info.update(attrs)
+
+ aggregate = fakes.FakeResource(
+ info=copy.deepcopy(aggregate_info),
+ loaded=True)
+ return aggregate
+
+ @staticmethod
+ def create_aggregates(attrs=None, count=2):
+ """Create multiple fake aggregates.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of aggregates to fake
+ :return:
+ A list of FakeResource objects faking the aggregates
+ """
+ aggregates = []
+ for i in range(0, count):
+ aggregates.append(FakeAggregate.create_one_aggregate(attrs))
+
+ return aggregates
+
+ @staticmethod
+ def get_aggregates(aggregates=None, count=2):
+ """Get an iterable MagicMock object with a list of faked aggregates.
+
+ If aggregates list is provided, then initialize the Mock object
+ with the list. Otherwise create one.
+
+ :param List aggregates:
+ A list of FakeResource objects faking aggregates
+ :param int count:
+ The number of aggregates to fake
+ :return:
+ An iterable Mock object with side_effect set to a list of faked
+ aggregates
+ """
+ if aggregates is None:
+ aggregates = FakeAggregate.create_aggregates(count)
+ return mock.MagicMock(side_effect=aggregates)
+
+
+class FakeComputev2Client(object):
+
+ def __init__(self, **kwargs):
+ self.agents = mock.Mock()
+ self.agents.resource_class = fakes.FakeResource(None, {})
+
+ self.aggregates = mock.Mock()
+ self.aggregates.resource_class = fakes.FakeResource(None, {})
+
+ self.availability_zones = mock.Mock()
+ self.availability_zones.resource_class = fakes.FakeResource(None, {})
+
+ self.images = mock.Mock()
+ self.images.resource_class = fakes.FakeResource(None, {})
+
+ self.servers = mock.Mock()
+ self.servers.resource_class = fakes.FakeResource(None, {})
+
+ self.services = mock.Mock()
+ self.services.resource_class = fakes.FakeResource(None, {})
+
+ self.extensions = mock.Mock()
+ self.extensions.resource_class = fakes.FakeResource(None, {})
+
+ self.flavors = mock.Mock()
+ self.flavors.resource_class = fakes.FakeResource(None, {})
+
+ self.flavor_access = mock.Mock()
+ self.flavor_access.resource_class = fakes.FakeResource(None, {})
+
+ self.quotas = mock.Mock()
+ self.quotas.resource_class = fakes.FakeResource(None, {})
+
+ self.quota_classes = mock.Mock()
+ self.quota_classes.resource_class = fakes.FakeResource(None, {})
+
+ self.volumes = mock.Mock()
+ self.volumes.resource_class = fakes.FakeResource(None, {})
+
+ self.hypervisors = mock.Mock()
+ self.hypervisors.resource_class = fakes.FakeResource(None, {})
+
+ self.hypervisors_stats = mock.Mock()
+ self.hypervisors_stats.resource_class = fakes.FakeResource(None, {})
+
+ self.security_groups = mock.Mock()
+ self.security_groups.resource_class = fakes.FakeResource(None, {})
+
+ self.security_group_rules = mock.Mock()
+ self.security_group_rules.resource_class = fakes.FakeResource(None, {})
+
+ self.floating_ips = mock.Mock()
+ self.floating_ips.resource_class = fakes.FakeResource(None, {})
+
+ self.floating_ip_pools = mock.Mock()
+ self.floating_ip_pools.resource_class = fakes.FakeResource(None, {})
+
+ self.networks = mock.Mock()
+ self.networks.resource_class = fakes.FakeResource(None, {})
+
+ self.keypairs = mock.Mock()
+ self.keypairs.resource_class = fakes.FakeResource(None, {})
+
+ self.hosts = mock.Mock()
+ self.hosts.resource_class = fakes.FakeResource(None, {})
+
+ self.server_groups = mock.Mock()
+ self.server_groups.resource_class = fakes.FakeResource(None, {})
+
+ self.auth_token = kwargs['token']
+
+ self.management_url = kwargs['endpoint']
+
+
+class TestComputev2(utils.TestCommand):
+
+ def setUp(self):
+ super(TestComputev2, self).setUp()
+
+ self.app.client_manager.compute = FakeComputev2Client(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN,
+ )
+
+ self.app.client_manager.identity = identity_fakes.FakeIdentityv2Client(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN,
+ )
+
+ self.app.client_manager.image = image_fakes.FakeImagev2Client(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN,
+ )
+
+ self.app.client_manager.network = network_fakes.FakeNetworkV2Client(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN,
+ )
+
+ self.app.client_manager.volume = volume_fakes.FakeVolumeClient(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN,
+ )
+
+
+class FakeAgent(object):
+ """Fake one or more agent."""
+
+ @staticmethod
+ def create_one_agent(attrs=None):
+ """Create a fake agent.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with agent_id, os, and so on
+ """
+
+ attrs = attrs or {}
+
+ # set default attributes.
+ agent_info = {
+ 'agent_id': 'agent-id-' + uuid.uuid4().hex,
+ 'os': 'agent-os-' + uuid.uuid4().hex,
+ 'architecture': 'agent-architecture',
+ 'version': '8.0',
+ 'url': 'http://127.0.0.1',
+ 'md5hash': 'agent-md5hash',
+ 'hypervisor': 'hypervisor',
+ }
+
+ # Overwrite default attributes.
+ agent_info.update(attrs)
+
+ agent = fakes.FakeResource(info=copy.deepcopy(agent_info),
+ loaded=True)
+ return agent
+
+ @staticmethod
+ def create_agents(attrs=None, count=2):
+ """Create multiple fake agents.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of agents to fake
+ :return:
+ A list of FakeResource objects faking the agents
+ """
+ agents = []
+ for i in range(0, count):
+ agents.append(FakeAgent.create_one_agent(attrs))
+
+ return agents
+
+
+class FakeExtension(object):
+ """Fake one or more extension."""
+
+ @staticmethod
+ def create_one_extension(attrs=None):
+ """Create a fake extension.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object with name, namespace, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ extension_info = {
+ 'name': 'name-' + uuid.uuid4().hex,
+ 'namespace': (
+ 'http://docs.openstack.org/compute/ext/multinic/api/v1.1'),
+ 'description': 'description-' + uuid.uuid4().hex,
+ 'updated': '2014-01-07T12:00:0-00:00',
+ 'alias': 'NMN',
+ 'links': ('[{"href":'
+ '"https://github.com/openstack/compute-api", "type":'
+ ' "text/html", "rel": "describedby"}]')
+ }
+
+ # Overwrite default attributes.
+ extension_info.update(attrs)
+
+ extension = fakes.FakeResource(
+ info=copy.deepcopy(extension_info),
+ loaded=True)
+ return extension
+
+
+class FakeHypervisor(object):
+ """Fake one or more hypervisor."""
+
+ @staticmethod
+ def create_one_hypervisor(attrs=None):
+ """Create a fake hypervisor.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, hypervisor_hostname, and so on
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ hypervisor_info = {
+ 'id': 'hypervisor-id-' + uuid.uuid4().hex,
+ 'hypervisor_hostname': 'hypervisor-hostname-' + uuid.uuid4().hex,
+ 'status': 'enabled',
+ 'host_ip': '192.168.0.10',
+ 'cpu_info': {
+ 'aaa': 'aaa',
+ },
+ 'free_disk_gb': 50,
+ 'hypervisor_version': 2004001,
+ 'disk_available_least': 50,
+ 'local_gb': 50,
+ 'free_ram_mb': 1024,
+ 'service': {
+ 'host': 'aaa',
+ 'disabled_reason': None,
+ 'id': 1,
+ },
+ 'vcpus_used': 0,
+ 'hypervisor_type': 'QEMU',
+ 'local_gb_used': 0,
+ 'vcpus': 4,
+ 'memory_mb_used': 512,
+ 'memory_mb': 1024,
+ 'current_workload': 0,
+ 'state': 'up',
+ 'running_vms': 0,
+ }
+
+ # Overwrite default attributes.
+ hypervisor_info.update(attrs)
+
+ hypervisor = fakes.FakeResource(info=copy.deepcopy(hypervisor_info),
+ loaded=True)
+ return hypervisor
+
+ @staticmethod
+ def create_hypervisors(attrs=None, count=2):
+ """Create multiple fake hypervisors.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of hypervisors to fake
+ :return:
+ A list of FakeResource objects faking the hypervisors
+ """
+ hypervisors = []
+ for i in range(0, count):
+ hypervisors.append(FakeHypervisor.create_one_hypervisor(attrs))
+
+ return hypervisors
+
+
+class FakeHypervisorStats(object):
+ """Fake one or more hypervisor stats."""
+
+ @staticmethod
+ def create_one_hypervisor_stats(attrs=None):
+ """Create a fake hypervisor stats.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with count, current_workload, and so on
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ stats_info = {
+ 'count': 2,
+ 'current_workload': 0,
+ 'disk_available_least': 50,
+ 'free_disk_gb': 100,
+ 'free_ram_mb': 23000,
+ 'local_gb': 100,
+ 'local_gb_used': 0,
+ 'memory_mb': 23800,
+ 'memory_mb_used': 1400,
+ 'running_vms': 3,
+ 'vcpus': 8,
+ 'vcpus_used': 3,
+ }
+
+ # Overwrite default attributes.
+ stats_info.update(attrs)
+
+ # Set default method.
+ hypervisor_stats_method = {'to_dict': stats_info}
+
+ hypervisor_stats = fakes.FakeResource(
+ info=copy.deepcopy(stats_info),
+ methods=copy.deepcopy(hypervisor_stats_method),
+ loaded=True)
+ return hypervisor_stats
+
+ @staticmethod
+ def create_hypervisors_stats(attrs=None, count=2):
+ """Create multiple fake hypervisors stats.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of hypervisors to fake
+ :return:
+ A list of FakeResource objects faking the hypervisors
+ """
+ hypervisors = []
+ for i in range(0, count):
+ hypervisors.append(
+ FakeHypervisorStats.create_one_hypervisor_stats(attrs))
+
+ return hypervisors
+
+
+class FakeSecurityGroup(object):
+ """Fake one or more security groups."""
+
+ @staticmethod
+ def create_one_security_group(attrs=None):
+ """Create a fake security group.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, name, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ security_group_attrs = {
+ 'id': 'security-group-id-' + uuid.uuid4().hex,
+ 'name': 'security-group-name-' + uuid.uuid4().hex,
+ 'description': 'security-group-description-' + uuid.uuid4().hex,
+ 'tenant_id': 'project-id-' + uuid.uuid4().hex,
+ 'rules': [],
+ }
+
+ # Overwrite default attributes.
+ security_group_attrs.update(attrs)
+
+ security_group = fakes.FakeResource(
+ info=copy.deepcopy(security_group_attrs),
+ loaded=True)
+ return security_group
+
+ @staticmethod
+ def create_security_groups(attrs=None, count=2):
+ """Create multiple fake security groups.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of security groups to fake
+ :return:
+ A list of FakeResource objects faking the security groups
+ """
+ security_groups = []
+ for i in range(0, count):
+ security_groups.append(
+ FakeSecurityGroup.create_one_security_group(attrs))
+
+ return security_groups
+
+ @staticmethod
+ def get_security_groups(security_groups=None, count=2):
+ """Get an iterable MagicMock object with a list of faked security groups.
+
+ If security groups list is provided, then initialize the Mock object
+ with the list. Otherwise create one.
+
+ :param List security groups:
+ A list of FakeResource objects faking security groups
+ :param int count:
+ The number of security groups to fake
+ :return:
+ An iterable Mock object with side_effect set to a list of faked
+ security groups
+ """
+ if security_groups is None:
+ security_groups = FakeSecurityGroup.create_security_groups(count)
+ return mock.MagicMock(side_effect=security_groups)
+
+
+class FakeSecurityGroupRule(object):
+ """Fake one or more security group rules."""
+
+ @staticmethod
+ def create_one_security_group_rule(attrs=None):
+ """Create a fake security group rule.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ security_group_rule_attrs = {
+ 'from_port': 0,
+ 'group': {},
+ 'id': 'security-group-rule-id-' + uuid.uuid4().hex,
+ 'ip_protocol': 'tcp',
+ 'ip_range': {'cidr': '0.0.0.0/0'},
+ 'parent_group_id': 'security-group-id-' + uuid.uuid4().hex,
+ 'to_port': 0,
+ }
+
+ # Overwrite default attributes.
+ security_group_rule_attrs.update(attrs)
+
+ security_group_rule = fakes.FakeResource(
+ info=copy.deepcopy(security_group_rule_attrs),
+ loaded=True)
+ return security_group_rule
+
+ @staticmethod
+ def create_security_group_rules(attrs=None, count=2):
+ """Create multiple fake security group rules.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of security group rules to fake
+ :return:
+ A list of FakeResource objects faking the security group rules
+ """
+ security_group_rules = []
+ for i in range(0, count):
+ security_group_rules.append(
+ FakeSecurityGroupRule.create_one_security_group_rule(attrs))
+
+ return security_group_rules
+
+
+class FakeServer(object):
+ """Fake one or more compute servers."""
+
+ @staticmethod
+ def create_one_server(attrs=None, methods=None):
+ """Create a fake server.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param Dictionary methods:
+ A dictionary with all methods
+ :return:
+ A FakeResource object, with id, name, metadata, and so on
+ """
+ attrs = attrs or {}
+ methods = methods or {}
+
+ # Set default attributes.
+ server_info = {
+ 'id': 'server-id-' + uuid.uuid4().hex,
+ 'name': 'server-name-' + uuid.uuid4().hex,
+ 'metadata': {},
+ 'image': {
+ 'id': 'image-id-' + uuid.uuid4().hex,
+ },
+ 'flavor': {
+ 'id': 'flavor-id-' + uuid.uuid4().hex,
+ },
+ 'OS-EXT-STS:power_state': 1,
+ }
+
+ # Overwrite default attributes.
+ server_info.update(attrs)
+
+ server = fakes.FakeResource(info=copy.deepcopy(server_info),
+ methods=methods,
+ loaded=True)
+ return server
+
+ @staticmethod
+ def create_servers(attrs=None, methods=None, count=2):
+ """Create multiple fake servers.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param Dictionary methods:
+ A dictionary with all methods
+ :param int count:
+ The number of servers to fake
+ :return:
+ A list of FakeResource objects faking the servers
+ """
+ servers = []
+ for i in range(0, count):
+ servers.append(FakeServer.create_one_server(attrs, methods))
+
+ return servers
+
+ @staticmethod
+ def get_servers(servers=None, count=2):
+ """Get an iterable MagicMock object with a list of faked servers.
+
+ If servers list is provided, then initialize the Mock object with the
+ list. Otherwise create one.
+
+ :param List servers:
+ A list of FakeResource objects faking servers
+ :param int count:
+ The number of servers to fake
+ :return:
+ An iterable Mock object with side_effect set to a list of faked
+ servers
+ """
+ if servers is None:
+ servers = FakeServer.create_servers(count)
+ return mock.MagicMock(side_effect=servers)
+
+
+class FakeService(object):
+ """Fake one or more services."""
+
+ @staticmethod
+ def create_one_service(attrs=None):
+ """Create a fake service.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, host, binary, and so on
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ service_info = {
+ 'id': 'id-' + uuid.uuid4().hex,
+ 'host': 'host-' + uuid.uuid4().hex,
+ 'binary': 'binary-' + uuid.uuid4().hex,
+ 'status': 'enabled',
+ 'zone': 'zone-' + uuid.uuid4().hex,
+ 'state': 'state-' + uuid.uuid4().hex,
+ 'updated_at': 'time-' + uuid.uuid4().hex,
+ 'disabled_reason': 'earthquake',
+ }
+
+ # Overwrite default attributes.
+ service_info.update(attrs)
+
+ service = fakes.FakeResource(info=copy.deepcopy(service_info),
+ loaded=True)
+
+ return service
+
+ @staticmethod
+ def create_services(attrs=None, count=2):
+ """Create multiple fake services.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of services to fake
+ :return:
+ A list of FakeResource objects faking the services
+ """
+ services = []
+ for i in range(0, count):
+ services.append(FakeService.create_one_service(attrs))
+
+ return services
+
+
+class FakeFlavor(object):
+ """Fake one or more flavors."""
+
+ @staticmethod
+ def create_one_flavor(attrs=None):
+ """Create a fake flavor.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, name, ram, vcpus, and so on
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ flavor_info = {
+ 'id': 'flavor-id-' + uuid.uuid4().hex,
+ 'name': 'flavor-name-' + uuid.uuid4().hex,
+ 'ram': 8192,
+ 'vcpus': 4,
+ 'disk': 128,
+ 'swap': 0,
+ 'rxtx_factor': 1.0,
+ 'OS-FLV-DISABLED:disabled': False,
+ 'os-flavor-access:is_public': True,
+ 'OS-FLV-EXT-DATA:ephemeral': 0,
+ 'properties': {'property': 'value'},
+ }
+
+ # Overwrite default attributes.
+ flavor_info.update(attrs)
+
+ # Set default methods.
+ flavor_methods = {
+ 'set_keys': None,
+ 'unset_keys': None,
+ 'get_keys': {'property': 'value'},
+ }
+
+ flavor = fakes.FakeResource(info=copy.deepcopy(flavor_info),
+ methods=flavor_methods,
+ loaded=True)
+
+ # Set attributes with special mappings in nova client.
+ flavor.disabled = flavor_info['OS-FLV-DISABLED:disabled']
+ flavor.is_public = flavor_info['os-flavor-access:is_public']
+ flavor.ephemeral = flavor_info['OS-FLV-EXT-DATA:ephemeral']
+
+ return flavor
+
+ @staticmethod
+ def create_flavors(attrs=None, count=2):
+ """Create multiple fake flavors.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of flavors to fake
+ :return:
+ A list of FakeResource objects faking the flavors
+ """
+ flavors = []
+ for i in range(0, count):
+ flavors.append(FakeFlavor.create_one_flavor(attrs))
+
+ return flavors
+
+ @staticmethod
+ def get_flavors(flavors=None, count=2):
+ """Get an iterable MagicMock object with a list of faked flavors.
+
+ If flavors list is provided, then initialize the Mock object with the
+ list. Otherwise create one.
+
+ :param List flavors:
+ A list of FakeResource objects faking flavors
+ :param int count:
+ The number of flavors to fake
+ :return:
+ An iterable Mock object with side_effect set to a list of faked
+ flavors
+ """
+ if flavors is None:
+ flavors = FakeFlavor.create_flavors(count)
+ return mock.MagicMock(side_effect=flavors)
+
+
+class FakeFlavorAccess(object):
+ """Fake one or more flavor accesses."""
+
+ @staticmethod
+ def create_one_flavor_access(attrs=None):
+ """Create a fake flavor access.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with flavor_id, tenat_id
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ flavor_access_info = {
+ 'flavor_id': 'flavor-id-' + uuid.uuid4().hex,
+ 'tenant_id': 'tenant-id-' + uuid.uuid4().hex,
+ }
+
+ # Overwrite default attributes.
+ flavor_access_info.update(attrs)
+
+ flavor_access = fakes.FakeResource(
+ info=copy.deepcopy(flavor_access_info), loaded=True)
+
+ return flavor_access
+
+
+class FakeKeypair(object):
+ """Fake one or more keypairs."""
+
+ @staticmethod
+ def create_one_keypair(attrs=None, no_pri=False):
+ """Create a fake keypair
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, name, fingerprint, and so on
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ keypair_info = {
+ 'name': 'keypair-name-' + uuid.uuid4().hex,
+ 'fingerprint': 'dummy',
+ 'public_key': 'dummy',
+ 'user_id': 'user'
+ }
+ if not no_pri:
+ keypair_info['private_key'] = 'private_key'
+
+ # Overwrite default attributes.
+ keypair_info.update(attrs)
+
+ keypair = fakes.FakeResource(info=copy.deepcopy(keypair_info),
+ loaded=True)
+
+ return keypair
+
+ @staticmethod
+ def create_keypairs(attrs=None, count=2):
+ """Create multiple fake keypairs.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of keypairs to fake
+ :return:
+ A list of FakeResource objects faking the keypairs
+ """
+
+ keypairs = []
+ for i in range(0, count):
+ keypairs.append(FakeKeypair.create_one_keypair(attrs))
+
+ return keypairs
+
+ @staticmethod
+ def get_keypairs(keypairs=None, count=2):
+ """Get an iterable MagicMock object with a list of faked keypairs.
+
+ If keypairs list is provided, then initialize the Mock object with the
+ list. Otherwise create one.
+
+ :param List keypairs:
+ A list of FakeResource objects faking keypairs
+ :param int count:
+ The number of keypairs to fake
+ :return:
+ An iterable Mock object with side_effect set to a list of faked
+ keypairs
+ """
+ if keypairs is None:
+ keypairs = FakeKeypair.create_keypairs(count)
+ return mock.MagicMock(side_effect=keypairs)
+
+
+class FakeAvailabilityZone(object):
+ """Fake one or more compute availability zones (AZs)."""
+
+ @staticmethod
+ def create_one_availability_zone(attrs=None):
+ """Create a fake AZ.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object with zoneName, zoneState, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ host_name = uuid.uuid4().hex
+ service_name = uuid.uuid4().hex
+ service_updated_at = uuid.uuid4().hex
+ availability_zone = {
+ 'zoneName': uuid.uuid4().hex,
+ 'zoneState': {'available': True},
+ 'hosts': {host_name: {service_name: {
+ 'available': True,
+ 'active': True,
+ 'updated_at': service_updated_at,
+ }}},
+ }
+
+ # Overwrite default attributes.
+ availability_zone.update(attrs)
+
+ availability_zone = fakes.FakeResource(
+ info=copy.deepcopy(availability_zone),
+ loaded=True)
+ return availability_zone
+
+ @staticmethod
+ def create_availability_zones(attrs=None, count=2):
+ """Create multiple fake AZs.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of AZs to fake
+ :return:
+ A list of FakeResource objects faking the AZs
+ """
+ availability_zones = []
+ for i in range(0, count):
+ availability_zone = \
+ FakeAvailabilityZone.create_one_availability_zone(attrs)
+ availability_zones.append(availability_zone)
+
+ return availability_zones
+
+
+class FakeFloatingIP(object):
+ """Fake one or more floating ip."""
+
+ @staticmethod
+ def create_one_floating_ip(attrs=None):
+ """Create a fake floating ip.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, ip, and so on
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ floating_ip_attrs = {
+ 'id': 'floating-ip-id-' + uuid.uuid4().hex,
+ 'ip': '1.0.9.0',
+ 'fixed_ip': '2.0.9.0',
+ 'instance_id': 'server-id-' + uuid.uuid4().hex,
+ 'pool': 'public',
+ }
+
+ # Overwrite default attributes.
+ floating_ip_attrs.update(attrs)
+
+ floating_ip = fakes.FakeResource(
+ info=copy.deepcopy(floating_ip_attrs),
+ loaded=True)
+
+ return floating_ip
+
+ @staticmethod
+ def create_floating_ips(attrs=None, count=2):
+ """Create multiple fake floating ips.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of floating ips to fake
+ :return:
+ A list of FakeResource objects faking the floating ips
+ """
+ floating_ips = []
+ for i in range(0, count):
+ floating_ips.append(FakeFloatingIP.create_one_floating_ip(attrs))
+ return floating_ips
+
+ @staticmethod
+ def get_floating_ips(floating_ips=None, count=2):
+ """Get an iterable MagicMock object with a list of faked floating ips.
+
+ If floating_ips list is provided, then initialize the Mock object
+ with the list. Otherwise create one.
+
+ :param List floating ips:
+ A list of FakeResource objects faking floating ips
+ :param int count:
+ The number of floating ips to fake
+ :return:
+ An iterable Mock object with side_effect set to a list of faked
+ floating ips
+ """
+ if floating_ips is None:
+ floating_ips = FakeFloatingIP.create_floating_ips(count)
+ return mock.MagicMock(side_effect=floating_ips)
+
+
+class FakeFloatingIPPool(object):
+ """Fake one or more floating ip pools."""
+
+ @staticmethod
+ def create_one_floating_ip_pool(attrs=None):
+ """Create a fake floating ip pool.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with name, etc
+ """
+ if attrs is None:
+ attrs = {}
+
+ # Set default attributes.
+ floating_ip_pool_attrs = {
+ 'name': 'floating-ip-pool-name-' + uuid.uuid4().hex,
+ }
+
+ # Overwrite default attributes.
+ floating_ip_pool_attrs.update(attrs)
+
+ floating_ip_pool = fakes.FakeResource(
+ info=copy.deepcopy(floating_ip_pool_attrs),
+ loaded=True)
+
+ return floating_ip_pool
+
+ @staticmethod
+ def create_floating_ip_pools(attrs=None, count=2):
+ """Create multiple fake floating ip pools.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of floating ip pools to fake
+ :return:
+ A list of FakeResource objects faking the floating ip pools
+ """
+ floating_ip_pools = []
+ for i in range(0, count):
+ floating_ip_pools.append(
+ FakeFloatingIPPool.create_one_floating_ip_pool(attrs)
+ )
+ return floating_ip_pools
+
+
+class FakeNetwork(object):
+ """Fake one or more networks."""
+
+ @staticmethod
+ def create_one_network(attrs=None):
+ """Create a fake network.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, label, cidr and so on
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ network_attrs = {
+ 'bridge': 'br100',
+ 'bridge_interface': None,
+ 'broadcast': '10.0.0.255',
+ 'cidr': '10.0.0.0/24',
+ 'cidr_v6': None,
+ 'created_at': '2016-02-11T11:17:37.000000',
+ 'deleted': False,
+ 'deleted_at': None,
+ 'dhcp_server': '10.0.0.1',
+ 'dhcp_start': '10.0.0.2',
+ 'dns1': '8.8.4.4',
+ 'dns2': None,
+ 'enable_dhcp': True,
+ 'gateway': '10.0.0.1',
+ 'gateway_v6': None,
+ 'host': None,
+ 'id': 'network-id-' + uuid.uuid4().hex,
+ 'injected': False,
+ 'label': 'network-label-' + uuid.uuid4().hex,
+ 'mtu': None,
+ 'multi_host': False,
+ 'netmask': '255.255.255.0',
+ 'netmask_v6': None,
+ 'priority': None,
+ 'project_id': 'project-id-' + uuid.uuid4().hex,
+ 'rxtx_base': None,
+ 'share_address': False,
+ 'updated_at': None,
+ 'vlan': None,
+ 'vpn_private_address': None,
+ 'vpn_public_address': None,
+ 'vpn_public_port': None,
+ }
+
+ # Overwrite default attributes.
+ network_attrs.update(attrs)
+
+ network = fakes.FakeResource(info=copy.deepcopy(network_attrs),
+ loaded=True)
+
+ return network
+
+ @staticmethod
+ def create_networks(attrs=None, count=2):
+ """Create multiple fake networks.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of networks to fake
+ :return:
+ A list of FakeResource objects faking the networks
+ """
+ networks = []
+ for i in range(0, count):
+ networks.append(FakeNetwork.create_one_network(attrs))
+
+ return networks
+
+ @staticmethod
+ def get_networks(networks=None, count=2):
+ """Get an iterable MagicMock object with a list of faked networks.
+
+ If networks list is provided, then initialize the Mock object with the
+ list. Otherwise create one.
+
+ :param List networks:
+ A list of FakeResource objects faking networks
+ :param int count:
+ The number of networks to fake
+ :return:
+ An iterable Mock object with side_effect set to a list of faked
+ networks
+ """
+ if networks is None:
+ networks = FakeNetwork.create_networks(count=count)
+ return mock.Mock(side_effect=networks)
+
+
+class FakeHost(object):
+ """Fake one host."""
+
+ @staticmethod
+ def create_one_host(attrs=None):
+ """Create a fake host.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with uuid and other attributes
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ host_info = {
+ "service_id": 1,
+ "host": "host1",
+ "uuid": 'host-id-' + uuid.uuid4().hex,
+ "vcpus": 10,
+ "memory_mb": 100,
+ "local_gb": 100,
+ "vcpus_used": 5,
+ "memory_mb_used": 50,
+ "local_gb_used": 10,
+ "hypervisor_type": "xen",
+ "hypervisor_version": 1,
+ "hypervisor_hostname": "devstack1",
+ "free_ram_mb": 50,
+ "free_disk_gb": 50,
+ "current_workload": 10,
+ "running_vms": 1,
+ "cpu_info": "",
+ "disk_available_least": 1,
+ "host_ip": "10.10.10.10",
+ "supported_instances": "",
+ "metrics": "",
+ "pci_stats": "",
+ "extra_resources": "",
+ "stats": "",
+ "numa_topology": "",
+ "ram_allocation_ratio": 1.0,
+ "cpu_allocation_ratio": 1.0,
+ "zone": 'zone-' + uuid.uuid4().hex,
+ "host_name": 'name-' + uuid.uuid4().hex,
+ "service": 'service-' + uuid.uuid4().hex,
+ "cpu": 4,
+ "disk_gb": 100,
+ 'project': 'project-' + uuid.uuid4().hex,
+ }
+ host_info.update(attrs)
+ host = fakes.FakeResource(
+ info=copy.deepcopy(host_info),
+ loaded=True)
+ return host
+
+
+class FakeServerGroup(object):
+ """Fake one server group"""
+
+ @staticmethod
+ def create_one_server_group(attrs=None):
+ """Create a fake server group
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id and other attributes
+ """
+ if attrs is None:
+ attrs = {}
+
+ # Set default attributes.
+ server_group_info = {
+ 'id': 'server-group-id-' + uuid.uuid4().hex,
+ 'members': [],
+ 'metadata': {},
+ 'name': 'server-group-name-' + uuid.uuid4().hex,
+ 'policies': [],
+ 'project_id': 'server-group-project-id-' + uuid.uuid4().hex,
+ 'user_id': 'server-group-user-id-' + uuid.uuid4().hex,
+ }
+
+ # Overwrite default attributes.
+ server_group_info.update(attrs)
+
+ server_group = fakes.FakeResource(
+ info=copy.deepcopy(server_group_info),
+ loaded=True)
+ return server_group
diff --git a/openstackclient/tests/unit/compute/v2/test_agent.py b/openstackclient/tests/unit/compute/v2/test_agent.py
new file mode 100644
index 00000000..169940e2
--- /dev/null
+++ b/openstackclient/tests/unit/compute/v2/test_agent.py
@@ -0,0 +1,320 @@
+# Copyright 2016 Easystack. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+import mock
+from mock import call
+
+from osc_lib import exceptions
+
+from openstackclient.compute.v2 import agent
+from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
+from openstackclient.tests.unit import utils as tests_utils
+
+
+class TestAgent(compute_fakes.TestComputev2):
+
+ attr = {}
+ attr['agent_id'] = 1
+ fake_agent = compute_fakes.FakeAgent.create_one_agent(attr)
+
+ columns = (
+ 'agent_id',
+ 'architecture',
+ 'hypervisor',
+ 'md5hash',
+ 'os',
+ 'url',
+ 'version',
+ )
+
+ data = (
+ fake_agent.agent_id,
+ fake_agent.architecture,
+ fake_agent.hypervisor,
+ fake_agent.md5hash,
+ fake_agent.os,
+ fake_agent.url,
+ fake_agent.version,
+ )
+
+ def setUp(self):
+ super(TestAgent, self).setUp()
+
+ self.agents_mock = self.app.client_manager.compute.agents
+ self.agents_mock.reset_mock()
+
+
+class TestAgentCreate(TestAgent):
+
+ def setUp(self):
+ super(TestAgentCreate, self).setUp()
+
+ self.agents_mock.create.return_value = self.fake_agent
+ self.cmd = agent.CreateAgent(self.app, None)
+
+ def test_agent_create(self):
+ arglist = [
+ self.fake_agent.os,
+ self.fake_agent.architecture,
+ self.fake_agent.version,
+ self.fake_agent.url,
+ self.fake_agent.md5hash,
+ self.fake_agent.hypervisor,
+ ]
+
+ verifylist = [
+ ('os', self.fake_agent.os),
+ ('architecture', self.fake_agent.architecture),
+ ('version', self.fake_agent.version),
+ ('url', self.fake_agent.url),
+ ('md5hash', self.fake_agent.md5hash),
+ ('hypervisor', self.fake_agent.hypervisor),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+ self.agents_mock.create.assert_called_with(parsed_args.os,
+ parsed_args.architecture,
+ parsed_args.version,
+ parsed_args.url,
+ parsed_args.md5hash,
+ parsed_args.hypervisor)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestAgentDelete(TestAgent):
+
+ fake_agents = compute_fakes.FakeAgent.create_agents(count=2)
+
+ def setUp(self):
+ super(TestAgentDelete, self).setUp()
+
+ self.agents_mock.get.return_value = self.fake_agents
+ self.cmd = agent.DeleteAgent(self.app, None)
+
+ def test_delete_one_agent(self):
+ arglist = [
+ self.fake_agents[0].agent_id
+ ]
+
+ verifylist = [
+ ('id', [self.fake_agents[0].agent_id]),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.agents_mock.delete.assert_called_with(
+ self.fake_agents[0].agent_id)
+ self.assertIsNone(result)
+
+ def test_delete_multiple_agents(self):
+ arglist = []
+ for n in self.fake_agents:
+ arglist.append(n.agent_id)
+ verifylist = [
+ ('id', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for n in self.fake_agents:
+ calls.append(call(n.agent_id))
+ self.agents_mock.delete.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_delete_multiple_agents_exception(self):
+ arglist = [
+ self.fake_agents[0].agent_id,
+ self.fake_agents[1].agent_id,
+ 'x-y-z',
+ ]
+ verifylist = [
+ ('id', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ ret_delete = [
+ None,
+ None,
+ exceptions.NotFound('404')
+ ]
+ self.agents_mock.delete = mock.Mock(side_effect=ret_delete)
+
+ self.assertRaises(exceptions.CommandError, self.cmd.take_action,
+ parsed_args)
+ calls = [
+ call(self.fake_agents[0].agent_id),
+ call(self.fake_agents[1].agent_id),
+ ]
+ self.agents_mock.delete.assert_has_calls(calls)
+
+ def test_agent_delete_no_input(self):
+ arglist = []
+ verifylist = None
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser,
+ self.cmd,
+ arglist,
+ verifylist)
+
+
+class TestAgentList(TestAgent):
+
+ agents = compute_fakes.FakeAgent.create_agents(count=3)
+ list_columns = (
+ "Agent ID",
+ "Hypervisor",
+ "OS",
+ "Architecture",
+ "Version",
+ "Md5Hash",
+ "URL",
+ )
+
+ list_data = []
+ for _agent in agents:
+ list_data.append((
+ _agent.agent_id,
+ _agent.hypervisor,
+ _agent.os,
+ _agent.architecture,
+ _agent.version,
+ _agent.md5hash,
+ _agent.url,
+ ))
+
+ def setUp(self):
+
+ super(TestAgentList, self).setUp()
+
+ self.agents_mock.list.return_value = self.agents
+ self.cmd = agent.ListAgent(self.app, None)
+
+ def test_agent_list(self):
+
+ arglist = []
+ verifylist = []
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.list_columns, columns)
+ self.assertEqual(self.list_data, list(data))
+
+ def test_agent_list_with_hypervisor(self):
+
+ arglist = [
+ '--hypervisor',
+ 'hypervisor',
+ ]
+ verifylist = [
+ ('hypervisor', 'hypervisor'),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.list_columns, columns)
+ self.assertEqual(self.list_data, list(data))
+
+
+class TestAgentSet(TestAgent):
+
+ def setUp(self):
+ super(TestAgentSet, self).setUp()
+
+ self.agents_mock.update.return_value = self.fake_agent
+ self.agents_mock.list.return_value = [self.fake_agent]
+ self.cmd = agent.SetAgent(self.app, None)
+
+ def test_agent_set_nothing(self):
+ arglist = [
+ '1',
+ ]
+ verifylist = [
+ ('id', '1'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ self.agents_mock.update.assert_called_with(parsed_args.id,
+ self.fake_agent.version,
+ self.fake_agent.url,
+ self.fake_agent.md5hash)
+ self.assertIsNone(result)
+
+ def test_agent_set_version(self):
+ arglist = [
+ '1',
+ '--agent-version', 'new-version',
+ ]
+
+ verifylist = [
+ ('id', '1'),
+ ('version', 'new-version'),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ self.agents_mock.update.assert_called_with(parsed_args.id,
+ parsed_args.version,
+ self.fake_agent.url,
+ self.fake_agent.md5hash)
+ self.assertIsNone(result)
+
+ def test_agent_set_url(self):
+ arglist = [
+ '1',
+ '--url', 'new-url',
+ ]
+
+ verifylist = [
+ ('id', '1'),
+ ('url', 'new-url'),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ self.agents_mock.update.assert_called_with(parsed_args.id,
+ self.fake_agent.version,
+ parsed_args.url,
+ self.fake_agent.md5hash)
+ self.assertIsNone(result)
+
+ def test_agent_set_md5hash(self):
+ arglist = [
+ '1',
+ '--md5hash', 'new-md5hash',
+ ]
+
+ verifylist = [
+ ('id', '1'),
+ ('md5hash', 'new-md5hash'),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ self.agents_mock.update.assert_called_with(parsed_args.id,
+ self.fake_agent.version,
+ self.fake_agent.url,
+ parsed_args.md5hash)
+ self.assertIsNone(result)
diff --git a/openstackclient/tests/unit/compute/v2/test_aggregate.py b/openstackclient/tests/unit/compute/v2/test_aggregate.py
new file mode 100644
index 00000000..c636d3de
--- /dev/null
+++ b/openstackclient/tests/unit/compute/v2/test_aggregate.py
@@ -0,0 +1,447 @@
+# Copyright 2016 Huawei, Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+import mock
+from mock import call
+
+from osc_lib import exceptions
+from osc_lib import utils
+
+from openstackclient.compute.v2 import aggregate
+from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
+from openstackclient.tests.unit import utils as tests_utils
+
+
+class TestAggregate(compute_fakes.TestComputev2):
+
+ fake_ag = compute_fakes.FakeAggregate.create_one_aggregate()
+
+ columns = (
+ 'availability_zone',
+ 'hosts',
+ 'id',
+ 'metadata',
+ 'name',
+ )
+
+ data = (
+ fake_ag.availability_zone,
+ fake_ag.hosts,
+ fake_ag.id,
+ fake_ag.metadata,
+ fake_ag.name,
+ )
+
+ def setUp(self):
+ super(TestAggregate, self).setUp()
+
+ # Get a shortcut to the AggregateManager Mock
+ self.aggregate_mock = self.app.client_manager.compute.aggregates
+ self.aggregate_mock.reset_mock()
+
+
+class TestAggregateAddHost(TestAggregate):
+
+ def setUp(self):
+ super(TestAggregateAddHost, self).setUp()
+
+ self.aggregate_mock.get.return_value = self.fake_ag
+ self.aggregate_mock.add_host.return_value = self.fake_ag
+ self.cmd = aggregate.AddAggregateHost(self.app, None)
+
+ def test_aggregate_add_host(self):
+ arglist = [
+ 'ag1',
+ 'host1',
+ ]
+ verifylist = [
+ ('aggregate', 'ag1'),
+ ('host', 'host1'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+ self.aggregate_mock.get.assert_called_once_with(parsed_args.aggregate)
+ self.aggregate_mock.add_host.assert_called_once_with(self.fake_ag,
+ parsed_args.host)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestAggregateCreate(TestAggregate):
+
+ def setUp(self):
+ super(TestAggregateCreate, self).setUp()
+
+ self.aggregate_mock.create.return_value = self.fake_ag
+ self.aggregate_mock.set_metadata.return_value = self.fake_ag
+ self.cmd = aggregate.CreateAggregate(self.app, None)
+
+ def test_aggregate_create(self):
+ arglist = [
+ 'ag1',
+ ]
+ verifylist = [
+ ('name', 'ag1'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+ self.aggregate_mock.create.assert_called_once_with(parsed_args.name,
+ None)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_aggregate_create_with_zone(self):
+ arglist = [
+ '--zone', 'zone1',
+ 'ag1',
+ ]
+ verifylist = [
+ ('zone', 'zone1'),
+ ('name', 'ag1'),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+ self.aggregate_mock.create.assert_called_once_with(parsed_args.name,
+ parsed_args.zone)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_aggregate_create_with_property(self):
+ arglist = [
+ '--property', 'key1=value1',
+ '--property', 'key2=value2',
+ 'ag1',
+ ]
+ verifylist = [
+ ('property', {'key1': 'value1', 'key2': 'value2'}),
+ ('name', 'ag1'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+ self.aggregate_mock.create.assert_called_once_with(parsed_args.name,
+ None)
+ self.aggregate_mock.set_metadata.assert_called_once_with(
+ self.fake_ag, parsed_args.property)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestAggregateDelete(TestAggregate):
+
+ fake_ags = compute_fakes.FakeAggregate.create_aggregates(count=2)
+
+ def setUp(self):
+ super(TestAggregateDelete, self).setUp()
+
+ self.aggregate_mock.get = (
+ compute_fakes.FakeAggregate.get_aggregates(self.fake_ags))
+ self.cmd = aggregate.DeleteAggregate(self.app, None)
+
+ def test_aggregate_delete(self):
+ arglist = [
+ self.fake_ags[0].id
+ ]
+ verifylist = [
+ ('aggregate', [self.fake_ags[0].id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.aggregate_mock.get.assert_called_once_with(self.fake_ags[0].id)
+ self.aggregate_mock.delete.assert_called_once_with(self.fake_ags[0].id)
+ self.assertIsNone(result)
+
+ def test_delete_multiple_aggregates(self):
+ arglist = []
+ for a in self.fake_ags:
+ arglist.append(a.id)
+ verifylist = [
+ ('aggregate', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for a in self.fake_ags:
+ calls.append(call(a.id))
+ self.aggregate_mock.delete.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_delete_multiple_agggregates_with_exception(self):
+ arglist = [
+ self.fake_ags[0].id,
+ 'unexist_aggregate',
+ ]
+ verifylist = [
+ ('aggregate', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [self.fake_ags[0], exceptions.CommandError]
+ with mock.patch.object(utils, 'find_resource',
+ side_effect=find_mock_result) as find_mock:
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 aggregates failed to delete.',
+ str(e))
+
+ find_mock.assert_any_call(self.aggregate_mock, self.fake_ags[0].id)
+ find_mock.assert_any_call(self.aggregate_mock, 'unexist_aggregate')
+
+ self.assertEqual(2, find_mock.call_count)
+ self.aggregate_mock.delete.assert_called_once_with(
+ self.fake_ags[0].id
+ )
+
+
+class TestAggregateList(TestAggregate):
+
+ list_columns = (
+ "ID",
+ "Name",
+ "Availability Zone",
+ )
+
+ list_columns_long = (
+ "ID",
+ "Name",
+ "Availability Zone",
+ "Properties",
+ )
+
+ list_data = ((
+ TestAggregate.fake_ag.id,
+ TestAggregate.fake_ag.name,
+ TestAggregate.fake_ag.availability_zone,
+ ), )
+
+ list_data_long = ((
+ TestAggregate.fake_ag.id,
+ TestAggregate.fake_ag.name,
+ TestAggregate.fake_ag.availability_zone,
+ {},
+ ), )
+
+ def setUp(self):
+ super(TestAggregateList, self).setUp()
+
+ self.aggregate_mock.list.return_value = [self.fake_ag]
+ self.cmd = aggregate.ListAggregate(self.app, None)
+
+ def test_aggregate_list(self):
+
+ parsed_args = self.check_parser(self.cmd, [], [])
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.list_columns, columns)
+ self.assertEqual(self.list_data, tuple(data))
+
+ def test_aggregate_list_with_long(self):
+ arglist = [
+ '--long',
+ ]
+ vertifylist = [
+ ('long', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, vertifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.list_columns_long, columns)
+ self.assertEqual(self.list_data_long, tuple(data))
+
+
+class TestAggregateRemoveHost(TestAggregate):
+
+ def setUp(self):
+ super(TestAggregateRemoveHost, self).setUp()
+
+ self.aggregate_mock.get.return_value = self.fake_ag
+ self.aggregate_mock.remove_host.return_value = self.fake_ag
+ self.cmd = aggregate.RemoveAggregateHost(self.app, None)
+
+ def test_aggregate_add_host(self):
+ arglist = [
+ 'ag1',
+ 'host1',
+ ]
+ verifylist = [
+ ('aggregate', 'ag1'),
+ ('host', 'host1'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+ self.aggregate_mock.get.assert_called_once_with(parsed_args.aggregate)
+ self.aggregate_mock.remove_host.assert_called_once_with(
+ self.fake_ag, parsed_args.host)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestAggregateSet(TestAggregate):
+
+ def setUp(self):
+ super(TestAggregateSet, self).setUp()
+
+ self.aggregate_mock.get.return_value = self.fake_ag
+ self.cmd = aggregate.SetAggregate(self.app, None)
+
+ def test_aggregate_set_no_option(self):
+ arglist = [
+ 'ag1',
+ ]
+ verifylist = [
+ ('aggregate', 'ag1'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ self.aggregate_mock.get.assert_called_once_with(parsed_args.aggregate)
+ self.assertNotCalled(self.aggregate_mock.update)
+ self.assertNotCalled(self.aggregate_mock.set_metadata)
+ self.assertIsNone(result)
+
+ def test_aggregate_set_with_name(self):
+ arglist = [
+ '--name', 'new_name',
+ 'ag1',
+ ]
+ verifylist = [
+ ('name', 'new_name'),
+ ('aggregate', 'ag1'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ self.aggregate_mock.get.assert_called_once_with(parsed_args.aggregate)
+ self.aggregate_mock.update.assert_called_once_with(
+ self.fake_ag, {'name': parsed_args.name})
+ self.assertNotCalled(self.aggregate_mock.set_metadata)
+ self.assertIsNone(result)
+
+ def test_aggregate_set_with_zone(self):
+ arglist = [
+ '--zone', 'new_zone',
+ 'ag1',
+ ]
+ verifylist = [
+ ('zone', 'new_zone'),
+ ('aggregate', 'ag1'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ self.aggregate_mock.get.assert_called_once_with(parsed_args.aggregate)
+ self.aggregate_mock.update.assert_called_once_with(
+ self.fake_ag, {'availability_zone': parsed_args.zone})
+ self.assertNotCalled(self.aggregate_mock.set_metadata)
+ self.assertIsNone(result)
+
+ def test_aggregate_set_with_property(self):
+ arglist = [
+ '--property', 'key1=value1',
+ '--property', 'key2=value2',
+ 'ag1',
+ ]
+ verifylist = [
+ ('property', {'key1': 'value1', 'key2': 'value2'}),
+ ('aggregate', 'ag1'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ self.aggregate_mock.get.assert_called_once_with(parsed_args.aggregate)
+ self.assertNotCalled(self.aggregate_mock.update)
+ self.aggregate_mock.set_metadata.assert_called_once_with(
+ self.fake_ag, parsed_args.property)
+ self.assertIsNone(result)
+
+
+class TestAggregateShow(TestAggregate):
+
+ columns = (
+ 'availability_zone',
+ 'hosts',
+ 'id',
+ 'name',
+ 'properties',
+ )
+
+ data = (
+ TestAggregate.fake_ag.availability_zone,
+ TestAggregate.fake_ag.hosts,
+ TestAggregate.fake_ag.id,
+ TestAggregate.fake_ag.name,
+ '',
+ )
+
+ def setUp(self):
+ super(TestAggregateShow, self).setUp()
+
+ self.aggregate_mock.get.return_value = self.fake_ag
+ self.cmd = aggregate.ShowAggregate(self.app, None)
+
+ def test_aggregate_show(self):
+ arglist = [
+ 'ag1',
+ ]
+ verifylist = [
+ ('aggregate', 'ag1'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+ self.aggregate_mock.get.assert_called_once_with(parsed_args.aggregate)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestAggregateUnset(TestAggregate):
+
+ def setUp(self):
+ super(TestAggregateUnset, self).setUp()
+
+ self.aggregate_mock.get.return_value = self.fake_ag
+ self.cmd = aggregate.UnsetAggregate(self.app, None)
+
+ def test_aggregate_unset(self):
+ arglist = [
+ '--property', 'unset_key',
+ 'ag1',
+ ]
+ verifylist = [
+ ('property', ['unset_key']),
+ ('aggregate', 'ag1'),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.aggregate_mock.set_metadata.assert_called_once_with(
+ self.fake_ag, {'unset_key': None})
+ self.assertIsNone(result)
+
+ def test_aggregate_unset_no_property(self):
+ arglist = [
+ 'ag1',
+ ]
+ verifylist = None
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser,
+ self.cmd,
+ arglist,
+ verifylist)
diff --git a/openstackclient/tests/unit/compute/v2/test_console.py b/openstackclient/tests/unit/compute/v2/test_console.py
new file mode 100644
index 00000000..d53d241e
--- /dev/null
+++ b/openstackclient/tests/unit/compute/v2/test_console.py
@@ -0,0 +1,196 @@
+# Copyright 2016 Huawei, Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+import mock
+
+from openstackclient.compute.v2 import console
+from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
+
+
+class TestConsole(compute_fakes.TestComputev2):
+
+ def setUp(self):
+ super(TestConsole, self).setUp()
+ self.servers_mock = self.app.client_manager.compute.servers
+ self.servers_mock.reset_mock()
+
+
+class TestConsoleUrlShow(TestConsole):
+
+ def setUp(self):
+ super(TestConsoleUrlShow, self).setUp()
+ fake_console_data = {'remote_console': {'url': 'http://localhost',
+ 'protocol': 'fake_protocol',
+ 'type': 'fake_type'}}
+ methods = {
+ 'get_vnc_console': fake_console_data,
+ 'get_spice_console': fake_console_data,
+ 'get_serial_console': fake_console_data,
+ 'get_rdp_console': fake_console_data,
+ 'get_mks_console': fake_console_data,
+ }
+ self.fake_server = compute_fakes.FakeServer.create_one_server(
+ methods=methods)
+ self.servers_mock.get.return_value = self.fake_server
+
+ self.columns = (
+ 'protocol',
+ 'type',
+ 'url',
+ )
+ self.data = (
+ fake_console_data['remote_console']['protocol'],
+ fake_console_data['remote_console']['type'],
+ fake_console_data['remote_console']['url']
+ )
+
+ self.cmd = console.ShowConsoleURL(self.app, None)
+
+ def test_console_url_show_by_default(self):
+ arglist = [
+ 'foo_vm',
+ ]
+ verifylist = [
+ ('url_type', 'novnc'),
+ ('server', 'foo_vm'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+ self.fake_server.get_vnc_console.assert_called_once_with('novnc')
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_console_url_show_with_novnc(self):
+ arglist = [
+ '--novnc',
+ 'foo_vm',
+ ]
+ verifylist = [
+ ('url_type', 'novnc'),
+ ('server', 'foo_vm'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+ self.fake_server.get_vnc_console.assert_called_once_with('novnc')
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_console_url_show_with_xvpvnc(self):
+ arglist = [
+ '--xvpvnc',
+ 'foo_vm',
+ ]
+ verifylist = [
+ ('url_type', 'xvpvnc'),
+ ('server', 'foo_vm'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+ self.fake_server.get_vnc_console.assert_called_once_with('xvpvnc')
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_console_url_show_with_spice(self):
+ arglist = [
+ '--spice',
+ 'foo_vm',
+ ]
+ verifylist = [
+ ('url_type', 'spice-html5'),
+ ('server', 'foo_vm'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+ self.fake_server.get_spice_console.assert_called_once_with(
+ 'spice-html5')
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_console_url_show_compatible(self):
+ methods = {
+ 'get_vnc_console': {'console': {'url': 'http://localhost',
+ 'type': 'fake_type'}},
+ }
+ old_fake_server = compute_fakes.FakeServer.create_one_server(
+ methods=methods)
+ old_columns = (
+ 'type',
+ 'url',
+ )
+ old_data = (
+ methods['get_vnc_console']['console']['type'],
+ methods['get_vnc_console']['console']['url']
+ )
+ arglist = [
+ 'foo_vm',
+ ]
+ verifylist = [
+ ('url_type', 'novnc'),
+ ('server', 'foo_vm'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ with mock.patch.object(self.servers_mock, 'get',
+ return_value=old_fake_server):
+ columns, data = self.cmd.take_action(parsed_args)
+ old_fake_server.get_vnc_console.assert_called_once_with('novnc')
+ self.assertEqual(old_columns, columns)
+ self.assertEqual(old_data, data)
+
+ def test_console_url_show_with_rdp(self):
+ arglist = [
+ '--rdp',
+ 'foo_vm',
+ ]
+ verifylist = [
+ ('url_type', 'rdp-html5'),
+ ('server', 'foo_vm'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+ self.fake_server.get_rdp_console.assert_called_once_with(
+ 'rdp-html5')
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_console_url_show_with_serial(self):
+ arglist = [
+ '--serial',
+ 'foo_vm',
+ ]
+ verifylist = [
+ ('url_type', 'serial'),
+ ('server', 'foo_vm'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+ self.fake_server.get_serial_console.assert_called_once_with(
+ 'serial')
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_console_url_show_with_mks(self):
+ arglist = [
+ '--mks',
+ 'foo_vm',
+ ]
+ verifylist = [
+ ('url_type', 'webmks'),
+ ('server', 'foo_vm'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+ self.fake_server.get_mks_console.assert_called_once_with()
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
diff --git a/openstackclient/tests/unit/compute/v2/test_flavor.py b/openstackclient/tests/unit/compute/v2/test_flavor.py
new file mode 100644
index 00000000..ace650eb
--- /dev/null
+++ b/openstackclient/tests/unit/compute/v2/test_flavor.py
@@ -0,0 +1,825 @@
+# Copyright 2015 Symantec Corporation
+#
+# 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.
+#
+
+import mock
+from mock import call
+
+from osc_lib import exceptions
+from osc_lib import utils
+
+from openstackclient.compute.v2 import flavor
+from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+from openstackclient.tests.unit import utils as tests_utils
+
+
+class TestFlavor(compute_fakes.TestComputev2):
+
+ def setUp(self):
+ super(TestFlavor, self).setUp()
+
+ # Get a shortcut to the FlavorManager Mock
+ self.flavors_mock = self.app.client_manager.compute.flavors
+ self.flavors_mock.reset_mock()
+
+ # Get a shortcut to the FlavorAccessManager Mock
+ self.flavor_access_mock = self.app.client_manager.compute.flavor_access
+ self.flavor_access_mock.reset_mock()
+
+ self.projects_mock = self.app.client_manager.identity.projects
+ self.projects_mock.reset_mock()
+
+
+class TestFlavorCreate(TestFlavor):
+
+ flavor = compute_fakes.FakeFlavor.create_one_flavor(
+ attrs={'links': 'flavor-links'})
+ project = identity_fakes.FakeProject.create_one_project()
+ columns = (
+ 'OS-FLV-DISABLED:disabled',
+ 'OS-FLV-EXT-DATA:ephemeral',
+ 'disk',
+ 'id',
+ 'name',
+ 'os-flavor-access:is_public',
+ 'properties',
+ 'ram',
+ 'rxtx_factor',
+ 'swap',
+ 'vcpus',
+ )
+ data = (
+ flavor.disabled,
+ flavor.ephemeral,
+ flavor.disk,
+ flavor.id,
+ flavor.name,
+ flavor.is_public,
+ utils.format_dict(flavor.properties),
+ flavor.ram,
+ flavor.rxtx_factor,
+ flavor.swap,
+ flavor.vcpus,
+ )
+
+ def setUp(self):
+ super(TestFlavorCreate, self).setUp()
+
+ # Return a project
+ self.projects_mock.get.return_value = self.project
+ self.flavors_mock.create.return_value = self.flavor
+ self.cmd = flavor.CreateFlavor(self.app, None)
+
+ def test_flavor_create_default_options(self):
+
+ arglist = [
+ self.flavor.name
+ ]
+ verifylist = [
+ ('name', self.flavor.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ default_args = (
+ self.flavor.name,
+ 256,
+ 1,
+ 0,
+ 'auto',
+ 0,
+ 0,
+ 1.0,
+ True
+ )
+ columns, data = self.cmd.take_action(parsed_args)
+ self.flavors_mock.create.assert_called_once_with(*default_args)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_flavor_create_all_options(self):
+
+ arglist = [
+ '--id', self.flavor.id,
+ '--ram', str(self.flavor.ram),
+ '--disk', str(self.flavor.disk),
+ '--ephemeral', str(self.flavor.ephemeral),
+ '--swap', str(self.flavor.swap),
+ '--vcpus', str(self.flavor.vcpus),
+ '--rxtx-factor', str(self.flavor.rxtx_factor),
+ '--public',
+ '--property', 'property=value',
+ self.flavor.name,
+ ]
+ verifylist = [
+ ('id', self.flavor.id),
+ ('ram', self.flavor.ram),
+ ('disk', self.flavor.disk),
+ ('ephemeral', self.flavor.ephemeral),
+ ('swap', self.flavor.swap),
+ ('vcpus', self.flavor.vcpus),
+ ('rxtx_factor', self.flavor.rxtx_factor),
+ ('public', True),
+ ('property', {'property': 'value'}),
+ ('name', self.flavor.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ args = (
+ self.flavor.name,
+ self.flavor.ram,
+ self.flavor.vcpus,
+ self.flavor.disk,
+ self.flavor.id,
+ self.flavor.ephemeral,
+ self.flavor.swap,
+ self.flavor.rxtx_factor,
+ self.flavor.is_public,
+ )
+ columns, data = self.cmd.take_action(parsed_args)
+ self.flavors_mock.create.assert_called_once_with(*args)
+ self.flavor.set_keys.assert_called_once_with({'property': 'value'})
+ self.flavor.get_keys.assert_called_once_with()
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_flavor_create_other_options(self):
+
+ self.flavor.is_public = False
+ arglist = [
+ '--id', self.flavor.id,
+ '--ram', str(self.flavor.ram),
+ '--disk', str(self.flavor.disk),
+ '--ephemeral', str(self.flavor.ephemeral),
+ '--swap', str(self.flavor.swap),
+ '--vcpus', str(self.flavor.vcpus),
+ '--rxtx-factor', str(self.flavor.rxtx_factor),
+ '--private',
+ '--project', self.project.id,
+ '--property', 'key1=value1',
+ '--property', 'key2=value2',
+ self.flavor.name,
+ ]
+ verifylist = [
+ ('id', self.flavor.id),
+ ('ram', self.flavor.ram),
+ ('disk', self.flavor.disk),
+ ('ephemeral', self.flavor.ephemeral),
+ ('swap', self.flavor.swap),
+ ('vcpus', self.flavor.vcpus),
+ ('rxtx_factor', self.flavor.rxtx_factor),
+ ('public', False),
+ ('project', self.project.id),
+ ('property', {'key1': 'value1', 'key2': 'value2'}),
+ ('name', self.flavor.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ args = (
+ self.flavor.name,
+ self.flavor.ram,
+ self.flavor.vcpus,
+ self.flavor.disk,
+ self.flavor.id,
+ self.flavor.ephemeral,
+ self.flavor.swap,
+ self.flavor.rxtx_factor,
+ self.flavor.is_public,
+ )
+ columns, data = self.cmd.take_action(parsed_args)
+ self.flavors_mock.create.assert_called_once_with(*args)
+ self.flavor_access_mock.add_tenant_access.assert_called_with(
+ self.flavor.id,
+ self.project.id,
+ )
+ self.flavor.set_keys.assert_called_with(
+ {'key1': 'value1', 'key2': 'value2'})
+ self.flavor.get_keys.assert_called_with()
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_public_flavor_create_with_project(self):
+ arglist = [
+ '--project', self.project.id,
+ self.flavor.name,
+ ]
+ verifylist = [
+ ('project', self.project.id),
+ ('name', self.flavor.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
+
+ def test_flavor_create_no_options(self):
+ arglist = []
+ verifylist = None
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser,
+ self.cmd,
+ arglist,
+ verifylist)
+
+
+class TestFlavorDelete(TestFlavor):
+
+ flavors = compute_fakes.FakeFlavor.create_flavors(count=2)
+
+ def setUp(self):
+ super(TestFlavorDelete, self).setUp()
+
+ self.flavors_mock.get = (
+ compute_fakes.FakeFlavor.get_flavors(self.flavors))
+ self.flavors_mock.delete.return_value = None
+
+ self.cmd = flavor.DeleteFlavor(self.app, None)
+
+ def test_flavor_delete(self):
+ arglist = [
+ self.flavors[0].id
+ ]
+ verifylist = [
+ ('flavor', [self.flavors[0].id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.flavors_mock.delete.assert_called_with(self.flavors[0].id)
+ self.assertIsNone(result)
+
+ def test_delete_multiple_flavors(self):
+ arglist = []
+ for f in self.flavors:
+ arglist.append(f.id)
+ verifylist = [
+ ('flavor', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for f in self.flavors:
+ calls.append(call(f.id))
+ self.flavors_mock.delete.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_multi_flavors_delete_with_exception(self):
+ arglist = [
+ self.flavors[0].id,
+ 'unexist_flavor',
+ ]
+ verifylist = [
+ ('flavor', [self.flavors[0].id, 'unexist_flavor'])
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [self.flavors[0], exceptions.CommandError]
+ self.flavors_mock.get = (
+ mock.MagicMock(side_effect=find_mock_result)
+ )
+ self.flavors_mock.find.side_effect = exceptions.NotFound(None)
+
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 flavors failed to delete.', str(e))
+
+ self.flavors_mock.get.assert_any_call(self.flavors[0].id)
+ self.flavors_mock.get.assert_any_call('unexist_flavor')
+ self.flavors_mock.delete.assert_called_once_with(self.flavors[0].id)
+
+
+class TestFlavorList(TestFlavor):
+
+ # Return value of self.flavors_mock.list().
+ flavors = compute_fakes.FakeFlavor.create_flavors(count=1)
+
+ columns = (
+ 'ID',
+ 'Name',
+ 'RAM',
+ 'Disk',
+ 'Ephemeral',
+ 'VCPUs',
+ 'Is Public',
+ )
+ columns_long = columns + (
+ 'Swap',
+ 'RXTX Factor',
+ 'Properties'
+ )
+
+ data = ((
+ flavors[0].id,
+ flavors[0].name,
+ flavors[0].ram,
+ flavors[0].disk,
+ flavors[0].ephemeral,
+ flavors[0].vcpus,
+ flavors[0].is_public,
+ ), )
+ data_long = (data[0] + (
+ flavors[0].swap,
+ flavors[0].rxtx_factor,
+ u'property=\'value\''
+ ), )
+
+ def setUp(self):
+ super(TestFlavorList, self).setUp()
+
+ self.flavors_mock.list.return_value = self.flavors
+
+ # Get the command object to test
+ self.cmd = flavor.ListFlavor(self.app, None)
+
+ def test_flavor_list_no_options(self):
+ arglist = []
+ verifylist = [
+ ('public', True),
+ ('all', False),
+ ('long', False),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'is_public': True,
+ 'limit': None,
+ 'marker': None
+ }
+
+ self.flavors_mock.list.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(tuple(self.data), tuple(data))
+
+ def test_flavor_list_all_flavors(self):
+ arglist = [
+ '--all',
+ ]
+ verifylist = [
+ ('all', True),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'is_public': None,
+ 'limit': None,
+ 'marker': None
+ }
+
+ self.flavors_mock.list.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(tuple(self.data), tuple(data))
+
+ def test_flavor_list_private_flavors(self):
+ arglist = [
+ '--private',
+ ]
+ verifylist = [
+ ('public', False),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'is_public': False,
+ 'limit': None,
+ 'marker': None
+ }
+
+ self.flavors_mock.list.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(tuple(self.data), tuple(data))
+
+ def test_flavor_list_public_flavors(self):
+ arglist = [
+ '--public',
+ ]
+ verifylist = [
+ ('public', True),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'is_public': True,
+ 'limit': None,
+ 'marker': None
+ }
+
+ self.flavors_mock.list.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(tuple(self.data), tuple(data))
+
+ def test_flavor_list_long(self):
+ arglist = [
+ '--long',
+ ]
+ verifylist = [
+ ('long', True),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'is_public': True,
+ 'limit': None,
+ 'marker': None
+ }
+
+ self.flavors_mock.list.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns_long, columns)
+ self.assertEqual(tuple(self.data_long), tuple(data))
+
+
+class TestFlavorSet(TestFlavor):
+
+ # Return value of self.flavors_mock.find().
+ flavor = compute_fakes.FakeFlavor.create_one_flavor(
+ attrs={'os-flavor-access:is_public': False})
+ project = identity_fakes.FakeProject.create_one_project()
+
+ def setUp(self):
+ super(TestFlavorSet, self).setUp()
+
+ self.flavors_mock.find.return_value = self.flavor
+ self.flavors_mock.get.side_effect = exceptions.NotFound(None)
+ # Return a project
+ self.projects_mock.get.return_value = self.project
+ self.cmd = flavor.SetFlavor(self.app, None)
+
+ def test_flavor_set_property(self):
+ arglist = [
+ '--property', 'FOO="B A R"',
+ 'baremetal'
+ ]
+ verifylist = [
+ ('property', {'FOO': '"B A R"'}),
+ ('flavor', 'baremetal')
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.flavors_mock.find.assert_called_with(name=parsed_args.flavor,
+ is_public=None)
+ self.flavor.set_keys.assert_called_with({'FOO': '"B A R"'})
+ self.assertIsNone(result)
+
+ def test_flavor_set_project(self):
+ arglist = [
+ '--project', self.project.id,
+ self.flavor.id,
+ ]
+ verifylist = [
+ ('project', self.project.id),
+ ('flavor', self.flavor.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.flavors_mock.find.assert_called_with(name=parsed_args.flavor,
+ is_public=None)
+ self.flavor_access_mock.add_tenant_access.assert_called_with(
+ self.flavor.id,
+ self.project.id,
+ )
+ self.flavor.set_keys.assert_not_called()
+ self.assertIsNone(result)
+
+ def test_flavor_set_no_project(self):
+ arglist = [
+ '--project',
+ self.flavor.id,
+ ]
+ verifylist = [
+ ('project', None),
+ ('flavor', self.flavor.id),
+ ]
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_flavor_set_no_flavor(self):
+ arglist = [
+ '--project', self.project.id,
+ ]
+ verifylist = [
+ ('project', self.project.id),
+ ]
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_flavor_set_with_unexist_flavor(self):
+ self.flavors_mock.get.side_effect = exceptions.NotFound(None)
+ self.flavors_mock.find.side_effect = exceptions.NotFound(None)
+
+ arglist = [
+ '--project', self.project.id,
+ 'unexist_flavor',
+ ]
+ verifylist = [
+ ('project', self.project.id),
+ ('flavor', 'unexist_flavor'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
+
+ def test_flavor_set_nothing(self):
+ arglist = [
+ self.flavor.id,
+ ]
+ verifylist = [
+ ('flavor', self.flavor.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ self.flavors_mock.find.assert_called_with(name=parsed_args.flavor,
+ is_public=None)
+ self.flavor_access_mock.add_tenant_access.assert_not_called()
+ self.assertIsNone(result)
+
+
+class TestFlavorShow(TestFlavor):
+
+ # Return value of self.flavors_mock.find().
+ flavor_access = compute_fakes.FakeFlavorAccess.create_one_flavor_access()
+ flavor = compute_fakes.FakeFlavor.create_one_flavor()
+
+ columns = (
+ 'OS-FLV-DISABLED:disabled',
+ 'OS-FLV-EXT-DATA:ephemeral',
+ 'access_project_ids',
+ 'disk',
+ 'id',
+ 'name',
+ 'os-flavor-access:is_public',
+ 'properties',
+ 'ram',
+ 'rxtx_factor',
+ 'swap',
+ 'vcpus',
+ )
+
+ data = (
+ flavor.disabled,
+ flavor.ephemeral,
+ None,
+ flavor.disk,
+ flavor.id,
+ flavor.name,
+ flavor.is_public,
+ utils.format_dict(flavor.get_keys()),
+ flavor.ram,
+ flavor.rxtx_factor,
+ flavor.swap,
+ flavor.vcpus,
+ )
+
+ def setUp(self):
+ super(TestFlavorShow, self).setUp()
+
+ # Return value of _find_resource()
+ self.flavors_mock.find.return_value = self.flavor
+ self.flavors_mock.get.side_effect = exceptions.NotFound(None)
+ self.flavor_access_mock.list.return_value = [self.flavor_access]
+ self.cmd = flavor.ShowFlavor(self.app, None)
+
+ def test_show_no_options(self):
+ arglist = []
+ verifylist = []
+
+ # Missing required args should boil here
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_public_flavor_show(self):
+ arglist = [
+ self.flavor.name,
+ ]
+ verifylist = [
+ ('flavor', self.flavor.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_private_flavor_show(self):
+ private_flavor = compute_fakes.FakeFlavor.create_one_flavor(
+ attrs={
+ 'os-flavor-access:is_public': False,
+ }
+ )
+ self.flavors_mock.find.return_value = private_flavor
+
+ arglist = [
+ private_flavor.name,
+ ]
+ verifylist = [
+ ('flavor', private_flavor.name),
+ ]
+
+ data_with_project = (
+ private_flavor.disabled,
+ private_flavor.ephemeral,
+ self.flavor_access.tenant_id,
+ private_flavor.disk,
+ private_flavor.id,
+ private_flavor.name,
+ private_flavor.is_public,
+ utils.format_dict(private_flavor.get_keys()),
+ private_flavor.ram,
+ private_flavor.rxtx_factor,
+ private_flavor.swap,
+ private_flavor.vcpus,
+ )
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.flavor_access_mock.list.assert_called_with(
+ flavor=private_flavor.id)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(data_with_project, data)
+
+
+class TestFlavorUnset(TestFlavor):
+
+ # Return value of self.flavors_mock.find().
+ flavor = compute_fakes.FakeFlavor.create_one_flavor(
+ attrs={'os-flavor-access:is_public': False})
+ project = identity_fakes.FakeProject.create_one_project()
+
+ def setUp(self):
+ super(TestFlavorUnset, self).setUp()
+
+ self.flavors_mock.find.return_value = self.flavor
+ self.flavors_mock.get.side_effect = exceptions.NotFound(None)
+ # Return a project
+ self.projects_mock.get.return_value = self.project
+ self.cmd = flavor.UnsetFlavor(self.app, None)
+
+ def test_flavor_unset_property(self):
+ arglist = [
+ '--property', 'property',
+ 'baremetal'
+ ]
+ verifylist = [
+ ('property', ['property']),
+ ('flavor', 'baremetal'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.flavors_mock.find.assert_called_with(name=parsed_args.flavor,
+ is_public=None)
+ self.flavor.unset_keys.assert_called_with(['property'])
+ self.flavor_access_mock.remove_tenant_access.assert_not_called()
+ self.assertIsNone(result)
+
+ def test_flavor_unset_project(self):
+ arglist = [
+ '--project', self.project.id,
+ self.flavor.id,
+ ]
+ verifylist = [
+ ('project', self.project.id),
+ ('flavor', self.flavor.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.assertIsNone(result)
+
+ self.flavors_mock.find.assert_called_with(name=parsed_args.flavor,
+ is_public=None)
+ self.flavor_access_mock.remove_tenant_access.assert_called_with(
+ self.flavor.id,
+ self.project.id,
+ )
+ self.flavor.unset_keys.assert_not_called()
+ self.assertIsNone(result)
+
+ def test_flavor_unset_no_project(self):
+ arglist = [
+ '--project',
+ self.flavor.id,
+ ]
+ verifylist = [
+ ('project', None),
+ ('flavor', self.flavor.id),
+ ]
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_flavor_unset_no_flavor(self):
+ arglist = [
+ '--project', self.project.id,
+ ]
+ verifylist = [
+ ('project', self.project.id),
+ ]
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_flavor_unset_with_unexist_flavor(self):
+ self.flavors_mock.get.side_effect = exceptions.NotFound(None)
+ self.flavors_mock.find.side_effect = exceptions.NotFound(None)
+
+ arglist = [
+ '--project', self.project.id,
+ 'unexist_flavor',
+ ]
+ verifylist = [
+ ('project', self.project.id),
+ ('flavor', 'unexist_flavor'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.assertRaises(exceptions.CommandError, self.cmd.take_action,
+ parsed_args)
+
+ def test_flavor_unset_nothing(self):
+ arglist = [
+ self.flavor.id,
+ ]
+ verifylist = [
+ ('flavor', self.flavor.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.assertIsNone(result)
+
+ self.flavor_access_mock.remove_tenant_access.assert_not_called()
diff --git a/openstackclient/tests/unit/compute/v2/test_host.py b/openstackclient/tests/unit/compute/v2/test_host.py
new file mode 100644
index 00000000..a388172f
--- /dev/null
+++ b/openstackclient/tests/unit/compute/v2/test_host.py
@@ -0,0 +1,179 @@
+# Copyright 2016 IBM Corporation
+#
+# 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 openstackclient.compute.v2 import host
+from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
+from openstackclient.tests.unit import utils as tests_utils
+
+
+class TestHost(compute_fakes.TestComputev2):
+
+ def setUp(self):
+ super(TestHost, self).setUp()
+
+ # Get a shortcut to the FlavorManager Mock
+ self.host_mock = self.app.client_manager.compute.hosts
+ self.host_mock.reset_mock()
+
+
+class TestHostList(TestHost):
+
+ host = compute_fakes.FakeHost.create_one_host()
+
+ columns = (
+ 'Host Name',
+ 'Service',
+ 'Zone',
+ )
+
+ data = [(
+ host.host_name,
+ host.service,
+ host.zone,
+ )]
+
+ def setUp(self):
+ super(TestHostList, self).setUp()
+
+ self.host_mock.list_all.return_value = [self.host]
+
+ self.cmd = host.ListHost(self.app, None)
+
+ def test_host_list_no_option(self):
+ arglist = []
+ verifylist = []
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.host_mock.list_all.assert_called_with(None)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_host_list_with_option(self):
+ arglist = [
+ '--zone', self.host.zone,
+ ]
+ verifylist = [
+ ('zone', self.host.zone),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.host_mock.list_all.assert_called_with(self.host.zone)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+
+class TestHostSet(TestHost):
+
+ def setUp(self):
+ super(TestHostSet, self).setUp()
+
+ self.host = compute_fakes.FakeHost.create_one_host()
+ self.host_mock.get.return_value = self.host
+ self.host_mock.update.return_value = None
+
+ self.cmd = host.SetHost(self.app, None)
+
+ def test_host_set_no_option(self):
+ arglist = [
+ self.host.host
+ ]
+ verifylist = [
+ ('host', self.host.host)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.assertIsNone(result)
+
+ body = {}
+ self.host_mock.update.assert_called_with(self.host.host, body)
+
+ def test_host_set(self):
+ arglist = [
+ '--enable',
+ '--disable-maintenance',
+ self.host.host
+ ]
+ verifylist = [
+ ('enable', True),
+ ('enable_maintenance', False),
+ ('host', self.host.host)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.assertIsNone(result)
+
+ body = {'status': 'enable', 'maintenance_mode': 'disable'}
+ self.host_mock.update.assert_called_with(self.host.host, body)
+
+
+class TestHostShow(TestHost):
+
+ host = compute_fakes.FakeHost.create_one_host()
+
+ columns = (
+ 'Host',
+ 'Project',
+ 'CPU',
+ 'Memory MB',
+ 'Disk GB',
+ )
+ data = [(
+ host.host,
+ host.project,
+ host.cpu,
+ host.memory_mb,
+ host.disk_gb,
+ )]
+
+ def setUp(self):
+ super(TestHostShow, self).setUp()
+
+ self.host_mock.get.return_value = [self.host]
+
+ self.cmd = host.ShowHost(self.app, None)
+
+ def test_host_show_no_option(self):
+ arglist = []
+ verifylist = []
+
+ # Missing required args should bail here
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_host_show_with_option(self):
+ arglist = [
+ self.host.host_name,
+ ]
+ verifylist = [
+ ('host', self.host.host_name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.host_mock.get.assert_called_with(self.host.host_name)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
diff --git a/openstackclient/tests/unit/compute/v2/test_hypervisor.py b/openstackclient/tests/unit/compute/v2/test_hypervisor.py
new file mode 100644
index 00000000..d94a107c
--- /dev/null
+++ b/openstackclient/tests/unit/compute/v2/test_hypervisor.py
@@ -0,0 +1,221 @@
+# Copyright 2016 EasyStack Corporation
+#
+# 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.
+#
+
+import copy
+
+from osc_lib import exceptions
+
+from openstackclient.compute.v2 import hypervisor
+from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
+from openstackclient.tests.unit import fakes
+
+
+class TestHypervisor(compute_fakes.TestComputev2):
+
+ def setUp(self):
+ super(TestHypervisor, self).setUp()
+
+ # Get a shortcut to the compute client hypervisors mock
+ self.hypervisors_mock = self.app.client_manager.compute.hypervisors
+ self.hypervisors_mock.reset_mock()
+
+ # Get a shortcut to the compute client aggregates mock
+ self.aggregates_mock = self.app.client_manager.compute.aggregates
+ self.aggregates_mock.reset_mock()
+
+
+class TestHypervisorList(TestHypervisor):
+
+ def setUp(self):
+ super(TestHypervisorList, self).setUp()
+
+ # Fake hypervisors to be listed up
+ self.hypervisors = compute_fakes.FakeHypervisor.create_hypervisors()
+ self.hypervisors_mock.list.return_value = self.hypervisors
+
+ self.columns = (
+ "ID",
+ "Hypervisor Hostname"
+ )
+ self.data = (
+ (
+ self.hypervisors[0].id,
+ self.hypervisors[0].hypervisor_hostname,
+ ),
+ (
+ self.hypervisors[1].id,
+ self.hypervisors[1].hypervisor_hostname,
+ ),
+ )
+
+ # Get the command object to test
+ self.cmd = hypervisor.ListHypervisor(self.app, None)
+
+ def test_hypervisor_list_no_option(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.hypervisors_mock.list.assert_called_with()
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, tuple(data))
+
+ def test_hypervisor_list_matching_option_found(self):
+ arglist = [
+ '--matching', self.hypervisors[0].hypervisor_hostname,
+ ]
+ verifylist = [
+ ('matching', self.hypervisors[0].hypervisor_hostname),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # Fake the return value of search()
+ self.hypervisors_mock.search.return_value = [self.hypervisors[0]]
+ self.data = (
+ (
+ self.hypervisors[0].id,
+ self.hypervisors[0].hypervisor_hostname,
+ ),
+ )
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.hypervisors_mock.search.assert_called_with(
+ self.hypervisors[0].hypervisor_hostname
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, tuple(data))
+
+ def test_hypervisor_list_matching_option_not_found(self):
+ arglist = [
+ '--matching', 'xxx',
+ ]
+ verifylist = [
+ ('matching', 'xxx'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # Fake exception raised from search()
+ self.hypervisors_mock.search.side_effect = exceptions.NotFound(None)
+
+ self.assertRaises(exceptions.NotFound,
+ self.cmd.take_action,
+ parsed_args)
+
+
+class TestHypervisorShow(TestHypervisor):
+
+ def setUp(self):
+ super(TestHypervisorShow, self).setUp()
+
+ # Fake hypervisors to be listed up
+ self.hypervisor = compute_fakes.FakeHypervisor.create_one_hypervisor()
+
+ # Return value of utils.find_resource()
+ self.hypervisors_mock.get.return_value = self.hypervisor
+
+ # Return value of compute_client.aggregates.list()
+ self.aggregates_mock.list.return_value = []
+
+ # Return value of compute_client.hypervisors.uptime()
+ uptime_info = {
+ 'status': self.hypervisor.status,
+ 'state': self.hypervisor.state,
+ 'id': self.hypervisor.id,
+ 'hypervisor_hostname': self.hypervisor.hypervisor_hostname,
+ 'uptime': ' 01:28:24 up 3 days, 11:15, 1 user, '
+ ' load average: 0.94, 0.62, 0.50\n',
+ }
+ self.hypervisors_mock.uptime.return_value = fakes.FakeResource(
+ info=copy.deepcopy(uptime_info),
+ loaded=True
+ )
+
+ self.columns = (
+ 'aggregates',
+ 'cpu_info',
+ 'current_workload',
+ 'disk_available_least',
+ 'free_disk_gb',
+ 'free_ram_mb',
+ 'host_ip',
+ 'hypervisor_hostname',
+ 'hypervisor_type',
+ 'hypervisor_version',
+ 'id',
+ 'local_gb',
+ 'local_gb_used',
+ 'memory_mb',
+ 'memory_mb_used',
+ 'running_vms',
+ 'service_host',
+ 'service_id',
+ 'state',
+ 'status',
+ 'vcpus',
+ 'vcpus_used',
+ )
+ self.data = (
+ [],
+ {'aaa': 'aaa'},
+ 0,
+ 50,
+ 50,
+ 1024,
+ '192.168.0.10',
+ self.hypervisor.hypervisor_hostname,
+ 'QEMU',
+ 2004001,
+ self.hypervisor.id,
+ 50,
+ 0,
+ 1024,
+ 512,
+ 0,
+ 'aaa',
+ 1,
+ 'up',
+ 'enabled',
+ 4,
+ 0,
+ )
+
+ # Get the command object to test
+ self.cmd = hypervisor.ShowHypervisor(self.app, None)
+
+ def test_hypervisor_show(self):
+ arglist = [
+ self.hypervisor.hypervisor_hostname,
+ ]
+ verifylist = [
+ ('hypervisor', self.hypervisor.hypervisor_hostname),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
diff --git a/openstackclient/tests/unit/compute/v2/test_hypervisor_stats.py b/openstackclient/tests/unit/compute/v2/test_hypervisor_stats.py
new file mode 100644
index 00000000..40086f9b
--- /dev/null
+++ b/openstackclient/tests/unit/compute/v2/test_hypervisor_stats.py
@@ -0,0 +1,79 @@
+# Copyright 2016 EasyStack Corporation
+#
+# 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 openstackclient.compute.v2 import hypervisor_stats
+from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
+
+
+class TestHypervisorStats(compute_fakes.TestComputev2):
+
+ def setUp(self):
+ super(TestHypervisorStats, self).setUp()
+
+ # Get a shortcut to the compute client hypervisors mock
+ self.hypervisors_mock = self.app.client_manager.compute.hypervisors
+ self.hypervisors_mock.reset_mock()
+
+
+class TestHypervisorStatsShow(TestHypervisorStats):
+
+ def setUp(self):
+ super(TestHypervisorStatsShow, self).setUp()
+
+ self.hypervisor_stats = \
+ compute_fakes.FakeHypervisorStats.create_one_hypervisor_stats()
+
+ self.hypervisors_mock.statistics.return_value =\
+ self.hypervisor_stats
+
+ self.cmd = hypervisor_stats.ShowHypervisorStats(self.app, None)
+
+ self.columns = (
+ 'count',
+ 'current_workload',
+ 'disk_available_least',
+ 'free_disk_gb',
+ 'free_ram_mb',
+ 'local_gb',
+ 'local_gb_used',
+ 'memory_mb',
+ 'memory_mb_used',
+ 'running_vms',
+ 'vcpus',
+ 'vcpus_used',
+ )
+
+ self.data = (
+ 2,
+ 0,
+ 50,
+ 100,
+ 23000,
+ 100,
+ 0,
+ 23800,
+ 1400,
+ 3,
+ 8,
+ 3,
+ )
+
+ def test_hypervisor_show_stats(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
diff --git a/openstackclient/tests/unit/compute/v2/test_keypair.py b/openstackclient/tests/unit/compute/v2/test_keypair.py
new file mode 100644
index 00000000..cb008545
--- /dev/null
+++ b/openstackclient/tests/unit/compute/v2/test_keypair.py
@@ -0,0 +1,312 @@
+# Copyright 2016 IBM
+#
+# 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.
+#
+
+import mock
+from mock import call
+
+from osc_lib import exceptions
+from osc_lib import utils
+
+from openstackclient.compute.v2 import keypair
+from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
+from openstackclient.tests.unit import utils as tests_utils
+
+
+class TestKeypair(compute_fakes.TestComputev2):
+
+ def setUp(self):
+ super(TestKeypair, self).setUp()
+
+ # Get a shortcut to the KeypairManager Mock
+ self.keypairs_mock = self.app.client_manager.compute.keypairs
+ self.keypairs_mock.reset_mock()
+
+
+class TestKeypairCreate(TestKeypair):
+
+ keypair = compute_fakes.FakeKeypair.create_one_keypair()
+
+ def setUp(self):
+ super(TestKeypairCreate, self).setUp()
+
+ self.columns = (
+ 'fingerprint',
+ 'name',
+ 'user_id'
+ )
+ self.data = (
+ self.keypair.fingerprint,
+ self.keypair.name,
+ self.keypair.user_id
+ )
+
+ # Get the command object to test
+ self.cmd = keypair.CreateKeypair(self.app, None)
+
+ self.keypairs_mock.create.return_value = self.keypair
+
+ def test_key_pair_create_no_options(self):
+
+ arglist = [
+ self.keypair.name,
+ ]
+ verifylist = [
+ ('name', self.keypair.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.keypairs_mock.create.assert_called_with(
+ self.keypair.name,
+ public_key=None
+ )
+
+ self.assertEqual({}, columns)
+ self.assertEqual({}, data)
+
+ def test_keypair_create_public_key(self):
+ # overwrite the setup one because we want to omit private_key
+ self.keypair = compute_fakes.FakeKeypair.create_one_keypair(
+ no_pri=True)
+ self.keypairs_mock.create.return_value = self.keypair
+
+ self.data = (
+ self.keypair.fingerprint,
+ self.keypair.name,
+ self.keypair.user_id
+ )
+
+ arglist = [
+ '--public-key', self.keypair.public_key,
+ self.keypair.name,
+ ]
+ verifylist = [
+ ('public_key', self.keypair.public_key),
+ ('name', self.keypair.name)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ with mock.patch('io.open') as mock_open:
+ mock_open.return_value = mock.MagicMock()
+ m_file = mock_open.return_value.__enter__.return_value
+ m_file.read.return_value = 'dummy'
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.keypairs_mock.create.assert_called_with(
+ self.keypair.name,
+ public_key=self.keypair.public_key
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestKeypairDelete(TestKeypair):
+
+ keypairs = compute_fakes.FakeKeypair.create_keypairs(count=2)
+
+ def setUp(self):
+ super(TestKeypairDelete, self).setUp()
+
+ self.keypairs_mock.get = compute_fakes.FakeKeypair.get_keypairs(
+ self.keypairs)
+ self.keypairs_mock.delete.return_value = None
+
+ self.cmd = keypair.DeleteKeypair(self.app, None)
+
+ def test_keypair_delete(self):
+ arglist = [
+ self.keypairs[0].name
+ ]
+ verifylist = [
+ ('name', [self.keypairs[0].name]),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ ret = self.cmd.take_action(parsed_args)
+
+ self.assertIsNone(ret)
+ self.keypairs_mock.delete.assert_called_with(self.keypairs[0].name)
+
+ def test_delete_multiple_keypairs(self):
+ arglist = []
+ for k in self.keypairs:
+ arglist.append(k.name)
+ verifylist = [
+ ('name', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for k in self.keypairs:
+ calls.append(call(k.name))
+ self.keypairs_mock.delete.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_delete_multiple_keypairs_with_exception(self):
+ arglist = [
+ self.keypairs[0].name,
+ 'unexist_keypair',
+ ]
+ verifylist = [
+ ('name', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [self.keypairs[0], exceptions.CommandError]
+ with mock.patch.object(utils, 'find_resource',
+ side_effect=find_mock_result) as find_mock:
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 public keys failed to delete.',
+ str(e))
+
+ find_mock.assert_any_call(
+ self.keypairs_mock, self.keypairs[0].name)
+ find_mock.assert_any_call(self.keypairs_mock, 'unexist_keypair')
+
+ self.assertEqual(2, find_mock.call_count)
+ self.keypairs_mock.delete.assert_called_once_with(
+ self.keypairs[0].name
+ )
+
+
+class TestKeypairList(TestKeypair):
+
+ # Return value of self.keypairs_mock.list().
+ keypairs = compute_fakes.FakeKeypair.create_keypairs(count=1)
+
+ columns = (
+ "Name",
+ "Fingerprint"
+ )
+
+ data = ((
+ keypairs[0].name,
+ keypairs[0].fingerprint
+ ), )
+
+ def setUp(self):
+ super(TestKeypairList, self).setUp()
+
+ self.keypairs_mock.list.return_value = self.keypairs
+
+ # Get the command object to test
+ self.cmd = keypair.ListKeypair(self.app, None)
+
+ def test_keypair_list_no_options(self):
+ arglist = []
+ verifylist = [
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+
+ self.keypairs_mock.list.assert_called_with()
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(tuple(self.data), tuple(data))
+
+
+class TestKeypairShow(TestKeypair):
+
+ keypair = compute_fakes.FakeKeypair.create_one_keypair()
+
+ def setUp(self):
+ super(TestKeypairShow, self).setUp()
+
+ self.keypairs_mock.get.return_value = self.keypair
+
+ self.cmd = keypair.ShowKeypair(self.app, None)
+
+ self.columns = (
+ "fingerprint",
+ "name",
+ "user_id"
+ )
+
+ self.data = (
+ self.keypair.fingerprint,
+ self.keypair.name,
+ self.keypair.user_id
+ )
+
+ def test_show_no_options(self):
+
+ arglist = []
+ verifylist = []
+
+ # Missing required args should boil here
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_keypair_show(self):
+ # overwrite the setup one because we want to omit private_key
+ self.keypair = compute_fakes.FakeKeypair.create_one_keypair(
+ no_pri=True)
+ self.keypairs_mock.get.return_value = self.keypair
+
+ self.data = (
+ self.keypair.fingerprint,
+ self.keypair.name,
+ self.keypair.user_id
+ )
+
+ arglist = [
+ self.keypair.name
+ ]
+ verifylist = [
+ ('name', self.keypair.name)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_keypair_show_public(self):
+
+ arglist = [
+ '--public-key',
+ self.keypair.name
+ ]
+ verifylist = [
+ ('public_key', True),
+ ('name', self.keypair.name)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual({}, columns)
+ self.assertEqual({}, data)
diff --git a/openstackclient/tests/unit/compute/v2/test_server.py b/openstackclient/tests/unit/compute/v2/test_server.py
new file mode 100644
index 00000000..d4843f51
--- /dev/null
+++ b/openstackclient/tests/unit/compute/v2/test_server.py
@@ -0,0 +1,1844 @@
+# Copyright 2013 Nebula Inc.
+#
+# 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.
+#
+import collections
+import getpass
+import mock
+from mock import call
+
+from osc_lib import exceptions
+from osc_lib import utils as common_utils
+
+from openstackclient.compute.v2 import server
+from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
+from openstackclient.tests.unit.image.v2 import fakes as image_fakes
+from openstackclient.tests.unit import utils
+from openstackclient.tests.unit.volume.v2 import fakes as volume_fakes
+
+
+class TestServer(compute_fakes.TestComputev2):
+
+ def setUp(self):
+ super(TestServer, self).setUp()
+
+ # Get a shortcut to the compute client ServerManager Mock
+ self.servers_mock = self.app.client_manager.compute.servers
+ self.servers_mock.reset_mock()
+
+ # Get a shortcut to the compute client ImageManager Mock
+ self.cimages_mock = self.app.client_manager.compute.images
+ self.cimages_mock.reset_mock()
+
+ # Get a shortcut to the compute client FlavorManager Mock
+ self.flavors_mock = self.app.client_manager.compute.flavors
+ self.flavors_mock.reset_mock()
+
+ # Get a shortcut to the compute client SecurityGroupManager Mock
+ self.security_groups_mock = \
+ self.app.client_manager.compute.security_groups
+ self.security_groups_mock.reset_mock()
+
+ # Get a shortcut to the image client ImageManager Mock
+ self.images_mock = self.app.client_manager.image.images
+ self.images_mock.reset_mock()
+
+ # Get a shortcut to the volume client VolumeManager Mock
+ self.volumes_mock = self.app.client_manager.volume.volumes
+ self.volumes_mock.reset_mock()
+
+ # Set object attributes to be tested. Could be overwritten in subclass.
+ self.attrs = {}
+
+ # Set object methods to be tested. Could be overwritten in subclass.
+ self.methods = {}
+
+ def setup_servers_mock(self, count):
+ servers = compute_fakes.FakeServer.create_servers(attrs=self.attrs,
+ methods=self.methods,
+ count=count)
+
+ # This is the return value for utils.find_resource()
+ self.servers_mock.get = compute_fakes.FakeServer.get_servers(servers,
+ 0)
+ return servers
+
+ def run_method_with_servers(self, method_name, server_count):
+ servers = self.setup_servers_mock(server_count)
+
+ arglist = []
+ verifylist = []
+
+ for s in servers:
+ arglist.append(s.id)
+ verifylist = [
+ ('server', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ for s in servers:
+ method = getattr(s, method_name)
+ method.assert_called_with()
+ self.assertIsNone(result)
+
+
+class TestServerAddFixedIP(TestServer):
+
+ def setUp(self):
+ super(TestServerAddFixedIP, self).setUp()
+
+ # Get a shortcut to the compute client ServerManager Mock
+ self.networks_mock = self.app.client_manager.compute.networks
+
+ # Get the command object to test
+ self.cmd = server.AddFixedIP(self.app, None)
+
+ # Set add_fixed_ip method to be tested.
+ self.methods = {
+ 'add_fixed_ip': None,
+ }
+
+ def test_server_add_fixed_ip(self):
+ servers = self.setup_servers_mock(count=1)
+ network = compute_fakes.FakeNetwork.create_one_network()
+ self.networks_mock.get.return_value = network
+
+ arglist = [
+ servers[0].id,
+ network.id,
+ ]
+ verifylist = [
+ ('server', servers[0].id),
+ ('network', network.id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ servers[0].add_fixed_ip.assert_called_once_with(
+ network.id,
+ )
+ self.assertIsNone(result)
+
+
+class TestServerAddFloatingIP(TestServer):
+
+ def setUp(self):
+ super(TestServerAddFloatingIP, self).setUp()
+
+ # Get a shortcut to the compute client ServerManager Mock
+ self.networks_mock = self.app.client_manager.compute.networks
+
+ # Get the command object to test
+ self.cmd = server.AddFloatingIP(self.app, None)
+
+ # Set add_floating_ip method to be tested.
+ self.methods = {
+ 'add_floating_ip': None,
+ }
+
+ def test_server_add_floating_ip(self):
+ servers = self.setup_servers_mock(count=1)
+
+ arglist = [
+ servers[0].id,
+ '1.2.3.4',
+ ]
+ verifylist = [
+ ('server', servers[0].id),
+ ('ip_address', '1.2.3.4'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ servers[0].add_floating_ip.assert_called_once_with('1.2.3.4')
+ self.assertIsNone(result)
+
+
+class TestServerAddSecurityGroup(TestServer):
+
+ def setUp(self):
+ super(TestServerAddSecurityGroup, self).setUp()
+
+ self.security_group = \
+ compute_fakes.FakeSecurityGroup.create_one_security_group()
+ # This is the return value for utils.find_resource() for security group
+ self.security_groups_mock.get.return_value = self.security_group
+
+ attrs = {
+ 'security_groups': [{'name': self.security_group.id}]
+ }
+ methods = {
+ 'add_security_group': None,
+ }
+
+ self.server = compute_fakes.FakeServer.create_one_server(
+ attrs=attrs,
+ methods=methods
+ )
+ # This is the return value for utils.find_resource() for server
+ self.servers_mock.get.return_value = self.server
+
+ # Get the command object to test
+ self.cmd = server.AddServerSecurityGroup(self.app, None)
+
+ def test_server_add_security_group(self):
+ arglist = [
+ self.server.id,
+ self.security_group.id
+ ]
+ verifylist = [
+ ('server', self.server.id),
+ ('group', self.security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.security_groups_mock.get.assert_called_with(
+ self.security_group.id,
+ )
+ self.servers_mock.get.assert_called_with(self.server.id)
+ self.server.add_security_group.assert_called_with(
+ self.security_group.id,
+ )
+ self.assertIsNone(result)
+
+
+class TestServerCreate(TestServer):
+
+ columns = (
+ 'OS-EXT-STS:power_state',
+ 'addresses',
+ 'flavor',
+ 'id',
+ 'image',
+ 'name',
+ 'networks',
+ 'properties',
+ )
+
+ def datalist(self):
+ datalist = (
+ server._format_servers_list_power_state(
+ getattr(self.new_server, 'OS-EXT-STS:power_state')),
+ '',
+ self.flavor.name + ' (' + self.new_server.flavor.get('id') + ')',
+ self.new_server.id,
+ self.image.name + ' (' + self.new_server.image.get('id') + ')',
+ self.new_server.name,
+ self.new_server.networks,
+ '',
+ )
+ return datalist
+
+ def setUp(self):
+ super(TestServerCreate, self).setUp()
+
+ attrs = {
+ 'networks': {},
+ }
+ self.new_server = compute_fakes.FakeServer.create_one_server(
+ attrs=attrs)
+
+ # This is the return value for utils.find_resource().
+ # This is for testing --wait option.
+ self.servers_mock.get.return_value = self.new_server
+
+ self.servers_mock.create.return_value = self.new_server
+
+ self.image = image_fakes.FakeImage.create_one_image()
+ self.cimages_mock.get.return_value = self.image
+
+ self.flavor = compute_fakes.FakeFlavor.create_one_flavor()
+ self.flavors_mock.get.return_value = self.flavor
+
+ self.volume = volume_fakes.FakeVolume.create_one_volume()
+ self.volumes_mock.get.return_value = self.volume
+ self.block_device_mapping = 'vda=' + self.volume.name + ':::0'
+
+ # Get the command object to test
+ self.cmd = server.CreateServer(self.app, None)
+
+ def test_server_create_no_options(self):
+ arglist = [
+ self.new_server.name,
+ ]
+ verifylist = [
+ ('server_name', self.new_server.name),
+ ]
+
+ self.assertRaises(utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_server_create_minimal(self):
+ arglist = [
+ '--image', 'image1',
+ '--flavor', 'flavor1',
+ self.new_server.name,
+ ]
+ verifylist = [
+ ('image', 'image1'),
+ ('flavor', 'flavor1'),
+ ('config_drive', False),
+ ('server_name', self.new_server.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = dict(
+ meta=None,
+ files={},
+ reservation_id=None,
+ min_count=1,
+ max_count=1,
+ security_groups=[],
+ userdata=None,
+ key_name=None,
+ availability_zone=None,
+ block_device_mapping={},
+ nics=[],
+ scheduler_hints={},
+ config_drive=None,
+ )
+ # ServerManager.create(name, image, flavor, **kwargs)
+ self.servers_mock.create.assert_called_with(
+ self.new_server.name,
+ self.image,
+ self.flavor,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist(), data)
+
+ def test_server_create_with_network(self):
+ arglist = [
+ '--image', 'image1',
+ '--flavor', 'flavor1',
+ '--nic', 'net-id=net1',
+ '--nic', 'port-id=port1',
+ self.new_server.name,
+ ]
+ verifylist = [
+ ('image', 'image1'),
+ ('flavor', 'flavor1'),
+ ('nic', ['net-id=net1', 'port-id=port1']),
+ ('config_drive', False),
+ ('server_name', self.new_server.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ get_endpoints = mock.Mock()
+ get_endpoints.return_value = {'network': []}
+ self.app.client_manager.auth_ref = mock.Mock()
+ self.app.client_manager.auth_ref.service_catalog = mock.Mock()
+ self.app.client_manager.auth_ref.service_catalog.get_endpoints = (
+ get_endpoints)
+
+ find_network = mock.Mock()
+ find_port = mock.Mock()
+ network_client = self.app.client_manager.network
+ network_client.find_network = find_network
+ network_client.find_port = find_port
+ network_resource = mock.Mock()
+ network_resource.id = 'net1_uuid'
+ port_resource = mock.Mock()
+ port_resource.id = 'port1_uuid'
+ find_network.return_value = network_resource
+ find_port.return_value = port_resource
+
+ # Mock sdk APIs.
+ _network = mock.Mock()
+ _network.id = 'net1_uuid'
+ _port = mock.Mock()
+ _port.id = 'port1_uuid'
+ find_network = mock.Mock()
+ find_port = mock.Mock()
+ find_network.return_value = _network
+ find_port.return_value = _port
+ self.app.client_manager.network.find_network = find_network
+ self.app.client_manager.network.find_port = find_port
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = dict(
+ meta=None,
+ files={},
+ reservation_id=None,
+ min_count=1,
+ max_count=1,
+ security_groups=[],
+ userdata=None,
+ key_name=None,
+ availability_zone=None,
+ block_device_mapping={},
+ nics=[{'net-id': 'net1_uuid',
+ 'v4-fixed-ip': '',
+ 'v6-fixed-ip': '',
+ 'port-id': ''},
+ {'net-id': '',
+ 'v4-fixed-ip': '',
+ 'v6-fixed-ip': '',
+ 'port-id': 'port1_uuid'}],
+ scheduler_hints={},
+ config_drive=None,
+ )
+ # ServerManager.create(name, image, flavor, **kwargs)
+ self.servers_mock.create.assert_called_with(
+ self.new_server.name,
+ self.image,
+ self.flavor,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist(), data)
+
+ @mock.patch('openstackclient.compute.v2.server.io.open')
+ def test_server_create_userdata(self, mock_open):
+ mock_file = mock.MagicMock(name='File')
+ mock_open.return_value = mock_file
+ mock_open.read.return_value = '#!/bin/sh'
+
+ arglist = [
+ '--image', 'image1',
+ '--flavor', 'flavor1',
+ '--user-data', 'userdata.sh',
+ self.new_server.name,
+ ]
+ verifylist = [
+ ('image', 'image1'),
+ ('flavor', 'flavor1'),
+ ('user_data', 'userdata.sh'),
+ ('config_drive', False),
+ ('server_name', self.new_server.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Ensure the userdata file is opened
+ mock_open.assert_called_with('userdata.sh')
+
+ # Ensure the userdata file is closed
+ mock_file.close.assert_called_with()
+
+ # Set expected values
+ kwargs = dict(
+ meta=None,
+ files={},
+ reservation_id=None,
+ min_count=1,
+ max_count=1,
+ security_groups=[],
+ userdata=mock_file,
+ key_name=None,
+ availability_zone=None,
+ block_device_mapping={},
+ nics=[],
+ scheduler_hints={},
+ config_drive=None,
+ )
+ # ServerManager.create(name, image, flavor, **kwargs)
+ self.servers_mock.create.assert_called_with(
+ self.new_server.name,
+ self.image,
+ self.flavor,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist(), data)
+
+ def test_server_create_with_block_device_mapping(self):
+ arglist = [
+ '--image', 'image1',
+ '--flavor', self.flavor.id,
+ '--block-device-mapping', self.block_device_mapping,
+ self.new_server.name,
+ ]
+ verifylist = [
+ ('image', 'image1'),
+ ('flavor', self.flavor.id),
+ ('block_device_mapping', [self.block_device_mapping]),
+ ('config_drive', False),
+ ('server_name', self.new_server.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # CreateServer.take_action() returns two tuples
+ columns, data = self.cmd.take_action(parsed_args)
+
+ real_volume_mapping = (
+ (self.block_device_mapping.split('=', 1)[1]).replace(
+ self.volume.name,
+ self.volume.id))
+
+ # Set expected values
+ kwargs = dict(
+ meta=None,
+ files={},
+ reservation_id=None,
+ min_count=1,
+ max_count=1,
+ security_groups=[],
+ userdata=None,
+ key_name=None,
+ availability_zone=None,
+ block_device_mapping={
+ 'vda': real_volume_mapping
+ },
+ nics=[],
+ scheduler_hints={},
+ config_drive=None,
+ )
+ # ServerManager.create(name, image, flavor, **kwargs)
+ self.servers_mock.create.assert_called_with(
+ self.new_server.name,
+ self.image,
+ self.flavor,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist(), data)
+
+
+class TestServerDelete(TestServer):
+
+ def setUp(self):
+ super(TestServerDelete, self).setUp()
+
+ self.servers_mock.delete.return_value = None
+
+ # Get the command object to test
+ self.cmd = server.DeleteServer(self.app, None)
+
+ def test_server_delete_no_options(self):
+ servers = self.setup_servers_mock(count=1)
+
+ arglist = [
+ servers[0].id,
+ ]
+ verifylist = [
+ ('server', [servers[0].id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.servers_mock.delete.assert_called_with(servers[0].id)
+ self.assertIsNone(result)
+
+ def test_server_delete_multi_servers(self):
+ servers = self.setup_servers_mock(count=3)
+
+ arglist = []
+ verifylist = []
+
+ for s in servers:
+ arglist.append(s.id)
+ verifylist = [
+ ('server', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for s in servers:
+ calls.append(call(s.id))
+ self.servers_mock.delete.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ @mock.patch.object(common_utils, 'wait_for_delete', return_value=True)
+ def test_server_delete_wait_ok(self, mock_wait_for_delete):
+ servers = self.setup_servers_mock(count=1)
+
+ arglist = [
+ servers[0].id, '--wait'
+ ]
+ verifylist = [
+ ('server', [servers[0].id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.servers_mock.delete.assert_called_with(servers[0].id)
+ mock_wait_for_delete.assert_called_once_with(
+ self.servers_mock,
+ servers[0].id,
+ callback=server._show_progress
+ )
+ self.assertIsNone(result)
+
+ @mock.patch.object(common_utils, 'wait_for_delete', return_value=False)
+ def test_server_delete_wait_fails(self, mock_wait_for_delete):
+ servers = self.setup_servers_mock(count=1)
+
+ arglist = [
+ servers[0].id, '--wait'
+ ]
+ verifylist = [
+ ('server', [servers[0].id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(SystemExit, self.cmd.take_action, parsed_args)
+
+ self.servers_mock.delete.assert_called_with(servers[0].id)
+ mock_wait_for_delete.assert_called_once_with(
+ self.servers_mock,
+ servers[0].id,
+ callback=server._show_progress
+ )
+
+
+class TestServerDumpCreate(TestServer):
+
+ def setUp(self):
+ super(TestServerDumpCreate, self).setUp()
+
+ # Get the command object to test
+ self.cmd = server.CreateServerDump(self.app, None)
+
+ # Set methods to be tested.
+ self.methods = {
+ 'trigger_crash_dump': None,
+ }
+
+ def test_server_dump_one_server(self):
+ self.run_method_with_servers('trigger_crash_dump', 1)
+
+ def test_server_dump_multi_servers(self):
+ self.run_method_with_servers('trigger_crash_dump', 3)
+
+
+class TestServerList(TestServer):
+
+ # Columns to be listed up.
+ columns = (
+ 'ID',
+ 'Name',
+ 'Status',
+ 'Networks',
+ 'Image Name',
+ )
+ columns_long = (
+ 'ID',
+ 'Name',
+ 'Status',
+ 'Task State',
+ 'Power State',
+ 'Networks',
+ 'Image Name',
+ 'Image ID',
+ 'Availability Zone',
+ 'Host',
+ 'Properties',
+ )
+
+ def setUp(self):
+ super(TestServerList, self).setUp()
+
+ self.search_opts = {
+ 'reservation_id': None,
+ 'ip': None,
+ 'ip6': None,
+ 'name': None,
+ 'instance_name': None,
+ 'status': None,
+ 'flavor': None,
+ 'image': None,
+ 'host': None,
+ 'tenant_id': None,
+ 'all_tenants': False,
+ 'user_id': None,
+ }
+
+ # Default params of the core function of the command in the case of no
+ # commandline option specified.
+ self.kwargs = {
+ 'search_opts': self.search_opts,
+ 'marker': None,
+ 'limit': None,
+ }
+
+ # The fake servers' attributes. Use the original attributes names in
+ # nova, not the ones printed by "server list" command.
+ self.attrs = {
+ 'status': 'ACTIVE',
+ 'OS-EXT-STS:task_state': 'None',
+ 'OS-EXT-STS:power_state': 0x01, # Running
+ 'networks': {
+ u'public': [u'10.20.30.40', u'2001:db8::5']
+ },
+ 'OS-EXT-AZ:availability_zone': 'availability-zone-xxx',
+ 'OS-EXT-SRV-ATTR:host': 'host-name-xxx',
+ 'Metadata': '',
+ }
+
+ # The servers to be listed.
+ self.servers = self.setup_servers_mock(3)
+ self.servers_mock.list.return_value = self.servers
+
+ self.image = image_fakes.FakeImage.create_one_image()
+ self.cimages_mock.get.return_value = self.image
+
+ self.flavor = compute_fakes.FakeFlavor.create_one_flavor()
+ self.flavors_mock.get.return_value = self.flavor
+
+ # Get the command object to test
+ self.cmd = server.ListServer(self.app, None)
+
+ # Prepare data returned by fake Nova API.
+ self.data = []
+ self.data_long = []
+
+ Image = collections.namedtuple('Image', 'id name')
+ self.images_mock.list.return_value = [
+ Image(id=s.image['id'], name=self.image.name)
+ for s in self.servers
+ ]
+
+ for s in self.servers:
+ self.data.append((
+ s.id,
+ s.name,
+ s.status,
+ server._format_servers_list_networks(s.networks),
+ self.image.name,
+ ))
+ self.data_long.append((
+ s.id,
+ s.name,
+ s.status,
+ getattr(s, 'OS-EXT-STS:task_state'),
+ server._format_servers_list_power_state(
+ getattr(s, 'OS-EXT-STS:power_state')
+ ),
+ server._format_servers_list_networks(s.networks),
+ self.image.name,
+ s.image['id'],
+ getattr(s, 'OS-EXT-AZ:availability_zone'),
+ getattr(s, 'OS-EXT-SRV-ATTR:host'),
+ s.Metadata,
+ ))
+
+ def test_server_list_no_option(self):
+ arglist = []
+ verifylist = [
+ ('all_projects', False),
+ ('long', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.servers_mock.list.assert_called_with(**self.kwargs)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(tuple(self.data), tuple(data))
+
+ def test_server_list_long_option(self):
+ arglist = [
+ '--long',
+ ]
+ verifylist = [
+ ('all_projects', False),
+ ('long', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.servers_mock.list.assert_called_with(**self.kwargs)
+ self.assertEqual(self.columns_long, columns)
+ self.assertEqual(tuple(self.data_long), tuple(data))
+
+ def test_server_list_with_image(self):
+
+ arglist = [
+ '--image', self.image.id
+ ]
+ verifylist = [
+ ('image', self.image.id)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.cimages_mock.get.assert_any_call(self.image.id)
+
+ self.search_opts['image'] = self.image.id
+ self.servers_mock.list.assert_called_with(**self.kwargs)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(tuple(self.data), tuple(data))
+
+ def test_server_list_with_flavor(self):
+
+ arglist = [
+ '--flavor', self.flavor.id
+ ]
+ verifylist = [
+ ('flavor', self.flavor.id)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.flavors_mock.get.assert_called_with(self.flavor.id)
+
+ self.search_opts['flavor'] = self.flavor.id
+ self.servers_mock.list.assert_called_with(**self.kwargs)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(tuple(self.data), tuple(data))
+
+
+class TestServerLock(TestServer):
+
+ def setUp(self):
+ super(TestServerLock, self).setUp()
+
+ # Get the command object to test
+ self.cmd = server.LockServer(self.app, None)
+
+ # Set methods to be tested.
+ self.methods = {
+ 'lock': None,
+ }
+
+ def test_server_lock_one_server(self):
+ self.run_method_with_servers('lock', 1)
+
+ def test_server_lock_multi_servers(self):
+ self.run_method_with_servers('lock', 3)
+
+
+class TestServerPause(TestServer):
+
+ def setUp(self):
+ super(TestServerPause, self).setUp()
+
+ # Get the command object to test
+ self.cmd = server.PauseServer(self.app, None)
+
+ # Set methods to be tested.
+ self.methods = {
+ 'pause': None,
+ }
+
+ def test_server_pause_one_server(self):
+ self.run_method_with_servers('pause', 1)
+
+ def test_server_pause_multi_servers(self):
+ self.run_method_with_servers('pause', 3)
+
+
+class TestServerRebuild(TestServer):
+
+ def setUp(self):
+ super(TestServerRebuild, self).setUp()
+
+ # Return value for utils.find_resource for image
+ self.image = image_fakes.FakeImage.create_one_image()
+ self.cimages_mock.get.return_value = self.image
+
+ # Fake the rebuilt new server.
+ new_server = compute_fakes.FakeServer.create_one_server()
+
+ # Fake the server to be rebuilt. The IDs of them should be the same.
+ attrs = {
+ 'id': new_server.id,
+ 'image': {
+ 'id': self.image.id
+ },
+ 'networks': {},
+ 'adminPass': 'passw0rd',
+ }
+ methods = {
+ 'rebuild': new_server,
+ }
+ self.server = compute_fakes.FakeServer.create_one_server(
+ attrs=attrs,
+ methods=methods
+ )
+
+ # Return value for utils.find_resource for server.
+ self.servers_mock.get.return_value = self.server
+
+ self.cmd = server.RebuildServer(self.app, None)
+
+ def test_rebuild_with_current_image(self):
+ arglist = [
+ self.server.id,
+ ]
+ verifylist = [
+ ('server', self.server.id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # Get the command object to test.
+ self.cmd.take_action(parsed_args)
+
+ self.servers_mock.get.assert_called_with(self.server.id)
+ self.cimages_mock.get.assert_called_with(self.image.id)
+ self.server.rebuild.assert_called_with(self.image, None)
+
+ def test_rebuild_with_current_image_and_password(self):
+ password = 'password-xxx'
+ arglist = [
+ self.server.id,
+ '--password', password
+ ]
+ verifylist = [
+ ('server', self.server.id),
+ ('password', password)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # Get the command object to test
+ self.cmd.take_action(parsed_args)
+
+ self.servers_mock.get.assert_called_with(self.server.id)
+ self.cimages_mock.get.assert_called_with(self.image.id)
+ self.server.rebuild.assert_called_with(self.image, password)
+
+ @mock.patch.object(common_utils, 'wait_for_status', return_value=True)
+ def test_rebuild_with_wait_ok(self, mock_wait_for_status):
+ arglist = [
+ '--wait',
+ self.server.id,
+ ]
+ verifylist = [
+ ('wait', True),
+ ('server', self.server.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # Get the command object to test.
+ self.cmd.take_action(parsed_args)
+
+ # kwargs = dict(success_status=['active', 'verify_resize'],)
+
+ mock_wait_for_status.assert_called_once_with(
+ self.servers_mock.get,
+ self.server.id,
+ callback=server._show_progress,
+ # **kwargs
+ )
+
+ self.servers_mock.get.assert_called_with(self.server.id)
+ self.cimages_mock.get.assert_called_with(self.image.id)
+ self.server.rebuild.assert_called_with(self.image, None)
+
+ @mock.patch.object(common_utils, 'wait_for_status', return_value=False)
+ def test_rebuild_with_wait_fails(self, mock_wait_for_status):
+ arglist = [
+ '--wait',
+ self.server.id,
+ ]
+ verifylist = [
+ ('wait', True),
+ ('server', self.server.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(SystemExit, self.cmd.take_action, parsed_args)
+
+ mock_wait_for_status.assert_called_once_with(
+ self.servers_mock.get,
+ self.server.id,
+ callback=server._show_progress
+ )
+
+ self.servers_mock.get.assert_called_with(self.server.id)
+ self.cimages_mock.get.assert_called_with(self.image.id)
+ self.server.rebuild.assert_called_with(self.image, None)
+
+
+class TestServerRemoveFixedIP(TestServer):
+
+ def setUp(self):
+ super(TestServerRemoveFixedIP, self).setUp()
+
+ # Get the command object to test
+ self.cmd = server.RemoveFixedIP(self.app, None)
+
+ # Set unshelve method to be tested.
+ self.methods = {
+ 'remove_fixed_ip': None,
+ }
+
+ def test_server_remove_fixed_ip(self):
+ servers = self.setup_servers_mock(count=1)
+
+ arglist = [
+ servers[0].id,
+ '1.2.3.4',
+ ]
+ verifylist = [
+ ('server', servers[0].id),
+ ('ip_address', '1.2.3.4'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ servers[0].remove_fixed_ip.assert_called_once_with('1.2.3.4')
+ self.assertIsNone(result)
+
+
+class TestServerRemoveFloatingIP(TestServer):
+
+ def setUp(self):
+ super(TestServerRemoveFloatingIP, self).setUp()
+
+ # Get the command object to test
+ self.cmd = server.RemoveFloatingIP(self.app, None)
+
+ # Set unshelve method to be tested.
+ self.methods = {
+ 'remove_floating_ip': None,
+ }
+
+ def test_server_remove_floating_ip(self):
+ servers = self.setup_servers_mock(count=1)
+
+ arglist = [
+ servers[0].id,
+ '1.2.3.4',
+ ]
+ verifylist = [
+ ('server', servers[0].id),
+ ('ip_address', '1.2.3.4'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ servers[0].remove_floating_ip.assert_called_once_with('1.2.3.4')
+ self.assertIsNone(result)
+
+
+class TestServerRemoveSecurityGroup(TestServer):
+
+ def setUp(self):
+ super(TestServerRemoveSecurityGroup, self).setUp()
+
+ self.security_group = \
+ compute_fakes.FakeSecurityGroup.create_one_security_group()
+ # This is the return value for utils.find_resource() for security group
+ self.security_groups_mock.get.return_value = self.security_group
+
+ attrs = {
+ 'security_groups': [{'name': self.security_group.id}]
+ }
+ methods = {
+ 'remove_security_group': None,
+ }
+
+ self.server = compute_fakes.FakeServer.create_one_server(
+ attrs=attrs,
+ methods=methods
+ )
+ # This is the return value for utils.find_resource() for server
+ self.servers_mock.get.return_value = self.server
+
+ # Get the command object to test
+ self.cmd = server.RemoveServerSecurityGroup(self.app, None)
+
+ def test_server_remove_security_group(self):
+ arglist = [
+ self.server.id,
+ self.security_group.id
+ ]
+ verifylist = [
+ ('server', self.server.id),
+ ('group', self.security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.security_groups_mock.get.assert_called_with(
+ self.security_group.id,
+ )
+ self.servers_mock.get.assert_called_with(self.server.id)
+ self.server.remove_security_group.assert_called_with(
+ self.security_group.id,
+ )
+ self.assertIsNone(result)
+
+
+class TestServerResize(TestServer):
+
+ def setUp(self):
+ super(TestServerResize, self).setUp()
+
+ self.server = compute_fakes.FakeServer.create_one_server()
+
+ # This is the return value for utils.find_resource()
+ self.servers_mock.get.return_value = self.server
+
+ self.servers_mock.resize.return_value = None
+ self.servers_mock.confirm_resize.return_value = None
+ self.servers_mock.revert_resize.return_value = None
+
+ # This is the return value for utils.find_resource()
+ self.flavors_get_return_value = \
+ compute_fakes.FakeFlavor.create_one_flavor()
+ self.flavors_mock.get.return_value = self.flavors_get_return_value
+
+ # Get the command object to test
+ self.cmd = server.ResizeServer(self.app, None)
+
+ def test_server_resize_no_options(self):
+ arglist = [
+ self.server.id,
+ ]
+ verifylist = [
+ ('confirm', False),
+ ('revert', False),
+ ('server', self.server.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.servers_mock.get.assert_called_with(self.server.id)
+
+ self.assertNotCalled(self.servers_mock.resize)
+ self.assertNotCalled(self.servers_mock.confirm_resize)
+ self.assertNotCalled(self.servers_mock.revert_resize)
+ self.assertIsNone(result)
+
+ def test_server_resize(self):
+ arglist = [
+ '--flavor', self.flavors_get_return_value.id,
+ self.server.id,
+ ]
+ verifylist = [
+ ('flavor', self.flavors_get_return_value.id),
+ ('confirm', False),
+ ('revert', False),
+ ('server', self.server.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.servers_mock.get.assert_called_with(self.server.id)
+ self.flavors_mock.get.assert_called_with(
+ self.flavors_get_return_value.id,
+ )
+ self.servers_mock.resize.assert_called_with(
+ self.server,
+ self.flavors_get_return_value,
+ )
+ self.assertNotCalled(self.servers_mock.confirm_resize)
+ self.assertNotCalled(self.servers_mock.revert_resize)
+ self.assertIsNone(result)
+
+ def test_server_resize_confirm(self):
+ arglist = [
+ '--confirm',
+ self.server.id,
+ ]
+ verifylist = [
+ ('confirm', True),
+ ('revert', False),
+ ('server', self.server.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.servers_mock.get.assert_called_with(self.server.id)
+ self.assertNotCalled(self.servers_mock.resize)
+ self.servers_mock.confirm_resize.assert_called_with(self.server)
+ self.assertNotCalled(self.servers_mock.revert_resize)
+ self.assertIsNone(result)
+
+ def test_server_resize_revert(self):
+ arglist = [
+ '--revert',
+ self.server.id,
+ ]
+ verifylist = [
+ ('confirm', False),
+ ('revert', True),
+ ('server', self.server.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.servers_mock.get.assert_called_with(self.server.id)
+ self.assertNotCalled(self.servers_mock.resize)
+ self.assertNotCalled(self.servers_mock.confirm_resize)
+ self.servers_mock.revert_resize.assert_called_with(self.server)
+ self.assertIsNone(result)
+
+ @mock.patch.object(common_utils, 'wait_for_status', return_value=True)
+ def test_server_resize_with_wait_ok(self, mock_wait_for_status):
+
+ arglist = [
+ '--flavor', self.flavors_get_return_value.id,
+ '--wait',
+ self.server.id,
+ ]
+
+ verifylist = [
+ ('flavor', self.flavors_get_return_value.id),
+ ('confirm', False),
+ ('revert', False),
+ ('wait', True),
+ ('server', self.server.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+
+ self.servers_mock.get.assert_called_with(
+ self.server.id,
+ )
+
+ kwargs = dict(success_status=['active', 'verify_resize'],)
+
+ mock_wait_for_status.assert_called_once_with(
+ self.servers_mock.get,
+ self.server.id,
+ callback=server._show_progress,
+ **kwargs
+ )
+
+ self.servers_mock.resize.assert_called_with(
+ self.server,
+ self.flavors_get_return_value
+ )
+ self.assertNotCalled(self.servers_mock.confirm_resize)
+ self.assertNotCalled(self.servers_mock.revert_resize)
+
+ @mock.patch.object(common_utils, 'wait_for_status', return_value=False)
+ def test_server_resize_with_wait_fails(self, mock_wait_for_status):
+
+ arglist = [
+ '--flavor', self.flavors_get_return_value.id,
+ '--wait',
+ self.server.id,
+ ]
+
+ verifylist = [
+ ('flavor', self.flavors_get_return_value.id),
+ ('confirm', False),
+ ('revert', False),
+ ('wait', True),
+ ('server', self.server.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(SystemExit, self.cmd.take_action, parsed_args)
+
+ self.servers_mock.get.assert_called_with(
+ self.server.id,
+ )
+
+ kwargs = dict(success_status=['active', 'verify_resize'],)
+
+ mock_wait_for_status.assert_called_once_with(
+ self.servers_mock.get,
+ self.server.id,
+ callback=server._show_progress,
+ **kwargs
+ )
+
+ self.servers_mock.resize.assert_called_with(
+ self.server,
+ self.flavors_get_return_value
+ )
+
+
+class TestServerRestore(TestServer):
+
+ def setUp(self):
+ super(TestServerRestore, self).setUp()
+
+ # Get the command object to test
+ self.cmd = server.RestoreServer(self.app, None)
+
+ # Set methods to be tested.
+ self.methods = {
+ 'restore': None,
+ }
+
+ def test_server_restore_one_server(self):
+ self.run_method_with_servers('restore', 1)
+
+ def test_server_restore_multi_servers(self):
+ self.run_method_with_servers('restore', 3)
+
+
+class TestServerResume(TestServer):
+
+ def setUp(self):
+ super(TestServerResume, self).setUp()
+
+ # Get the command object to test
+ self.cmd = server.ResumeServer(self.app, None)
+
+ # Set methods to be tested.
+ self.methods = {
+ 'resume': None,
+ }
+
+ def test_server_resume_one_server(self):
+ self.run_method_with_servers('resume', 1)
+
+ def test_server_resume_multi_servers(self):
+ self.run_method_with_servers('resume', 3)
+
+
+class TestServerSet(TestServer):
+
+ def setUp(self):
+ super(TestServerSet, self).setUp()
+
+ self.methods = {
+ 'update': None,
+ 'reset_state': None,
+ 'change_password': None,
+ }
+
+ self.fake_servers = self.setup_servers_mock(2)
+
+ # Get the command object to test
+ self.cmd = server.SetServer(self.app, None)
+
+ def test_server_set_no_option(self):
+ arglist = [
+ 'foo_vm'
+ ]
+ verifylist = [
+ ('server', 'foo_vm')
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.assertNotCalled(self.fake_servers[0].update)
+ self.assertNotCalled(self.fake_servers[0].reset_state)
+ self.assertNotCalled(self.fake_servers[0].change_password)
+ self.assertNotCalled(self.servers_mock.set_meta)
+ self.assertIsNone(result)
+
+ def test_server_set_with_state(self):
+ for index, state in enumerate(['active', 'error']):
+ arglist = [
+ '--state', state,
+ 'foo_vm',
+ ]
+ verifylist = [
+ ('state', state),
+ ('server', 'foo_vm'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.fake_servers[index].reset_state.assert_called_once_with(
+ state=state)
+ self.assertIsNone(result)
+
+ def test_server_set_with_invalid_state(self):
+ arglist = [
+ '--state', 'foo_state',
+ 'foo_vm',
+ ]
+ verifylist = [
+ ('state', 'foo_state'),
+ ('server', 'foo_vm'),
+ ]
+ self.assertRaises(utils.ParserException,
+ self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_server_set_with_name(self):
+ arglist = [
+ '--name', 'foo_name',
+ 'foo_vm',
+ ]
+ verifylist = [
+ ('name', 'foo_name'),
+ ('server', 'foo_vm'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.fake_servers[0].update.assert_called_once_with(name='foo_name')
+ self.assertIsNone(result)
+
+ def test_server_set_with_property(self):
+ arglist = [
+ '--property', 'key1=value1',
+ '--property', 'key2=value2',
+ 'foo_vm',
+ ]
+ verifylist = [
+ ('property', {'key1': 'value1', 'key2': 'value2'}),
+ ('server', 'foo_vm'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.servers_mock.set_meta.assert_called_once_with(
+ self.fake_servers[0], parsed_args.property)
+ self.assertIsNone(result)
+
+ @mock.patch.object(getpass, 'getpass',
+ return_value=mock.sentinel.fake_pass)
+ def test_server_set_with_root_password(self, mock_getpass):
+ arglist = [
+ '--root-password',
+ 'foo_vm',
+ ]
+ verifylist = [
+ ('root_password', True),
+ ('server', 'foo_vm'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.fake_servers[0].change_password.assert_called_once_with(
+ mock.sentinel.fake_pass)
+ self.assertIsNone(result)
+
+
+class TestServerShelve(TestServer):
+
+ def setUp(self):
+ super(TestServerShelve, self).setUp()
+
+ # Get the command object to test
+ self.cmd = server.ShelveServer(self.app, None)
+
+ # Set shelve method to be tested.
+ self.methods = {
+ 'shelve': None,
+ }
+
+ def test_shelve_one_server(self):
+ self.run_method_with_servers('shelve', 1)
+
+ def test_shelve_multi_servers(self):
+ self.run_method_with_servers('shelve', 3)
+
+
+class TestServerShow(TestServer):
+
+ def setUp(self):
+ super(TestServerShow, self).setUp()
+
+ self.image = image_fakes.FakeImage.create_one_image()
+ self.flavor = compute_fakes.FakeFlavor.create_one_flavor()
+ server_info = {
+ 'image': {'id': self.image.id},
+ 'flavor': {'id': self.flavor.id},
+ 'tenant_id': 'tenant-id-xxx',
+ 'networks': {'public': ['10.20.30.40', '2001:db8::f']},
+ }
+ # Fake the server.diagnostics() method. The return value contains http
+ # response and data. The data is a dict. Sincce this method itself is
+ # faked, we don't need to fake everything of the return value exactly.
+ resp = mock.Mock()
+ resp.status_code = 200
+ server_method = {
+ 'diagnostics': (resp, {'test': 'test'}),
+ }
+ self.server = compute_fakes.FakeServer.create_one_server(
+ attrs=server_info, methods=server_method)
+
+ # This is the return value for utils.find_resource()
+ self.servers_mock.get.return_value = self.server
+ self.cimages_mock.get.return_value = self.image
+ self.flavors_mock.get.return_value = self.flavor
+
+ # Get the command object to test
+ self.cmd = server.ShowServer(self.app, None)
+
+ self.columns = (
+ 'OS-EXT-STS:power_state',
+ 'addresses',
+ 'flavor',
+ 'id',
+ 'image',
+ 'name',
+ 'networks',
+ 'project_id',
+ 'properties',
+ )
+
+ self.data = (
+ 'Running',
+ 'public=10.20.30.40, 2001:db8::f',
+ self.flavor.name + " (" + self.flavor.id + ")",
+ self.server.id,
+ self.image.name + " (" + self.image.id + ")",
+ self.server.name,
+ {'public': ['10.20.30.40', '2001:db8::f']},
+ 'tenant-id-xxx',
+ '',
+ )
+
+ def test_show_no_options(self):
+ arglist = []
+ verifylist = []
+
+ self.assertRaises(utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_show(self):
+ arglist = [
+ self.server.name,
+ ]
+ verifylist = [
+ ('diagnostics', False),
+ ('server', self.server.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_show_diagnostics(self):
+ arglist = [
+ '--diagnostics',
+ self.server.name,
+ ]
+ verifylist = [
+ ('diagnostics', True),
+ ('server', self.server.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(('test',), columns)
+ self.assertEqual(('test',), data)
+
+
+class TestServerStart(TestServer):
+
+ def setUp(self):
+ super(TestServerStart, self).setUp()
+
+ # Get the command object to test
+ self.cmd = server.StartServer(self.app, None)
+
+ # Set methods to be tested.
+ self.methods = {
+ 'start': None,
+ }
+
+ def test_server_start_one_server(self):
+ self.run_method_with_servers('start', 1)
+
+ def test_server_start_multi_servers(self):
+ self.run_method_with_servers('start', 3)
+
+
+class TestServerStop(TestServer):
+
+ def setUp(self):
+ super(TestServerStop, self).setUp()
+
+ # Get the command object to test
+ self.cmd = server.StopServer(self.app, None)
+
+ # Set methods to be tested.
+ self.methods = {
+ 'stop': None,
+ }
+
+ def test_server_stop_one_server(self):
+ self.run_method_with_servers('stop', 1)
+
+ def test_server_stop_multi_servers(self):
+ self.run_method_with_servers('stop', 3)
+
+
+class TestServerSuspend(TestServer):
+
+ def setUp(self):
+ super(TestServerSuspend, self).setUp()
+
+ # Get the command object to test
+ self.cmd = server.SuspendServer(self.app, None)
+
+ # Set methods to be tested.
+ self.methods = {
+ 'suspend': None,
+ }
+
+ def test_server_suspend_one_server(self):
+ self.run_method_with_servers('suspend', 1)
+
+ def test_server_suspend_multi_servers(self):
+ self.run_method_with_servers('suspend', 3)
+
+
+class TestServerUnlock(TestServer):
+
+ def setUp(self):
+ super(TestServerUnlock, self).setUp()
+
+ # Get the command object to test
+ self.cmd = server.UnlockServer(self.app, None)
+
+ # Set methods to be tested.
+ self.methods = {
+ 'unlock': None,
+ }
+
+ def test_server_unlock_one_server(self):
+ self.run_method_with_servers('unlock', 1)
+
+ def test_server_unlock_multi_servers(self):
+ self.run_method_with_servers('unlock', 3)
+
+
+class TestServerUnpause(TestServer):
+
+ def setUp(self):
+ super(TestServerUnpause, self).setUp()
+
+ # Get the command object to test
+ self.cmd = server.UnpauseServer(self.app, None)
+
+ # Set methods to be tested.
+ self.methods = {
+ 'unpause': None,
+ }
+
+ def test_server_unpause_one_server(self):
+ self.run_method_with_servers('unpause', 1)
+
+ def test_server_unpause_multi_servers(self):
+ self.run_method_with_servers('unpause', 3)
+
+
+class TestServerUnset(TestServer):
+
+ def setUp(self):
+ super(TestServerUnset, self).setUp()
+
+ self.fake_server = self.setup_servers_mock(1)[0]
+
+ # Get the command object to test
+ self.cmd = server.UnsetServer(self.app, None)
+
+ def test_server_unset_no_option(self):
+ arglist = [
+ 'foo_vm',
+ ]
+ verifylist = [
+ ('server', 'foo_vm'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.assertNotCalled(self.servers_mock.delete_meta)
+ self.assertIsNone(result)
+
+ def test_server_unset_with_property(self):
+ arglist = [
+ '--property', 'key1',
+ '--property', 'key2',
+ 'foo_vm',
+ ]
+ verifylist = [
+ ('property', ['key1', 'key2']),
+ ('server', 'foo_vm'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.servers_mock.delete_meta.assert_called_once_with(
+ self.fake_server, ['key1', 'key2'])
+ self.assertIsNone(result)
+
+
+class TestServerUnshelve(TestServer):
+
+ def setUp(self):
+ super(TestServerUnshelve, self).setUp()
+
+ # Get the command object to test
+ self.cmd = server.UnshelveServer(self.app, None)
+
+ # Set unshelve method to be tested.
+ self.methods = {
+ 'unshelve': None,
+ }
+
+ def test_unshelve_one_server(self):
+ self.run_method_with_servers('unshelve', 1)
+
+ def test_unshelve_multi_servers(self):
+ self.run_method_with_servers('unshelve', 3)
+
+
+class TestServerGeneral(TestServer):
+ OLD = {
+ 'private': [
+ {
+ 'addr': '192.168.0.3',
+ 'version': 4,
+ },
+ ]
+ }
+ NEW = {
+ 'foo': [
+ {
+ 'OS-EXT-IPS-MAC:mac_addr': 'fa:16:3e:93:b3:01',
+ 'version': 4,
+ 'addr': '10.10.1.2',
+ 'OS-EXT-IPS:type': 'fixed',
+ },
+ {
+ 'OS-EXT-IPS-MAC:mac_addr': 'fa:16:3e:93:b3:02',
+ 'version': 6,
+ 'addr': '0:0:0:0:0:ffff:a0a:103',
+ 'OS-EXT-IPS:type': 'floating',
+ },
+ ]
+ }
+ ODD = {'jenkins': ['10.3.3.18', '124.12.125.4']}
+
+ def test_get_ip_address(self):
+ self.assertEqual("192.168.0.3",
+ server._get_ip_address(self.OLD, 'private', [4, 6]))
+ self.assertEqual("10.10.1.2",
+ server._get_ip_address(self.NEW, 'fixed', [4, 6]))
+ self.assertEqual("10.10.1.2",
+ server._get_ip_address(self.NEW, 'private', [4, 6]))
+ self.assertEqual("0:0:0:0:0:ffff:a0a:103",
+ server._get_ip_address(self.NEW, 'public', [6]))
+ self.assertEqual("0:0:0:0:0:ffff:a0a:103",
+ server._get_ip_address(self.NEW, 'floating', [6]))
+ self.assertEqual("124.12.125.4",
+ server._get_ip_address(self.ODD, 'public', [4, 6]))
+ self.assertEqual("10.3.3.18",
+ server._get_ip_address(self.ODD, 'private', [4, 6]))
+ self.assertRaises(exceptions.CommandError,
+ server._get_ip_address, self.NEW, 'public', [4])
+ self.assertRaises(exceptions.CommandError,
+ server._get_ip_address, self.NEW, 'admin', [4])
+ self.assertRaises(exceptions.CommandError,
+ server._get_ip_address, self.OLD, 'public', [4, 6])
+ self.assertRaises(exceptions.CommandError,
+ server._get_ip_address, self.OLD, 'private', [6])
+
+ def test_format_servers_list_power_state(self):
+ self.assertEqual("NOSTATE",
+ server._format_servers_list_power_state(0x00))
+ self.assertEqual("Running",
+ server._format_servers_list_power_state(0x01))
+ self.assertEqual("",
+ server._format_servers_list_power_state(0x02))
+ self.assertEqual("Paused",
+ server._format_servers_list_power_state(0x03))
+ self.assertEqual("Shutdown",
+ server._format_servers_list_power_state(0x04))
+ self.assertEqual("",
+ server._format_servers_list_power_state(0x05))
+ self.assertEqual("Crashed",
+ server._format_servers_list_power_state(0x06))
+ self.assertEqual("Suspended",
+ server._format_servers_list_power_state(0x07))
+ self.assertEqual("N/A",
+ server._format_servers_list_power_state(0x08))
+
+ def test_format_servers_list_networks(self):
+ # Setup network info to test.
+ networks = {
+ u'public': [u'10.20.30.40', u'2001:db8::f'],
+ u'private': [u'2001:db8::f', u'10.20.30.40'],
+ }
+
+ # Prepare expected data.
+ # Since networks is a dict, whose items are in random order, there
+ # could be two results after formatted.
+ data_1 = (u'private=2001:db8::f, 10.20.30.40; '
+ u'public=10.20.30.40, 2001:db8::f')
+ data_2 = (u'public=10.20.30.40, 2001:db8::f; '
+ u'private=2001:db8::f, 10.20.30.40')
+
+ # Call _format_servers_list_networks().
+ networks_format = server._format_servers_list_networks(networks)
+
+ msg = ('Network string is not formatted correctly.\n'
+ 'reference = %s or %s\n'
+ 'actual = %s\n' %
+ (data_1, data_2, networks_format))
+ self.assertIn(networks_format, (data_1, data_2), msg)
+
+ @mock.patch('osc_lib.utils.find_resource')
+ def test_prep_server_detail(self, find_resource):
+ # Setup mock method return value. utils.find_resource() will be called
+ # three times in _prep_server_detail():
+ # - The first time, return server info.
+ # - The second time, return image info.
+ # - The third time, return flavor info.
+ _image = image_fakes.FakeImage.create_one_image()
+ _flavor = compute_fakes.FakeFlavor.create_one_flavor()
+ server_info = {
+ 'image': {u'id': _image.id},
+ 'flavor': {u'id': _flavor.id},
+ 'tenant_id': u'tenant-id-xxx',
+ 'networks': {u'public': [u'10.20.30.40', u'2001:db8::f']},
+ 'links': u'http://xxx.yyy.com',
+ }
+ _server = compute_fakes.FakeServer.create_one_server(attrs=server_info)
+ find_resource.side_effect = [_server, _image, _flavor]
+
+ # Prepare result data.
+ info = {
+ 'id': _server.id,
+ 'name': _server.name,
+ 'addresses': u'public=10.20.30.40, 2001:db8::f',
+ 'flavor': u'%s (%s)' % (_flavor.name, _flavor.id),
+ 'image': u'%s (%s)' % (_image.name, _image.id),
+ 'project_id': u'tenant-id-xxx',
+ 'properties': '',
+ 'OS-EXT-STS:power_state': server._format_servers_list_power_state(
+ getattr(_server, 'OS-EXT-STS:power_state')),
+ }
+
+ # Call _prep_server_detail().
+ server_detail = server._prep_server_detail(
+ self.app.client_manager.compute,
+ _server
+ )
+ # 'networks' is used to create _server. Remove it.
+ server_detail.pop('networks')
+
+ # Check the results.
+ self.assertEqual(info, server_detail)
diff --git a/openstackclient/tests/unit/compute/v2/test_server_backup.py b/openstackclient/tests/unit/compute/v2/test_server_backup.py
new file mode 100644
index 00000000..9aa63fc7
--- /dev/null
+++ b/openstackclient/tests/unit/compute/v2/test_server_backup.py
@@ -0,0 +1,271 @@
+# 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.
+#
+
+import mock
+
+from osc_lib import exceptions
+from osc_lib import utils as common_utils
+
+from openstackclient.compute.v2 import server_backup
+from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
+from openstackclient.tests.unit.image.v2 import fakes as image_fakes
+
+
+class TestServerBackup(compute_fakes.TestComputev2):
+
+ def setUp(self):
+ super(TestServerBackup, self).setUp()
+
+ # Get a shortcut to the compute client ServerManager Mock
+ self.servers_mock = self.app.client_manager.compute.servers
+ self.servers_mock.reset_mock()
+
+ # Get a shortcut to the image client ImageManager Mock
+ self.images_mock = self.app.client_manager.image.images
+ self.images_mock.reset_mock()
+
+ # Set object attributes to be tested. Could be overwritten in subclass.
+ self.attrs = {}
+
+ # Set object methods to be tested. Could be overwritten in subclass.
+ self.methods = {}
+
+ def setup_servers_mock(self, count):
+ servers = compute_fakes.FakeServer.create_servers(
+ attrs=self.attrs,
+ methods=self.methods,
+ count=count,
+ )
+
+ # This is the return value for utils.find_resource()
+ self.servers_mock.get = compute_fakes.FakeServer.get_servers(
+ servers,
+ 0,
+ )
+ return servers
+
+
+class TestServerBackupCreate(TestServerBackup):
+
+ # Just return whatever Image is testing with these days
+ def image_columns(self, image):
+ columnlist = tuple(sorted(image.keys()))
+ return columnlist
+
+ def image_data(self, image):
+ datalist = (
+ image['id'],
+ image['name'],
+ image['owner'],
+ image['protected'],
+ 'active',
+ common_utils.format_list(image.get('tags')),
+ image['visibility'],
+ )
+ return datalist
+
+ def setUp(self):
+ super(TestServerBackupCreate, self).setUp()
+
+ # Get the command object to test
+ self.cmd = server_backup.CreateServerBackup(self.app, None)
+
+ self.methods = {
+ 'backup': None,
+ }
+
+ def setup_images_mock(self, count, servers=None):
+ if servers:
+ images = image_fakes.FakeImage.create_images(
+ attrs={
+ 'name': servers[0].name,
+ 'status': 'active',
+ },
+ count=count,
+ )
+ else:
+ images = image_fakes.FakeImage.create_images(
+ attrs={
+ 'status': 'active',
+ },
+ count=count,
+ )
+
+ self.images_mock.get = mock.MagicMock(side_effect=images)
+ return images
+
+ def test_server_backup_defaults(self):
+ servers = self.setup_servers_mock(count=1)
+ images = self.setup_images_mock(count=1, servers=servers)
+
+ arglist = [
+ servers[0].id,
+ ]
+ verifylist = [
+ ('name', None),
+ ('type', None),
+ ('rotate', None),
+ ('wait', False),
+ ('server', servers[0].id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # ServerManager.backup(server, backup_name, backup_type, rotation)
+ self.servers_mock.backup.assert_called_with(
+ servers[0].id,
+ servers[0].name,
+ '',
+ 1,
+ )
+
+ self.assertEqual(self.image_columns(images[0]), columns)
+ self.assertEqual(self.image_data(images[0]), data)
+
+ def test_server_backup_create_options(self):
+ servers = self.setup_servers_mock(count=1)
+ images = self.setup_images_mock(count=1, servers=servers)
+
+ arglist = [
+ '--name', 'image',
+ '--type', 'daily',
+ '--rotate', '2',
+ servers[0].id,
+ ]
+ verifylist = [
+ ('name', 'image'),
+ ('type', 'daily'),
+ ('rotate', 2),
+ ('server', servers[0].id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # ServerManager.backup(server, backup_name, backup_type, rotation)
+ self.servers_mock.backup.assert_called_with(
+ servers[0].id,
+ 'image',
+ 'daily',
+ 2,
+ )
+
+ self.assertEqual(self.image_columns(images[0]), columns)
+ self.assertEqual(self.image_data(images[0]), data)
+
+ @mock.patch.object(common_utils, 'wait_for_status', return_value=False)
+ def test_server_backup_wait_fail(self, mock_wait_for_status):
+ servers = self.setup_servers_mock(count=1)
+ images = image_fakes.FakeImage.create_images(
+ attrs={
+ 'name': servers[0].name,
+ 'status': 'active',
+ },
+ count=5,
+ )
+
+ self.images_mock.get = mock.MagicMock(
+ side_effect=images,
+ )
+
+ arglist = [
+ '--name', 'image',
+ '--type', 'daily',
+ '--wait',
+ servers[0].id,
+ ]
+ verifylist = [
+ ('name', 'image'),
+ ('type', 'daily'),
+ ('wait', True),
+ ('server', servers[0].id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(
+ exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args,
+ )
+
+ # ServerManager.backup(server, backup_name, backup_type, rotation)
+ self.servers_mock.backup.assert_called_with(
+ servers[0].id,
+ 'image',
+ 'daily',
+ 1,
+ )
+
+ mock_wait_for_status.assert_called_once_with(
+ self.images_mock.get,
+ images[0].id,
+ callback=mock.ANY
+ )
+
+ @mock.patch.object(common_utils, 'wait_for_status', return_value=True)
+ def test_server_backup_wait_ok(self, mock_wait_for_status):
+ servers = self.setup_servers_mock(count=1)
+ images = image_fakes.FakeImage.create_images(
+ attrs={
+ 'name': servers[0].name,
+ 'status': 'active',
+ },
+ count=5,
+ )
+
+ self.images_mock.get = mock.MagicMock(
+ side_effect=images,
+ )
+
+ arglist = [
+ '--name', 'image',
+ '--type', 'daily',
+ '--wait',
+ servers[0].id,
+ ]
+ verifylist = [
+ ('name', 'image'),
+ ('type', 'daily'),
+ ('wait', True),
+ ('server', servers[0].id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # ServerManager.backup(server, backup_name, backup_type, rotation)
+ self.servers_mock.backup.assert_called_with(
+ servers[0].id,
+ 'image',
+ 'daily',
+ 1,
+ )
+
+ mock_wait_for_status.assert_called_once_with(
+ self.images_mock.get,
+ images[0].id,
+ callback=mock.ANY
+ )
+
+ self.assertEqual(self.image_columns(images[0]), columns)
+ self.assertEqual(self.image_data(images[0]), data)
diff --git a/openstackclient/tests/unit/compute/v2/test_server_group.py b/openstackclient/tests/unit/compute/v2/test_server_group.py
new file mode 100644
index 00000000..d474f41d
--- /dev/null
+++ b/openstackclient/tests/unit/compute/v2/test_server_group.py
@@ -0,0 +1,284 @@
+# Copyright 2016 Huawei, Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+import mock
+
+from osc_lib import exceptions
+from osc_lib import utils
+
+from openstackclient.compute.v2 import server_group
+from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
+from openstackclient.tests.unit import utils as tests_utils
+
+
+class TestServerGroup(compute_fakes.TestComputev2):
+
+ fake_server_group = compute_fakes.FakeServerGroup.create_one_server_group()
+
+ columns = (
+ 'id',
+ 'members',
+ 'name',
+ 'policies',
+ 'project_id',
+ 'user_id',
+ )
+
+ data = (
+ fake_server_group.id,
+ utils.format_list(fake_server_group.members),
+ fake_server_group.name,
+ utils.format_list(fake_server_group.policies),
+ fake_server_group.project_id,
+ fake_server_group.user_id,
+ )
+
+ def setUp(self):
+ super(TestServerGroup, self).setUp()
+
+ # Get a shortcut to the ServerGroupsManager Mock
+ self.server_groups_mock = self.app.client_manager.compute.server_groups
+ self.server_groups_mock.reset_mock()
+
+
+class TestServerGroupCreate(TestServerGroup):
+
+ def setUp(self):
+ super(TestServerGroupCreate, self).setUp()
+
+ self.server_groups_mock.create.return_value = self.fake_server_group
+ self.cmd = server_group.CreateServerGroup(self.app, None)
+
+ def test_server_group_create(self):
+ arglist = [
+ '--policy', 'affinity',
+ 'affinity_group',
+ ]
+ verifylist = [
+ ('policy', ['affinity']),
+ ('name', 'affinity_group'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+ self.server_groups_mock.create.assert_called_once_with(
+ name=parsed_args.name,
+ policies=parsed_args.policy,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_server_group_create_with_multiple_policies(self):
+ arglist = [
+ '--policy', 'affinity',
+ '--policy', 'soft-affinity',
+ 'affinity_group',
+ ]
+ verifylist = [
+ ('policy', ['affinity', 'soft-affinity']),
+ ('name', 'affinity_group'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+ self.server_groups_mock.create.assert_called_once_with(
+ name=parsed_args.name,
+ policies=parsed_args.policy,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_server_group_create_no_policy(self):
+ arglist = [
+ 'affinity_group',
+ ]
+ verifylist = None
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser,
+ self.cmd,
+ arglist,
+ verifylist)
+
+
+class TestServerGroupDelete(TestServerGroup):
+
+ def setUp(self):
+ super(TestServerGroupDelete, self).setUp()
+
+ self.server_groups_mock.get.return_value = self.fake_server_group
+ self.cmd = server_group.DeleteServerGroup(self.app, None)
+
+ def test_server_group_delete(self):
+ arglist = [
+ 'affinity_group',
+ ]
+ verifylist = [
+ ('server_group', ['affinity_group']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.server_groups_mock.get.assert_called_once_with('affinity_group')
+ self.server_groups_mock.delete.assert_called_once_with(
+ self.fake_server_group.id
+ )
+ self.assertIsNone(result)
+
+ def test_server_group_multiple_delete(self):
+ arglist = [
+ 'affinity_group',
+ 'anti_affinity_group'
+ ]
+ verifylist = [
+ ('server_group', ['affinity_group', 'anti_affinity_group']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.server_groups_mock.get.assert_any_call('affinity_group')
+ self.server_groups_mock.get.assert_any_call('anti_affinity_group')
+ self.server_groups_mock.delete.assert_called_with(
+ self.fake_server_group.id
+ )
+ self.assertEqual(2, self.server_groups_mock.get.call_count)
+ self.assertEqual(2, self.server_groups_mock.delete.call_count)
+ self.assertIsNone(result)
+
+ def test_server_group_delete_no_input(self):
+ arglist = []
+ verifylist = None
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser,
+ self.cmd,
+ arglist,
+ verifylist)
+
+ def test_server_group_multiple_delete_with_exception(self):
+ arglist = [
+ 'affinity_group',
+ 'anti_affinity_group'
+ ]
+ verifylist = [
+ ('server_group', ['affinity_group', 'anti_affinity_group']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ find_mock_result = [self.fake_server_group, exceptions.CommandError]
+ with mock.patch.object(utils, 'find_resource',
+ side_effect=find_mock_result) as find_mock:
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 server groups failed to delete.',
+ str(e))
+
+ find_mock.assert_any_call(self.server_groups_mock,
+ 'affinity_group')
+ find_mock.assert_any_call(self.server_groups_mock,
+ 'anti_affinity_group')
+
+ self.assertEqual(2, find_mock.call_count)
+ self.server_groups_mock.delete.assert_called_once_with(
+ self.fake_server_group.id
+ )
+
+
+class TestServerGroupList(TestServerGroup):
+
+ list_columns = (
+ 'ID',
+ 'Name',
+ 'Policies',
+ )
+
+ list_columns_long = (
+ 'ID',
+ 'Name',
+ 'Policies',
+ 'Members',
+ 'Project Id',
+ 'User Id',
+ )
+
+ list_data = ((
+ TestServerGroup.fake_server_group.id,
+ TestServerGroup.fake_server_group.name,
+ utils.format_list(TestServerGroup.fake_server_group.policies),
+ ),)
+
+ list_data_long = ((
+ TestServerGroup.fake_server_group.id,
+ TestServerGroup.fake_server_group.name,
+ utils.format_list(TestServerGroup.fake_server_group.policies),
+ utils.format_list(TestServerGroup.fake_server_group.members),
+ TestServerGroup.fake_server_group.project_id,
+ TestServerGroup.fake_server_group.user_id,
+ ),)
+
+ def setUp(self):
+ super(TestServerGroupList, self).setUp()
+
+ self.server_groups_mock.list.return_value = [self.fake_server_group]
+ self.cmd = server_group.ListServerGroup(self.app, None)
+
+ def test_server_group_list(self):
+ arglist = []
+ verifylist = [
+ ('all_projects', False),
+ ('long', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+ self.server_groups_mock.list.assert_called_once_with(False)
+
+ self.assertEqual(self.list_columns, columns)
+ self.assertEqual(self.list_data, tuple(data))
+
+ def test_server_group_list_with_all_projects_and_long(self):
+ arglist = [
+ '--all-projects',
+ '--long',
+ ]
+ verifylist = [
+ ('all_projects', True),
+ ('long', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+ self.server_groups_mock.list.assert_called_once_with(True)
+
+ self.assertEqual(self.list_columns_long, columns)
+ self.assertEqual(self.list_data_long, tuple(data))
+
+
+class TestServerGroupShow(TestServerGroup):
+
+ def setUp(self):
+ super(TestServerGroupShow, self).setUp()
+
+ self.server_groups_mock.get.return_value = self.fake_server_group
+ self.cmd = server_group.ShowServerGroup(self.app, None)
+
+ def test_server_group_show(self):
+ arglist = [
+ 'affinity_group',
+ ]
+ verifylist = [
+ ('server_group', 'affinity_group'),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
diff --git a/openstackclient/tests/unit/compute/v2/test_server_image.py b/openstackclient/tests/unit/compute/v2/test_server_image.py
new file mode 100644
index 00000000..f53f08e6
--- /dev/null
+++ b/openstackclient/tests/unit/compute/v2/test_server_image.py
@@ -0,0 +1,228 @@
+# 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.
+#
+import mock
+
+from osc_lib import exceptions
+from osc_lib import utils as common_utils
+
+from openstackclient.compute.v2 import server_image
+from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
+from openstackclient.tests.unit.image.v2 import fakes as image_fakes
+
+
+class TestServerImage(compute_fakes.TestComputev2):
+
+ def setUp(self):
+ super(TestServerImage, self).setUp()
+
+ # Get a shortcut to the compute client ServerManager Mock
+ self.servers_mock = self.app.client_manager.compute.servers
+ self.servers_mock.reset_mock()
+
+ # Get a shortcut to the image client ImageManager Mock
+ self.images_mock = self.app.client_manager.image.images
+ self.images_mock.reset_mock()
+
+ # Set object attributes to be tested. Could be overwritten in subclass.
+ self.attrs = {}
+
+ # Set object methods to be tested. Could be overwritten in subclass.
+ self.methods = {}
+
+ def setup_servers_mock(self, count):
+ servers = compute_fakes.FakeServer.create_servers(
+ attrs=self.attrs,
+ methods=self.methods,
+ count=count,
+ )
+
+ # This is the return value for utils.find_resource()
+ self.servers_mock.get = compute_fakes.FakeServer.get_servers(
+ servers,
+ 0,
+ )
+ return servers
+
+
+class TestServerImageCreate(TestServerImage):
+
+ def image_columns(self, image):
+ columnlist = tuple(sorted(image.keys()))
+ return columnlist
+
+ def image_data(self, image):
+ datalist = (
+ image['id'],
+ image['name'],
+ image['owner'],
+ image['protected'],
+ 'active',
+ common_utils.format_list(image.get('tags')),
+ image['visibility'],
+ )
+ return datalist
+
+ def setUp(self):
+ super(TestServerImageCreate, self).setUp()
+
+ # Get the command object to test
+ self.cmd = server_image.CreateServerImage(self.app, None)
+
+ self.methods = {
+ 'create_image': None,
+ }
+
+ def setup_images_mock(self, count, servers=None):
+ if servers:
+ images = image_fakes.FakeImage.create_images(
+ attrs={
+ 'name': servers[0].name,
+ 'status': 'active',
+ },
+ count=count,
+ )
+ else:
+ images = image_fakes.FakeImage.create_images(
+ attrs={
+ 'status': 'active',
+ },
+ count=count,
+ )
+
+ self.images_mock.get = mock.MagicMock(side_effect=images)
+ self.servers_mock.create_image = mock.MagicMock(
+ return_value=images[0].id,
+ )
+ return images
+
+ def test_server_image_create_defaults(self):
+ servers = self.setup_servers_mock(count=1)
+ images = self.setup_images_mock(count=1, servers=servers)
+
+ arglist = [
+ servers[0].id,
+ ]
+ verifylist = [
+ ('server', servers[0].id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # ServerManager.create_image(server, image_name, metadata=)
+ self.servers_mock.create_image.assert_called_with(
+ servers[0].id,
+ servers[0].name,
+ )
+
+ self.assertEqual(self.image_columns(images[0]), columns)
+ self.assertEqual(self.image_data(images[0]), data)
+
+ def test_server_image_create_options(self):
+ servers = self.setup_servers_mock(count=1)
+ images = self.setup_images_mock(count=1, servers=servers)
+
+ arglist = [
+ '--name', 'img-nam',
+ servers[0].id,
+ ]
+ verifylist = [
+ ('name', 'img-nam'),
+ ('server', servers[0].id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # ServerManager.create_image(server, image_name, metadata=)
+ self.servers_mock.create_image.assert_called_with(
+ servers[0].id,
+ 'img-nam',
+ )
+
+ self.assertEqual(self.image_columns(images[0]), columns)
+ self.assertEqual(self.image_data(images[0]), data)
+
+ @mock.patch.object(common_utils, 'wait_for_status', return_value=False)
+ def test_server_create_image_wait_fail(self, mock_wait_for_status):
+ servers = self.setup_servers_mock(count=1)
+ images = self.setup_images_mock(count=1, servers=servers)
+
+ arglist = [
+ '--wait',
+ servers[0].id,
+ ]
+ verifylist = [
+ ('wait', True),
+ ('server', servers[0].id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(
+ exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args,
+ )
+
+ # ServerManager.create_image(server, image_name, metadata=)
+ self.servers_mock.create_image.assert_called_with(
+ servers[0].id,
+ servers[0].name,
+ )
+
+ mock_wait_for_status.assert_called_once_with(
+ self.images_mock.get,
+ images[0].id,
+ callback=mock.ANY
+ )
+
+ @mock.patch.object(common_utils, 'wait_for_status', return_value=True)
+ def test_server_create_image_wait_ok(self, mock_wait_for_status):
+ servers = self.setup_servers_mock(count=1)
+ images = self.setup_images_mock(count=1, servers=servers)
+
+ arglist = [
+ '--wait',
+ servers[0].id,
+ ]
+ verifylist = [
+ ('wait', True),
+ ('server', servers[0].id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # ServerManager.create_image(server, image_name, metadata=)
+ self.servers_mock.create_image.assert_called_with(
+ servers[0].id,
+ servers[0].name,
+ )
+
+ mock_wait_for_status.assert_called_once_with(
+ self.images_mock.get,
+ images[0].id,
+ callback=mock.ANY
+ )
+
+ self.assertEqual(self.image_columns(images[0]), columns)
+ self.assertEqual(self.image_data(images[0]), data)
diff --git a/openstackclient/tests/unit/compute/v2/test_service.py b/openstackclient/tests/unit/compute/v2/test_service.py
new file mode 100644
index 00000000..1fd3b7d5
--- /dev/null
+++ b/openstackclient/tests/unit/compute/v2/test_service.py
@@ -0,0 +1,410 @@
+# Copyright 2015 Mirantis, Inc.
+#
+# 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.
+#
+
+import mock
+from mock import call
+
+from osc_lib import exceptions
+
+from openstackclient.compute.v2 import service
+from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
+
+
+class TestService(compute_fakes.TestComputev2):
+
+ def setUp(self):
+ super(TestService, self).setUp()
+
+ # Get a shortcut to the ServiceManager Mock
+ self.service_mock = self.app.client_manager.compute.services
+ self.service_mock.reset_mock()
+
+
+class TestServiceDelete(TestService):
+
+ services = compute_fakes.FakeService.create_services(count=2)
+
+ def setUp(self):
+ super(TestServiceDelete, self).setUp()
+
+ self.service_mock.delete.return_value = None
+
+ # Get the command object to test
+ self.cmd = service.DeleteService(self.app, None)
+
+ def test_service_delete(self):
+ arglist = [
+ self.services[0].binary,
+ ]
+ verifylist = [
+ ('service', [self.services[0].binary]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.service_mock.delete.assert_called_with(
+ self.services[0].binary,
+ )
+ self.assertIsNone(result)
+
+ def test_multi_services_delete(self):
+ arglist = []
+ for s in self.services:
+ arglist.append(s.binary)
+ verifylist = [
+ ('service', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for s in self.services:
+ calls.append(call(s.binary))
+ self.service_mock.delete.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_multi_services_delete_with_exception(self):
+ arglist = [
+ self.services[0].binary,
+ 'unexist_service',
+ ]
+ verifylist = [
+ ('service', arglist)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ delete_mock_result = [None, exceptions.CommandError]
+ self.service_mock.delete = (
+ mock.MagicMock(side_effect=delete_mock_result)
+ )
+
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual(
+ '1 of 2 compute services failed to delete.', str(e))
+
+ self.service_mock.delete.assert_any_call(self.services[0].binary)
+ self.service_mock.delete.assert_any_call('unexist_service')
+
+
+class TestServiceList(TestService):
+
+ service = compute_fakes.FakeService.create_one_service()
+
+ columns = (
+ 'ID',
+ 'Binary',
+ 'Host',
+ 'Zone',
+ 'Status',
+ 'State',
+ 'Updated At',
+ )
+ columns_long = columns + (
+ 'Disabled Reason',
+ )
+
+ data = [(
+ service.id,
+ service.binary,
+ service.host,
+ service.zone,
+ service.status,
+ service.state,
+ service.updated_at,
+ )]
+ data_long = [data[0] + (service.disabled_reason, )]
+
+ def setUp(self):
+ super(TestServiceList, self).setUp()
+
+ self.service_mock.list.return_value = [self.service]
+
+ # Get the command object to test
+ self.cmd = service.ListService(self.app, None)
+
+ def test_service_list(self):
+ arglist = [
+ '--host', self.service.host,
+ '--service', self.service.binary,
+ ]
+ verifylist = [
+ ('host', self.service.host),
+ ('service', self.service.binary),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.service_mock.list.assert_called_with(
+ self.service.host,
+ self.service.binary,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_service_list_with_long_option(self):
+ arglist = [
+ '--host', self.service.host,
+ '--service', self.service.binary,
+ '--long'
+ ]
+ verifylist = [
+ ('host', self.service.host),
+ ('service', self.service.binary),
+ ('long', True)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.service_mock.list.assert_called_with(
+ self.service.host,
+ self.service.binary,
+ )
+
+ self.assertEqual(self.columns_long, columns)
+ self.assertEqual(self.data_long, list(data))
+
+
+class TestServiceSet(TestService):
+
+ def setUp(self):
+ super(TestServiceSet, self).setUp()
+
+ self.service = compute_fakes.FakeService.create_one_service()
+
+ self.service_mock.enable.return_value = self.service
+ self.service_mock.disable.return_value = self.service
+
+ self.cmd = service.SetService(self.app, None)
+
+ def test_set_nothing(self):
+ arglist = [
+ self.service.host,
+ self.service.binary,
+ ]
+ verifylist = [
+ ('host', self.service.host),
+ ('service', self.service.binary),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ self.service_mock.enable.assert_not_called()
+ self.service_mock.disable.assert_not_called()
+ self.service_mock.disable_log_reason.assert_not_called()
+ self.assertIsNone(result)
+
+ def test_service_set_enable(self):
+ arglist = [
+ '--enable',
+ self.service.host,
+ self.service.binary,
+ ]
+ verifylist = [
+ ('enable', True),
+ ('host', self.service.host),
+ ('service', self.service.binary),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.service_mock.enable.assert_called_with(
+ self.service.host,
+ self.service.binary
+ )
+ self.assertIsNone(result)
+
+ def test_service_set_disable(self):
+ arglist = [
+ '--disable',
+ self.service.host,
+ self.service.binary,
+ ]
+ verifylist = [
+ ('disable', True),
+ ('host', self.service.host),
+ ('service', self.service.binary),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.service_mock.disable.assert_called_with(
+ self.service.host,
+ self.service.binary
+ )
+ self.assertIsNone(result)
+
+ def test_service_set_disable_with_reason(self):
+ reason = 'earthquake'
+ arglist = [
+ '--disable',
+ '--disable-reason', reason,
+ self.service.host,
+ self.service.binary,
+ ]
+ verifylist = [
+ ('disable', True),
+ ('disable_reason', reason),
+ ('host', self.service.host),
+ ('service', self.service.binary),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.service_mock.disable_log_reason.assert_called_with(
+ self.service.host,
+ self.service.binary,
+ reason
+ )
+ self.assertIsNone(result)
+
+ def test_service_set_only_with_disable_reason(self):
+ reason = 'earthquake'
+ arglist = [
+ '--disable-reason', reason,
+ self.service.host,
+ self.service.binary,
+ ]
+ verifylist = [
+ ('disable_reason', reason),
+ ('host', self.service.host),
+ ('service', self.service.binary),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail("CommandError should be raised.")
+ except exceptions.CommandError as e:
+ self.assertEqual("Cannot specify option --disable-reason without "
+ "--disable specified.", str(e))
+
+ def test_service_set_enable_with_disable_reason(self):
+ reason = 'earthquake'
+ arglist = [
+ '--enable',
+ '--disable-reason', reason,
+ self.service.host,
+ self.service.binary,
+ ]
+ verifylist = [
+ ('enable', True),
+ ('disable_reason', reason),
+ ('host', self.service.host),
+ ('service', self.service.binary),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail("CommandError should be raised.")
+ except exceptions.CommandError as e:
+ self.assertEqual("Cannot specify option --disable-reason without "
+ "--disable specified.", str(e))
+
+ def test_service_set_state_up(self):
+ arglist = [
+ '--up',
+ self.service.host,
+ self.service.binary,
+ ]
+ verifylist = [
+ ('up', True),
+ ('host', self.service.host),
+ ('service', self.service.binary),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.service_mock.force_down.assert_called_once_with(
+ self.service.host, self.service.binary, force_down=False)
+ self.assertNotCalled(self.service_mock.enable)
+ self.assertNotCalled(self.service_mock.disable)
+ self.assertIsNone(result)
+
+ def test_service_set_state_down(self):
+ arglist = [
+ '--down',
+ self.service.host,
+ self.service.binary,
+ ]
+ verifylist = [
+ ('down', True),
+ ('host', self.service.host),
+ ('service', self.service.binary),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.service_mock.force_down.assert_called_once_with(
+ self.service.host, self.service.binary, force_down=True)
+ self.assertNotCalled(self.service_mock.enable)
+ self.assertNotCalled(self.service_mock.disable)
+ self.assertIsNone(result)
+
+ def test_service_set_enable_and_state_down(self):
+ arglist = [
+ '--enable',
+ '--down',
+ self.service.host,
+ self.service.binary,
+ ]
+ verifylist = [
+ ('enable', True),
+ ('down', True),
+ ('host', self.service.host),
+ ('service', self.service.binary),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.service_mock.enable.assert_called_once_with(
+ self.service.host, self.service.binary)
+ self.service_mock.force_down.assert_called_once_with(
+ self.service.host, self.service.binary, force_down=True)
+ self.assertIsNone(result)
+
+ def test_service_set_enable_and_state_down_with_exception(self):
+ arglist = [
+ '--enable',
+ '--down',
+ self.service.host,
+ self.service.binary,
+ ]
+ verifylist = [
+ ('enable', True),
+ ('down', True),
+ ('host', self.service.host),
+ ('service', self.service.binary),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ with mock.patch.object(self.service_mock, 'enable',
+ side_effect=Exception()):
+ self.assertRaises(exceptions.CommandError,
+ self.cmd.take_action, parsed_args)
+ self.service_mock.force_down.assert_called_once_with(
+ self.service.host, self.service.binary, force_down=True)
diff --git a/openstackclient/tests/unit/fakes.py b/openstackclient/tests/unit/fakes.py
new file mode 100644
index 00000000..786cd6d4
--- /dev/null
+++ b/openstackclient/tests/unit/fakes.py
@@ -0,0 +1,242 @@
+# Copyright 2013 Nebula Inc.
+#
+# 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.
+#
+
+import json
+import mock
+import sys
+
+from keystoneauth1 import fixture
+import requests
+import six
+
+
+AUTH_TOKEN = "foobar"
+AUTH_URL = "http://0.0.0.0"
+USERNAME = "itchy"
+PASSWORD = "scratchy"
+PROJECT_NAME = "poochie"
+REGION_NAME = "richie"
+INTERFACE = "catchy"
+VERSION = "3"
+
+TEST_RESPONSE_DICT = fixture.V2Token(token_id=AUTH_TOKEN,
+ user_name=USERNAME)
+_s = TEST_RESPONSE_DICT.add_service('identity', name='keystone')
+_s.add_endpoint(AUTH_URL + ':5000/v2.0')
+_s = TEST_RESPONSE_DICT.add_service('network', name='neutron')
+_s.add_endpoint(AUTH_URL + ':9696')
+_s = TEST_RESPONSE_DICT.add_service('compute', name='nova')
+_s.add_endpoint(AUTH_URL + ':8774/v2')
+_s = TEST_RESPONSE_DICT.add_service('image', name='glance')
+_s.add_endpoint(AUTH_URL + ':9292')
+_s = TEST_RESPONSE_DICT.add_service('object', name='swift')
+_s.add_endpoint(AUTH_URL + ':8080/v1')
+
+TEST_RESPONSE_DICT_V3 = fixture.V3Token(user_name=USERNAME)
+TEST_RESPONSE_DICT_V3.set_project_scope()
+
+TEST_VERSIONS = fixture.DiscoveryList(href=AUTH_URL)
+
+
+def to_unicode_dict(catalog_dict):
+ """Converts dict to unicode dict
+
+ """
+ if isinstance(catalog_dict, dict):
+ return {to_unicode_dict(key): to_unicode_dict(value)
+ for key, value in catalog_dict.items()}
+ elif isinstance(catalog_dict, list):
+ return [to_unicode_dict(element) for element in catalog_dict]
+ elif isinstance(catalog_dict, str):
+ return catalog_dict + u""
+ else:
+ return catalog_dict
+
+
+class FakeStdout(object):
+
+ def __init__(self):
+ self.content = []
+
+ def write(self, text):
+ self.content.append(text)
+
+ def make_string(self):
+ result = ''
+ for line in self.content:
+ result = result + line
+ return result
+
+
+class FakeLog(object):
+
+ def __init__(self):
+ self.messages = {}
+
+ def debug(self, msg):
+ self.messages['debug'] = msg
+
+ def info(self, msg):
+ self.messages['info'] = msg
+
+ def warning(self, msg):
+ self.messages['warning'] = msg
+
+ def error(self, msg):
+ self.messages['error'] = msg
+
+ def critical(self, msg):
+ self.messages['critical'] = msg
+
+
+class FakeApp(object):
+
+ def __init__(self, _stdout, _log):
+ self.stdout = _stdout
+ self.client_manager = None
+ self.stdin = sys.stdin
+ self.stdout = _stdout or sys.stdout
+ self.stderr = sys.stderr
+ self.log = _log
+
+
+class FakeOptions(object):
+ def __init__(self, **kwargs):
+ self.os_beta_command = False
+
+
+class FakeClient(object):
+
+ def __init__(self, **kwargs):
+ self.endpoint = kwargs['endpoint']
+ self.token = kwargs['token']
+
+
+class FakeClientManager(object):
+ _api_version = {
+ 'image': '2',
+ }
+
+ def __init__(self):
+ self.compute = None
+ self.identity = None
+ self.image = None
+ self.object_store = None
+ self.volume = None
+ self.network = None
+ self.session = None
+ self.auth_ref = None
+ self.auth_plugin_name = None
+ self.network_endpoint_enabled = True
+
+ def get_configuration(self):
+ return {
+ 'auth': {
+ 'username': USERNAME,
+ 'password': PASSWORD,
+ 'token': AUTH_TOKEN,
+ },
+ 'region': REGION_NAME,
+ 'identity_api_version': VERSION,
+ }
+
+ def is_network_endpoint_enabled(self):
+ return self.network_endpoint_enabled
+
+
+class FakeModule(object):
+
+ def __init__(self, name, version):
+ self.name = name
+ self.__version__ = version
+
+
+class FakeResource(object):
+
+ def __init__(self, manager=None, info=None, loaded=False, methods=None):
+ """Set attributes and methods for a resource.
+
+ :param manager:
+ The resource manager
+ :param Dictionary info:
+ A dictionary with all attributes
+ :param bool loaded:
+ True if the resource is loaded in memory
+ :param Dictionary methods:
+ A dictionary with all methods
+ """
+ info = info or {}
+ methods = methods or {}
+
+ self.__name__ = type(self).__name__
+ self.manager = manager
+ self._info = info
+ self._add_details(info)
+ self._add_methods(methods)
+ self._loaded = loaded
+
+ def _add_details(self, info):
+ for (k, v) in six.iteritems(info):
+ setattr(self, k, v)
+
+ def _add_methods(self, methods):
+ """Fake methods with MagicMock objects.
+
+ For each <@key, @value> pairs in methods, add an callable MagicMock
+ object named @key as an attribute, and set the mock's return_value to
+ @value. When users access the attribute with (), @value will be
+ returned, which looks like a function call.
+ """
+ for (name, ret) in six.iteritems(methods):
+ method = mock.MagicMock(return_value=ret)
+ setattr(self, name, method)
+
+ def __repr__(self):
+ reprkeys = sorted(k for k in self.__dict__.keys() if k[0] != '_' and
+ k != 'manager')
+ info = ", ".join("%s=%s" % (k, getattr(self, k)) for k in reprkeys)
+ return "<%s %s>" % (self.__class__.__name__, info)
+
+ def keys(self):
+ return self._info.keys()
+
+ @property
+ def info(self):
+ return self._info
+
+
+class FakeResponse(requests.Response):
+
+ def __init__(self, headers=None, status_code=200,
+ data=None, encoding=None):
+ super(FakeResponse, self).__init__()
+
+ headers = headers or {}
+
+ self.status_code = status_code
+
+ self.headers.update(headers)
+ self._content = json.dumps(data)
+ if not isinstance(self._content, six.binary_type):
+ self._content = self._content.encode()
+
+
+class FakeModel(dict):
+
+ def __getattr__(self, key):
+ try:
+ return self[key]
+ except KeyError:
+ raise AttributeError(key)
diff --git a/openstackclient/tests/unit/identity/__init__.py b/openstackclient/tests/unit/identity/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/unit/identity/__init__.py
diff --git a/openstackclient/tests/unit/identity/v2_0/__init__.py b/openstackclient/tests/unit/identity/v2_0/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v2_0/__init__.py
diff --git a/openstackclient/tests/unit/identity/v2_0/fakes.py b/openstackclient/tests/unit/identity/v2_0/fakes.py
new file mode 100644
index 00000000..3d25cadf
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v2_0/fakes.py
@@ -0,0 +1,515 @@
+# Copyright 2013 Nebula Inc.
+#
+# 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.
+#
+
+import copy
+import mock
+import uuid
+
+from keystoneauth1 import access
+from keystoneauth1 import fixture
+
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit import utils
+
+
+project_id = '8-9-64'
+project_name = 'beatles'
+project_description = 'Fab Four'
+
+PROJECT = {
+ 'id': project_id,
+ 'name': project_name,
+ 'description': project_description,
+ 'enabled': True,
+}
+
+PROJECT_2 = {
+ 'id': project_id + '-2222',
+ 'name': project_name + ' reprise',
+ 'description': project_description + 'plus four more',
+ 'enabled': True,
+}
+
+role_id = '1'
+role_name = 'boss'
+
+ROLE = {
+ 'id': role_id,
+ 'name': role_name,
+}
+
+ROLE_2 = {
+ 'id': '2',
+ 'name': 'bigboss',
+}
+
+service_id = '1925-10-11'
+service_name = 'elmore'
+service_description = 'Leonard, Elmore, rip'
+service_type = 'author'
+
+SERVICE = {
+ 'id': service_id,
+ 'name': service_name,
+ 'description': service_description,
+ 'type': service_type,
+}
+
+user_id = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'
+user_name = 'paul'
+user_description = 'Sir Paul'
+user_email = 'paul@applecorps.com'
+
+USER = {
+ 'id': user_id,
+ 'name': user_name,
+ 'tenantId': project_id,
+ 'email': user_email,
+ 'enabled': True,
+}
+
+token_expires = '2016-09-05T18:04:52+0000'
+token_id = 'token-id-' + uuid.uuid4().hex
+
+TOKEN = {
+ 'expires': token_expires,
+ 'id': token_id,
+ 'tenant_id': 'project-id',
+ 'user_id': 'user-id',
+}
+
+UNSCOPED_TOKEN = {
+ 'expires': token_expires,
+ 'id': token_id,
+ 'user_id': 'user-id',
+}
+
+endpoint_name = service_name
+endpoint_adminurl = 'https://admin.example.com/v2/UUID'
+endpoint_region = 'RegionOne'
+endpoint_internalurl = 'https://internal.example.com/v2/UUID'
+endpoint_type = service_type
+endpoint_id = '11b41ee1b00841128b7333d4bf1a6140'
+endpoint_publicurl = 'https://public.example.com/v2/UUID'
+endpoint_service_id = service_id
+
+ENDPOINT = {
+ 'service_name': endpoint_name,
+ 'adminurl': endpoint_adminurl,
+ 'region': endpoint_region,
+ 'internalurl': endpoint_internalurl,
+ 'service_type': endpoint_type,
+ 'id': endpoint_id,
+ 'publicurl': endpoint_publicurl,
+ 'service_id': endpoint_service_id,
+}
+
+
+def fake_auth_ref(fake_token, fake_service=None):
+ """Create an auth_ref using keystoneauth's fixtures"""
+ token_copy = copy.deepcopy(fake_token)
+ token_copy['token_id'] = token_copy.pop('id')
+ token = fixture.V2Token(**token_copy)
+ # An auth_ref is actually an access info object
+ auth_ref = access.create(body=token)
+
+ # Create a service catalog
+ if fake_service:
+ service = token.add_service(
+ fake_service.type,
+ fake_service.name,
+ )
+ # TODO(dtroyer): Add an 'id' element to KSA's _Service fixure
+ service['id'] = fake_service.id
+ for e in fake_service.endpoints:
+ # KSA's _Service fixture copies publicURL to internalURL and
+ # adminURL if they do not exist. Soooo helpful...
+ internal = e.get('internalURL', None)
+ admin = e.get('adminURL', None)
+ region = e.get('region_id') or e.get('region', '<none>')
+ endpoint = service.add_endpoint(
+ public=e['publicURL'],
+ internal=internal,
+ admin=admin,
+ region=region,
+ )
+ # ...so undo that helpfulness
+ if not internal:
+ endpoint['internalURL'] = None
+ if not admin:
+ endpoint['adminURL'] = None
+
+ return auth_ref
+
+
+class FakeIdentityv2Client(object):
+
+ def __init__(self, **kwargs):
+ self.roles = mock.Mock()
+ self.roles.resource_class = fakes.FakeResource(None, {})
+ self.services = mock.Mock()
+ self.services.resource_class = fakes.FakeResource(None, {})
+ self.tenants = mock.Mock()
+ self.tenants.resource_class = fakes.FakeResource(None, {})
+ self.tokens = mock.Mock()
+ self.tokens.resource_class = fakes.FakeResource(None, {})
+ self.users = mock.Mock()
+ self.users.resource_class = fakes.FakeResource(None, {})
+ self.ec2 = mock.Mock()
+ self.ec2.resource_class = fakes.FakeResource(None, {})
+ self.endpoints = mock.Mock()
+ self.endpoints.resource_class = fakes.FakeResource(None, {})
+ self.extensions = mock.Mock()
+ self.extensions.resource_class = fakes.FakeResource(None, {})
+ self.auth_token = kwargs['token']
+ self.management_url = kwargs['endpoint']
+
+ def __getattr__(self, name):
+ # Map v3 'projects' back to v2 'tenants'
+ if name == "projects":
+ return self.tenants
+ else:
+ raise AttributeError(name)
+
+
+class TestIdentityv2(utils.TestCommand):
+
+ def setUp(self):
+ super(TestIdentityv2, self).setUp()
+
+ self.app.client_manager.identity = FakeIdentityv2Client(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN,
+ )
+
+
+class FakeExtension(object):
+ """Fake one or more extension."""
+
+ @staticmethod
+ def create_one_extension(attrs=None):
+ """Create a fake extension.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object with name, namespace, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ extension_info = {
+ 'name': 'name-' + uuid.uuid4().hex,
+ 'namespace': ('http://docs.openstack.org/identity/'
+ 'api/ext/OS-KSCRUD/v1.0'),
+ 'description': 'description-' + uuid.uuid4().hex,
+ 'updated': '2013-07-07T12:00:0-00:00',
+ 'alias': 'OS-KSCRUD',
+ 'links': ('[{"href":'
+ '"https://github.com/openstack/identity-api", "type":'
+ ' "text/html", "rel": "describedby"}]')
+ }
+
+ # Overwrite default attributes.
+ extension_info.update(attrs)
+
+ extension = fakes.FakeResource(
+ info=copy.deepcopy(extension_info),
+ loaded=True)
+ return extension
+
+
+class FakeCatalog(object):
+ """Fake one or more catalog."""
+
+ @staticmethod
+ def create_catalog(attrs=None):
+ """Create a fake catalog.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object with id, name, type and so on.
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ catalog_info = {
+ 'id': 'service-id-' + uuid.uuid4().hex,
+ 'type': 'compute',
+ 'name': 'supernova',
+ 'endpoints': [
+ {
+ 'region': 'one',
+ 'publicURL': 'https://public.one.example.com',
+ 'internalURL': 'https://internal.one.example.com',
+ 'adminURL': 'https://admin.one.example.com',
+ },
+ {
+ 'region': 'two',
+ 'publicURL': 'https://public.two.example.com',
+ 'internalURL': 'https://internal.two.example.com',
+ 'adminURL': 'https://admin.two.example.com',
+ },
+ {
+ 'region': None,
+ 'publicURL': 'https://public.none.example.com',
+ 'internalURL': 'https://internal.none.example.com',
+ 'adminURL': 'https://admin.none.example.com',
+ },
+ ],
+ }
+ # Overwrite default attributes.
+ catalog_info.update(attrs)
+
+ catalog = fakes.FakeResource(
+ info=copy.deepcopy(catalog_info),
+ loaded=True)
+
+ return catalog
+
+
+class FakeProject(object):
+ """Fake one or more project."""
+
+ @staticmethod
+ def create_one_project(attrs=None):
+ """Create a fake project.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, name, and so on
+ """
+
+ attrs = attrs or {}
+
+ # set default attributes.
+ project_info = {
+ 'id': 'project-id-' + uuid.uuid4().hex,
+ 'name': 'project-name-' + uuid.uuid4().hex,
+ 'description': 'project_description',
+ 'enabled': True,
+ }
+ project_info.update(attrs)
+
+ project = fakes.FakeResource(info=copy.deepcopy(project_info),
+ loaded=True)
+ return project
+
+ @staticmethod
+ def create_projects(attrs=None, count=2):
+ """Create multiple fake projects.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of projects to fake
+ :return:
+ A list of FakeResource objects faking the projects
+ """
+ projects = []
+ for i in range(0, count):
+ projects.append(FakeProject.create_one_project(attrs))
+
+ return projects
+
+
+class FakeEndpoint(object):
+ """Fake one or more endpoint."""
+
+ @staticmethod
+ def create_one_endpoint(attrs=None):
+ """Create a fake agent.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, name, region, and so on
+ """
+
+ attrs = attrs or {}
+
+ # set default attributes.
+ endpoint_info = {
+ 'service_name': 'service-name-' + uuid.uuid4().hex,
+ 'adminurl': 'http://endpoint_adminurl',
+ 'region': 'endpoint_region',
+ 'internalurl': 'http://endpoint_internalurl',
+ 'service_type': 'service_type',
+ 'id': 'endpoint-id-' + uuid.uuid4().hex,
+ 'publicurl': 'http://endpoint_publicurl',
+ 'service_id': 'service-name-' + uuid.uuid4().hex,
+
+ }
+ endpoint_info.update(attrs)
+
+ endpoint = fakes.FakeResource(info=copy.deepcopy(endpoint_info),
+ loaded=True)
+ return endpoint
+
+ @staticmethod
+ def create_endpoints(attrs=None, count=2):
+ """Create multiple fake endpoints.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of endpoints to fake
+ :return:
+ A list of FakeResource objects faking the endpoints
+ """
+ endpoints = []
+ for i in range(0, count):
+ endpoints.append(FakeEndpoint.create_one_endpoint(attrs))
+
+ return endpoints
+
+
+class FakeService(object):
+ """Fake one or more service."""
+
+ @staticmethod
+ def create_one_service(attrs=None):
+ """Create a fake service.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, name, type, and so on
+ """
+
+ attrs = attrs or {}
+
+ # set default attributes.
+ service_info = {
+ 'id': 'service-id-' + uuid.uuid4().hex,
+ 'name': 'service-name-' + uuid.uuid4().hex,
+ 'description': 'service_description',
+ 'type': 'service_type',
+
+ }
+ service_info.update(attrs)
+
+ service = fakes.FakeResource(info=copy.deepcopy(service_info),
+ loaded=True)
+ return service
+
+ @staticmethod
+ def create_services(attrs=None, count=2):
+ """Create multiple fake services.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of services to fake
+ :return:
+ A list of FakeResource objects faking the services
+ """
+ services = []
+ for i in range(0, count):
+ services.append(FakeService.create_one_service(attrs))
+
+ return services
+
+
+class FakeRole(object):
+ """Fake one or more role."""
+
+ @staticmethod
+ def create_one_role(attrs=None):
+ """Create a fake role.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, name, and so on
+ """
+
+ attrs = attrs or {}
+
+ # set default attributes.
+ role_info = {
+ 'id': 'role-id' + uuid.uuid4().hex,
+ 'name': 'role-name' + uuid.uuid4().hex,
+ }
+ role_info.update(attrs)
+
+ role = fakes.FakeResource(info=copy.deepcopy(role_info),
+ loaded=True)
+ return role
+
+ @staticmethod
+ def create_roles(attrs=None, count=2):
+ """Create multiple fake roles.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of roles to fake
+ :return:
+ A list of FakeResource objects faking the roles
+ """
+ roles = []
+ for i in range(0, count):
+ roles.append(FakeRole.create_one_role(attrs))
+
+ return roles
+
+
+class FakeUser(object):
+ """Fake one or more user."""
+
+ @staticmethod
+ def create_one_user(attrs=None):
+ """Create a fake user.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, name, and so on
+ """
+ attrs = attrs or {}
+
+ # set default attributes.
+ user_info = {
+ 'id': 'user-id-' + uuid.uuid4().hex,
+ 'name': 'user-name-' + uuid.uuid4().hex,
+ 'tenantId': 'project-id-' + uuid.uuid4().hex,
+ 'email': 'admin@openstack.org',
+ 'enabled': True,
+ }
+ user_info.update(attrs)
+
+ user = fakes.FakeResource(info=copy.deepcopy(user_info),
+ loaded=True)
+ return user
+
+ @staticmethod
+ def create_users(attrs=None, count=2):
+ """Create multiple fake users.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of users to fake
+ :return:
+ A list of FakeResource objects faking the users
+ """
+ users = []
+ for i in range(0, count):
+ users.append(FakeUser.create_one_user(attrs))
+
+ return users
diff --git a/openstackclient/tests/unit/identity/v2_0/test_catalog.py b/openstackclient/tests/unit/identity/v2_0/test_catalog.py
new file mode 100644
index 00000000..c32f9fb8
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v2_0/test_catalog.py
@@ -0,0 +1,176 @@
+# 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.
+#
+
+import mock
+
+from openstackclient.identity.v2_0 import catalog
+from openstackclient.tests.unit.identity.v2_0 import fakes as identity_fakes
+from openstackclient.tests.unit import utils
+
+
+class TestCatalog(utils.TestCommand):
+
+ service_catalog = identity_fakes.FakeCatalog.create_catalog()
+
+ def setUp(self):
+ super(TestCatalog, self).setUp()
+
+ self.sc_mock = mock.MagicMock()
+ self.sc_mock.service_catalog.catalog.return_value = [
+ self.service_catalog,
+ ]
+
+ self.auth_mock = mock.MagicMock()
+ self.app.client_manager.session = self.auth_mock
+
+ self.auth_mock.auth.get_auth_ref.return_value = self.sc_mock
+
+
+class TestCatalogList(TestCatalog):
+
+ columns = (
+ 'Name',
+ 'Type',
+ 'Endpoints',
+ )
+
+ def setUp(self):
+ super(TestCatalogList, self).setUp()
+
+ # Get the command object to test
+ self.cmd = catalog.ListCatalog(self.app, None)
+
+ def test_catalog_list(self):
+ auth_ref = identity_fakes.fake_auth_ref(
+ identity_fakes.TOKEN,
+ fake_service=self.service_catalog,
+ )
+ self.ar_mock = mock.PropertyMock(return_value=auth_ref)
+ type(self.app.client_manager).auth_ref = self.ar_mock
+
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+ datalist = ((
+ 'supernova',
+ 'compute',
+ 'one\n publicURL: https://public.one.example.com\n '
+ 'internalURL: https://internal.one.example.com\n '
+ 'adminURL: https://admin.one.example.com\n'
+ 'two\n publicURL: https://public.two.example.com\n '
+ 'internalURL: https://internal.two.example.com\n '
+ 'adminURL: https://admin.two.example.com\n'
+ '<none>\n publicURL: https://public.none.example.com\n '
+ 'internalURL: https://internal.none.example.com\n '
+ 'adminURL: https://admin.none.example.com\n',
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_catalog_list_with_endpoint_url(self):
+ attr = {
+ 'id': 'qwertyuiop',
+ 'type': 'compute',
+ 'name': 'supernova',
+ 'endpoints': [
+ {
+ 'region': 'one',
+ 'publicURL': 'https://public.one.example.com',
+ },
+ {
+ 'region': 'two',
+ 'publicURL': 'https://public.two.example.com',
+ 'internalURL': 'https://internal.two.example.com',
+ },
+ ],
+ }
+ service_catalog = identity_fakes.FakeCatalog.create_catalog(attr)
+ auth_ref = identity_fakes.fake_auth_ref(
+ identity_fakes.TOKEN,
+ fake_service=service_catalog,
+ )
+ self.ar_mock = mock.PropertyMock(return_value=auth_ref)
+ type(self.app.client_manager).auth_ref = self.ar_mock
+
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+ datalist = ((
+ 'supernova',
+ 'compute',
+ 'one\n publicURL: https://public.one.example.com\n'
+ 'two\n publicURL: https://public.two.example.com\n '
+ 'internalURL: https://internal.two.example.com\n'
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+
+class TestCatalogShow(TestCatalog):
+
+ def setUp(self):
+ super(TestCatalogShow, self).setUp()
+
+ # Get the command object to test
+ self.cmd = catalog.ShowCatalog(self.app, None)
+
+ def test_catalog_show(self):
+ auth_ref = identity_fakes.fake_auth_ref(
+ identity_fakes.UNSCOPED_TOKEN,
+ fake_service=self.service_catalog,
+ )
+ self.ar_mock = mock.PropertyMock(return_value=auth_ref)
+ type(self.app.client_manager).auth_ref = self.ar_mock
+
+ arglist = [
+ 'compute',
+ ]
+ verifylist = [
+ ('service', 'compute'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ collist = ('endpoints', 'id', 'name', 'type')
+ self.assertEqual(collist, columns)
+ datalist = (
+ 'one\n publicURL: https://public.one.example.com\n '
+ 'internalURL: https://internal.one.example.com\n '
+ 'adminURL: https://admin.one.example.com\n'
+ 'two\n publicURL: https://public.two.example.com\n '
+ 'internalURL: https://internal.two.example.com\n '
+ 'adminURL: https://admin.two.example.com\n'
+ '<none>\n publicURL: https://public.none.example.com\n '
+ 'internalURL: https://internal.none.example.com\n '
+ 'adminURL: https://admin.none.example.com\n',
+ self.service_catalog.id,
+ 'supernova',
+ 'compute',
+ )
+ self.assertEqual(datalist, data)
diff --git a/openstackclient/tests/unit/identity/v2_0/test_endpoint.py b/openstackclient/tests/unit/identity/v2_0/test_endpoint.py
new file mode 100644
index 00000000..915e04a5
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v2_0/test_endpoint.py
@@ -0,0 +1,239 @@
+# 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 openstackclient.identity.v2_0 import endpoint
+from openstackclient.tests.unit.identity.v2_0 import fakes as identity_fakes
+
+
+class TestEndpoint(identity_fakes.TestIdentityv2):
+
+ fake_service = identity_fakes.FakeService.create_one_service()
+ attr = {
+ 'service_name': fake_service.name,
+ 'service_id': fake_service.id,
+ }
+ fake_endpoint = identity_fakes.FakeEndpoint.create_one_endpoint(attr)
+
+ def setUp(self):
+ super(TestEndpoint, self).setUp()
+
+ # Get a shortcut to the EndpointManager Mock
+ self.endpoints_mock = self.app.client_manager.identity.endpoints
+ self.endpoints_mock.reset_mock()
+
+ # Get a shortcut to the ServiceManager Mock
+ self.services_mock = self.app.client_manager.identity.services
+ self.services_mock.reset_mock()
+
+
+class TestEndpointCreate(TestEndpoint):
+
+ def setUp(self):
+ super(TestEndpointCreate, self).setUp()
+
+ self.endpoints_mock.create.return_value = self.fake_endpoint
+
+ self.services_mock.get.return_value = self.fake_service
+
+ # Get the command object to test
+ self.cmd = endpoint.CreateEndpoint(self.app, None)
+
+ def test_endpoint_create(self):
+ arglist = [
+ '--publicurl', self.fake_endpoint.publicurl,
+ '--internalurl', self.fake_endpoint.internalurl,
+ '--adminurl', self.fake_endpoint.adminurl,
+ '--region', self.fake_endpoint.region,
+ self.fake_service.id,
+ ]
+ verifylist = [
+ ('adminurl', self.fake_endpoint.adminurl),
+ ('internalurl', self.fake_endpoint.internalurl),
+ ('publicurl', self.fake_endpoint.publicurl),
+ ('region', self.fake_endpoint.region),
+ ('service', self.fake_service.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # EndpointManager.create(region, service_id, publicurl, adminurl,
+ # internalurl)
+ self.endpoints_mock.create.assert_called_with(
+ self.fake_endpoint.region,
+ self.fake_service.id,
+ self.fake_endpoint.publicurl,
+ self.fake_endpoint.adminurl,
+ self.fake_endpoint.internalurl,
+ )
+
+ collist = ('adminurl', 'id', 'internalurl', 'publicurl',
+ 'region', 'service_id', 'service_name', 'service_type')
+ self.assertEqual(collist, columns)
+ datalist = (
+ self.fake_endpoint.adminurl,
+ self.fake_endpoint.id,
+ self.fake_endpoint.internalurl,
+ self.fake_endpoint.publicurl,
+ self.fake_endpoint.region,
+ self.fake_endpoint.service_id,
+ self.fake_endpoint.service_name,
+ self.fake_endpoint.service_type,
+ )
+
+ self.assertEqual(datalist, data)
+
+
+class TestEndpointDelete(TestEndpoint):
+
+ def setUp(self):
+ super(TestEndpointDelete, self).setUp()
+
+ self.endpoints_mock.get.return_value = self.fake_endpoint
+ self.endpoints_mock.delete.return_value = None
+
+ # Get the command object to test
+ self.cmd = endpoint.DeleteEndpoint(self.app, None)
+
+ def test_endpoint_delete_no_options(self):
+ arglist = [
+ self.fake_endpoint.id,
+ ]
+ verifylist = [
+ ('endpoints', [self.fake_endpoint.id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.endpoints_mock.delete.assert_called_with(
+ self.fake_endpoint.id,
+ )
+ self.assertIsNone(result)
+
+
+class TestEndpointList(TestEndpoint):
+
+ def setUp(self):
+ super(TestEndpointList, self).setUp()
+
+ self.endpoints_mock.list.return_value = [self.fake_endpoint]
+
+ self.services_mock.get.return_value = self.fake_service
+
+ # Get the command object to test
+ self.cmd = endpoint.ListEndpoint(self.app, None)
+
+ def test_endpoint_list_no_options(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.endpoints_mock.list.assert_called_with()
+
+ collist = ('ID', 'Region', 'Service Name', 'Service Type')
+ self.assertEqual(collist, columns)
+ datalist = ((
+ self.fake_endpoint.id,
+ self.fake_endpoint.region,
+ self.fake_endpoint.service_name,
+ self.fake_endpoint.service_type,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_endpoint_list_long(self):
+ arglist = [
+ '--long',
+ ]
+ verifylist = [
+ ('long', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.endpoints_mock.list.assert_called_with()
+
+ collist = ('ID', 'Region', 'Service Name', 'Service Type',
+ 'PublicURL', 'AdminURL', 'InternalURL')
+ self.assertEqual(collist, columns)
+ datalist = ((
+ self.fake_endpoint.id,
+ self.fake_endpoint.region,
+ self.fake_endpoint.service_name,
+ self.fake_endpoint.service_type,
+ self.fake_endpoint.publicurl,
+ self.fake_endpoint.adminurl,
+ self.fake_endpoint.internalurl,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+
+class TestEndpointShow(TestEndpoint):
+
+ def setUp(self):
+ super(TestEndpointShow, self).setUp()
+
+ self.endpoints_mock.list.return_value = [self.fake_endpoint]
+
+ self.services_mock.get.return_value = self.fake_service
+
+ # Get the command object to test
+ self.cmd = endpoint.ShowEndpoint(self.app, None)
+
+ def test_endpoint_show(self):
+ arglist = [
+ self.fake_endpoint.id,
+ ]
+ verifylist = [
+ ('endpoint_or_service', self.fake_endpoint.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # EndpointManager.list()
+ self.endpoints_mock.list.assert_called_with()
+ # ServiceManager.get(name)
+ self.services_mock.get.assert_called_with(
+ self.fake_endpoint.service_id,
+ )
+
+ collist = ('adminurl', 'id', 'internalurl', 'publicurl',
+ 'region', 'service_id', 'service_name', 'service_type')
+ self.assertEqual(collist, columns)
+ datalist = (
+ self.fake_endpoint.adminurl,
+ self.fake_endpoint.id,
+ self.fake_endpoint.internalurl,
+ self.fake_endpoint.publicurl,
+ self.fake_endpoint.region,
+ self.fake_endpoint.service_id,
+ self.fake_endpoint.service_name,
+ self.fake_endpoint.service_type,
+ )
+ self.assertEqual(datalist, data)
diff --git a/openstackclient/tests/unit/identity/v2_0/test_project.py b/openstackclient/tests/unit/identity/v2_0/test_project.py
new file mode 100644
index 00000000..c1f00762
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v2_0/test_project.py
@@ -0,0 +1,635 @@
+# Copyright 2013 Nebula Inc.
+#
+# 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 keystoneauth1 import exceptions as ks_exc
+from osc_lib import exceptions
+
+from openstackclient.identity.v2_0 import project
+from openstackclient.tests.unit.identity.v2_0 import fakes as identity_fakes
+
+
+class TestProject(identity_fakes.TestIdentityv2):
+
+ fake_project = identity_fakes.FakeProject.create_one_project()
+
+ columns = (
+ 'description',
+ 'enabled',
+ 'id',
+ 'name',
+ )
+ datalist = (
+ fake_project.description,
+ True,
+ fake_project.id,
+ fake_project.name,
+ )
+
+ def setUp(self):
+ super(TestProject, self).setUp()
+
+ # Get a shortcut to the TenantManager Mock
+ self.projects_mock = self.app.client_manager.identity.tenants
+ self.projects_mock.reset_mock()
+
+
+class TestProjectCreate(TestProject):
+
+ def setUp(self):
+ super(TestProjectCreate, self).setUp()
+
+ self.projects_mock.create.return_value = self.fake_project
+
+ # Get the command object to test
+ self.cmd = project.CreateProject(self.app, None)
+
+ def test_project_create_no_options(self):
+ arglist = [
+ self.fake_project.name,
+ ]
+ verifylist = [
+ ('enable', False),
+ ('disable', False),
+ ('name', self.fake_project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'description': None,
+ 'enabled': True,
+ }
+ self.projects_mock.create.assert_called_with(
+ self.fake_project.name,
+ **kwargs
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_project_create_description(self):
+ arglist = [
+ '--description', 'new desc',
+ self.fake_project.name,
+ ]
+ verifylist = [
+ ('description', 'new desc'),
+ ('name', self.fake_project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'description': 'new desc',
+ 'enabled': True,
+ }
+ self.projects_mock.create.assert_called_with(
+ self.fake_project.name,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_project_create_enable(self):
+ arglist = [
+ '--enable',
+ self.fake_project.name,
+ ]
+ verifylist = [
+ ('enable', True),
+ ('disable', False),
+ ('name', self.fake_project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'description': None,
+ 'enabled': True,
+ }
+ self.projects_mock.create.assert_called_with(
+ self.fake_project.name,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_project_create_disable(self):
+ arglist = [
+ '--disable',
+ self.fake_project.name,
+ ]
+ verifylist = [
+ ('enable', False),
+ ('disable', True),
+ ('name', self.fake_project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'description': None,
+ 'enabled': False,
+ }
+ self.projects_mock.create.assert_called_with(
+ self.fake_project.name,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_project_create_property(self):
+ arglist = [
+ '--property', 'fee=fi',
+ '--property', 'fo=fum',
+ self.fake_project.name,
+ ]
+ verifylist = [
+ ('property', {'fee': 'fi', 'fo': 'fum'}),
+ ('name', self.fake_project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'description': None,
+ 'enabled': True,
+ 'fee': 'fi',
+ 'fo': 'fum',
+ }
+ self.projects_mock.create.assert_called_with(
+ self.fake_project.name,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_project_create_or_show_exists(self):
+ def _raise_conflict(*args, **kwargs):
+ raise ks_exc.Conflict(None)
+
+ # need to make this throw an exception...
+ self.projects_mock.create.side_effect = _raise_conflict
+
+ self.projects_mock.get.return_value = self.fake_project
+
+ arglist = [
+ '--or-show',
+ self.fake_project.name,
+ ]
+ verifylist = [
+ ('or_show', True),
+ ('name', self.fake_project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # ProjectManager.create(name, description, enabled)
+ self.projects_mock.get.assert_called_with(self.fake_project.name)
+
+ # Set expected values
+ kwargs = {
+ 'description': None,
+ 'enabled': True,
+ }
+ self.projects_mock.create.assert_called_with(
+ self.fake_project.name,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_project_create_or_show_not_exists(self):
+ arglist = [
+ '--or-show',
+ self.fake_project.name,
+ ]
+ verifylist = [
+ ('or_show', True),
+ ('name', self.fake_project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'description': None,
+ 'enabled': True,
+ }
+ self.projects_mock.create.assert_called_with(
+ self.fake_project.name,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+
+class TestProjectDelete(TestProject):
+
+ def setUp(self):
+ super(TestProjectDelete, self).setUp()
+
+ # This is the return value for utils.find_resource()
+ self.projects_mock.get.return_value = self.fake_project
+ self.projects_mock.delete.return_value = None
+
+ # Get the command object to test
+ self.cmd = project.DeleteProject(self.app, None)
+
+ def test_project_delete_no_options(self):
+ arglist = [
+ self.fake_project.id,
+ ]
+ verifylist = [
+ ('projects', [self.fake_project.id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.projects_mock.delete.assert_called_with(
+ self.fake_project.id,
+ )
+ self.assertIsNone(result)
+
+
+class TestProjectList(TestProject):
+
+ def setUp(self):
+ super(TestProjectList, self).setUp()
+
+ self.projects_mock.list.return_value = [self.fake_project]
+
+ # Get the command object to test
+ self.cmd = project.ListProject(self.app, None)
+
+ def test_project_list_no_options(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.projects_mock.list.assert_called_with()
+
+ collist = ('ID', 'Name')
+ self.assertEqual(collist, columns)
+ datalist = ((
+ self.fake_project.id,
+ self.fake_project.name,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_project_list_long(self):
+ arglist = [
+ '--long',
+ ]
+ verifylist = [
+ ('long', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.projects_mock.list.assert_called_with()
+
+ collist = ('ID', 'Name', 'Description', 'Enabled')
+ self.assertEqual(collist, columns)
+ datalist = ((
+ self.fake_project.id,
+ self.fake_project.name,
+ self.fake_project.description,
+ True,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+
+class TestProjectSet(TestProject):
+
+ def setUp(self):
+ super(TestProjectSet, self).setUp()
+
+ self.projects_mock.get.return_value = self.fake_project
+ self.projects_mock.update.return_value = self.fake_project
+
+ # Get the command object to test
+ self.cmd = project.SetProject(self.app, None)
+
+ def test_project_set_no_options(self):
+ arglist = [
+ self.fake_project.name,
+ ]
+ verifylist = [
+ ('project', self.fake_project.name),
+ ('enable', False),
+ ('disable', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.assertIsNone(result)
+
+ def test_project_set_unexist_project(self):
+ arglist = [
+ "unexist-project",
+ ]
+ verifylist = [
+ ('project', "unexist-project"),
+ ('name', None),
+ ('description', None),
+ ('enable', False),
+ ('disable', False),
+ ('property', None),
+ ]
+ self.projects_mock.get.side_effect = exceptions.NotFound(None)
+ self.projects_mock.find.side_effect = exceptions.NotFound(None)
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(
+ exceptions.CommandError, self.cmd.take_action, parsed_args)
+
+ def test_project_set_name(self):
+ arglist = [
+ '--name', self.fake_project.name,
+ self.fake_project.name,
+ ]
+ verifylist = [
+ ('name', self.fake_project.name),
+ ('enable', False),
+ ('disable', False),
+ ('project', self.fake_project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'description': self.fake_project.description,
+ 'enabled': True,
+ 'tenant_name': self.fake_project.name,
+ }
+ self.projects_mock.update.assert_called_with(
+ self.fake_project.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_project_set_description(self):
+ arglist = [
+ '--description', self.fake_project.description,
+ self.fake_project.name,
+ ]
+ verifylist = [
+ ('description', self.fake_project.description),
+ ('enable', False),
+ ('disable', False),
+ ('project', self.fake_project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'description': self.fake_project.description,
+ 'enabled': True,
+ 'tenant_name': self.fake_project.name,
+ }
+ self.projects_mock.update.assert_called_with(
+ self.fake_project.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_project_set_enable(self):
+ arglist = [
+ '--enable',
+ self.fake_project.name,
+ ]
+ verifylist = [
+ ('enable', True),
+ ('disable', False),
+ ('project', self.fake_project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'description': self.fake_project.description,
+ 'enabled': True,
+ 'tenant_name': self.fake_project.name,
+ }
+ self.projects_mock.update.assert_called_with(
+ self.fake_project.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_project_set_disable(self):
+ arglist = [
+ '--disable',
+ self.fake_project.name,
+ ]
+ verifylist = [
+ ('enable', False),
+ ('disable', True),
+ ('project', self.fake_project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'description': self.fake_project.description,
+ 'enabled': False,
+ 'tenant_name': self.fake_project.name,
+ }
+ self.projects_mock.update.assert_called_with(
+ self.fake_project.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_project_set_property(self):
+ arglist = [
+ '--property', 'fee=fi',
+ '--property', 'fo=fum',
+ self.fake_project.name,
+ ]
+ verifylist = [
+ ('property', {'fee': 'fi', 'fo': 'fum'}),
+ ('project', self.fake_project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'description': self.fake_project.description,
+ 'enabled': True,
+ 'tenant_name': self.fake_project.name,
+ 'fee': 'fi',
+ 'fo': 'fum',
+ }
+ self.projects_mock.update.assert_called_with(
+ self.fake_project.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+
+class TestProjectShow(TestProject):
+
+ fake_proj_show = identity_fakes.FakeProject.create_one_project()
+
+ def setUp(self):
+ super(TestProjectShow, self).setUp()
+
+ self.projects_mock.get.return_value = self.fake_proj_show
+
+ # Get the command object to test
+ self.cmd = project.ShowProject(self.app, None)
+
+ def test_project_show(self):
+ arglist = [
+ self.fake_proj_show.id,
+ ]
+ verifylist = [
+ ('project', self.fake_proj_show.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.projects_mock.get.assert_called_with(
+ self.fake_proj_show.id,
+ )
+
+ collist = ('description', 'enabled', 'id', 'name', 'properties')
+ self.assertEqual(collist, columns)
+ datalist = (
+ self.fake_proj_show.description,
+ True,
+ self.fake_proj_show.id,
+ self.fake_proj_show.name,
+ '',
+ )
+ self.assertEqual(datalist, data)
+
+
+class TestProjectUnset(TestProject):
+
+ attr = {'fee': 'fi', 'fo': 'fum'}
+ fake_proj = identity_fakes.FakeProject.create_one_project(attr)
+
+ def setUp(self):
+ super(TestProjectUnset, self).setUp()
+
+ self.projects_mock.get.return_value = self.fake_proj
+
+ # Get the command object to test
+ self.cmd = project.UnsetProject(self.app, None)
+
+ def test_project_unset_no_options(self):
+ arglist = [
+ self.fake_proj.name,
+ ]
+ verifylist = [
+ ('project', self.fake_proj.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.assertIsNone(result)
+
+ def test_project_unset_key(self):
+ arglist = [
+ '--property', 'fee',
+ '--property', 'fo',
+ self.fake_proj.name,
+ ]
+ verifylist = [
+ ('property', ['fee', 'fo']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ # Set expected values
+ kwargs = {
+ 'description': self.fake_proj.description,
+ 'enabled': True,
+ 'fee': None,
+ 'fo': None,
+ 'id': self.fake_proj.id,
+ 'name': self.fake_proj.name,
+ }
+
+ self.projects_mock.update.assert_called_with(
+ self.fake_proj.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
diff --git a/openstackclient/tests/unit/identity/v2_0/test_role.py b/openstackclient/tests/unit/identity/v2_0/test_role.py
new file mode 100644
index 00000000..68ebf141
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v2_0/test_role.py
@@ -0,0 +1,480 @@
+# Copyright 2013 Nebula Inc.
+#
+# 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.
+#
+
+import mock
+
+from keystoneauth1 import exceptions as ks_exc
+from osc_lib import exceptions
+
+from openstackclient.identity.v2_0 import role
+from openstackclient.tests.unit.identity.v2_0 import fakes as identity_fakes
+
+
+class TestRole(identity_fakes.TestIdentityv2):
+
+ attr = {}
+ attr['endpoints'] = [
+ {
+ 'publicURL': identity_fakes.ENDPOINT['publicurl'],
+ },
+ ]
+ fake_service = identity_fakes.FakeService.create_one_service(attr)
+ fake_role = identity_fakes.FakeRole.create_one_role()
+ fake_project = identity_fakes.FakeProject.create_one_project()
+ attr = {}
+ attr = {
+ 'tenantId': fake_project.id,
+ }
+ fake_user = identity_fakes.FakeUser.create_one_user(attr)
+
+ def setUp(self):
+ super(TestRole, self).setUp()
+
+ # Get a shortcut to the TenantManager Mock
+ self.projects_mock = self.app.client_manager.identity.tenants
+ self.projects_mock.reset_mock()
+
+ # Get a shortcut to the UserManager Mock
+ self.users_mock = self.app.client_manager.identity.users
+ self.users_mock.reset_mock()
+
+ # Get a shortcut to the RoleManager Mock
+ self.roles_mock = self.app.client_manager.identity.roles
+ self.roles_mock.reset_mock()
+
+ auth_ref = identity_fakes.fake_auth_ref(
+ identity_fakes.TOKEN,
+ fake_service=self.fake_service,
+ )
+ self.ar_mock = mock.PropertyMock(return_value=auth_ref)
+ type(self.app.client_manager).auth_ref = self.ar_mock
+
+
+class TestRoleAdd(TestRole):
+
+ def setUp(self):
+ super(TestRoleAdd, self).setUp()
+
+ self.projects_mock.get.return_value = self.fake_project
+
+ self.users_mock.get.return_value = self.fake_user
+
+ self.roles_mock.get.return_value = self.fake_role
+ self.roles_mock.add_user_role.return_value = self.fake_role
+
+ # Get the command object to test
+ self.cmd = role.AddRole(self.app, None)
+
+ def test_role_add(self):
+ arglist = [
+ '--project', self.fake_project.name,
+ '--user', self.fake_user.name,
+ self.fake_role.name,
+ ]
+ verifylist = [
+ ('project', self.fake_project.name),
+ ('user', self.fake_user.name),
+ ('role', self.fake_role.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # RoleManager.add_user_role(user, role, tenant=None)
+ self.roles_mock.add_user_role.assert_called_with(
+ self.fake_user.id,
+ self.fake_role.id,
+ self.fake_project.id,
+ )
+
+ collist = ('id', 'name')
+ self.assertEqual(collist, columns)
+ datalist = (
+ self.fake_role.id,
+ self.fake_role.name,
+ )
+ self.assertEqual(datalist, data)
+
+
+class TestRoleCreate(TestRole):
+
+ fake_role_c = identity_fakes.FakeRole.create_one_role()
+ columns = (
+ 'id',
+ 'name'
+ )
+ datalist = (
+ fake_role_c.id,
+ fake_role_c.name,
+ )
+
+ def setUp(self):
+ super(TestRoleCreate, self).setUp()
+
+ self.roles_mock.create.return_value = self.fake_role_c
+
+ # Get the command object to test
+ self.cmd = role.CreateRole(self.app, None)
+
+ def test_role_create_no_options(self):
+ arglist = [
+ self.fake_role_c.name,
+ ]
+ verifylist = [
+ ('role_name', self.fake_role_c.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # RoleManager.create(name)
+ self.roles_mock.create.assert_called_with(
+ self.fake_role_c.name,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_role_create_or_show_exists(self):
+ def _raise_conflict(*args, **kwargs):
+ raise ks_exc.Conflict(None)
+
+ # need to make this throw an exception...
+ self.roles_mock.create.side_effect = _raise_conflict
+
+ self.roles_mock.get.return_value = self.fake_role_c
+
+ arglist = [
+ '--or-show',
+ self.fake_role_c.name,
+ ]
+ verifylist = [
+ ('role_name', self.fake_role_c.name),
+ ('or_show', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # RoleManager.get(name, description, enabled)
+ self.roles_mock.get.assert_called_with(self.fake_role_c.name)
+
+ # RoleManager.create(name)
+ self.roles_mock.create.assert_called_with(
+ self.fake_role_c.name,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_role_create_or_show_not_exists(self):
+ arglist = [
+ '--or-show',
+ self.fake_role_c.name,
+ ]
+ verifylist = [
+ ('role_name', self.fake_role_c.name),
+ ('or_show', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # RoleManager.create(name)
+ self.roles_mock.create.assert_called_with(
+ self.fake_role_c.name,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+
+class TestRoleDelete(TestRole):
+
+ def setUp(self):
+ super(TestRoleDelete, self).setUp()
+
+ self.roles_mock.get.return_value = self.fake_role
+ self.roles_mock.delete.return_value = None
+
+ # Get the command object to test
+ self.cmd = role.DeleteRole(self.app, None)
+
+ def test_role_delete_no_options(self):
+ arglist = [
+ self.fake_role.name,
+ ]
+ verifylist = [
+ ('roles', [self.fake_role.name]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.roles_mock.delete.assert_called_with(
+ self.fake_role.id,
+ )
+ self.assertIsNone(result)
+
+
+class TestRoleList(TestRole):
+
+ def setUp(self):
+ super(TestRoleList, self).setUp()
+
+ self.roles_mock.list.return_value = [self.fake_role]
+
+ # Get the command object to test
+ self.cmd = role.ListRole(self.app, None)
+
+ def test_role_list_no_options(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.roles_mock.list.assert_called_with()
+
+ collist = ('ID', 'Name')
+ self.assertEqual(collist, columns)
+ datalist = ((
+ self.fake_role.id,
+ self.fake_role.name,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+
+class TestUserRoleList(TestRole):
+
+ columns = (
+ 'ID',
+ 'Name',
+ 'Project',
+ 'User'
+ )
+
+ def setUp(self):
+ super(TestUserRoleList, self).setUp()
+
+ self.projects_mock.get.return_value = self.fake_project
+
+ self.users_mock.get.return_value = self.fake_user
+
+ self.roles_mock.roles_for_user.return_value = [self.fake_role]
+
+ # Get the command object to test
+ self.cmd = role.ListUserRole(self.app, None)
+
+ def test_user_role_list_no_options_unscoped_token(self):
+ auth_ref = identity_fakes.fake_auth_ref(
+ identity_fakes.UNSCOPED_TOKEN,
+ fake_service=self.fake_service,
+ )
+ self.ar_mock = mock.PropertyMock(return_value=auth_ref)
+ type(self.app.client_manager).auth_ref = self.ar_mock
+
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # This argument combination should raise a CommandError
+ self.assertRaises(
+ exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args,
+ )
+
+ def test_user_role_list_no_options_scoped_token(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.roles_mock.roles_for_user.assert_called_with(
+ self.fake_user.id,
+ self.fake_project.id,
+ )
+
+ collist = ('ID', 'Name', 'Project', 'User')
+ self.assertEqual(collist, columns)
+ datalist = ((
+ self.fake_role.id,
+ self.fake_role.name,
+ self.fake_project.name,
+ self.fake_user.name,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_user_role_list_project_unscoped_token(self):
+ auth_ref = identity_fakes.fake_auth_ref(
+ identity_fakes.UNSCOPED_TOKEN,
+ fake_service=self.fake_service,
+ )
+ self.ar_mock = mock.PropertyMock(return_value=auth_ref)
+ type(self.app.client_manager).auth_ref = self.ar_mock
+
+ self.projects_mock.get.return_value = self.fake_project
+ arglist = [
+ '--project', self.fake_project.name,
+ ]
+ verifylist = [
+ ('project', self.fake_project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.roles_mock.roles_for_user.assert_called_with(
+ self.fake_user.id,
+ self.fake_project.id,
+ )
+
+ self.assertEqual(columns, columns)
+ datalist = ((
+ self.fake_role.id,
+ self.fake_role.name,
+ self.fake_project.name,
+ self.fake_user.name,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_user_role_list_project_scoped_token(self):
+ self.projects_mock.get.return_value = self.fake_project
+ arglist = [
+ '--project', self.fake_project.name,
+ ]
+ verifylist = [
+ ('project', self.fake_project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.roles_mock.roles_for_user.assert_called_with(
+ self.fake_user.id,
+ self.fake_project.id,
+ )
+
+ self.assertEqual(columns, columns)
+ datalist = ((
+ self.fake_role.id,
+ self.fake_role.name,
+ self.fake_project.name,
+ self.fake_user.name,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+
+class TestRoleRemove(TestRole):
+
+ def setUp(self):
+ super(TestRoleRemove, self).setUp()
+
+ self.projects_mock.get.return_value = self.fake_project
+
+ self.users_mock.get.return_value = self.fake_user
+
+ self.roles_mock.get.return_value = self.fake_role
+ self.roles_mock.remove_user_role.return_value = None
+
+ # Get the command object to test
+ self.cmd = role.RemoveRole(self.app, None)
+
+ def test_role_remove(self):
+ arglist = [
+ '--project', self.fake_project.name,
+ '--user', self.fake_user.name,
+ self.fake_role.name,
+ ]
+ verifylist = [
+ ('role', self.fake_role.name),
+ ('project', self.fake_project.name),
+ ('user', self.fake_user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # RoleManager.remove_user_role(user, role, tenant=None)
+ self.roles_mock.remove_user_role.assert_called_with(
+ self.fake_user.id,
+ self.fake_role.id,
+ self.fake_project.id,
+ )
+ self.assertIsNone(result)
+
+
+class TestRoleShow(TestRole):
+
+ def setUp(self):
+ super(TestRoleShow, self).setUp()
+
+ self.roles_mock.get.return_value = self.fake_role
+
+ # Get the command object to test
+ self.cmd = role.ShowRole(self.app, None)
+
+ def test_service_show(self):
+ arglist = [
+ self.fake_role.name,
+ ]
+ verifylist = [
+ ('role', self.fake_role.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # RoleManager.get(role)
+ self.roles_mock.get.assert_called_with(
+ self.fake_role.name,
+ )
+
+ collist = ('id', 'name')
+ self.assertEqual(collist, columns)
+ datalist = (
+ self.fake_role.id,
+ self.fake_role.name,
+ )
+ self.assertEqual(datalist, data)
diff --git a/openstackclient/tests/unit/identity/v2_0/test_role_assignment.py b/openstackclient/tests/unit/identity/v2_0/test_role_assignment.py
new file mode 100644
index 00000000..27306959
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v2_0/test_role_assignment.py
@@ -0,0 +1,271 @@
+# 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.
+#
+
+import copy
+import mock
+
+from osc_lib import exceptions
+
+from openstackclient.identity.v2_0 import role_assignment
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit.identity.v2_0 import fakes as identity_fakes
+
+
+class TestRoleAssignment(identity_fakes.TestIdentityv2):
+
+ def setUp(self):
+ super(TestRoleAssignment, self).setUp()
+
+
+class TestRoleAssignmentList(TestRoleAssignment):
+
+ columns = (
+ 'Role',
+ 'User',
+ 'Project',
+ )
+
+ def setUp(self):
+ super(TestRoleAssignment, self).setUp()
+
+ # Get a shortcut to the UserManager Mock
+ self.users_mock = self.app.client_manager.identity.users
+ self.users_mock.reset_mock()
+
+ # Get a shortcut to the ProjectManager Mock
+ self.projects_mock = self.app.client_manager.identity.projects
+ self.projects_mock.reset_mock()
+
+ # Get a shortcut to the RoleManager Mock
+ self.roles_mock = self.app.client_manager.identity.roles
+ self.roles_mock.reset_mock()
+
+ self.projects_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.PROJECT),
+ loaded=True,
+ )
+
+ self.users_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.USER),
+ loaded=True,
+ )
+
+ self.roles_mock.roles_for_user.return_value = [
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.ROLE),
+ loaded=True,
+ ),
+ ]
+
+ # Get the command object to test
+ self.cmd = role_assignment.ListRoleAssignment(self.app, None)
+
+ def test_role_assignment_list_no_filters(self):
+
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # This argument combination should raise a CommandError
+ self.assertRaises(
+ exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args,
+ )
+
+ def test_role_assignment_list_only_project_filter(self):
+
+ arglist = [
+ '--project', identity_fakes.project_name,
+ ]
+ verifylist = [
+ ('project', identity_fakes.project_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # This argument combination should raise a CommandError
+ self.assertRaises(
+ exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args,
+ )
+
+ def test_role_assignment_list_only_user_filter(self):
+
+ arglist = [
+ '--user', identity_fakes.user_name,
+ ]
+ verifylist = [
+ ('user', identity_fakes.user_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # This argument combination should raise a CommandError
+ self.assertRaises(
+ exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args,
+ )
+
+ def test_role_assignment_list_project_and_user(self):
+
+ self.roles_mock.roles_for_user.return_value = [
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(
+ identity_fakes.ROLE),
+ loaded=True,
+ ),
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(
+ identity_fakes.ROLE_2),
+ loaded=True,
+ ),
+ ]
+
+ arglist = [
+ '--project', identity_fakes.project_name,
+ '--user', identity_fakes.user_name,
+ ]
+ verifylist = [
+ ('user', identity_fakes.user_name),
+ ('project', identity_fakes.project_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.roles_mock.roles_for_user.assert_called_with(
+ identity_fakes.user_id,
+ identity_fakes.project_id,
+ )
+
+ self.assertEqual(self.columns, columns)
+ datalist = ((
+ identity_fakes.role_id,
+ identity_fakes.user_id,
+ identity_fakes.project_id,
+ ), (identity_fakes.ROLE_2['id'],
+ identity_fakes.user_id,
+ identity_fakes.project_id,
+ ),)
+ self.assertEqual(datalist, tuple(data))
+
+ def test_role_assignment_list_def_creds(self):
+
+ auth_ref = self.app.client_manager.auth_ref = mock.MagicMock()
+ auth_ref.project_id.return_value = identity_fakes.project_id
+ auth_ref.user_id.return_value = identity_fakes.user_id
+
+ self.roles_mock.roles_for_user.return_value = [
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(
+ identity_fakes.ROLE),
+ loaded=True,
+ ),
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(
+ identity_fakes.ROLE_2),
+ loaded=True,
+ ),
+ ]
+
+ arglist = [
+ '--auth-user',
+ '--auth-project',
+ ]
+ verifylist = [
+ ('authuser', True),
+ ('authproject', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.roles_mock.roles_for_user.assert_called_with(
+ identity_fakes.user_id,
+ identity_fakes.project_id,
+ )
+
+ self.assertEqual(self.columns, columns)
+ datalist = ((
+ identity_fakes.role_id,
+ identity_fakes.user_id,
+ identity_fakes.project_id,
+ ), (identity_fakes.ROLE_2['id'],
+ identity_fakes.user_id,
+ identity_fakes.project_id,
+ ),)
+ self.assertEqual(datalist, tuple(data))
+
+ def test_role_assignment_list_by_name_project_and_user(self):
+
+ self.roles_mock.roles_for_user.return_value = [
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(
+ identity_fakes.ROLE),
+ loaded=True,
+ ),
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(
+ identity_fakes.ROLE_2),
+ loaded=True,
+ ),
+ ]
+
+ arglist = [
+ '--project', identity_fakes.project_name,
+ '--user', identity_fakes.user_name,
+ '--names'
+ ]
+ verifylist = [
+ ('user', identity_fakes.user_name),
+ ('project', identity_fakes.project_name),
+ ('names', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.roles_mock.roles_for_user.assert_called_with(
+ identity_fakes.user_id,
+ identity_fakes.project_id,
+ )
+
+ self.assertEqual(self.columns, columns)
+ datalist = ((
+ identity_fakes.role_name,
+ identity_fakes.user_name,
+ identity_fakes.project_name,
+ ), (identity_fakes.ROLE_2['name'],
+ identity_fakes.user_name,
+ identity_fakes.project_name,
+ ),)
+ self.assertEqual(datalist, tuple(data))
diff --git a/openstackclient/tests/unit/identity/v2_0/test_service.py b/openstackclient/tests/unit/identity/v2_0/test_service.py
new file mode 100644
index 00000000..1948bf4a
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v2_0/test_service.py
@@ -0,0 +1,316 @@
+# Copyright 2013 Nebula Inc.
+#
+# 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 keystoneclient import exceptions as identity_exc
+from osc_lib import exceptions
+
+from openstackclient.identity.v2_0 import service
+from openstackclient.tests.unit.identity.v2_0 import fakes as identity_fakes
+
+
+class TestService(identity_fakes.TestIdentityv2):
+ fake_service = identity_fakes.FakeService.create_one_service()
+
+ def setUp(self):
+ super(TestService, self).setUp()
+
+ # Get a shortcut to the ServiceManager Mock
+ self.services_mock = self.app.client_manager.identity.services
+ self.services_mock.reset_mock()
+
+
+class TestServiceCreate(TestService):
+
+ fake_service_c = identity_fakes.FakeService.create_one_service()
+ columns = (
+ 'description',
+ 'id',
+ 'name',
+ 'type',
+ )
+ datalist = (
+ fake_service_c.description,
+ fake_service_c.id,
+ fake_service_c.name,
+ fake_service_c.type,
+ )
+
+ def setUp(self):
+ super(TestServiceCreate, self).setUp()
+
+ self.services_mock.create.return_value = self.fake_service_c
+
+ # Get the command object to test
+ self.cmd = service.CreateService(self.app, None)
+
+ def test_service_create_with_type_positional(self):
+ arglist = [
+ self.fake_service_c.type,
+ ]
+ verifylist = [
+ ('type_or_name', self.fake_service_c.type),
+ ('type', None),
+ ('description', None),
+ ('name', None),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # ServiceManager.create(name, service_type, description)
+ self.services_mock.create.assert_called_with(
+ None,
+ self.fake_service_c.type,
+ None,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_service_create_with_type_option(self):
+ arglist = [
+ '--type', self.fake_service_c.type,
+ self.fake_service_c.name,
+ ]
+ verifylist = [
+ ('type_or_name', self.fake_service_c.name),
+ ('type', self.fake_service_c.type),
+ ('description', None),
+ ('name', None),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # ServiceManager.create(name, service_type, description)
+ self.services_mock.create.assert_called_with(
+ self.fake_service_c.name,
+ self.fake_service_c.type,
+ None,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_service_create_with_name_option(self):
+ arglist = [
+ '--name', self.fake_service_c.name,
+ self.fake_service_c.type,
+ ]
+ verifylist = [
+ ('type_or_name', self.fake_service_c.type),
+ ('type', None),
+ ('description', None),
+ ('name', self.fake_service_c.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # ServiceManager.create(name, service_type, description)
+ self.services_mock.create.assert_called_with(
+ self.fake_service_c.name,
+ self.fake_service_c.type,
+ None,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_service_create_description(self):
+ arglist = [
+ '--name', self.fake_service_c.name,
+ '--description', self.fake_service_c.description,
+ self.fake_service_c.type,
+ ]
+ verifylist = [
+ ('type_or_name', self.fake_service_c.type),
+ ('type', None),
+ ('description', self.fake_service_c.description),
+ ('name', self.fake_service_c.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # ServiceManager.create(name, service_type, description)
+ self.services_mock.create.assert_called_with(
+ self.fake_service_c.name,
+ self.fake_service_c.type,
+ self.fake_service_c.description,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+
+class TestServiceDelete(TestService):
+
+ def setUp(self):
+ super(TestServiceDelete, self).setUp()
+
+ self.services_mock.get.side_effect = identity_exc.NotFound(None)
+ self.services_mock.find.return_value = self.fake_service
+ self.services_mock.delete.return_value = None
+
+ # Get the command object to test
+ self.cmd = service.DeleteService(self.app, None)
+
+ def test_service_delete_no_options(self):
+ arglist = [
+ self.fake_service.name,
+ ]
+ verifylist = [
+ ('services', [self.fake_service.name]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.services_mock.delete.assert_called_with(
+ self.fake_service.id,
+ )
+ self.assertIsNone(result)
+
+
+class TestServiceList(TestService):
+
+ def setUp(self):
+ super(TestServiceList, self).setUp()
+
+ self.services_mock.list.return_value = [self.fake_service]
+
+ # Get the command object to test
+ self.cmd = service.ListService(self.app, None)
+
+ def test_service_list_no_options(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.services_mock.list.assert_called_with()
+
+ collist = ('ID', 'Name', 'Type')
+ self.assertEqual(collist, columns)
+ datalist = ((
+ self.fake_service.id,
+ self.fake_service.name,
+ self.fake_service.type,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_service_list_long(self):
+ arglist = [
+ '--long',
+ ]
+ verifylist = [
+ ('long', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.services_mock.list.assert_called_with()
+
+ collist = ('ID', 'Name', 'Type', 'Description')
+ self.assertEqual(collist, columns)
+ datalist = ((
+ self.fake_service.id,
+ self.fake_service.name,
+ self.fake_service.type,
+ self.fake_service.description,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+
+class TestServiceShow(TestService):
+
+ fake_service_s = identity_fakes.FakeService.create_one_service()
+
+ def setUp(self):
+ super(TestServiceShow, self).setUp()
+
+ self.services_mock.get.side_effect = identity_exc.NotFound(None)
+ self.services_mock.find.return_value = self.fake_service_s
+
+ # Get the command object to test
+ self.cmd = service.ShowService(self.app, None)
+
+ def test_service_show(self):
+ arglist = [
+ self.fake_service_s.name,
+ ]
+ verifylist = [
+ ('service', self.fake_service_s.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # ServiceManager.find(id)
+ self.services_mock.find.assert_called_with(
+ name=self.fake_service_s.name,
+ )
+
+ collist = ('description', 'id', 'name', 'type')
+ self.assertEqual(collist, columns)
+ datalist = (
+ self.fake_service_s.description,
+ self.fake_service_s.id,
+ self.fake_service_s.name,
+ self.fake_service_s.type,
+ )
+ self.assertEqual(datalist, data)
+
+ def test_service_show_nounique(self):
+ self.services_mock.find.side_effect = identity_exc.NoUniqueMatch(None)
+ arglist = [
+ 'nounique_service',
+ ]
+ verifylist = [
+ ('service', 'nounique_service'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual(
+ "Multiple service matches found for 'nounique_service',"
+ " use an ID to be more specific.", str(e))
diff --git a/openstackclient/tests/unit/identity/v2_0/test_token.py b/openstackclient/tests/unit/identity/v2_0/test_token.py
new file mode 100644
index 00000000..dd7f4f4a
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v2_0/test_token.py
@@ -0,0 +1,115 @@
+# Copyright 2014 eBay Inc.
+#
+# 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.
+#
+
+import mock
+
+from openstackclient.identity.v2_0 import token
+from openstackclient.tests.unit.identity.v2_0 import fakes as identity_fakes
+
+
+class TestToken(identity_fakes.TestIdentityv2):
+
+ fake_user = identity_fakes.FakeUser.create_one_user()
+ fake_project = identity_fakes.FakeProject.create_one_project()
+
+ def setUp(self):
+ super(TestToken, self).setUp()
+
+ # Get a shortcut to the Auth Ref Mock
+ self.ar_mock = mock.PropertyMock()
+ type(self.app.client_manager).auth_ref = self.ar_mock
+
+
+class TestTokenIssue(TestToken):
+
+ def setUp(self):
+ super(TestTokenIssue, self).setUp()
+
+ self.cmd = token.IssueToken(self.app, None)
+
+ def test_token_issue(self):
+ auth_ref = identity_fakes.fake_auth_ref(
+ identity_fakes.TOKEN,
+ )
+ self.ar_mock = mock.PropertyMock(return_value=auth_ref)
+ type(self.app.client_manager).auth_ref = self.ar_mock
+
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ collist = ('expires', 'id', 'project_id', 'user_id')
+ self.assertEqual(collist, columns)
+ datalist = (
+ identity_fakes.token_expires,
+ identity_fakes.token_id,
+ 'project-id',
+ 'user-id',
+ )
+ self.assertEqual(datalist, data)
+
+ def test_token_issue_with_unscoped_token(self):
+ auth_ref = identity_fakes.fake_auth_ref(
+ identity_fakes.UNSCOPED_TOKEN,
+ )
+ self.ar_mock = mock.PropertyMock(return_value=auth_ref)
+ type(self.app.client_manager).auth_ref = self.ar_mock
+
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # DisplayCommandBase.take_action() returns two tuples
+ columns, data = self.cmd.take_action(parsed_args)
+
+ collist = (
+ 'expires',
+ 'id',
+ 'user_id',
+ )
+ self.assertEqual(collist, columns)
+ datalist = (
+ identity_fakes.token_expires,
+ identity_fakes.token_id,
+ 'user-id',
+ )
+ self.assertEqual(datalist, data)
+
+
+class TestTokenRevoke(TestToken):
+
+ TOKEN = 'fob'
+
+ def setUp(self):
+ super(TestTokenRevoke, self).setUp()
+ self.tokens_mock = self.app.client_manager.identity.tokens
+ self.tokens_mock.reset_mock()
+ self.tokens_mock.delete.return_value = True
+ self.cmd = token.RevokeToken(self.app, None)
+
+ def test_token_revoke(self):
+ arglist = [self.TOKEN]
+ verifylist = [('token', self.TOKEN)]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.tokens_mock.delete.assert_called_with(self.TOKEN)
+ self.assertIsNone(result)
diff --git a/openstackclient/tests/unit/identity/v2_0/test_user.py b/openstackclient/tests/unit/identity/v2_0/test_user.py
new file mode 100644
index 00000000..765f8559
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v2_0/test_user.py
@@ -0,0 +1,793 @@
+# Copyright 2013 Nebula Inc.
+#
+# 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.
+#
+
+import mock
+
+from keystoneauth1 import exceptions as ks_exc
+from osc_lib import exceptions
+
+from openstackclient.identity.v2_0 import user
+from openstackclient.tests.unit.identity.v2_0 import fakes as identity_fakes
+
+
+class TestUser(identity_fakes.TestIdentityv2):
+
+ fake_project = identity_fakes.FakeProject.create_one_project()
+ attr = {
+ 'tenantId': fake_project.id,
+ }
+ fake_user = identity_fakes.FakeUser.create_one_user(attr)
+
+ def setUp(self):
+ super(TestUser, self).setUp()
+
+ # Get a shortcut to the TenantManager Mock
+ self.projects_mock = self.app.client_manager.identity.tenants
+ self.projects_mock.reset_mock()
+
+ # Get a shortcut to the UserManager Mock
+ self.users_mock = self.app.client_manager.identity.users
+ self.users_mock.reset_mock()
+
+
+class TestUserCreate(TestUser):
+
+ fake_project_c = identity_fakes.FakeProject.create_one_project()
+ attr = {
+ 'tenantId': fake_project_c.id,
+ }
+ fake_user_c = identity_fakes.FakeUser.create_one_user(attr)
+
+ columns = (
+ 'email',
+ 'enabled',
+ 'id',
+ 'name',
+ 'project_id',
+ )
+ datalist = (
+ fake_user_c.email,
+ True,
+ fake_user_c.id,
+ fake_user_c.name,
+ fake_project_c.id,
+ )
+
+ def setUp(self):
+ super(TestUserCreate, self).setUp()
+
+ self.projects_mock.get.return_value = self.fake_project_c
+
+ self.users_mock.create.return_value = self.fake_user_c
+
+ # Get the command object to test
+ self.cmd = user.CreateUser(self.app, None)
+
+ def test_user_create_no_options(self):
+ arglist = [
+ self.fake_user_c.name,
+ ]
+ verifylist = [
+ ('enable', False),
+ ('disable', False),
+ ('name', self.fake_user_c.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': True,
+ 'tenant_id': None,
+ }
+ # UserManager.create(name, password, email, tenant_id=, enabled=)
+ self.users_mock.create.assert_called_with(
+ self.fake_user_c.name,
+ None,
+ None,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_user_create_password(self):
+ arglist = [
+ '--password', 'secret',
+ self.fake_user_c.name,
+ ]
+ verifylist = [
+ ('name', self.fake_user_c.name),
+ ('password_prompt', False),
+ ('password', 'secret')
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': True,
+ 'tenant_id': None,
+ }
+ # UserManager.create(name, password, email, tenant_id=, enabled=)
+ self.users_mock.create.assert_called_with(
+ self.fake_user_c.name,
+ 'secret',
+ None,
+ **kwargs
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_user_create_password_prompt(self):
+ arglist = [
+ '--password-prompt',
+ self.fake_user_c.name,
+ ]
+ verifylist = [
+ ('name', self.fake_user_c.name),
+ ('password_prompt', True)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ mocker = mock.Mock()
+ mocker.return_value = 'abc123'
+ with mock.patch("osc_lib.utils.get_password", mocker):
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': True,
+ 'tenant_id': None,
+ }
+ # UserManager.create(name, password, email, tenant_id=, enabled=)
+ self.users_mock.create.assert_called_with(
+ self.fake_user_c.name,
+ 'abc123',
+ None,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_user_create_email(self):
+ arglist = [
+ '--email', 'barney@example.com',
+ self.fake_user_c.name,
+ ]
+ verifylist = [
+ ('name', self.fake_user_c.name),
+ ('email', 'barney@example.com'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': True,
+ 'tenant_id': None,
+ }
+ # UserManager.create(name, password, email, tenant_id=, enabled=)
+ self.users_mock.create.assert_called_with(
+ self.fake_user_c.name,
+ None,
+ 'barney@example.com',
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_user_create_project(self):
+ # Return the new project
+ self.projects_mock.get.return_value = self.fake_project_c
+
+ # Set up to return an updated user
+ attr = {
+ 'tenantId': self.fake_project_c.id,
+ }
+ user_2 = identity_fakes.FakeUser.create_one_user(attr)
+ self.users_mock.create.return_value = user_2
+
+ arglist = [
+ '--project', self.fake_project_c.name,
+ user_2.name,
+ ]
+ verifylist = [
+ ('name', user_2.name),
+ ('project', self.fake_project_c.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': True,
+ 'tenant_id': self.fake_project_c.id,
+ }
+ # UserManager.create(name, password, email, tenant_id=, enabled=)
+ self.users_mock.create.assert_called_with(
+ user_2.name,
+ None,
+ None,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ datalist = (
+ user_2.email,
+ True,
+ user_2.id,
+ user_2.name,
+ self.fake_project_c.id,
+ )
+ self.assertEqual(datalist, data)
+
+ def test_user_create_enable(self):
+ arglist = [
+ '--enable',
+ self.fake_user_c.name,
+ ]
+ verifylist = [
+ ('name', self.fake_user_c.name),
+ ('enable', True),
+ ('disable', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': True,
+ 'tenant_id': None,
+ }
+ # UserManager.create(name, password, email, tenant_id=, enabled=)
+ self.users_mock.create.assert_called_with(
+ self.fake_user_c.name,
+ None,
+ None,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_user_create_disable(self):
+ arglist = [
+ '--disable',
+ self.fake_user_c.name,
+ ]
+ verifylist = [
+ ('name', self.fake_user_c.name),
+ ('enable', False),
+ ('disable', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': False,
+ 'tenant_id': None,
+ }
+ # UserManager.create(name, password, email, tenant_id=, enabled=)
+ self.users_mock.create.assert_called_with(
+ self.fake_user_c.name,
+ None,
+ None,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_user_create_or_show_exists(self):
+ def _raise_conflict(*args, **kwargs):
+ raise ks_exc.Conflict(None)
+
+ # need to make this throw an exception...
+ self.users_mock.create.side_effect = _raise_conflict
+
+ self.users_mock.get.return_value = self.fake_user_c
+
+ arglist = [
+ '--or-show',
+ self.fake_user_c.name,
+ ]
+ verifylist = [
+ ('name', self.fake_user_c.name),
+ ('or_show', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # UserManager.create(name, password, email, tenant_id=, enabled=)
+ self.users_mock.get.assert_called_with(self.fake_user_c.name)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_user_create_or_show_not_exists(self):
+ arglist = [
+ '--or-show',
+ self.fake_user_c.name,
+ ]
+ verifylist = [
+ ('name', self.fake_user_c.name),
+ ('or_show', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': True,
+ 'tenant_id': None,
+ }
+ # UserManager.create(name, password, email, tenant_id=, enabled=)
+ self.users_mock.create.assert_called_with(
+ self.fake_user_c.name,
+ None,
+ None,
+ **kwargs
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+
+class TestUserDelete(TestUser):
+
+ def setUp(self):
+ super(TestUserDelete, self).setUp()
+
+ # This is the return value for utils.find_resource()
+ self.users_mock.get.return_value = self.fake_user
+ self.users_mock.delete.return_value = None
+
+ # Get the command object to test
+ self.cmd = user.DeleteUser(self.app, None)
+
+ def test_user_delete_no_options(self):
+ arglist = [
+ self.fake_user.id,
+ ]
+ verifylist = [
+ ('users', [self.fake_user.id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.users_mock.delete.assert_called_with(
+ self.fake_user.id,
+ )
+ self.assertIsNone(result)
+
+
+class TestUserList(TestUser):
+
+ fake_project_l = identity_fakes.FakeProject.create_one_project()
+ attr = {
+ 'tenantId': fake_project_l.id,
+ }
+ fake_user_l = identity_fakes.FakeUser.create_one_user(attr)
+
+ columns = (
+ 'ID',
+ 'Name',
+ )
+ datalist = (
+ (
+ fake_user_l.id,
+ fake_user_l.name,
+ ),
+ )
+
+ def setUp(self):
+ super(TestUserList, self).setUp()
+
+ self.projects_mock.get.return_value = self.fake_project_l
+ self.projects_mock.list.return_value = [self.fake_project_l]
+
+ self.users_mock.list.return_value = [self.fake_user_l]
+
+ # Get the command object to test
+ self.cmd = user.ListUser(self.app, None)
+
+ def test_user_list_no_options(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.users_mock.list.assert_called_with(tenant_id=None)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_user_list_project(self):
+ arglist = [
+ '--project', self.fake_project_l.id,
+ ]
+ verifylist = [
+ ('project', self.fake_project_l.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ project_id = self.fake_project_l.id
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.users_mock.list.assert_called_with(tenant_id=project_id)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_user_list_long(self):
+ arglist = [
+ '--long',
+ ]
+ verifylist = [
+ ('long', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.users_mock.list.assert_called_with(tenant_id=None)
+
+ collist = ('ID', 'Name', 'Project', 'Email', 'Enabled')
+ self.assertEqual(collist, columns)
+ datalist = ((
+ self.fake_user_l.id,
+ self.fake_user_l.name,
+ self.fake_project_l.name,
+ self.fake_user_l.email,
+ True,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+
+class TestUserSet(TestUser):
+
+ def setUp(self):
+ super(TestUserSet, self).setUp()
+
+ self.projects_mock.get.return_value = self.fake_project
+ self.users_mock.get.return_value = self.fake_user
+
+ # Get the command object to test
+ self.cmd = user.SetUser(self.app, None)
+
+ def test_user_set_no_options(self):
+ arglist = [
+ self.fake_user.name,
+ ]
+ verifylist = [
+ ('name', None),
+ ('password', None),
+ ('email', None),
+ ('project', None),
+ ('enable', False),
+ ('disable', False),
+ ('user', self.fake_user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.assertIsNone(result)
+
+ def test_user_set_unexist_user(self):
+ arglist = [
+ "unexist-user",
+ ]
+ verifylist = [
+ ('name', None),
+ ('password', None),
+ ('email', None),
+ ('project', None),
+ ('enable', False),
+ ('disable', False),
+ ('user', "unexist-user"),
+ ]
+ self.users_mock.get.side_effect = exceptions.NotFound(None)
+ self.users_mock.find.side_effect = exceptions.NotFound(None)
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(
+ exceptions.CommandError, self.cmd.take_action, parsed_args)
+
+ def test_user_set_name(self):
+ arglist = [
+ '--name', 'qwerty',
+ self.fake_user.name,
+ ]
+ verifylist = [
+ ('name', 'qwerty'),
+ ('password', None),
+ ('email', None),
+ ('project', None),
+ ('enable', False),
+ ('disable', False),
+ ('user', self.fake_user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': True,
+ 'name': 'qwerty',
+ }
+ # UserManager.update(user, **kwargs)
+ self.users_mock.update.assert_called_with(
+ self.fake_user.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_user_set_password(self):
+ arglist = [
+ '--password', 'secret',
+ self.fake_user.name,
+ ]
+ verifylist = [
+ ('name', None),
+ ('password', 'secret'),
+ ('password_prompt', False),
+ ('email', None),
+ ('project', None),
+ ('enable', False),
+ ('disable', False),
+ ('user', self.fake_user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # UserManager.update_password(user, password)
+ self.users_mock.update_password.assert_called_with(
+ self.fake_user.id,
+ 'secret',
+ )
+ self.assertIsNone(result)
+
+ def test_user_set_password_prompt(self):
+ arglist = [
+ '--password-prompt',
+ self.fake_user.name,
+ ]
+ verifylist = [
+ ('name', None),
+ ('password', None),
+ ('password_prompt', True),
+ ('email', None),
+ ('project', None),
+ ('enable', False),
+ ('disable', False),
+ ('user', self.fake_user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ mocker = mock.Mock()
+ mocker.return_value = 'abc123'
+ with mock.patch("osc_lib.utils.get_password", mocker):
+ result = self.cmd.take_action(parsed_args)
+
+ # UserManager.update_password(user, password)
+ self.users_mock.update_password.assert_called_with(
+ self.fake_user.id,
+ 'abc123',
+ )
+ self.assertIsNone(result)
+
+ def test_user_set_email(self):
+ arglist = [
+ '--email', 'barney@example.com',
+ self.fake_user.name,
+ ]
+ verifylist = [
+ ('name', None),
+ ('password', None),
+ ('email', 'barney@example.com'),
+ ('project', None),
+ ('enable', False),
+ ('disable', False),
+ ('user', self.fake_user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'email': 'barney@example.com',
+ 'enabled': True,
+ }
+ # UserManager.update(user, **kwargs)
+ self.users_mock.update.assert_called_with(
+ self.fake_user.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_user_set_project(self):
+ arglist = [
+ '--project', self.fake_project.id,
+ self.fake_user.name,
+ ]
+ verifylist = [
+ ('name', None),
+ ('password', None),
+ ('email', None),
+ ('project', self.fake_project.id),
+ ('enable', False),
+ ('disable', False),
+ ('user', self.fake_user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # UserManager.update_tenant(user, tenant)
+ self.users_mock.update_tenant.assert_called_with(
+ self.fake_user.id,
+ self.fake_project.id,
+ )
+ self.assertIsNone(result)
+
+ def test_user_set_enable(self):
+ arglist = [
+ '--enable',
+ self.fake_user.name,
+ ]
+ verifylist = [
+ ('name', None),
+ ('password', None),
+ ('email', None),
+ ('project', None),
+ ('enable', True),
+ ('disable', False),
+ ('user', self.fake_user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': True,
+ }
+ # UserManager.update(user, **kwargs)
+ self.users_mock.update.assert_called_with(
+ self.fake_user.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_user_set_disable(self):
+ arglist = [
+ '--disable',
+ self.fake_user.name,
+ ]
+ verifylist = [
+ ('name', None),
+ ('password', None),
+ ('email', None),
+ ('project', None),
+ ('enable', False),
+ ('disable', True),
+ ('user', self.fake_user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': False,
+ }
+ # UserManager.update(user, **kwargs)
+ self.users_mock.update.assert_called_with(
+ self.fake_user.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+
+class TestUserShow(TestUser):
+
+ def setUp(self):
+ super(TestUserShow, self).setUp()
+
+ self.users_mock.get.return_value = self.fake_user
+
+ # Get the command object to test
+ self.cmd = user.ShowUser(self.app, None)
+
+ def test_user_show(self):
+ arglist = [
+ self.fake_user.id,
+ ]
+ verifylist = [
+ ('user', self.fake_user.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.users_mock.get.assert_called_with(self.fake_user.id)
+
+ collist = ('email', 'enabled', 'id', 'name', 'project_id')
+ self.assertEqual(collist, columns)
+ datalist = (
+ self.fake_user.email,
+ True,
+ self.fake_user.id,
+ self.fake_user.name,
+ self.fake_project.id,
+ )
+ self.assertEqual(datalist, data)
diff --git a/openstackclient/tests/unit/identity/v3/__init__.py b/openstackclient/tests/unit/identity/v3/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v3/__init__.py
diff --git a/openstackclient/tests/unit/identity/v3/fakes.py b/openstackclient/tests/unit/identity/v3/fakes.py
new file mode 100644
index 00000000..7b76fa60
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v3/fakes.py
@@ -0,0 +1,914 @@
+# Copyright 2013 Nebula Inc.
+#
+# 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.
+#
+
+import copy
+import mock
+import uuid
+
+from keystoneauth1 import access
+from keystoneauth1 import fixture
+
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit import utils
+
+base_url = 'http://identity:5000/v3/'
+
+domain_id = 'd1'
+domain_name = 'oftheking'
+domain_description = 'domain description'
+
+DOMAIN = {
+ 'id': domain_id,
+ 'name': domain_name,
+ 'description': domain_description,
+ 'enabled': True,
+ 'links': base_url + 'domains/' + domain_id,
+}
+
+group_id = 'gr-010'
+group_name = 'spencer davis'
+
+GROUP = {
+ 'id': group_id,
+ 'name': group_name,
+ 'links': base_url + 'groups/' + group_id,
+}
+
+mapping_id = 'test_mapping'
+mapping_rules_file_path = '/tmp/path/to/file'
+# Copied from
+# (https://github.com/openstack/keystone/blob\
+# master/keystone/tests/mapping_fixtures.py
+EMPLOYEE_GROUP_ID = "0cd5e9"
+DEVELOPER_GROUP_ID = "xyz"
+MAPPING_RULES = [
+ {
+ "local": [
+ {
+ "group": {
+ "id": EMPLOYEE_GROUP_ID
+ }
+ }
+ ],
+ "remote": [
+ {
+ "type": "orgPersonType",
+ "not_any_of": [
+ "Contractor",
+ "Guest"
+ ]
+ }
+ ]
+ }
+]
+
+MAPPING_RULES_2 = [
+ {
+ "local": [
+ {
+ "group": {
+ "id": DEVELOPER_GROUP_ID
+ }
+ }
+ ],
+ "remote": [
+ {
+ "type": "orgPersonType",
+ "any_one_of": [
+ "Contractor"
+ ]
+ }
+ ]
+ }
+]
+
+
+MAPPING_RESPONSE = {
+ "id": mapping_id,
+ "rules": MAPPING_RULES
+}
+
+MAPPING_RESPONSE_2 = {
+ "id": mapping_id,
+ "rules": MAPPING_RULES_2
+}
+
+project_id = '8-9-64'
+project_name = 'beatles'
+project_description = 'Fab Four'
+
+PROJECT = {
+ 'id': project_id,
+ 'name': project_name,
+ 'description': project_description,
+ 'enabled': True,
+ 'domain_id': domain_id,
+ 'links': base_url + 'projects/' + project_id,
+}
+
+PROJECT_2 = {
+ 'id': project_id + '-2222',
+ 'name': project_name + ' reprise',
+ 'description': project_description + 'plus four more',
+ 'enabled': True,
+ 'domain_id': domain_id,
+ 'links': base_url + 'projects/' + project_id,
+}
+
+region_id = 'region_one'
+region_parent_region_id = 'region_two'
+region_description = 'region one'
+
+REGION = {
+ 'id': region_id,
+ 'description': region_description,
+ 'parent_region_id': region_parent_region_id,
+ 'links': base_url + 'regions/' + region_id,
+}
+
+PROJECT_WITH_PARENT = {
+ 'id': project_id + '-with-parent',
+ 'name': project_name + ' and their parents',
+ 'description': project_description + ' plus another four',
+ 'enabled': True,
+ 'domain_id': domain_id,
+ 'parent_id': project_id,
+ 'links': base_url + 'projects/' + (project_id + '-with-parent'),
+}
+
+PROJECT_WITH_GRANDPARENT = {
+ 'id': project_id + '-with-grandparent',
+ 'name': project_name + ', granny and grandpa',
+ 'description': project_description + ' plus another eight?',
+ 'enabled': True,
+ 'domain_id': domain_id,
+ 'parent_id': PROJECT_WITH_PARENT['id'],
+ 'links': base_url + 'projects/' + (project_id + '-with-grandparent'),
+}
+
+parents = [{'project': PROJECT}]
+grandparents = [{'project': PROJECT}, {'project': PROJECT_WITH_PARENT}]
+ids_for_parents = [PROJECT['id']]
+ids_for_parents_and_grandparents = [PROJECT['id'], PROJECT_WITH_PARENT['id']]
+
+children = [{'project': PROJECT_WITH_GRANDPARENT}]
+ids_for_children = [PROJECT_WITH_GRANDPARENT['id']]
+
+
+role_id = 'r1'
+role_name = 'roller'
+
+ROLE = {
+ 'id': role_id,
+ 'name': role_name,
+ 'domain': None,
+ 'links': base_url + 'roles/' + role_id,
+}
+
+ROLE_2 = {
+ 'id': 'r2',
+ 'name': 'Rolls Royce',
+ 'domain': domain_id,
+ 'links': base_url + 'roles/' + 'r2',
+}
+
+service_id = 's-123'
+service_name = 'Texaco'
+service_type = 'gas'
+service_description = 'oil brand'
+
+SERVICE = {
+ 'id': service_id,
+ 'name': service_name,
+ 'type': service_type,
+ 'description': service_description,
+ 'enabled': True,
+ 'links': base_url + 'services/' + service_id,
+}
+
+SERVICE_WITHOUT_NAME = {
+ 'id': service_id,
+ 'type': service_type,
+ 'description': service_description,
+ 'enabled': True,
+ 'links': base_url + 'services/' + service_id,
+}
+
+endpoint_id = 'e-123'
+endpoint_url = 'http://127.0.0.1:35357'
+endpoint_region = 'RegionOne'
+endpoint_interface = 'admin'
+
+ENDPOINT = {
+ 'id': endpoint_id,
+ 'url': endpoint_url,
+ 'region': endpoint_region,
+ 'interface': endpoint_interface,
+ 'service_id': service_id,
+ 'enabled': True,
+ 'links': base_url + 'endpoints/' + endpoint_id,
+}
+
+user_id = 'bbbbbbb-aaaa-aaaa-aaaa-bbbbbbbaaaa'
+user_name = 'paul'
+user_description = 'Sir Paul'
+user_email = 'paul@applecorps.com'
+
+USER = {
+ 'id': user_id,
+ 'name': user_name,
+ 'default_project_id': project_id,
+ 'email': user_email,
+ 'enabled': True,
+ 'domain_id': domain_id,
+ 'links': base_url + 'users/' + user_id,
+}
+
+trust_id = 't-456'
+trust_expires = None
+trust_impersonation = False
+trust_roles = {"id": role_id, "name": role_name},
+
+TRUST = {
+ 'expires_at': trust_expires,
+ 'id': trust_id,
+ 'impersonation': trust_impersonation,
+ 'links': base_url + 'trusts/' + trust_id,
+ 'project_id': project_id,
+ 'roles': trust_roles,
+ 'trustee_user_id': user_id,
+ 'trustor_user_id': user_id,
+}
+
+token_expires = '2016-09-05T18:04:52+0000'
+token_id = 'tttttttt-tttt-tttt-tttt-tttttttttttt'
+
+UNSCOPED_TOKEN = {
+ 'expires': token_expires,
+ 'id': token_id,
+ 'user_id': user_id,
+}
+
+TOKEN_WITH_PROJECT_ID = {
+ 'expires': token_expires,
+ 'id': token_id,
+ 'project_id': project_id,
+ 'user_id': user_id,
+}
+
+TOKEN_WITH_DOMAIN_ID = {
+ 'expires': token_expires,
+ 'id': token_id,
+ 'domain_id': domain_id,
+ 'user_id': user_id,
+}
+
+idp_id = 'test_idp'
+idp_description = 'super exciting IdP description'
+idp_remote_ids = ['entity1', 'entity2']
+formatted_idp_remote_ids = 'entity1, entity2'
+
+IDENTITY_PROVIDER = {
+ 'id': idp_id,
+ 'remote_ids': idp_remote_ids,
+ 'enabled': True,
+ 'description': idp_description
+}
+
+protocol_id = 'protocol'
+
+mapping_id = 'test_mapping'
+mapping_id_updated = 'prod_mapping'
+
+sp_id = 'BETA'
+sp_description = 'Service Provider to burst into'
+service_provider_url = 'https://beta.example.com/Shibboleth.sso/POST/SAML'
+sp_auth_url = ('https://beta.example.com/v3/OS-FEDERATION/identity_providers/'
+ 'idp/protocol/saml2/auth')
+
+SERVICE_PROVIDER = {
+ 'id': sp_id,
+ 'enabled': True,
+ 'description': sp_description,
+ 'sp_url': service_provider_url,
+ 'auth_url': sp_auth_url
+}
+
+PROTOCOL_ID_MAPPING = {
+ 'id': protocol_id,
+ 'mapping': mapping_id
+}
+
+PROTOCOL_OUTPUT = {
+ 'id': protocol_id,
+ 'mapping_id': mapping_id,
+ 'identity_provider': idp_id
+}
+
+PROTOCOL_OUTPUT_UPDATED = {
+ 'id': protocol_id,
+ 'mapping_id': mapping_id_updated,
+ 'identity_provider': idp_id
+}
+
+# Assignments
+
+ASSIGNMENT_WITH_PROJECT_ID_AND_USER_ID = {
+ 'scope': {'project': {'id': project_id}},
+ 'user': {'id': user_id},
+ 'role': {'id': role_id},
+}
+
+ASSIGNMENT_WITH_PROJECT_ID_AND_USER_ID_INCLUDE_NAMES = {
+ 'scope': {
+ 'project': {
+ 'domain': {'id': domain_id,
+ 'name': domain_name},
+ 'id': project_id,
+ 'name': project_name}},
+ 'user': {
+ 'domain': {'id': domain_id,
+ 'name': domain_name},
+ 'id': user_id,
+ 'name': user_name},
+ 'role': {'id': role_id,
+ 'name': role_name},
+}
+
+ASSIGNMENT_WITH_PROJECT_ID_AND_USER_ID_INHERITED = {
+ 'scope': {'project': {'id': project_id},
+ 'OS-INHERIT:inherited_to': 'projects'},
+ 'user': {'id': user_id},
+ 'role': {'id': role_id},
+}
+
+ASSIGNMENT_WITH_PROJECT_ID_AND_GROUP_ID = {
+ 'scope': {'project': {'id': project_id}},
+ 'group': {'id': group_id},
+ 'role': {'id': role_id},
+}
+
+ASSIGNMENT_WITH_DOMAIN_ID_AND_USER_ID = {
+ 'scope': {'domain': {'id': domain_id}},
+ 'user': {'id': user_id},
+ 'role': {'id': role_id},
+}
+
+ASSIGNMENT_WITH_DOMAIN_ROLE = {
+ 'scope': {'domain': {'id': domain_id}},
+ 'user': {'id': user_id},
+ 'role': {'id': ROLE_2['id']},
+}
+
+ASSIGNMENT_WITH_DOMAIN_ID_AND_USER_ID_INCLUDE_NAMES = {
+ 'scope': {
+ 'domain': {'id': domain_id,
+ 'name': domain_name}},
+ 'user': {
+ 'domain': {'id': domain_id,
+ 'name': domain_name},
+ 'id': user_id,
+ 'name': user_name},
+ 'role': {'id': role_id,
+ 'name': role_name},
+}
+
+ASSIGNMENT_WITH_DOMAIN_ID_AND_USER_ID_INHERITED = {
+ 'scope': {'domain': {'id': domain_id},
+ 'OS-INHERIT:inherited_to': 'projects'},
+ 'user': {'id': user_id},
+ 'role': {'id': role_id},
+}
+
+ASSIGNMENT_WITH_DOMAIN_ID_AND_GROUP_ID = {
+ 'scope': {'domain': {'id': domain_id}},
+ 'group': {'id': group_id},
+ 'role': {'id': role_id},
+}
+
+consumer_id = 'test consumer id'
+consumer_description = 'someone we trust'
+consumer_secret = 'test consumer secret'
+
+OAUTH_CONSUMER = {
+ 'id': consumer_id,
+ 'secret': consumer_secret,
+ 'description': consumer_description
+}
+
+access_token_id = 'test access token id'
+access_token_secret = 'test access token secret'
+access_token_expires = '2014-05-18T03:13:18.152071Z'
+
+OAUTH_ACCESS_TOKEN = {
+ 'id': access_token_id,
+ 'expires': access_token_expires,
+ 'key': access_token_id,
+ 'secret': access_token_secret
+}
+
+request_token_id = 'test request token id'
+request_token_secret = 'test request token secret'
+request_token_expires = '2014-05-17T11:10:51.511336Z'
+
+OAUTH_REQUEST_TOKEN = {
+ 'id': request_token_id,
+ 'expires': request_token_expires,
+ 'key': request_token_id,
+ 'secret': request_token_secret
+}
+
+oauth_verifier_pin = '6d74XaDS'
+OAUTH_VERIFIER = {
+ 'oauth_verifier': oauth_verifier_pin
+}
+
+
+def fake_auth_ref(fake_token, fake_service=None):
+ """Create an auth_ref using keystoneauth's fixtures"""
+ token_copy = copy.deepcopy(fake_token)
+ token_id = token_copy.pop('id')
+ token = fixture.V3Token(**token_copy)
+ # An auth_ref is actually an access info object
+ auth_ref = access.create(
+ body=token,
+ auth_token=token_id,
+ )
+
+ # Create a service catalog
+ if fake_service:
+ service = token.add_service(
+ fake_service['type'],
+ fake_service['name'],
+ )
+ # TODO(dtroyer): Add an 'id' element to KSA's _Service fixure
+ service['id'] = fake_service['id']
+ for e in fake_service['endpoints']:
+ region = e.get('region_id') or e.get('region', '<none>')
+ service.add_endpoint(
+ e['interface'],
+ e['url'],
+ region=region,
+ )
+
+ return auth_ref
+
+
+class FakeAuth(object):
+
+ def __init__(self, auth_method_class=None):
+ self._auth_method_class = auth_method_class
+
+ def get_token(self, *args, **kwargs):
+ return token_id
+
+
+class FakeSession(object):
+
+ def __init__(self, **kwargs):
+ self.auth = FakeAuth()
+
+
+class FakeIdentityv3Client(object):
+
+ def __init__(self, **kwargs):
+ self.domains = mock.Mock()
+ self.domains.resource_class = fakes.FakeResource(None, {})
+ self.credentials = mock.Mock()
+ self.credentials.resource_class = fakes.FakeResource(None, {})
+ self.endpoints = mock.Mock()
+ self.endpoints.resource_class = fakes.FakeResource(None, {})
+ self.groups = mock.Mock()
+ self.groups.resource_class = fakes.FakeResource(None, {})
+ self.oauth1 = mock.Mock()
+ self.oauth1.resource_class = fakes.FakeResource(None, {})
+ self.projects = mock.Mock()
+ self.projects.resource_class = fakes.FakeResource(None, {})
+ self.regions = mock.Mock()
+ self.regions.resource_class = fakes.FakeResource(None, {})
+ self.roles = mock.Mock()
+ self.roles.resource_class = fakes.FakeResource(None, {})
+ self.services = mock.Mock()
+ self.services.resource_class = fakes.FakeResource(None, {})
+ self.session = mock.Mock()
+ self.session.auth.auth_ref.service_catalog.resource_class = \
+ fakes.FakeResource(None, {})
+ self.tokens = mock.Mock()
+ self.tokens.resource_class = fakes.FakeResource(None, {})
+ self.trusts = mock.Mock()
+ self.trusts.resource_class = fakes.FakeResource(None, {})
+ self.users = mock.Mock()
+ self.users.resource_class = fakes.FakeResource(None, {})
+ self.role_assignments = mock.Mock()
+ self.role_assignments.resource_class = fakes.FakeResource(None, {})
+ self.auth_token = kwargs['token']
+ self.management_url = kwargs['endpoint']
+ self.auth = FakeAuth()
+ self.auth.client = mock.Mock()
+ self.auth.client.resource_class = fakes.FakeResource(None, {})
+
+
+class FakeFederationManager(object):
+
+ def __init__(self, **kwargs):
+ self.identity_providers = mock.Mock()
+ self.identity_providers.resource_class = fakes.FakeResource(None, {})
+ self.mappings = mock.Mock()
+ self.mappings.resource_class = fakes.FakeResource(None, {})
+ self.protocols = mock.Mock()
+ self.protocols.resource_class = fakes.FakeResource(None, {})
+ self.projects = mock.Mock()
+ self.projects.resource_class = fakes.FakeResource(None, {})
+ self.domains = mock.Mock()
+ self.domains.resource_class = fakes.FakeResource(None, {})
+ self.service_providers = mock.Mock()
+ self.service_providers.resource_class = fakes.FakeResource(None, {})
+
+
+class FakeFederatedClient(FakeIdentityv3Client):
+
+ def __init__(self, **kwargs):
+ super(FakeFederatedClient, self).__init__(**kwargs)
+ self.federation = FakeFederationManager()
+
+
+class FakeOAuth1Client(FakeIdentityv3Client):
+
+ def __init__(self, **kwargs):
+ super(FakeOAuth1Client, self).__init__(**kwargs)
+
+ self.access_tokens = mock.Mock()
+ self.access_tokens.resource_class = fakes.FakeResource(None, {})
+ self.consumers = mock.Mock()
+ self.consumers.resource_class = fakes.FakeResource(None, {})
+ self.request_tokens = mock.Mock()
+ self.request_tokens.resource_class = fakes.FakeResource(None, {})
+
+
+class TestIdentityv3(utils.TestCommand):
+
+ def setUp(self):
+ super(TestIdentityv3, self).setUp()
+
+ self.app.client_manager.identity = FakeIdentityv3Client(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN,
+ )
+
+
+class TestFederatedIdentity(utils.TestCommand):
+
+ def setUp(self):
+ super(TestFederatedIdentity, self).setUp()
+
+ self.app.client_manager.identity = FakeFederatedClient(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN
+ )
+
+
+class TestOAuth1(utils.TestCommand):
+
+ def setUp(self):
+ super(TestOAuth1, self).setUp()
+
+ self.app.client_manager.identity = FakeOAuth1Client(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN
+ )
+
+
+class FakeProject(object):
+ """Fake one or more project."""
+
+ @staticmethod
+ def create_one_project(attrs=None):
+ """Create a fake project.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, name, and so on
+ """
+
+ attrs = attrs or {}
+
+ # set default attributes.
+ project_info = {
+ 'id': 'project-id-' + uuid.uuid4().hex,
+ 'name': 'project-name-' + uuid.uuid4().hex,
+ 'description': 'project-description-' + uuid.uuid4().hex,
+ 'enabled': True,
+ 'is_domain': False,
+ 'domain_id': 'domain-id-' + uuid.uuid4().hex,
+ 'parent_id': 'parent-id-' + uuid.uuid4().hex,
+ 'links': 'links-' + uuid.uuid4().hex,
+ }
+ project_info.update(attrs)
+
+ project = fakes.FakeResource(info=copy.deepcopy(project_info),
+ loaded=True)
+ return project
+
+
+class FakeDomain(object):
+ """Fake one or more domain."""
+
+ @staticmethod
+ def create_one_domain(attrs=None):
+ """Create a fake domain.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, name, and so on
+ """
+
+ attrs = attrs or {}
+
+ # set default attributes.
+ domain_info = {
+ 'id': 'domain-id-' + uuid.uuid4().hex,
+ 'name': 'domain-name-' + uuid.uuid4().hex,
+ 'description': 'domain-description-' + uuid.uuid4().hex,
+ 'enabled': True,
+ 'links': 'links-' + uuid.uuid4().hex,
+ }
+ domain_info.update(attrs)
+
+ domain = fakes.FakeResource(info=copy.deepcopy(domain_info),
+ loaded=True)
+ return domain
+
+
+class FakeCredential(object):
+ """Fake one or more credential."""
+
+ @staticmethod
+ def create_one_credential(attrs=None):
+ """Create a fake credential.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, type, and so on
+ """
+
+ attrs = attrs or {}
+
+ # set default attributes.
+ credential_info = {
+ 'id': 'credential-id-' + uuid.uuid4().hex,
+ 'type': 'cert',
+ 'user_id': 'user-id-' + uuid.uuid4().hex,
+ 'blob': 'credential-data-' + uuid.uuid4().hex,
+ 'project_id': 'project-id-' + uuid.uuid4().hex,
+ 'links': 'links-' + uuid.uuid4().hex,
+ }
+ credential_info.update(attrs)
+
+ credential = fakes.FakeResource(
+ info=copy.deepcopy(credential_info), loaded=True)
+ return credential
+
+ @staticmethod
+ def create_credentials(attrs=None, count=2):
+ """Create multiple fake credentials.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of credentials to fake
+ :return:
+ A list of FakeResource objects faking the credentials
+ """
+ credentials = []
+ for i in range(0, count):
+ credential = FakeCredential.create_one_credential(attrs)
+ credentials.append(credential)
+
+ return credentials
+
+ @staticmethod
+ def get_credentials(credentials=None, count=2):
+ """Get an iterable MagicMock object with a list of faked credentials.
+
+ If credentials list is provided, then initialize the Mock object with
+ the list. Otherwise create one.
+
+ :param List credentials:
+ A list of FakeResource objects faking credentials
+ :param Integer count:
+ The number of credentials to be faked
+ :return
+ An iterable Mock object with side_effect set to a list of faked
+ credentials
+ """
+ if credentials is None:
+ credentials = FakeCredential.create_credentials(count)
+
+ return mock.MagicMock(side_effect=credentials)
+
+
+class FakeUser(object):
+ """Fake one or more user."""
+
+ @staticmethod
+ def create_one_user(attrs=None):
+ """Create a fake user.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, name, and so on
+ """
+
+ attrs = attrs or {}
+
+ # set default attributes.
+ user_info = {
+ 'id': 'user-id-' + uuid.uuid4().hex,
+ 'name': 'user-name-' + uuid.uuid4().hex,
+ 'default_project_id': 'project-' + uuid.uuid4().hex,
+ 'email': 'user-email-' + uuid.uuid4().hex,
+ 'enabled': True,
+ 'domain_id': 'domain-id-' + uuid.uuid4().hex,
+ 'links': 'links-' + uuid.uuid4().hex,
+ }
+ user_info.update(attrs)
+
+ user = fakes.FakeResource(info=copy.deepcopy(user_info),
+ loaded=True)
+ return user
+
+
+class FakeGroup(object):
+ """Fake one or more group."""
+
+ @staticmethod
+ def create_one_group(attrs=None):
+ """Create a fake group.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, name, and so on
+ """
+
+ attrs = attrs or {}
+
+ # set default attributes.
+ group_info = {
+ 'id': 'group-id-' + uuid.uuid4().hex,
+ 'name': 'group-name-' + uuid.uuid4().hex,
+ 'links': 'links-' + uuid.uuid4().hex,
+ 'domain_id': 'domain-id-' + uuid.uuid4().hex,
+ 'description': 'group-description-' + uuid.uuid4().hex,
+ }
+ group_info.update(attrs)
+
+ group = fakes.FakeResource(info=copy.deepcopy(group_info),
+ loaded=True)
+ return group
+
+ @staticmethod
+ def create_groups(attrs=None, count=2):
+ """Create multiple fake groups.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of groups to fake
+ :return:
+ A list of FakeResource objects faking the groups
+ """
+ groups = []
+ for i in range(0, count):
+ group = FakeGroup.create_one_group(attrs)
+ groups.append(group)
+
+ return groups
+
+ @staticmethod
+ def get_groups(groups=None, count=2):
+ """Get an iterable MagicMock object with a list of faked groups.
+
+ If groups list is provided, then initialize the Mock object with
+ the list. Otherwise create one.
+
+ :param List groups:
+ A list of FakeResource objects faking groups
+ :param Integer count:
+ The number of groups to be faked
+ :return
+ An iterable Mock object with side_effect set to a list of faked
+ groups
+ """
+ if groups is None:
+ groups = FakeGroup.create_groups(count)
+
+ return mock.MagicMock(side_effect=groups)
+
+
+class FakeEndpoint(object):
+ """Fake one or more endpoint."""
+
+ @staticmethod
+ def create_one_endpoint(attrs=None):
+ """Create a fake endpoint.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, url, and so on
+ """
+
+ attrs = attrs or {}
+
+ # set default attributes.
+ endpoint_info = {
+ 'id': 'endpoint-id-' + uuid.uuid4().hex,
+ 'url': 'url-' + uuid.uuid4().hex,
+ 'region': 'endpoint-region-' + uuid.uuid4().hex,
+ 'interface': 'admin',
+ 'service_id': 'service-id-' + uuid.uuid4().hex,
+ 'enabled': True,
+ 'links': 'links-' + uuid.uuid4().hex,
+ }
+ endpoint_info.update(attrs)
+
+ endpoint = fakes.FakeResource(info=copy.deepcopy(endpoint_info),
+ loaded=True)
+ return endpoint
+
+
+class FakeService(object):
+ """Fake one or more service."""
+
+ @staticmethod
+ def create_one_service(attrs=None):
+ """Create a fake service.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, name, and so on
+ """
+
+ attrs = attrs or {}
+
+ # set default attributes.
+ service_info = {
+ 'id': 'service-id-' + uuid.uuid4().hex,
+ 'name': 'service-name-' + uuid.uuid4().hex,
+ 'type': 'service-type-' + uuid.uuid4().hex,
+ 'description': 'service-description-' + uuid.uuid4().hex,
+ 'enabled': True,
+ 'links': 'links-' + uuid.uuid4().hex,
+ }
+ service_info.update(attrs)
+
+ service = fakes.FakeResource(info=copy.deepcopy(service_info),
+ loaded=True)
+ return service
+
+
+class FakeRoleAssignment(object):
+ """Fake one or more role assignment."""
+
+ @staticmethod
+ def create_one_role_assignment(attrs=None):
+ """Create a fake role assignment.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with scope, user, and so on
+ """
+
+ attrs = attrs or {}
+
+ # set default attributes.
+ role_assignment_info = {
+ 'scope': {'project': {'id': 'project-id-' + uuid.uuid4().hex}},
+ 'user': {'id': 'user-id-' + uuid.uuid4().hex},
+ 'role': {'id': 'role-id-' + uuid.uuid4().hex},
+ }
+ role_assignment_info.update(attrs)
+
+ role_assignment = fakes.FakeResource(
+ info=copy.deepcopy(role_assignment_info), loaded=True)
+
+ return role_assignment
diff --git a/openstackclient/tests/unit/identity/v3/test_catalog.py b/openstackclient/tests/unit/identity/v3/test_catalog.py
new file mode 100644
index 00000000..986c05f3
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v3/test_catalog.py
@@ -0,0 +1,142 @@
+# 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.
+#
+
+import mock
+
+from openstackclient.identity.v3 import catalog
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+from openstackclient.tests.unit import utils
+
+
+class TestCatalog(utils.TestCommand):
+
+ fake_service = {
+ 'id': 'qwertyuiop',
+ 'type': 'compute',
+ 'name': 'supernova',
+ 'endpoints': [
+ {
+ 'region': 'onlyone',
+ 'url': 'https://public.example.com',
+ 'interface': 'public',
+ },
+ {
+ 'region_id': 'onlyone',
+ 'url': 'https://admin.example.com',
+ 'interface': 'admin',
+ },
+ {
+ 'url': 'https://internal.example.com',
+ 'interface': 'internal',
+ },
+ {
+ 'region': None,
+ 'url': 'https://none.example.com',
+ 'interface': 'none',
+ },
+ ],
+ }
+
+ def setUp(self):
+ super(TestCatalog, self).setUp()
+
+ self.sc_mock = mock.MagicMock()
+ self.sc_mock.service_catalog.catalog.return_value = [
+ self.fake_service,
+ ]
+
+ self.auth_mock = mock.MagicMock()
+ self.app.client_manager.session = self.auth_mock
+
+ self.auth_mock.auth.get_auth_ref.return_value = self.sc_mock
+
+
+class TestCatalogList(TestCatalog):
+
+ def setUp(self):
+ super(TestCatalogList, self).setUp()
+
+ # Get the command object to test
+ self.cmd = catalog.ListCatalog(self.app, None)
+
+ def test_catalog_list(self):
+ auth_ref = identity_fakes.fake_auth_ref(
+ identity_fakes.TOKEN_WITH_PROJECT_ID,
+ fake_service=self.fake_service,
+ )
+ self.ar_mock = mock.PropertyMock(return_value=auth_ref)
+ type(self.app.client_manager).auth_ref = self.ar_mock
+
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ collist = ('Name', 'Type', 'Endpoints')
+ self.assertEqual(collist, columns)
+ datalist = ((
+ 'supernova',
+ 'compute',
+ 'onlyone\n public: https://public.example.com\n'
+ 'onlyone\n admin: https://admin.example.com\n'
+ '<none>\n internal: https://internal.example.com\n'
+ '<none>\n none: https://none.example.com\n',
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+
+class TestCatalogShow(TestCatalog):
+
+ def setUp(self):
+ super(TestCatalogShow, self).setUp()
+
+ # Get the command object to test
+ self.cmd = catalog.ShowCatalog(self.app, None)
+
+ def test_catalog_show(self):
+ auth_ref = identity_fakes.fake_auth_ref(
+ identity_fakes.TOKEN_WITH_PROJECT_ID,
+ fake_service=self.fake_service,
+ )
+ self.ar_mock = mock.PropertyMock(return_value=auth_ref)
+ type(self.app.client_manager).auth_ref = self.ar_mock
+
+ arglist = [
+ 'compute',
+ ]
+ verifylist = [
+ ('service', 'compute'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ collist = ('endpoints', 'id', 'name', 'type')
+ self.assertEqual(collist, columns)
+ datalist = (
+ 'onlyone\n public: https://public.example.com\nonlyone\n'
+ ' admin: https://admin.example.com\n'
+ '<none>\n internal: https://internal.example.com\n'
+ '<none>\n none: https://none.example.com\n',
+ 'qwertyuiop',
+ 'supernova',
+ 'compute',
+ )
+ self.assertEqual(datalist, data)
diff --git a/openstackclient/tests/unit/identity/v3/test_consumer.py b/openstackclient/tests/unit/identity/v3/test_consumer.py
new file mode 100644
index 00000000..403250ef
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v3/test_consumer.py
@@ -0,0 +1,219 @@
+# 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.
+
+import copy
+
+from openstackclient.identity.v3 import consumer
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+
+
+class TestOAuth1(identity_fakes.TestOAuth1):
+
+ def setUp(self):
+ super(TestOAuth1, self).setUp()
+ identity_client = self.app.client_manager.identity
+ self.consumers_mock = identity_client.oauth1.consumers
+ self.consumers_mock.reset_mock()
+
+
+class TestConsumerCreate(TestOAuth1):
+
+ def setUp(self):
+ super(TestConsumerCreate, self).setUp()
+
+ self.consumers_mock.create.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.OAUTH_CONSUMER),
+ loaded=True,
+ )
+
+ self.cmd = consumer.CreateConsumer(self.app, None)
+
+ def test_create_consumer(self):
+ arglist = [
+ '--description', identity_fakes.consumer_description,
+ ]
+ verifylist = [
+ ('description', identity_fakes.consumer_description),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.consumers_mock.create.assert_called_with(
+ identity_fakes.consumer_description,
+ )
+
+ collist = ('description', 'id', 'secret')
+ self.assertEqual(collist, columns)
+ datalist = (
+ identity_fakes.consumer_description,
+ identity_fakes.consumer_id,
+ identity_fakes.consumer_secret,
+ )
+ self.assertEqual(datalist, data)
+
+
+class TestConsumerDelete(TestOAuth1):
+
+ def setUp(self):
+ super(TestConsumerDelete, self).setUp()
+
+ # This is the return value for utils.find_resource()
+ self.consumers_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.OAUTH_CONSUMER),
+ loaded=True,
+ )
+
+ self.consumers_mock.delete.return_value = None
+ self.cmd = consumer.DeleteConsumer(self.app, None)
+
+ def test_delete_consumer(self):
+ arglist = [
+ identity_fakes.consumer_id,
+ ]
+ verifylist = [
+ ('consumer', [identity_fakes.consumer_id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.consumers_mock.delete.assert_called_with(
+ identity_fakes.consumer_id,
+ )
+ self.assertIsNone(result)
+
+
+class TestConsumerList(TestOAuth1):
+
+ def setUp(self):
+ super(TestConsumerList, self).setUp()
+
+ self.consumers_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.OAUTH_CONSUMER),
+ loaded=True,
+ )
+ self.consumers_mock.list.return_value = [
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.OAUTH_CONSUMER),
+ loaded=True,
+ ),
+ ]
+
+ # Get the command object to test
+ self.cmd = consumer.ListConsumer(self.app, None)
+
+ def test_consumer_list(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.consumers_mock.list.assert_called_with()
+
+ collist = ('ID', 'Description')
+ self.assertEqual(collist, columns)
+ datalist = ((
+ identity_fakes.consumer_id,
+ identity_fakes.consumer_description,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+
+class TestConsumerSet(TestOAuth1):
+
+ def setUp(self):
+ super(TestConsumerSet, self).setUp()
+
+ self.consumers_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.OAUTH_CONSUMER),
+ loaded=True,
+ )
+
+ consumer_updated = copy.deepcopy(identity_fakes.OAUTH_CONSUMER)
+ consumer_updated['description'] = "consumer new description"
+ self.consumers_mock.update.return_value = fakes.FakeResource(
+ None,
+ consumer_updated,
+ loaded=True,
+ )
+
+ self.cmd = consumer.SetConsumer(self.app, None)
+
+ def test_consumer_update(self):
+ new_description = "consumer new description"
+
+ arglist = [
+ '--description', new_description,
+ identity_fakes.consumer_id,
+ ]
+ verifylist = [
+ ('description', new_description),
+ ('consumer', identity_fakes.consumer_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ kwargs = {'description': new_description}
+ self.consumers_mock.update.assert_called_with(
+ identity_fakes.consumer_id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+
+class TestConsumerShow(TestOAuth1):
+
+ def setUp(self):
+ super(TestConsumerShow, self).setUp()
+
+ consumer_no_secret = copy.deepcopy(identity_fakes.OAUTH_CONSUMER)
+ del consumer_no_secret['secret']
+ self.consumers_mock.get.return_value = fakes.FakeResource(
+ None,
+ consumer_no_secret,
+ loaded=True,
+ )
+
+ # Get the command object to test
+ self.cmd = consumer.ShowConsumer(self.app, None)
+
+ def test_consumer_show(self):
+ arglist = [
+ identity_fakes.consumer_id,
+ ]
+ verifylist = [
+ ('consumer', identity_fakes.consumer_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.consumers_mock.get.assert_called_with(
+ identity_fakes.consumer_id,
+ )
+
+ collist = ('description', 'id')
+ self.assertEqual(collist, columns)
+ datalist = (
+ identity_fakes.consumer_description,
+ identity_fakes.consumer_id,
+ )
+ self.assertEqual(datalist, data)
diff --git a/openstackclient/tests/unit/identity/v3/test_credential.py b/openstackclient/tests/unit/identity/v3/test_credential.py
new file mode 100644
index 00000000..fd3ae6b2
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v3/test_credential.py
@@ -0,0 +1,357 @@
+# 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.
+
+import mock
+from mock import call
+
+from osc_lib import exceptions
+
+from openstackclient.identity.v3 import credential
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+from openstackclient.tests.unit import utils
+
+
+class TestCredential(identity_fakes.TestIdentityv3):
+
+ def setUp(self):
+ super(TestCredential, self).setUp()
+
+ # Get a shortcut to the CredentialManager Mock
+ self.credentials_mock = self.app.client_manager.identity.credentials
+ self.credentials_mock.reset_mock()
+
+ # Get a shortcut to the UserManager Mock
+ self.users_mock = self.app.client_manager.identity.users
+ self.users_mock.reset_mock()
+
+ # Get a shortcut to the ProjectManager Mock
+ self.projects_mock = self.app.client_manager.identity.projects
+ self.projects_mock.reset_mock()
+
+
+class TestCredentialCreate(TestCredential):
+
+ user = identity_fakes.FakeUser.create_one_user()
+ project = identity_fakes.FakeProject.create_one_project()
+ columns = (
+ 'blob',
+ 'id',
+ 'project_id',
+ 'type',
+ 'user_id',
+ )
+
+ def setUp(self):
+ super(TestCredentialCreate, self).setUp()
+
+ self.credential = identity_fakes.FakeCredential.create_one_credential(
+ attrs={'user_id': self.user.id, 'project_id': self.project.id})
+ self.credentials_mock.create.return_value = self.credential
+ self.users_mock.get.return_value = self.user
+ self.projects_mock.get.return_value = self.project
+ self.data = (
+ self.credential.blob,
+ self.credential.id,
+ self.credential.project_id,
+ self.credential.type,
+ self.credential.user_id,
+ )
+
+ self.cmd = credential.CreateCredential(self.app, None)
+
+ def test_credential_create_no_options(self):
+ arglist = [
+ self.credential.user_id,
+ self.credential.blob,
+ ]
+ verifylist = [
+ ('user', self.credential.user_id),
+ ('data', self.credential.blob),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ kwargs = {
+ 'user': self.credential.user_id,
+ 'type': self.credential.type,
+ 'blob': self.credential.blob,
+ 'project': None,
+ }
+ self.credentials_mock.create.assert_called_once_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_credential_create_with_options(self):
+ arglist = [
+ self.credential.user_id,
+ self.credential.blob,
+ '--type', self.credential.type,
+ '--project', self.credential.project_id,
+ ]
+ verifylist = [
+ ('user', self.credential.user_id),
+ ('data', self.credential.blob),
+ ('type', self.credential.type),
+ ('project', self.credential.project_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ kwargs = {
+ 'user': self.credential.user_id,
+ 'type': self.credential.type,
+ 'blob': self.credential.blob,
+ 'project': self.credential.project_id,
+ }
+ self.credentials_mock.create.assert_called_once_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_credential_create_with_invalid_type(self):
+ arglist = [
+ self.credential.user_id,
+ self.credential.blob,
+ '--type', 'invalid_type',
+ ]
+ verifylist = [
+ ('user', self.credential.user_id),
+ ('data', self.credential.blob),
+ ('type', 'invalid_type'),
+ ]
+ self.assertRaises(utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+
+class TestCredentialDelete(TestCredential):
+
+ credentials = identity_fakes.FakeCredential.create_credentials(count=2)
+
+ def setUp(self):
+ super(TestCredentialDelete, self).setUp()
+
+ self.credentials_mock.delete.return_value = None
+
+ # Get the command object to test
+ self.cmd = credential.DeleteCredential(self.app, None)
+
+ def test_credential_delete(self):
+ arglist = [
+ self.credentials[0].id,
+ ]
+ verifylist = [
+ ('credential', [self.credentials[0].id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.credentials_mock.delete.assert_called_with(
+ self.credentials[0].id,
+ )
+ self.assertIsNone(result)
+
+ def test_credential_multi_delete(self):
+ arglist = []
+ for c in self.credentials:
+ arglist.append(c.id)
+ verifylist = [
+ ('credential', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for c in self.credentials:
+ calls.append(call(c.id))
+ self.credentials_mock.delete.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_credential_multi_delete_with_exception(self):
+ arglist = [
+ self.credentials[0].id,
+ 'unexist_credential',
+ ]
+ verifylist = [
+ ('credential', [self.credentials[0].id, 'unexist_credential'])
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ delete_mock_result = [None, exceptions.CommandError]
+ self.credentials_mock.delete = (
+ mock.MagicMock(side_effect=delete_mock_result)
+ )
+
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 credential failed to delete.', str(e))
+
+ self.credentials_mock.delete.assert_any_call(self.credentials[0].id)
+ self.credentials_mock.delete.assert_any_call('unexist_credential')
+
+
+class TestCredentialList(TestCredential):
+
+ credential = identity_fakes.FakeCredential.create_one_credential()
+
+ columns = ('ID', 'Type', 'User ID', 'Data', 'Project ID')
+ data = ((
+ credential.id,
+ credential.type,
+ credential.user_id,
+ credential.blob,
+ credential.project_id,
+ ), )
+
+ def setUp(self):
+ super(TestCredentialList, self).setUp()
+
+ self.credentials_mock.list.return_value = [self.credential]
+
+ # Get the command object to test
+ self.cmd = credential.ListCredential(self.app, None)
+
+ def test_domain_list_no_options(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.credentials_mock.list.assert_called_with()
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, tuple(data))
+
+
+class TestCredentialSet(TestCredential):
+
+ credential = identity_fakes.FakeCredential.create_one_credential()
+
+ def setUp(self):
+ super(TestCredentialSet, self).setUp()
+ self.cmd = credential.SetCredential(self.app, None)
+
+ def test_credential_set_no_options(self):
+ arglist = [
+ self.credential.id,
+ ]
+
+ self.assertRaises(utils.ParserException,
+ self.check_parser, self.cmd, arglist, [])
+
+ def test_credential_set_missing_user(self):
+ arglist = [
+ '--type', 'ec2',
+ '--data', self.credential.blob,
+ self.credential.id,
+ ]
+
+ self.assertRaises(utils.ParserException,
+ self.check_parser, self.cmd, arglist, [])
+
+ def test_credential_set_missing_type(self):
+ arglist = [
+ '--user', self.credential.user_id,
+ '--data', self.credential.blob,
+ self.credential.id,
+ ]
+
+ self.assertRaises(utils.ParserException,
+ self.check_parser, self.cmd, arglist, [])
+
+ def test_credential_set_missing_data(self):
+ arglist = [
+ '--user', self.credential.user_id,
+ '--type', 'ec2',
+ self.credential.id,
+ ]
+
+ self.assertRaises(utils.ParserException,
+ self.check_parser, self.cmd, arglist, [])
+
+ def test_credential_set_valid(self):
+ arglist = [
+ '--user', self.credential.user_id,
+ '--type', 'ec2',
+ '--data', self.credential.blob,
+ self.credential.id,
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, [])
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.assertIsNone(result)
+
+ def test_credential_set_valid_with_project(self):
+ arglist = [
+ '--user', self.credential.user_id,
+ '--type', 'ec2',
+ '--data', self.credential.blob,
+ '--project', self.credential.project_id,
+ self.credential.id,
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, [])
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.assertIsNone(result)
+
+
+class TestCredentialShow(TestCredential):
+
+ columns = (
+ 'blob',
+ 'id',
+ 'project_id',
+ 'type',
+ 'user_id',
+ )
+
+ def setUp(self):
+ super(TestCredentialShow, self).setUp()
+
+ self.credential = identity_fakes.FakeCredential.create_one_credential()
+ self.credentials_mock.get.return_value = self.credential
+ self.data = (
+ self.credential.blob,
+ self.credential.id,
+ self.credential.project_id,
+ self.credential.type,
+ self.credential.user_id,
+ )
+
+ self.cmd = credential.ShowCredential(self.app, None)
+
+ def test_credential_show(self):
+ arglist = [
+ self.credential.id,
+ ]
+ verifylist = [
+ ('credential', self.credential.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.credentials_mock.get.assert_called_once_with(self.credential.id)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
diff --git a/openstackclient/tests/unit/identity/v3/test_domain.py b/openstackclient/tests/unit/identity/v3/test_domain.py
new file mode 100644
index 00000000..36f13d33
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v3/test_domain.py
@@ -0,0 +1,401 @@
+# 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 openstackclient.identity.v3 import domain
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+
+
+class TestDomain(identity_fakes.TestIdentityv3):
+
+ def setUp(self):
+ super(TestDomain, self).setUp()
+
+ # Get a shortcut to the DomainManager Mock
+ self.domains_mock = self.app.client_manager.identity.domains
+ self.domains_mock.reset_mock()
+
+
+class TestDomainCreate(TestDomain):
+
+ columns = (
+ 'description',
+ 'enabled',
+ 'id',
+ 'name',
+ )
+
+ def setUp(self):
+ super(TestDomainCreate, self).setUp()
+
+ self.domain = identity_fakes.FakeDomain.create_one_domain()
+ self.domains_mock.create.return_value = self.domain
+ self.datalist = (
+ self.domain.description,
+ True,
+ self.domain.id,
+ self.domain.name,
+ )
+
+ # Get the command object to test
+ self.cmd = domain.CreateDomain(self.app, None)
+
+ def test_domain_create_no_options(self):
+ arglist = [
+ self.domain.name,
+ ]
+ verifylist = [
+ ('name', self.domain.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': self.domain.name,
+ 'description': None,
+ 'enabled': True,
+ }
+ self.domains_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_domain_create_description(self):
+ arglist = [
+ '--description', 'new desc',
+ self.domain.name,
+ ]
+ verifylist = [
+ ('description', 'new desc'),
+ ('name', self.domain.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': self.domain.name,
+ 'description': 'new desc',
+ 'enabled': True,
+ }
+ self.domains_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_domain_create_enable(self):
+ arglist = [
+ '--enable',
+ self.domain.name,
+ ]
+ verifylist = [
+ ('enable', True),
+ ('name', self.domain.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': self.domain.name,
+ 'description': None,
+ 'enabled': True,
+ }
+ self.domains_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_domain_create_disable(self):
+ arglist = [
+ '--disable',
+ self.domain.name,
+ ]
+ verifylist = [
+ ('disable', True),
+ ('name', self.domain.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': self.domain.name,
+ 'description': None,
+ 'enabled': False,
+ }
+ self.domains_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+
+class TestDomainDelete(TestDomain):
+
+ domain = identity_fakes.FakeDomain.create_one_domain()
+
+ def setUp(self):
+ super(TestDomainDelete, self).setUp()
+
+ # This is the return value for utils.find_resource()
+ self.domains_mock.get.return_value = self.domain
+ self.domains_mock.delete.return_value = None
+
+ # Get the command object to test
+ self.cmd = domain.DeleteDomain(self.app, None)
+
+ def test_domain_delete(self):
+ arglist = [
+ self.domain.id,
+ ]
+ verifylist = [
+ ('domain', [self.domain.id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.domains_mock.delete.assert_called_with(
+ self.domain.id,
+ )
+ self.assertIsNone(result)
+
+
+class TestDomainList(TestDomain):
+
+ domain = identity_fakes.FakeDomain.create_one_domain()
+
+ def setUp(self):
+ super(TestDomainList, self).setUp()
+
+ self.domains_mock.list.return_value = [self.domain]
+
+ # Get the command object to test
+ self.cmd = domain.ListDomain(self.app, None)
+
+ def test_domain_list_no_options(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.domains_mock.list.assert_called_with()
+
+ collist = ('ID', 'Name', 'Enabled', 'Description')
+ self.assertEqual(collist, columns)
+ datalist = ((
+ self.domain.id,
+ self.domain.name,
+ True,
+ self.domain.description,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+
+class TestDomainSet(TestDomain):
+
+ domain = identity_fakes.FakeDomain.create_one_domain()
+
+ def setUp(self):
+ super(TestDomainSet, self).setUp()
+
+ self.domains_mock.get.return_value = self.domain
+
+ self.domains_mock.update.return_value = self.domain
+
+ # Get the command object to test
+ self.cmd = domain.SetDomain(self.app, None)
+
+ def test_domain_set_no_options(self):
+ arglist = [
+ self.domain.name,
+ ]
+ verifylist = [
+ ('domain', self.domain.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ kwargs = {}
+ self.domains_mock.update.assert_called_with(
+ self.domain.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_domain_set_name(self):
+ arglist = [
+ '--name', 'qwerty',
+ self.domain.id,
+ ]
+ verifylist = [
+ ('name', 'qwerty'),
+ ('domain', self.domain.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': 'qwerty',
+ }
+ self.domains_mock.update.assert_called_with(
+ self.domain.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_domain_set_description(self):
+ arglist = [
+ '--description', 'new desc',
+ self.domain.id,
+ ]
+ verifylist = [
+ ('description', 'new desc'),
+ ('domain', self.domain.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'description': 'new desc',
+ }
+ self.domains_mock.update.assert_called_with(
+ self.domain.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_domain_set_enable(self):
+ arglist = [
+ '--enable',
+ self.domain.id,
+ ]
+ verifylist = [
+ ('enable', True),
+ ('domain', self.domain.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': True,
+ }
+ self.domains_mock.update.assert_called_with(
+ self.domain.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_domain_set_disable(self):
+ arglist = [
+ '--disable',
+ self.domain.id,
+ ]
+ verifylist = [
+ ('disable', True),
+ ('domain', self.domain.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': False,
+ }
+ self.domains_mock.update.assert_called_with(
+ self.domain.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+
+class TestDomainShow(TestDomain):
+
+ def setUp(self):
+ super(TestDomainShow, self).setUp()
+
+ self.domain = identity_fakes.FakeDomain.create_one_domain()
+ self.domains_mock.get.return_value = self.domain
+ # Get the command object to test
+ self.cmd = domain.ShowDomain(self.app, None)
+
+ def test_domain_show(self):
+ arglist = [
+ self.domain.id,
+ ]
+ verifylist = [
+ ('domain', self.domain.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.app.client_manager.identity.tokens.get_token_data.return_value = \
+ {'token':
+ {'project':
+ {'domain':
+ {'id': 'd1',
+ 'name': 'd1'
+ }
+ }
+ }
+ }
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.domains_mock.get.assert_called_with(
+ self.domain.id,
+ )
+
+ collist = ('description', 'enabled', 'id', 'name')
+ self.assertEqual(collist, columns)
+ datalist = (
+ self.domain.description,
+ True,
+ self.domain.id,
+ self.domain.name,
+ )
+ self.assertEqual(datalist, data)
diff --git a/openstackclient/tests/unit/identity/v3/test_endpoint.py b/openstackclient/tests/unit/identity/v3/test_endpoint.py
new file mode 100644
index 00000000..765fbedd
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v3/test_endpoint.py
@@ -0,0 +1,750 @@
+# 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 openstackclient.identity.v3 import endpoint
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+
+
+class TestEndpoint(identity_fakes.TestIdentityv3):
+
+ def setUp(self):
+ super(TestEndpoint, self).setUp()
+
+ # Get a shortcut to the EndpointManager Mock
+ self.endpoints_mock = self.app.client_manager.identity.endpoints
+ self.endpoints_mock.reset_mock()
+
+ # Get a shortcut to the ServiceManager Mock
+ self.services_mock = self.app.client_manager.identity.services
+ self.services_mock.reset_mock()
+
+
+class TestEndpointCreate(TestEndpoint):
+
+ service = identity_fakes.FakeService.create_one_service()
+
+ columns = (
+ 'enabled',
+ 'id',
+ 'interface',
+ 'region',
+ 'service_id',
+ 'service_name',
+ 'service_type',
+ 'url',
+ )
+
+ def setUp(self):
+ super(TestEndpointCreate, self).setUp()
+
+ self.endpoint = identity_fakes.FakeEndpoint.create_one_endpoint(
+ attrs={'service_id': self.service.id})
+ self.endpoints_mock.create.return_value = self.endpoint
+
+ # This is the return value for common.find_resource(service)
+ self.services_mock.get.return_value = self.service
+
+ # Get the command object to test
+ self.cmd = endpoint.CreateEndpoint(self.app, None)
+
+ def test_endpoint_create_no_options(self):
+ arglist = [
+ self.service.id,
+ self.endpoint.interface,
+ self.endpoint.url,
+ ]
+ verifylist = [
+ ('enabled', True),
+ ('service', self.service.id),
+ ('interface', self.endpoint.interface),
+ ('url', self.endpoint.url),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'service': self.service.id,
+ 'url': self.endpoint.url,
+ 'interface': self.endpoint.interface,
+ 'enabled': True,
+ 'region': None,
+ }
+
+ self.endpoints_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ datalist = (
+ True,
+ self.endpoint.id,
+ self.endpoint.interface,
+ self.endpoint.region,
+ self.service.id,
+ self.service.name,
+ self.service.type,
+ self.endpoint.url,
+ )
+ self.assertEqual(datalist, data)
+
+ def test_endpoint_create_region(self):
+ arglist = [
+ self.service.id,
+ self.endpoint.interface,
+ self.endpoint.url,
+ '--region', self.endpoint.region,
+ ]
+ verifylist = [
+ ('enabled', True),
+ ('service', self.service.id),
+ ('interface', self.endpoint.interface),
+ ('url', self.endpoint.url),
+ ('region', self.endpoint.region),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'service': self.service.id,
+ 'url': self.endpoint.url,
+ 'interface': self.endpoint.interface,
+ 'enabled': True,
+ 'region': self.endpoint.region,
+ }
+
+ self.endpoints_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ datalist = (
+ True,
+ self.endpoint.id,
+ self.endpoint.interface,
+ self.endpoint.region,
+ self.service.id,
+ self.service.name,
+ self.service.type,
+ self.endpoint.url,
+ )
+ self.assertEqual(datalist, data)
+
+ def test_endpoint_create_enable(self):
+ arglist = [
+ self.service.id,
+ self.endpoint.interface,
+ self.endpoint.url,
+ '--enable'
+ ]
+ verifylist = [
+ ('enabled', True),
+ ('service', self.service.id),
+ ('interface', self.endpoint.interface),
+ ('url', self.endpoint.url),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'service': self.service.id,
+ 'url': self.endpoint.url,
+ 'interface': self.endpoint.interface,
+ 'enabled': True,
+ 'region': None,
+ }
+
+ self.endpoints_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ datalist = (
+ True,
+ self.endpoint.id,
+ self.endpoint.interface,
+ self.endpoint.region,
+ self.service.id,
+ self.service.name,
+ self.service.type,
+ self.endpoint.url,
+ )
+ self.assertEqual(datalist, data)
+
+ def test_endpoint_create_disable(self):
+ arglist = [
+ self.service.id,
+ self.endpoint.interface,
+ self.endpoint.url,
+ '--disable',
+ ]
+ verifylist = [
+ ('enabled', False),
+ ('service', self.service.id),
+ ('interface', self.endpoint.interface),
+ ('url', self.endpoint.url),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'service': self.service.id,
+ 'url': self.endpoint.url,
+ 'interface': self.endpoint.interface,
+ 'enabled': False,
+ 'region': None,
+ }
+
+ self.endpoints_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ datalist = (
+ True,
+ self.endpoint.id,
+ self.endpoint.interface,
+ self.endpoint.region,
+ self.service.id,
+ self.service.name,
+ self.service.type,
+ self.endpoint.url,
+ )
+ self.assertEqual(datalist, data)
+
+
+class TestEndpointDelete(TestEndpoint):
+
+ endpoint = identity_fakes.FakeEndpoint.create_one_endpoint()
+
+ def setUp(self):
+ super(TestEndpointDelete, self).setUp()
+
+ # This is the return value for utils.find_resource(endpoint)
+ self.endpoints_mock.get.return_value = self.endpoint
+ self.endpoints_mock.delete.return_value = None
+
+ # Get the command object to test
+ self.cmd = endpoint.DeleteEndpoint(self.app, None)
+
+ def test_endpoint_delete(self):
+ arglist = [
+ self.endpoint.id,
+ ]
+ verifylist = [
+ ('endpoint', [self.endpoint.id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.endpoints_mock.delete.assert_called_with(
+ self.endpoint.id,
+ )
+ self.assertIsNone(result)
+
+
+class TestEndpointList(TestEndpoint):
+
+ service = identity_fakes.FakeService.create_one_service()
+ endpoint = identity_fakes.FakeEndpoint.create_one_endpoint(
+ attrs={'service_id': service.id})
+
+ columns = (
+ 'ID',
+ 'Region',
+ 'Service Name',
+ 'Service Type',
+ 'Enabled',
+ 'Interface',
+ 'URL',
+ )
+
+ def setUp(self):
+ super(TestEndpointList, self).setUp()
+
+ self.endpoints_mock.list.return_value = [self.endpoint]
+
+ # This is the return value for common.find_resource(service)
+ self.services_mock.get.return_value = self.service
+
+ # Get the command object to test
+ self.cmd = endpoint.ListEndpoint(self.app, None)
+
+ def test_endpoint_list_no_options(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.endpoints_mock.list.assert_called_with()
+
+ self.assertEqual(self.columns, columns)
+ datalist = (
+ (
+ self.endpoint.id,
+ self.endpoint.region,
+ self.service.name,
+ self.service.type,
+ True,
+ self.endpoint.interface,
+ self.endpoint.url,
+ ),
+ )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_endpoint_list_service(self):
+ arglist = [
+ '--service', self.service.id,
+ ]
+ verifylist = [
+ ('service', self.service.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'service': self.service.id,
+ }
+ self.endpoints_mock.list.assert_called_with(**kwargs)
+
+ self.assertEqual(self.columns, columns)
+ datalist = (
+ (
+ self.endpoint.id,
+ self.endpoint.region,
+ self.service.name,
+ self.service.type,
+ True,
+ self.endpoint.interface,
+ self.endpoint.url,
+ ),
+ )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_endpoint_list_interface(self):
+ arglist = [
+ '--interface', self.endpoint.interface,
+ ]
+ verifylist = [
+ ('interface', self.endpoint.interface),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'interface': self.endpoint.interface,
+ }
+ self.endpoints_mock.list.assert_called_with(**kwargs)
+
+ self.assertEqual(self.columns, columns)
+ datalist = (
+ (
+ self.endpoint.id,
+ self.endpoint.region,
+ self.service.name,
+ self.service.type,
+ True,
+ self.endpoint.interface,
+ self.endpoint.url,
+ ),
+ )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_endpoint_list_region(self):
+ arglist = [
+ '--region', self.endpoint.region,
+ ]
+ verifylist = [
+ ('region', self.endpoint.region),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'region': self.endpoint.region,
+ }
+ self.endpoints_mock.list.assert_called_with(**kwargs)
+
+ self.assertEqual(self.columns, columns)
+ datalist = (
+ (
+ self.endpoint.id,
+ self.endpoint.region,
+ self.service.name,
+ self.service.type,
+ True,
+ self.endpoint.interface,
+ self.endpoint.url,
+ ),
+ )
+ self.assertEqual(datalist, tuple(data))
+
+
+class TestEndpointSet(TestEndpoint):
+
+ service = identity_fakes.FakeService.create_one_service()
+ endpoint = identity_fakes.FakeEndpoint.create_one_endpoint(
+ attrs={'service_id': service.id})
+
+ def setUp(self):
+ super(TestEndpointSet, self).setUp()
+
+ # This is the return value for utils.find_resource(endpoint)
+ self.endpoints_mock.get.return_value = self.endpoint
+
+ self.endpoints_mock.update.return_value = self.endpoint
+
+ # This is the return value for common.find_resource(service)
+ self.services_mock.get.return_value = self.service
+
+ # Get the command object to test
+ self.cmd = endpoint.SetEndpoint(self.app, None)
+
+ def test_endpoint_set_no_options(self):
+ arglist = [
+ self.endpoint.id,
+ ]
+ verifylist = [
+ ('endpoint', self.endpoint.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ kwargs = {
+ 'enabled': None,
+ 'interface': None,
+ 'region': None,
+ 'service': None,
+ 'url': None,
+ }
+ self.endpoints_mock.update.assert_called_with(
+ self.endpoint.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_endpoint_set_interface(self):
+ arglist = [
+ '--interface', 'public',
+ self.endpoint.id
+ ]
+ verifylist = [
+ ('interface', 'public'),
+ ('endpoint', self.endpoint.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': None,
+ 'interface': 'public',
+ 'url': None,
+ 'region': None,
+ 'service': None,
+ }
+ self.endpoints_mock.update.assert_called_with(
+ self.endpoint.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_endpoint_set_url(self):
+ arglist = [
+ '--url', 'http://localhost:5000',
+ self.endpoint.id
+ ]
+ verifylist = [
+ ('url', 'http://localhost:5000'),
+ ('endpoint', self.endpoint.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': None,
+ 'interface': None,
+ 'url': 'http://localhost:5000',
+ 'region': None,
+ 'service': None,
+ }
+ self.endpoints_mock.update.assert_called_with(
+ self.endpoint.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_endpoint_set_service(self):
+ arglist = [
+ '--service', self.service.id,
+ self.endpoint.id
+ ]
+ verifylist = [
+ ('service', self.service.id),
+ ('endpoint', self.endpoint.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': None,
+ 'interface': None,
+ 'url': None,
+ 'region': None,
+ 'service': self.service.id,
+ }
+ self.endpoints_mock.update.assert_called_with(
+ self.endpoint.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_endpoint_set_region(self):
+ arglist = [
+ '--region', 'e-rzzz',
+ self.endpoint.id
+ ]
+ verifylist = [
+ ('region', 'e-rzzz'),
+ ('endpoint', self.endpoint.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': None,
+ 'interface': None,
+ 'url': None,
+ 'region': 'e-rzzz',
+ 'service': None,
+ }
+ self.endpoints_mock.update.assert_called_with(
+ self.endpoint.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_endpoint_set_enable(self):
+ arglist = [
+ '--enable',
+ self.endpoint.id
+ ]
+ verifylist = [
+ ('enabled', True),
+ ('endpoint', self.endpoint.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': True,
+ 'interface': None,
+ 'url': None,
+ 'region': None,
+ 'service': None,
+ }
+ self.endpoints_mock.update.assert_called_with(
+ self.endpoint.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_endpoint_set_disable(self):
+ arglist = [
+ '--disable',
+ self.endpoint.id
+ ]
+ verifylist = [
+ ('disabled', True),
+ ('endpoint', self.endpoint.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': False,
+ 'interface': None,
+ 'url': None,
+ 'region': None,
+ 'service': None,
+ }
+ self.endpoints_mock.update.assert_called_with(
+ self.endpoint.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+
+class TestEndpointShow(TestEndpoint):
+
+ service = identity_fakes.FakeService.create_one_service()
+ endpoint = identity_fakes.FakeEndpoint.create_one_endpoint(
+ attrs={'service_id': service.id})
+
+ def setUp(self):
+ super(TestEndpointShow, self).setUp()
+
+ self.endpoints_mock.get.return_value = self.endpoint
+
+ # This is the return value for common.find_resource(service)
+ self.services_mock.get.return_value = self.service
+
+ # Get the command object to test
+ self.cmd = endpoint.ShowEndpoint(self.app, None)
+
+ def test_endpoint_show(self):
+ arglist = [
+ self.endpoint.id,
+ ]
+ verifylist = [
+ ('endpoint', self.endpoint.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.endpoints_mock.get.assert_called_with(
+ self.endpoint.id,
+ )
+
+ collist = (
+ 'enabled',
+ 'id',
+ 'interface',
+ 'region',
+ 'service_id',
+ 'service_name',
+ 'service_type',
+ 'url',
+ )
+ self.assertEqual(collist, columns)
+ datalist = (
+ True,
+ self.endpoint.id,
+ self.endpoint.interface,
+ self.endpoint.region,
+ self.service.id,
+ self.service.name,
+ self.service.type,
+ self.endpoint.url,
+ )
+ self.assertEqual(datalist, data)
+
+
+class TestEndpointCreateServiceWithoutName(TestEndpointCreate):
+
+ service = identity_fakes.FakeService.create_one_service(
+ attrs={'service_name': ''})
+
+ def setUp(self):
+ super(TestEndpointCreate, self).setUp()
+
+ self.endpoint = identity_fakes.FakeEndpoint.create_one_endpoint(
+ attrs={'service_id': self.service.id})
+
+ self.endpoints_mock.create.return_value = self.endpoint
+
+ # This is the return value for common.find_resource(service)
+ self.services_mock.get.return_value = self.service
+
+ # Get the command object to test
+ self.cmd = endpoint.CreateEndpoint(self.app, None)
+
+
+class TestEndpointListServiceWithoutName(TestEndpointList):
+
+ service = identity_fakes.FakeService.create_one_service(
+ attrs={'service_name': ''})
+ endpoint = identity_fakes.FakeEndpoint.create_one_endpoint(
+ attrs={'service_id': service.id})
+
+ def setUp(self):
+ super(TestEndpointList, self).setUp()
+
+ self.endpoints_mock.list.return_value = [self.endpoint]
+
+ # This is the return value for common.find_resource(service)
+ self.services_mock.get.return_value = self.service
+
+ # Get the command object to test
+ self.cmd = endpoint.ListEndpoint(self.app, None)
+
+
+class TestEndpointShowServiceWithoutName(TestEndpointShow):
+
+ service = identity_fakes.FakeService.create_one_service(
+ attrs={'service_name': ''})
+ endpoint = identity_fakes.FakeEndpoint.create_one_endpoint(
+ attrs={'service_id': service.id})
+
+ def setUp(self):
+ super(TestEndpointShow, self).setUp()
+
+ self.endpoints_mock.get.return_value = self.endpoint
+
+ # This is the return value for common.find_resource(service)
+ self.services_mock.get.return_value = self.service
+
+ # Get the command object to test
+ self.cmd = endpoint.ShowEndpoint(self.app, None)
diff --git a/openstackclient/tests/unit/identity/v3/test_group.py b/openstackclient/tests/unit/identity/v3/test_group.py
new file mode 100644
index 00000000..d35e98c6
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v3/test_group.py
@@ -0,0 +1,569 @@
+# 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.
+#
+
+import mock
+from mock import call
+
+from keystoneauth1 import exceptions as ks_exc
+from osc_lib import exceptions
+
+from openstackclient.identity.v3 import group
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+
+
+class TestGroup(identity_fakes.TestIdentityv3):
+
+ def setUp(self):
+ super(TestGroup, self).setUp()
+
+ # Get a shortcut to the DomainManager Mock
+ self.domains_mock = self.app.client_manager.identity.domains
+ self.domains_mock.reset_mock()
+
+ # Get a shortcut to the GroupManager Mock
+ self.groups_mock = self.app.client_manager.identity.groups
+ self.groups_mock.reset_mock()
+
+ # Get a shortcut to the UserManager Mock
+ self.users_mock = self.app.client_manager.identity.users
+ self.users_mock.reset_mock()
+
+
+class TestGroupAddUser(TestGroup):
+
+ group = identity_fakes.FakeGroup.create_one_group()
+ user = identity_fakes.FakeUser.create_one_user()
+
+ def setUp(self):
+ super(TestGroupAddUser, self).setUp()
+
+ self.groups_mock.get.return_value = self.group
+ self.users_mock.get.return_value = self.user
+ self.users_mock.add_to_group.return_value = None
+
+ self.cmd = group.AddUserToGroup(self.app, None)
+
+ def test_group_add_user(self):
+ arglist = [
+ self.group.name,
+ self.user.name,
+ ]
+ verifylist = [
+ ('group', self.group.name),
+ ('user', self.user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.users_mock.add_to_group.assert_called_once_with(
+ self.user.id, self.group.id)
+ self.assertIsNone(result)
+
+
+class TestGroupCheckUser(TestGroup):
+
+ group = identity_fakes.FakeGroup.create_one_group()
+ user = identity_fakes.FakeUser.create_one_user()
+
+ def setUp(self):
+ super(TestGroupCheckUser, self).setUp()
+
+ self.groups_mock.get.return_value = self.group
+ self.users_mock.get.return_value = self.user
+ self.users_mock.check_in_group.return_value = None
+
+ self.cmd = group.CheckUserInGroup(self.app, None)
+
+ def test_group_check_user(self):
+ arglist = [
+ self.group.name,
+ self.user.name,
+ ]
+ verifylist = [
+ ('group', self.group.name),
+ ('user', self.user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.users_mock.check_in_group.assert_called_once_with(
+ self.user.id, self.group.id)
+ self.assertIsNone(result)
+
+
+class TestGroupCreate(TestGroup):
+
+ domain = identity_fakes.FakeDomain.create_one_domain()
+
+ columns = (
+ 'description',
+ 'domain_id',
+ 'id',
+ 'name',
+ )
+
+ def setUp(self):
+ super(TestGroupCreate, self).setUp()
+ self.group = identity_fakes.FakeGroup.create_one_group(
+ attrs={'domain_id': self.domain.id})
+ self.data = (
+ self.group.description,
+ self.group.domain_id,
+ self.group.id,
+ self.group.name,
+ )
+
+ self.groups_mock.create.return_value = self.group
+ self.groups_mock.get.return_value = self.group
+ self.domains_mock.get.return_value = self.domain
+
+ self.cmd = group.CreateGroup(self.app, None)
+
+ def test_group_create(self):
+ arglist = [
+ self.group.name,
+ ]
+ verifylist = [
+ ('name', self.group.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.groups_mock.create.assert_called_once_with(
+ name=self.group.name,
+ domain=None,
+ description=None,
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_group_create_with_options(self):
+ arglist = [
+ '--domain', self.domain.name,
+ '--description', self.group.description,
+ self.group.name,
+ ]
+ verifylist = [
+ ('domain', self.domain.name),
+ ('description', self.group.description),
+ ('name', self.group.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.groups_mock.create.assert_called_once_with(
+ name=self.group.name,
+ domain=self.domain.id,
+ description=self.group.description,
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_group_create_or_show(self):
+ self.groups_mock.create.side_effect = ks_exc.Conflict()
+ arglist = [
+ '--or-show',
+ self.group.name,
+ ]
+ verifylist = [
+ ('or_show', True),
+ ('name', self.group.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.groups_mock.get.assert_called_once_with(self.group.name)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestGroupDelete(TestGroup):
+
+ domain = identity_fakes.FakeDomain.create_one_domain()
+ groups = identity_fakes.FakeGroup.create_groups(
+ attrs={'domain_id': domain.id}, count=2)
+
+ def setUp(self):
+ super(TestGroupDelete, self).setUp()
+
+ self.groups_mock.get = (
+ identity_fakes.FakeGroup.get_groups(self.groups))
+ self.groups_mock.delete.return_value = None
+ self.domains_mock.get.return_value = self.domain
+
+ self.cmd = group.DeleteGroup(self.app, None)
+
+ def test_group_delete(self):
+ arglist = [
+ self.groups[0].id,
+ ]
+ verifylist = [
+ ('groups', [self.groups[0].id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.groups_mock.get.assert_called_once_with(self.groups[0].id)
+ self.groups_mock.delete.assert_called_once_with(self.groups[0].id)
+ self.assertIsNone(result)
+
+ def test_group_multi_delete(self):
+ arglist = []
+ verifylist = []
+
+ for g in self.groups:
+ arglist.append(g.id)
+ verifylist = [
+ ('groups', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for g in self.groups:
+ calls.append(call(g.id))
+ self.groups_mock.delete.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_group_delete_with_domain(self):
+ get_mock_result = [exceptions.CommandError, self.groups[0]]
+ self.groups_mock.get = (
+ mock.MagicMock(side_effect=get_mock_result))
+
+ arglist = [
+ '--domain', self.domain.id,
+ self.groups[0].id,
+ ]
+ verifylist = [
+ ('domain', self.groups[0].domain_id),
+ ('groups', [self.groups[0].id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.groups_mock.get.assert_any_call(
+ self.groups[0].id, domain_id=self.domain.id)
+ self.groups_mock.delete.assert_called_once_with(self.groups[0].id)
+ self.assertIsNone(result)
+
+
+class TestGroupList(TestGroup):
+
+ domain = identity_fakes.FakeDomain.create_one_domain()
+ group = identity_fakes.FakeGroup.create_one_group()
+ user = identity_fakes.FakeUser.create_one_user()
+
+ columns = (
+ 'ID',
+ 'Name',
+ )
+ datalist = (
+ (
+ group.id,
+ group.name,
+ ),
+ )
+
+ def setUp(self):
+ super(TestGroupList, self).setUp()
+
+ self.groups_mock.get.return_value = self.group
+ self.groups_mock.list.return_value = [self.group]
+
+ self.domains_mock.get.return_value = self.domain
+
+ self.users_mock.get.return_value = self.user
+
+ # Get the command object to test
+ self.cmd = group.ListGroup(self.app, None)
+
+ def test_group_list_no_options(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'domain': None,
+ 'user': None,
+ }
+
+ self.groups_mock.list.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_group_list_domain(self):
+ arglist = [
+ '--domain', self.domain.id,
+ ]
+ verifylist = [
+ ('domain', self.domain.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'domain': self.domain.id,
+ 'user': None,
+ }
+
+ self.groups_mock.list.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_group_list_user(self):
+ arglist = [
+ '--user', self.user.name,
+ ]
+ verifylist = [
+ ('user', self.user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'domain': None,
+ 'user': self.user.id,
+ }
+
+ self.groups_mock.list.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_group_list_long(self):
+ arglist = [
+ '--long',
+ ]
+ verifylist = [
+ ('long', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'domain': None,
+ 'user': None,
+ }
+
+ self.groups_mock.list.assert_called_with(
+ **kwargs
+ )
+
+ columns = self.columns + (
+ 'Domain ID',
+ 'Description',
+ )
+ datalist = ((
+ self.group.id,
+ self.group.name,
+ self.group.domain_id,
+ self.group.description,
+ ), )
+ self.assertEqual(columns, columns)
+ self.assertEqual(datalist, tuple(data))
+
+
+class TestGroupRemoveUser(TestGroup):
+
+ group = identity_fakes.FakeGroup.create_one_group()
+ user = identity_fakes.FakeUser.create_one_user()
+
+ def setUp(self):
+ super(TestGroupRemoveUser, self).setUp()
+
+ self.groups_mock.get.return_value = self.group
+ self.users_mock.get.return_value = self.user
+ self.users_mock.remove_from_group.return_value = None
+
+ self.cmd = group.RemoveUserFromGroup(self.app, None)
+
+ def test_group_remove_user(self):
+ arglist = [
+ self.group.id,
+ self.user.id,
+ ]
+ verifylist = [
+ ('group', self.group.id),
+ ('user', self.user.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.users_mock.remove_from_group.assert_called_once_with(
+ self.user.id, self.group.id)
+ self.assertIsNone(result)
+
+
+class TestGroupSet(TestGroup):
+
+ domain = identity_fakes.FakeDomain.create_one_domain()
+ group = identity_fakes.FakeGroup.create_one_group(
+ attrs={'domain_id': domain.id})
+
+ def setUp(self):
+ super(TestGroupSet, self).setUp()
+
+ self.groups_mock.get.return_value = self.group
+ self.domains_mock.get.return_value = self.domain
+ self.groups_mock.update.return_value = None
+
+ self.cmd = group.SetGroup(self.app, None)
+
+ def test_group_set_nothing(self):
+ arglist = [
+ self.group.id,
+ ]
+ verifylist = [
+ ('group', self.group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.groups_mock.update.assert_called_once_with(self.group.id)
+ self.assertIsNone(result)
+
+ def test_group_set_name_and_description(self):
+ arglist = [
+ '--name', 'new_name',
+ '--description', 'new_description',
+ self.group.id,
+ ]
+ verifylist = [
+ ('name', 'new_name'),
+ ('description', 'new_description'),
+ ('group', self.group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ kwargs = {
+ 'name': 'new_name',
+ 'description': 'new_description',
+ }
+ self.groups_mock.update.assert_called_once_with(
+ self.group.id, **kwargs)
+ self.assertIsNone(result)
+
+ def test_group_set_with_domain(self):
+ get_mock_result = [exceptions.CommandError, self.group]
+ self.groups_mock.get = (
+ mock.MagicMock(side_effect=get_mock_result))
+
+ arglist = [
+ '--domain', self.domain.id,
+ self.group.id,
+ ]
+ verifylist = [
+ ('domain', self.domain.id),
+ ('group', self.group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.groups_mock.get.assert_any_call(
+ self.group.id, domain_id=self.domain.id)
+ self.groups_mock.update.assert_called_once_with(self.group.id)
+ self.assertIsNone(result)
+
+
+class TestGroupShow(TestGroup):
+
+ domain = identity_fakes.FakeDomain.create_one_domain()
+
+ columns = (
+ 'description',
+ 'domain_id',
+ 'id',
+ 'name',
+ )
+
+ def setUp(self):
+ super(TestGroupShow, self).setUp()
+ self.group = identity_fakes.FakeGroup.create_one_group(
+ attrs={'domain_id': self.domain.id})
+ self.data = (
+ self.group.description,
+ self.group.domain_id,
+ self.group.id,
+ self.group.name,
+ )
+
+ self.groups_mock.get.return_value = self.group
+ self.domains_mock.get.return_value = self.domain
+
+ self.cmd = group.ShowGroup(self.app, None)
+
+ def test_group_show(self):
+ arglist = [
+ self.group.id,
+ ]
+ verifylist = [
+ ('group', self.group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.groups_mock.get.assert_called_once_with(self.group.id)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_group_show_with_domain(self):
+ get_mock_result = [exceptions.CommandError, self.group]
+ self.groups_mock.get = (
+ mock.MagicMock(side_effect=get_mock_result))
+
+ arglist = [
+ '--domain', self.domain.id,
+ self.group.id,
+ ]
+ verifylist = [
+ ('domain', self.domain.id),
+ ('group', self.group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.groups_mock.get.assert_any_call(
+ self.group.id, domain_id=self.domain.id)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
diff --git a/openstackclient/tests/unit/identity/v3/test_identity_provider.py b/openstackclient/tests/unit/identity/v3/test_identity_provider.py
new file mode 100644
index 00000000..cb672a92
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v3/test_identity_provider.py
@@ -0,0 +1,593 @@
+# Copyright 2014 CERN.
+#
+# 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.
+
+import copy
+import mock
+
+from openstackclient.identity.v3 import identity_provider
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+
+
+class TestIdentityProvider(identity_fakes.TestFederatedIdentity):
+
+ def setUp(self):
+ super(TestIdentityProvider, self).setUp()
+
+ federation_lib = self.app.client_manager.identity.federation
+ self.identity_providers_mock = federation_lib.identity_providers
+ self.identity_providers_mock.reset_mock()
+
+
+class TestIdentityProviderCreate(TestIdentityProvider):
+
+ columns = (
+ 'description',
+ 'enabled',
+ 'id',
+ 'remote_ids',
+ )
+ datalist = (
+ identity_fakes.idp_description,
+ True,
+ identity_fakes.idp_id,
+ identity_fakes.formatted_idp_remote_ids,
+ )
+
+ def setUp(self):
+ super(TestIdentityProviderCreate, self).setUp()
+
+ copied_idp = copy.deepcopy(identity_fakes.IDENTITY_PROVIDER)
+ resource = fakes.FakeResource(None, copied_idp, loaded=True)
+ self.identity_providers_mock.create.return_value = resource
+ self.cmd = identity_provider.CreateIdentityProvider(self.app, None)
+
+ def test_create_identity_provider_no_options(self):
+ arglist = [
+ identity_fakes.idp_id,
+ ]
+ verifylist = [
+ ('identity_provider_id', identity_fakes.idp_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'remote_ids': None,
+ 'enabled': True,
+ 'description': None,
+ }
+
+ self.identity_providers_mock.create.assert_called_with(
+ id=identity_fakes.idp_id,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_create_identity_provider_description(self):
+ arglist = [
+ '--description', identity_fakes.idp_description,
+ identity_fakes.idp_id,
+ ]
+ verifylist = [
+ ('identity_provider_id', identity_fakes.idp_id),
+ ('description', identity_fakes.idp_description),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'remote_ids': None,
+ 'description': identity_fakes.idp_description,
+ 'enabled': True,
+ }
+
+ self.identity_providers_mock.create.assert_called_with(
+ id=identity_fakes.idp_id,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_create_identity_provider_remote_id(self):
+ arglist = [
+ identity_fakes.idp_id,
+ '--remote-id', identity_fakes.idp_remote_ids[0]
+ ]
+ verifylist = [
+ ('identity_provider_id', identity_fakes.idp_id),
+ ('remote_id', identity_fakes.idp_remote_ids[:1]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'remote_ids': identity_fakes.idp_remote_ids[:1],
+ 'description': None,
+ 'enabled': True,
+ }
+
+ self.identity_providers_mock.create.assert_called_with(
+ id=identity_fakes.idp_id,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_create_identity_provider_remote_ids_multiple(self):
+ arglist = [
+ '--remote-id', identity_fakes.idp_remote_ids[0],
+ '--remote-id', identity_fakes.idp_remote_ids[1],
+ identity_fakes.idp_id
+ ]
+ verifylist = [
+ ('identity_provider_id', identity_fakes.idp_id),
+ ('remote_id', identity_fakes.idp_remote_ids),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'remote_ids': identity_fakes.idp_remote_ids,
+ 'description': None,
+ 'enabled': True,
+ }
+
+ self.identity_providers_mock.create.assert_called_with(
+ id=identity_fakes.idp_id,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_create_identity_provider_remote_ids_file(self):
+ arglist = [
+ '--remote-id-file', '/tmp/file_name',
+ identity_fakes.idp_id,
+ ]
+ verifylist = [
+ ('identity_provider_id', identity_fakes.idp_id),
+ ('remote_id_file', '/tmp/file_name'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ mocker = mock.Mock()
+ mocker.return_value = "\n".join(identity_fakes.idp_remote_ids)
+ with mock.patch("openstackclient.identity.v3.identity_provider."
+ "utils.read_blob_file_contents", mocker):
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'remote_ids': identity_fakes.idp_remote_ids,
+ 'description': None,
+ 'enabled': True,
+ }
+
+ self.identity_providers_mock.create.assert_called_with(
+ id=identity_fakes.idp_id,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_create_identity_provider_disabled(self):
+
+ # Prepare FakeResource object
+ IDENTITY_PROVIDER = copy.deepcopy(identity_fakes.IDENTITY_PROVIDER)
+ IDENTITY_PROVIDER['enabled'] = False
+ IDENTITY_PROVIDER['description'] = None
+
+ resource = fakes.FakeResource(None, IDENTITY_PROVIDER, loaded=True)
+ self.identity_providers_mock.create.return_value = resource
+
+ arglist = [
+ '--disable',
+ identity_fakes.idp_id,
+ ]
+ verifylist = [
+ ('identity_provider_id', identity_fakes.idp_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'remote_ids': None,
+ 'enabled': False,
+ 'description': None,
+ }
+
+ self.identity_providers_mock.create.assert_called_with(
+ id=identity_fakes.idp_id,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ datalist = (
+ None,
+ False,
+ identity_fakes.idp_id,
+ identity_fakes.formatted_idp_remote_ids
+ )
+ self.assertEqual(datalist, data)
+
+
+class TestIdentityProviderDelete(TestIdentityProvider):
+
+ def setUp(self):
+ super(TestIdentityProviderDelete, self).setUp()
+
+ # This is the return value for utils.find_resource()
+ self.identity_providers_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.IDENTITY_PROVIDER),
+ loaded=True,
+ )
+
+ self.identity_providers_mock.delete.return_value = None
+ self.cmd = identity_provider.DeleteIdentityProvider(self.app, None)
+
+ def test_delete_identity_provider(self):
+ arglist = [
+ identity_fakes.idp_id,
+ ]
+ verifylist = [
+ ('identity_provider', [identity_fakes.idp_id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.identity_providers_mock.delete.assert_called_with(
+ identity_fakes.idp_id,
+ )
+ self.assertIsNone(result)
+
+
+class TestIdentityProviderList(TestIdentityProvider):
+
+ def setUp(self):
+ super(TestIdentityProviderList, self).setUp()
+
+ self.identity_providers_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.IDENTITY_PROVIDER),
+ loaded=True,
+ )
+ self.identity_providers_mock.list.return_value = [
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.IDENTITY_PROVIDER),
+ loaded=True,
+ ),
+ ]
+
+ # Get the command object to test
+ self.cmd = identity_provider.ListIdentityProvider(self.app, None)
+
+ def test_identity_provider_list_no_options(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.identity_providers_mock.list.assert_called_with()
+
+ collist = ('ID', 'Enabled', 'Description')
+ self.assertEqual(collist, columns)
+ datalist = ((
+ identity_fakes.idp_id,
+ True,
+ identity_fakes.idp_description,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+
+class TestIdentityProviderSet(TestIdentityProvider):
+
+ columns = (
+ 'description',
+ 'enabled',
+ 'id',
+ 'remote_ids',
+ )
+ datalist = (
+ identity_fakes.idp_description,
+ True,
+ identity_fakes.idp_id,
+ identity_fakes.idp_remote_ids,
+ )
+
+ def setUp(self):
+ super(TestIdentityProviderSet, self).setUp()
+ self.cmd = identity_provider.SetIdentityProvider(self.app, None)
+
+ def test_identity_provider_set_description(self):
+ """Set Identity Provider's description. """
+
+ def prepare(self):
+ """Prepare fake return objects before the test is executed"""
+ updated_idp = copy.deepcopy(identity_fakes.IDENTITY_PROVIDER)
+ updated_idp['enabled'] = False
+ resources = fakes.FakeResource(
+ None,
+ updated_idp,
+ loaded=True
+ )
+ self.identity_providers_mock.update.return_value = resources
+
+ prepare(self)
+ new_description = 'new desc'
+ arglist = [
+ '--description', new_description,
+ identity_fakes.idp_id
+ ]
+ verifylist = [
+ ('identity_provider', identity_fakes.idp_id),
+ ('description', new_description),
+ ('enable', False),
+ ('disable', False),
+ ('remote_id', None)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.cmd.take_action(parsed_args)
+ self.identity_providers_mock.update.assert_called_with(
+ identity_fakes.idp_id,
+ description=new_description,
+ )
+
+ def test_identity_provider_disable(self):
+ """Disable Identity Provider
+
+ Set Identity Provider's ``enabled`` attribute to False.
+ """
+
+ def prepare(self):
+ """Prepare fake return objects before the test is executed"""
+ updated_idp = copy.deepcopy(identity_fakes.IDENTITY_PROVIDER)
+ updated_idp['enabled'] = False
+ resources = fakes.FakeResource(
+ None,
+ updated_idp,
+ loaded=True
+ )
+ self.identity_providers_mock.update.return_value = resources
+
+ prepare(self)
+ arglist = [
+ '--disable', identity_fakes.idp_id,
+ '--remote-id', identity_fakes.idp_remote_ids[0],
+ '--remote-id', identity_fakes.idp_remote_ids[1]
+ ]
+ verifylist = [
+ ('identity_provider', identity_fakes.idp_id),
+ ('description', None),
+ ('enable', False),
+ ('disable', True),
+ ('remote_id', identity_fakes.idp_remote_ids)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+ self.identity_providers_mock.update.assert_called_with(
+ identity_fakes.idp_id,
+ enabled=False,
+ remote_ids=identity_fakes.idp_remote_ids
+ )
+
+ def test_identity_provider_enable(self):
+ """Enable Identity Provider.
+
+ Set Identity Provider's ``enabled`` attribute to True.
+ """
+
+ def prepare(self):
+ """Prepare fake return objects before the test is executed"""
+ resources = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.IDENTITY_PROVIDER),
+ loaded=True
+ )
+ self.identity_providers_mock.update.return_value = resources
+
+ prepare(self)
+ arglist = [
+ '--enable', identity_fakes.idp_id,
+ '--remote-id', identity_fakes.idp_remote_ids[0],
+ '--remote-id', identity_fakes.idp_remote_ids[1]
+ ]
+ verifylist = [
+ ('identity_provider', identity_fakes.idp_id),
+ ('description', None),
+ ('enable', True),
+ ('disable', False),
+ ('remote_id', identity_fakes.idp_remote_ids)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+ self.identity_providers_mock.update.assert_called_with(
+ identity_fakes.idp_id, enabled=True,
+ remote_ids=identity_fakes.idp_remote_ids)
+
+ def test_identity_provider_replace_remote_ids(self):
+ """Enable Identity Provider.
+
+ Set Identity Provider's ``enabled`` attribute to True.
+ """
+
+ def prepare(self):
+ """Prepare fake return objects before the test is executed"""
+ self.new_remote_id = 'new_entity'
+
+ updated_idp = copy.deepcopy(identity_fakes.IDENTITY_PROVIDER)
+ updated_idp['remote_ids'] = [self.new_remote_id]
+ resources = fakes.FakeResource(
+ None,
+ updated_idp,
+ loaded=True
+ )
+ self.identity_providers_mock.update.return_value = resources
+
+ prepare(self)
+ arglist = [
+ '--enable', identity_fakes.idp_id,
+ '--remote-id', self.new_remote_id
+ ]
+ verifylist = [
+ ('identity_provider', identity_fakes.idp_id),
+ ('description', None),
+ ('enable', True),
+ ('disable', False),
+ ('remote_id', [self.new_remote_id])
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+ self.identity_providers_mock.update.assert_called_with(
+ identity_fakes.idp_id, enabled=True,
+ remote_ids=[self.new_remote_id])
+
+ def test_identity_provider_replace_remote_ids_file(self):
+ """Enable Identity Provider.
+
+ Set Identity Provider's ``enabled`` attribute to True.
+ """
+
+ def prepare(self):
+ """Prepare fake return objects before the test is executed"""
+ self.new_remote_id = 'new_entity'
+
+ updated_idp = copy.deepcopy(identity_fakes.IDENTITY_PROVIDER)
+ updated_idp['remote_ids'] = [self.new_remote_id]
+ resources = fakes.FakeResource(
+ None,
+ updated_idp,
+ loaded=True
+ )
+ self.identity_providers_mock.update.return_value = resources
+
+ prepare(self)
+ arglist = [
+ '--enable', identity_fakes.idp_id,
+ '--remote-id-file', self.new_remote_id,
+ ]
+ verifylist = [
+ ('identity_provider', identity_fakes.idp_id),
+ ('description', None),
+ ('enable', True),
+ ('disable', False),
+ ('remote_id_file', self.new_remote_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ mocker = mock.Mock()
+ mocker.return_value = self.new_remote_id
+ with mock.patch("openstackclient.identity.v3.identity_provider."
+ "utils.read_blob_file_contents", mocker):
+ self.cmd.take_action(parsed_args)
+ self.identity_providers_mock.update.assert_called_with(
+ identity_fakes.idp_id, enabled=True,
+ remote_ids=[self.new_remote_id])
+
+ def test_identity_provider_no_options(self):
+ def prepare(self):
+ """Prepare fake return objects before the test is executed"""
+ resources = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.IDENTITY_PROVIDER),
+ loaded=True
+ )
+ self.identity_providers_mock.get.return_value = resources
+
+ resources = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.IDENTITY_PROVIDER),
+ loaded=True,
+ )
+ self.identity_providers_mock.update.return_value = resources
+
+ prepare(self)
+ arglist = [
+ identity_fakes.idp_id,
+ ]
+ verifylist = [
+ ('identity_provider', identity_fakes.idp_id),
+ ('enable', False),
+ ('disable', False),
+ ('remote_id', None)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+
+
+class TestIdentityProviderShow(TestIdentityProvider):
+
+ def setUp(self):
+ super(TestIdentityProviderShow, self).setUp()
+
+ ret = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.IDENTITY_PROVIDER),
+ loaded=True,
+ )
+
+ self.identity_providers_mock.get.side_effect = [Exception("Not found"),
+ ret]
+ self.identity_providers_mock.get.return_value = ret
+
+ # Get the command object to test
+ self.cmd = identity_provider.ShowIdentityProvider(self.app, None)
+
+ def test_identity_provider_show(self):
+ arglist = [
+ identity_fakes.idp_id,
+ ]
+ verifylist = [
+ ('identity_provider', identity_fakes.idp_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.identity_providers_mock.get.assert_called_with(
+ identity_fakes.idp_id,
+ id='test_idp'
+ )
+
+ collist = ('description', 'enabled', 'id', 'remote_ids')
+ self.assertEqual(collist, columns)
+ datalist = (
+ identity_fakes.idp_description,
+ True,
+ identity_fakes.idp_id,
+ identity_fakes.formatted_idp_remote_ids
+ )
+ self.assertEqual(datalist, data)
diff --git a/openstackclient/tests/unit/identity/v3/test_mappings.py b/openstackclient/tests/unit/identity/v3/test_mappings.py
new file mode 100644
index 00000000..5086724c
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v3/test_mappings.py
@@ -0,0 +1,244 @@
+# Copyright 2014 CERN.
+#
+# 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.
+
+import copy
+import mock
+
+from osc_lib import exceptions
+
+from openstackclient.identity.v3 import mapping
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+
+
+class TestMapping(identity_fakes.TestFederatedIdentity):
+
+ def setUp(self):
+ super(TestMapping, self).setUp()
+
+ federation_lib = self.app.client_manager.identity.federation
+ self.mapping_mock = federation_lib.mappings
+ self.mapping_mock.reset_mock()
+
+
+class TestMappingCreate(TestMapping):
+
+ def setUp(self):
+ super(TestMappingCreate, self).setUp()
+ self.mapping_mock.create.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.MAPPING_RESPONSE),
+ loaded=True
+ )
+ self.cmd = mapping.CreateMapping(self.app, None)
+
+ def test_create_mapping(self):
+ arglist = [
+ '--rules', identity_fakes.mapping_rules_file_path,
+ identity_fakes.mapping_id
+ ]
+ verifylist = [
+ ('mapping', identity_fakes.mapping_id),
+ ('rules', identity_fakes.mapping_rules_file_path)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ mocker = mock.Mock()
+ mocker.return_value = identity_fakes.MAPPING_RULES
+ with mock.patch("openstackclient.identity.v3.mapping."
+ "CreateMapping._read_rules", mocker):
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.mapping_mock.create.assert_called_with(
+ mapping_id=identity_fakes.mapping_id,
+ rules=identity_fakes.MAPPING_RULES)
+
+ collist = ('id', 'rules')
+ self.assertEqual(collist, columns)
+
+ datalist = (identity_fakes.mapping_id,
+ identity_fakes.MAPPING_RULES)
+ self.assertEqual(datalist, data)
+
+
+class TestMappingDelete(TestMapping):
+
+ def setUp(self):
+ super(TestMappingDelete, self).setUp()
+ self.mapping_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.MAPPING_RESPONSE),
+ loaded=True)
+
+ self.mapping_mock.delete.return_value = None
+ self.cmd = mapping.DeleteMapping(self.app, None)
+
+ def test_delete_mapping(self):
+ arglist = [
+ identity_fakes.mapping_id
+ ]
+ verifylist = [
+ ('mapping', [identity_fakes.mapping_id])
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.mapping_mock.delete.assert_called_with(
+ identity_fakes.mapping_id)
+ self.assertIsNone(result)
+
+
+class TestMappingList(TestMapping):
+
+ def setUp(self):
+ super(TestMappingList, self).setUp()
+ self.mapping_mock.get.return_value = fakes.FakeResource(
+ None,
+ {'id': identity_fakes.mapping_id},
+ loaded=True)
+ # Pretend list command returns list of two mappings.
+ # NOTE(marek-denis): We are returning FakeResources with mapping id
+ # only as ShowMapping class is implemented in a way where rules will
+ # not be displayed, only mapping ids.
+ self.mapping_mock.list.return_value = [
+ fakes.FakeResource(
+ None,
+ {'id': identity_fakes.mapping_id},
+ loaded=True,
+ ),
+ fakes.FakeResource(
+ None,
+ {'id': 'extra_mapping'},
+ loaded=True,
+ ),
+ ]
+
+ # Get the command object to test
+ self.cmd = mapping.ListMapping(self.app, None)
+
+ def test_mapping_list(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.mapping_mock.list.assert_called_with()
+
+ collist = ('ID',)
+ self.assertEqual(collist, columns)
+
+ datalist = [(identity_fakes.mapping_id,), ('extra_mapping',)]
+ self.assertEqual(datalist, data)
+
+
+class TestMappingSet(TestMapping):
+
+ def setUp(self):
+ super(TestMappingSet, self).setUp()
+
+ self.mapping_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.MAPPING_RESPONSE),
+ loaded=True
+ )
+
+ self.mapping_mock.update.return_value = fakes.FakeResource(
+ None,
+ identity_fakes.MAPPING_RESPONSE_2,
+ loaded=True
+ )
+
+ # Get the command object to test
+ self.cmd = mapping.SetMapping(self.app, None)
+
+ def test_set_new_rules(self):
+ arglist = [
+ '--rules', identity_fakes.mapping_rules_file_path,
+ identity_fakes.mapping_id
+ ]
+ verifylist = [
+ ('mapping', identity_fakes.mapping_id),
+ ('rules', identity_fakes.mapping_rules_file_path)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ mocker = mock.Mock()
+ mocker.return_value = identity_fakes.MAPPING_RULES_2
+ with mock.patch("openstackclient.identity.v3.mapping."
+ "SetMapping._read_rules", mocker):
+ columns, data = self.cmd.take_action(parsed_args)
+ self.mapping_mock.update.assert_called_with(
+ mapping=identity_fakes.mapping_id,
+ rules=identity_fakes.MAPPING_RULES_2)
+
+ collist = ('id', 'rules')
+ self.assertEqual(collist, columns)
+ datalist = (identity_fakes.mapping_id,
+ identity_fakes.MAPPING_RULES_2)
+ self.assertEqual(datalist, data)
+
+ def test_set_rules_wrong_file_path(self):
+ arglist = [
+ '--rules', identity_fakes.mapping_rules_file_path,
+ identity_fakes.mapping_id
+ ]
+ verifylist = [
+ ('mapping', identity_fakes.mapping_id),
+ ('rules', identity_fakes.mapping_rules_file_path)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(
+ exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
+
+
+class TestMappingShow(TestMapping):
+
+ def setUp(self):
+ super(TestMappingShow, self).setUp()
+
+ self.mapping_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.MAPPING_RESPONSE),
+ loaded=True
+ )
+
+ self.cmd = mapping.ShowMapping(self.app, None)
+
+ def test_mapping_show(self):
+ arglist = [
+ identity_fakes.mapping_id
+ ]
+ verifylist = [
+ ('mapping', identity_fakes.mapping_id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.mapping_mock.get.assert_called_with(
+ identity_fakes.mapping_id)
+
+ collist = ('id', 'rules')
+ self.assertEqual(collist, columns)
+
+ datalist = (identity_fakes.mapping_id,
+ identity_fakes.MAPPING_RULES)
+ self.assertEqual(datalist, data)
diff --git a/openstackclient/tests/unit/identity/v3/test_oauth.py b/openstackclient/tests/unit/identity/v3/test_oauth.py
new file mode 100644
index 00000000..3aabd9b8
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v3/test_oauth.py
@@ -0,0 +1,173 @@
+# 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.
+
+import copy
+
+from openstackclient.identity.v3 import token
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+
+
+class TestOAuth1(identity_fakes.TestOAuth1):
+
+ def setUp(self):
+ super(TestOAuth1, self).setUp()
+ identity_client = self.app.client_manager.identity
+ self.access_tokens_mock = identity_client.oauth1.access_tokens
+ self.access_tokens_mock.reset_mock()
+ self.request_tokens_mock = identity_client.oauth1.request_tokens
+ self.request_tokens_mock.reset_mock()
+ self.projects_mock = identity_client.projects
+ self.projects_mock.reset_mock()
+ self.roles_mock = identity_client.roles
+ self.roles_mock.reset_mock()
+
+
+class TestAccessTokenCreate(TestOAuth1):
+
+ def setUp(self):
+ super(TestAccessTokenCreate, self).setUp()
+
+ self.access_tokens_mock.create.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.OAUTH_ACCESS_TOKEN),
+ loaded=True,
+ )
+
+ self.cmd = token.CreateAccessToken(self.app, None)
+
+ def test_create_access_tokens(self):
+ arglist = [
+ '--consumer-key', identity_fakes.consumer_id,
+ '--consumer-secret', identity_fakes.consumer_secret,
+ '--request-key', identity_fakes.request_token_id,
+ '--request-secret', identity_fakes.request_token_secret,
+ '--verifier', identity_fakes.oauth_verifier_pin,
+ ]
+ verifylist = [
+ ('consumer_key', identity_fakes.consumer_id),
+ ('consumer_secret', identity_fakes.consumer_secret),
+ ('request_key', identity_fakes.request_token_id),
+ ('request_secret', identity_fakes.request_token_secret),
+ ('verifier', identity_fakes.oauth_verifier_pin),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.access_tokens_mock.create.assert_called_with(
+ identity_fakes.consumer_id,
+ identity_fakes.consumer_secret,
+ identity_fakes.request_token_id,
+ identity_fakes.request_token_secret,
+ identity_fakes.oauth_verifier_pin,
+ )
+
+ collist = ('expires', 'id', 'key', 'secret')
+ self.assertEqual(collist, columns)
+ datalist = (
+ identity_fakes.access_token_expires,
+ identity_fakes.access_token_id,
+ identity_fakes.access_token_id,
+ identity_fakes.access_token_secret,
+ )
+ self.assertEqual(datalist, data)
+
+
+class TestRequestTokenAuthorize(TestOAuth1):
+
+ def setUp(self):
+ super(TestRequestTokenAuthorize, self).setUp()
+
+ self.roles_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.ROLE),
+ loaded=True,
+ )
+
+ copied_verifier = copy.deepcopy(identity_fakes.OAUTH_VERIFIER)
+ resource = fakes.FakeResource(None, copied_verifier, loaded=True)
+ self.request_tokens_mock.authorize.return_value = resource
+ self.cmd = token.AuthorizeRequestToken(self.app, None)
+
+ def test_authorize_request_tokens(self):
+ arglist = [
+ '--request-key', identity_fakes.request_token_id,
+ '--role', identity_fakes.role_name,
+ ]
+ verifylist = [
+ ('request_key', identity_fakes.request_token_id),
+ ('role', [identity_fakes.role_name]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.request_tokens_mock.authorize.assert_called_with(
+ identity_fakes.request_token_id,
+ [identity_fakes.role_id],
+ )
+
+ collist = ('oauth_verifier',)
+ self.assertEqual(collist, columns)
+ datalist = (
+ identity_fakes.oauth_verifier_pin,
+ )
+ self.assertEqual(datalist, data)
+
+
+class TestRequestTokenCreate(TestOAuth1):
+
+ def setUp(self):
+ super(TestRequestTokenCreate, self).setUp()
+
+ self.request_tokens_mock.create.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.OAUTH_REQUEST_TOKEN),
+ loaded=True,
+ )
+
+ self.projects_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.PROJECT),
+ loaded=True,
+ )
+
+ self.cmd = token.CreateRequestToken(self.app, None)
+
+ def test_create_request_tokens(self):
+ arglist = [
+ '--consumer-key', identity_fakes.consumer_id,
+ '--consumer-secret', identity_fakes.consumer_secret,
+ '--project', identity_fakes.project_id,
+ ]
+ verifylist = [
+ ('consumer_key', identity_fakes.consumer_id),
+ ('consumer_secret', identity_fakes.consumer_secret),
+ ('project', identity_fakes.project_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.request_tokens_mock.create.assert_called_with(
+ identity_fakes.consumer_id,
+ identity_fakes.consumer_secret,
+ identity_fakes.project_id,
+ )
+
+ collist = ('expires', 'id', 'key', 'secret')
+ self.assertEqual(collist, columns)
+ datalist = (
+ identity_fakes.request_token_expires,
+ identity_fakes.request_token_id,
+ identity_fakes.request_token_id,
+ identity_fakes.request_token_secret,
+ )
+ self.assertEqual(datalist, data)
diff --git a/openstackclient/tests/unit/identity/v3/test_project.py b/openstackclient/tests/unit/identity/v3/test_project.py
new file mode 100644
index 00000000..702d9209
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v3/test_project.py
@@ -0,0 +1,978 @@
+# Copyright 2013 Nebula Inc.
+#
+# 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.
+#
+
+import mock
+
+from osc_lib import exceptions
+
+from openstackclient.identity.v3 import project
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+
+
+class TestProject(identity_fakes.TestIdentityv3):
+
+ def setUp(self):
+ super(TestProject, self).setUp()
+
+ # Get a shortcut to the DomainManager Mock
+ self.domains_mock = self.app.client_manager.identity.domains
+ self.domains_mock.reset_mock()
+
+ # Get a shortcut to the ProjectManager Mock
+ self.projects_mock = self.app.client_manager.identity.projects
+ self.projects_mock.reset_mock()
+
+
+class TestProjectCreate(TestProject):
+
+ domain = identity_fakes.FakeDomain.create_one_domain()
+
+ columns = (
+ 'description',
+ 'domain_id',
+ 'enabled',
+ 'id',
+ 'is_domain',
+ 'name',
+ 'parent_id',
+ )
+
+ def setUp(self):
+ super(TestProjectCreate, self).setUp()
+
+ self.project = identity_fakes.FakeProject.create_one_project(
+ attrs={'domain_id': self.domain.id})
+ self.domains_mock.get.return_value = self.domain
+ self.projects_mock.create.return_value = self.project
+ self.datalist = (
+ self.project.description,
+ self.project.domain_id,
+ True,
+ self.project.id,
+ False,
+ self.project.name,
+ self.project.parent_id,
+ )
+ # Get the command object to test
+ self.cmd = project.CreateProject(self.app, None)
+
+ def test_project_create_no_options(self):
+ arglist = [
+ self.project.name,
+ ]
+ verifylist = [
+ ('parent', None),
+ ('enable', False),
+ ('disable', False),
+ ('name', self.project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': self.project.name,
+ 'domain': None,
+ 'description': None,
+ 'enabled': True,
+ 'parent': None,
+ }
+ # ProjectManager.create(name=, domain=, description=,
+ # enabled=, **kwargs)
+ self.projects_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ collist = (
+ 'description',
+ 'domain_id',
+ 'enabled',
+ 'id',
+ 'is_domain',
+ 'name',
+ 'parent_id',
+ )
+ self.assertEqual(collist, columns)
+ datalist = (
+ self.project.description,
+ self.project.domain_id,
+ True,
+ self.project.id,
+ False,
+ self.project.name,
+ self.project.parent_id,
+ )
+ self.assertEqual(datalist, data)
+
+ def test_project_create_description(self):
+ arglist = [
+ '--description', 'new desc',
+ self.project.name,
+ ]
+ verifylist = [
+ ('description', 'new desc'),
+ ('enable', False),
+ ('disable', False),
+ ('name', self.project.name),
+ ('parent', None),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': self.project.name,
+ 'domain': None,
+ 'description': 'new desc',
+ 'enabled': True,
+ 'parent': None,
+ }
+ # ProjectManager.create(name=, domain=, description=,
+ # enabled=, **kwargs)
+ self.projects_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_project_create_domain(self):
+ arglist = [
+ '--domain', self.project.domain_id,
+ self.project.name,
+ ]
+ verifylist = [
+ ('domain', self.project.domain_id),
+ ('enable', False),
+ ('disable', False),
+ ('name', self.project.name),
+ ('parent', None),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': self.project.name,
+ 'domain': self.project.domain_id,
+ 'description': None,
+ 'enabled': True,
+ 'parent': None,
+ }
+ # ProjectManager.create(name=, domain=, description=,
+ # enabled=, **kwargs)
+ self.projects_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_project_create_domain_no_perms(self):
+ arglist = [
+ '--domain', self.project.domain_id,
+ self.project.name,
+ ]
+ verifylist = [
+ ('domain', self.project.domain_id),
+ ('enable', False),
+ ('disable', False),
+ ('name', self.project.name),
+ ('parent', None),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ mocker = mock.Mock()
+ mocker.return_value = None
+
+ with mock.patch("osc_lib.utils.find_resource", mocker):
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': self.project.name,
+ 'domain': self.project.domain_id,
+ 'description': None,
+ 'enabled': True,
+ 'parent': None,
+ }
+ self.projects_mock.create.assert_called_with(
+ **kwargs
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_project_create_enable(self):
+ arglist = [
+ '--enable',
+ self.project.name,
+ ]
+ verifylist = [
+ ('enable', True),
+ ('disable', False),
+ ('name', self.project.name),
+ ('parent', None),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': self.project.name,
+ 'domain': None,
+ 'description': None,
+ 'enabled': True,
+ 'parent': None,
+ }
+ # ProjectManager.create(name=, domain=, description=,
+ # enabled=, **kwargs)
+ self.projects_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_project_create_disable(self):
+ arglist = [
+ '--disable',
+ self.project.name,
+ ]
+ verifylist = [
+ ('enable', False),
+ ('disable', True),
+ ('name', self.project.name),
+ ('parent', None),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': self.project.name,
+ 'domain': None,
+ 'description': None,
+ 'enabled': False,
+ 'parent': None,
+ }
+ # ProjectManager.create(name=, domain=,
+ # description=, enabled=, **kwargs)
+ self.projects_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_project_create_property(self):
+ arglist = [
+ '--property', 'fee=fi',
+ '--property', 'fo=fum',
+ self.project.name,
+ ]
+ verifylist = [
+ ('property', {'fee': 'fi', 'fo': 'fum'}),
+ ('name', self.project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': self.project.name,
+ 'domain': None,
+ 'description': None,
+ 'enabled': True,
+ 'parent': None,
+ 'fee': 'fi',
+ 'fo': 'fum',
+ }
+ # ProjectManager.create(name=, domain=, description=,
+ # enabled=, **kwargs)
+ self.projects_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_project_create_parent(self):
+ self.parent = identity_fakes.FakeProject.create_one_project()
+ self.project = identity_fakes.FakeProject.create_one_project(
+ attrs={'domain_id': self.domain.id, 'parent_id': self.parent.id})
+ self.projects_mock.get.return_value = self.parent
+ self.projects_mock.create.return_value = self.project
+
+ arglist = [
+ '--domain', self.project.domain_id,
+ '--parent', self.parent.name,
+ self.project.name,
+ ]
+ verifylist = [
+ ('domain', self.project.domain_id),
+ ('parent', self.parent.name),
+ ('enable', False),
+ ('disable', False),
+ ('name', self.project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ kwargs = {
+ 'name': self.project.name,
+ 'domain': self.project.domain_id,
+ 'parent': self.parent.id,
+ 'description': None,
+ 'enabled': True,
+ }
+
+ self.projects_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ collist = (
+ 'description',
+ 'domain_id',
+ 'enabled',
+ 'id',
+ 'is_domain',
+ 'name',
+ 'parent_id',
+ )
+ self.assertEqual(columns, collist)
+ datalist = (
+ self.project.description,
+ self.project.domain_id,
+ self.project.enabled,
+ self.project.id,
+ self.project.is_domain,
+ self.project.name,
+ self.parent.id,
+ )
+ self.assertEqual(data, datalist)
+
+ def test_project_create_invalid_parent(self):
+ self.projects_mock.resource_class.__name__ = 'Project'
+ self.projects_mock.get.side_effect = exceptions.NotFound(
+ 'Invalid parent')
+ self.projects_mock.find.side_effect = exceptions.NotFound(
+ 'Invalid parent')
+
+ arglist = [
+ '--domain', self.project.domain_id,
+ '--parent', 'invalid',
+ self.project.name,
+ ]
+ verifylist = [
+ ('domain', self.project.domain_id),
+ ('parent', 'invalid'),
+ ('enable', False),
+ ('disable', False),
+ ('name', self.project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(
+ exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args,
+ )
+
+
+class TestProjectDelete(TestProject):
+
+ project = identity_fakes.FakeProject.create_one_project()
+
+ def setUp(self):
+ super(TestProjectDelete, self).setUp()
+
+ # This is the return value for utils.find_resource()
+ self.projects_mock.get.return_value = self.project
+ self.projects_mock.delete.return_value = None
+
+ # Get the command object to test
+ self.cmd = project.DeleteProject(self.app, None)
+
+ def test_project_delete_no_options(self):
+ arglist = [
+ self.project.id,
+ ]
+ verifylist = [
+ ('projects', [self.project.id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.projects_mock.delete.assert_called_with(
+ self.project.id,
+ )
+ self.assertIsNone(result)
+
+
+class TestProjectList(TestProject):
+
+ domain = identity_fakes.FakeDomain.create_one_domain()
+ project = identity_fakes.FakeProject.create_one_project(
+ attrs={'domain_id': domain.id})
+
+ columns = (
+ 'ID',
+ 'Name',
+ )
+ datalist = (
+ (
+ project.id,
+ project.name,
+ ),
+ )
+
+ def setUp(self):
+ super(TestProjectList, self).setUp()
+
+ self.projects_mock.list.return_value = [self.project]
+
+ # Get the command object to test
+ self.cmd = project.ListProject(self.app, None)
+
+ def test_project_list_no_options(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.projects_mock.list.assert_called_with()
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_project_list_long(self):
+ arglist = [
+ '--long',
+ ]
+ verifylist = [
+ ('long', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.projects_mock.list.assert_called_with()
+
+ collist = ('ID', 'Name', 'Domain ID', 'Description', 'Enabled')
+ self.assertEqual(collist, columns)
+ datalist = ((
+ self.project.id,
+ self.project.name,
+ self.project.domain_id,
+ self.project.description,
+ True,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_project_list_domain(self):
+ arglist = [
+ '--domain', self.project.domain_id,
+ ]
+ verifylist = [
+ ('domain', self.project.domain_id),
+ ]
+
+ self.domains_mock.get.return_value = self.domain
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.projects_mock.list.assert_called_with(
+ domain=self.project.domain_id)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_project_list_domain_no_perms(self):
+ arglist = [
+ '--domain', self.project.domain_id,
+ ]
+ verifylist = [
+ ('domain', self.project.domain_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ mocker = mock.Mock()
+ mocker.return_value = None
+
+ with mock.patch("osc_lib.utils.find_resource", mocker):
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.projects_mock.list.assert_called_with(
+ domain=self.project.domain_id)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+
+class TestProjectSet(TestProject):
+
+ domain = identity_fakes.FakeDomain.create_one_domain()
+ project = identity_fakes.FakeProject.create_one_project(
+ attrs={'domain_id': domain.id})
+
+ def setUp(self):
+ super(TestProjectSet, self).setUp()
+
+ self.domains_mock.get.return_value = self.domain
+
+ self.projects_mock.get.return_value = self.project
+ self.projects_mock.update.return_value = self.project
+
+ # Get the command object to test
+ self.cmd = project.SetProject(self.app, None)
+
+ def test_project_set_no_options(self):
+ arglist = [
+ self.project.name,
+ ]
+ verifylist = [
+ ('project', self.project.name),
+ ('enable', False),
+ ('disable', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.assertIsNone(result)
+
+ def test_project_set_name(self):
+ arglist = [
+ '--name', 'qwerty',
+ '--domain', self.project.domain_id,
+ self.project.name,
+ ]
+ verifylist = [
+ ('name', 'qwerty'),
+ ('domain', self.project.domain_id),
+ ('enable', False),
+ ('disable', False),
+ ('project', self.project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': 'qwerty',
+ }
+ # ProjectManager.update(project, name=, domain=, description=,
+ # enabled=, **kwargs)
+ self.projects_mock.update.assert_called_with(
+ self.project.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_project_set_description(self):
+ arglist = [
+ '--domain', self.project.domain_id,
+ '--description', 'new desc',
+ self.project.name,
+ ]
+ verifylist = [
+ ('domain', self.project.domain_id),
+ ('description', 'new desc'),
+ ('enable', False),
+ ('disable', False),
+ ('project', self.project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'description': 'new desc',
+ }
+ self.projects_mock.update.assert_called_with(
+ self.project.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_project_set_enable(self):
+ arglist = [
+ '--domain', self.project.domain_id,
+ '--enable',
+ self.project.name,
+ ]
+ verifylist = [
+ ('domain', self.project.domain_id),
+ ('enable', True),
+ ('disable', False),
+ ('project', self.project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': True,
+ }
+ self.projects_mock.update.assert_called_with(
+ self.project.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_project_set_disable(self):
+ arglist = [
+ '--domain', self.project.domain_id,
+ '--disable',
+ self.project.name,
+ ]
+ verifylist = [
+ ('domain', self.project.domain_id),
+ ('enable', False),
+ ('disable', True),
+ ('project', self.project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': False,
+ }
+ self.projects_mock.update.assert_called_with(
+ self.project.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_project_set_property(self):
+ arglist = [
+ '--domain', self.project.domain_id,
+ '--property', 'fee=fi',
+ '--property', 'fo=fum',
+ self.project.name,
+ ]
+ verifylist = [
+ ('domain', self.project.domain_id),
+ ('property', {'fee': 'fi', 'fo': 'fum'}),
+ ('project', self.project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'fee': 'fi',
+ 'fo': 'fum',
+ }
+ self.projects_mock.update.assert_called_with(
+ self.project.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+
+class TestProjectShow(TestProject):
+
+ domain = identity_fakes.FakeDomain.create_one_domain()
+
+ def setUp(self):
+ super(TestProjectShow, self).setUp()
+
+ self.project = identity_fakes.FakeProject.create_one_project(
+ attrs={'domain_id': self.domain.id})
+
+ # Get the command object to test
+ self.cmd = project.ShowProject(self.app, None)
+
+ def test_project_show(self):
+
+ self.projects_mock.get.side_effect = [Exception("Not found"),
+ self.project]
+ self.projects_mock.get.return_value = self.project
+
+ arglist = [
+ self.project.id,
+ ]
+ verifylist = [
+ ('project', self.project.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.app.client_manager.identity.tokens.get_token_data.return_value = \
+ {'token':
+ {'project':
+ {'domain': {},
+ 'name': parsed_args.project,
+ 'id': parsed_args.project
+ }
+ }
+ }
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.projects_mock.get.assert_called_with(
+ self.project.id,
+ parents_as_list=False,
+ subtree_as_list=False,
+ )
+
+ collist = (
+ 'description',
+ 'domain_id',
+ 'enabled',
+ 'id',
+ 'is_domain',
+ 'name',
+ 'parent_id',
+ )
+ self.assertEqual(collist, columns)
+ datalist = (
+ self.project.description,
+ self.project.domain_id,
+ True,
+ self.project.id,
+ False,
+ self.project.name,
+ self.project.parent_id,
+ )
+ self.assertEqual(datalist, data)
+
+ def test_project_show_parents(self):
+ self.project = identity_fakes.FakeProject.create_one_project(
+ attrs={
+ 'parent_id': self.project.parent_id,
+ 'parents': [{'project': {'id': self.project.parent_id}}]
+ }
+ )
+ self.projects_mock.get.side_effect = [Exception("Not found"),
+ self.project]
+ self.projects_mock.get.return_value = self.project
+
+ arglist = [
+ self.project.id,
+ '--parents',
+ ]
+ verifylist = [
+ ('project', self.project.id),
+ ('parents', True),
+ ('children', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.app.client_manager.identity.tokens.get_token_data.return_value = \
+ {'token':
+ {'project':
+ {'domain': {},
+ 'name': parsed_args.project,
+ 'id': parsed_args.project
+ }
+ }
+ }
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.projects_mock.get.assert_called_with(
+ self.project.id,
+ parents_as_list=True,
+ subtree_as_list=False,
+ )
+
+ collist = (
+ 'description',
+ 'domain_id',
+ 'enabled',
+ 'id',
+ 'is_domain',
+ 'name',
+ 'parent_id',
+ 'parents',
+ )
+ self.assertEqual(columns, collist)
+ datalist = (
+ self.project.description,
+ self.project.domain_id,
+ self.project.enabled,
+ self.project.id,
+ self.project.is_domain,
+ self.project.name,
+ self.project.parent_id,
+ [self.project.parent_id],
+ )
+ self.assertEqual(data, datalist)
+
+ def test_project_show_subtree(self):
+ self.project = identity_fakes.FakeProject.create_one_project(
+ attrs={
+ 'parent_id': self.project.parent_id,
+ 'subtree': [{'project': {'id': 'children-id'}}]
+ }
+ )
+ self.projects_mock.get.side_effect = [Exception("Not found"),
+ self.project]
+ self.projects_mock.get.return_value = self.project
+
+ arglist = [
+ self.project.id,
+ '--children',
+ ]
+ verifylist = [
+ ('project', self.project.id),
+ ('parents', False),
+ ('children', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.app.client_manager.identity.tokens.get_token_data.return_value = \
+ {'token':
+ {'project':
+ {'domain': {},
+ 'name': parsed_args.project,
+ 'id': parsed_args.project
+ }
+ }
+ }
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.projects_mock.get.assert_called_with(
+ self.project.id,
+ parents_as_list=False,
+ subtree_as_list=True,
+ )
+
+ collist = (
+ 'description',
+ 'domain_id',
+ 'enabled',
+ 'id',
+ 'is_domain',
+ 'name',
+ 'parent_id',
+ 'subtree',
+ )
+ self.assertEqual(columns, collist)
+ datalist = (
+ self.project.description,
+ self.project.domain_id,
+ self.project.enabled,
+ self.project.id,
+ self.project.is_domain,
+ self.project.name,
+ self.project.parent_id,
+ ['children-id'],
+ )
+ self.assertEqual(data, datalist)
+
+ def test_project_show_parents_and_children(self):
+ self.project = identity_fakes.FakeProject.create_one_project(
+ attrs={
+ 'parent_id': self.project.parent_id,
+ 'parents': [{'project': {'id': self.project.parent_id}}],
+ 'subtree': [{'project': {'id': 'children-id'}}]
+ }
+ )
+ self.projects_mock.get.side_effect = [Exception("Not found"),
+ self.project]
+ self.projects_mock.get.return_value = self.project
+
+ arglist = [
+ self.project.id,
+ '--parents',
+ '--children',
+ ]
+ verifylist = [
+ ('project', self.project.id),
+ ('parents', True),
+ ('children', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.app.client_manager.identity.tokens.get_token_data.return_value = \
+ {'token':
+ {'project':
+ {'domain': {},
+ 'name': parsed_args.project,
+ 'id': parsed_args.project
+ }
+ }
+ }
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.projects_mock.get.assert_called_with(
+ self.project.id,
+ parents_as_list=True,
+ subtree_as_list=True,
+ )
+
+ collist = (
+ 'description',
+ 'domain_id',
+ 'enabled',
+ 'id',
+ 'is_domain',
+ 'name',
+ 'parent_id',
+ 'parents',
+ 'subtree',
+ )
+ self.assertEqual(columns, collist)
+ datalist = (
+ self.project.description,
+ self.project.domain_id,
+ self.project.enabled,
+ self.project.id,
+ self.project.is_domain,
+ self.project.name,
+ self.project.parent_id,
+ [self.project.parent_id],
+ ['children-id'],
+ )
+ self.assertEqual(data, datalist)
diff --git a/openstackclient/tests/unit/identity/v3/test_protocol.py b/openstackclient/tests/unit/identity/v3/test_protocol.py
new file mode 100644
index 00000000..30b4aa4a
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v3/test_protocol.py
@@ -0,0 +1,188 @@
+# Copyright 2014 CERN.
+#
+# 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.
+
+import copy
+
+from openstackclient.identity.v3 import federation_protocol
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+
+
+class TestProtocol(identity_fakes.TestFederatedIdentity):
+
+ def setUp(self):
+ super(TestProtocol, self).setUp()
+
+ federation_lib = self.app.client_manager.identity.federation
+ self.protocols_mock = federation_lib.protocols
+ self.protocols_mock.reset_mock()
+
+
+class TestProtocolCreate(TestProtocol):
+
+ def setUp(self):
+ super(TestProtocolCreate, self).setUp()
+
+ proto = copy.deepcopy(identity_fakes.PROTOCOL_OUTPUT)
+ resource = fakes.FakeResource(None, proto, loaded=True)
+ self.protocols_mock.create.return_value = resource
+ self.cmd = federation_protocol.CreateProtocol(self.app, None)
+
+ def test_create_protocol(self):
+ argslist = [
+ identity_fakes.protocol_id,
+ '--identity-provider', identity_fakes.idp_id,
+ '--mapping', identity_fakes.mapping_id
+ ]
+
+ verifylist = [
+ ('federation_protocol', identity_fakes.protocol_id),
+ ('identity_provider', identity_fakes.idp_id),
+ ('mapping', identity_fakes.mapping_id)
+ ]
+ parsed_args = self.check_parser(self.cmd, argslist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+ self.protocols_mock.create.assert_called_with(
+ protocol_id=identity_fakes.protocol_id,
+ identity_provider=identity_fakes.idp_id,
+ mapping=identity_fakes.mapping_id)
+
+ collist = ('id', 'identity_provider', 'mapping')
+ self.assertEqual(collist, columns)
+
+ datalist = (identity_fakes.protocol_id,
+ identity_fakes.idp_id,
+ identity_fakes.mapping_id)
+ self.assertEqual(datalist, data)
+
+
+class TestProtocolDelete(TestProtocol):
+
+ def setUp(self):
+ super(TestProtocolDelete, self).setUp()
+
+ # This is the return value for utils.find_resource()
+ self.protocols_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.PROTOCOL_OUTPUT),
+ loaded=True,
+ )
+
+ self.protocols_mock.delete.return_value = None
+ self.cmd = federation_protocol.DeleteProtocol(self.app, None)
+
+ def test_delete_identity_provider(self):
+ arglist = [
+ '--identity-provider', identity_fakes.idp_id,
+ identity_fakes.protocol_id
+ ]
+ verifylist = [
+ ('federation_protocol', [identity_fakes.protocol_id]),
+ ('identity_provider', identity_fakes.idp_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.protocols_mock.delete.assert_called_with(
+ identity_fakes.idp_id, identity_fakes.protocol_id)
+ self.assertIsNone(result)
+
+
+class TestProtocolList(TestProtocol):
+
+ def setUp(self):
+ super(TestProtocolList, self).setUp()
+
+ self.protocols_mock.get.return_value = fakes.FakeResource(
+ None, identity_fakes.PROTOCOL_ID_MAPPING, loaded=True)
+
+ self.protocols_mock.list.return_value = [fakes.FakeResource(
+ None, identity_fakes.PROTOCOL_ID_MAPPING, loaded=True)]
+
+ self.cmd = federation_protocol.ListProtocols(self.app, None)
+
+ def test_list_protocols(self):
+ arglist = ['--identity-provider', identity_fakes.idp_id]
+ verifylist = [('identity_provider', identity_fakes.idp_id)]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.protocols_mock.list.assert_called_with(identity_fakes.idp_id)
+
+
+class TestProtocolSet(TestProtocol):
+
+ def setUp(self):
+ super(TestProtocolSet, self).setUp()
+ self.protocols_mock.get.return_value = fakes.FakeResource(
+ None, identity_fakes.PROTOCOL_OUTPUT, loaded=True)
+ self.protocols_mock.update.return_value = fakes.FakeResource(
+ None, identity_fakes.PROTOCOL_OUTPUT_UPDATED, loaded=True)
+
+ self.cmd = federation_protocol.SetProtocol(self.app, None)
+
+ def test_set_new_mapping(self):
+ arglist = [
+ identity_fakes.protocol_id,
+ '--identity-provider', identity_fakes.idp_id,
+ '--mapping', identity_fakes.mapping_id
+ ]
+ verifylist = [('identity_provider', identity_fakes.idp_id),
+ ('federation_protocol', identity_fakes.protocol_id),
+ ('mapping', identity_fakes.mapping_id)]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.protocols_mock.update.assert_called_with(
+ identity_fakes.idp_id, identity_fakes.protocol_id,
+ identity_fakes.mapping_id)
+
+ collist = ('id', 'identity_provider', 'mapping')
+ self.assertEqual(collist, columns)
+
+ datalist = (identity_fakes.protocol_id, identity_fakes.idp_id,
+ identity_fakes.mapping_id_updated)
+ self.assertEqual(datalist, data)
+
+
+class TestProtocolShow(TestProtocol):
+
+ def setUp(self):
+ super(TestProtocolShow, self).setUp()
+ self.protocols_mock.get.return_value = fakes.FakeResource(
+ None, identity_fakes.PROTOCOL_OUTPUT, loaded=False)
+
+ self.cmd = federation_protocol.ShowProtocol(self.app, None)
+
+ def test_show_protocol(self):
+ arglist = [identity_fakes.protocol_id, '--identity-provider',
+ identity_fakes.idp_id]
+ verifylist = [('federation_protocol', identity_fakes.protocol_id),
+ ('identity_provider', identity_fakes.idp_id)]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.protocols_mock.get.assert_called_with(identity_fakes.idp_id,
+ identity_fakes.protocol_id)
+
+ collist = ('id', 'identity_provider', 'mapping')
+ self.assertEqual(collist, columns)
+
+ datalist = (identity_fakes.protocol_id,
+ identity_fakes.idp_id,
+ identity_fakes.mapping_id)
+ self.assertEqual(datalist, data)
diff --git a/openstackclient/tests/unit/identity/v3/test_region.py b/openstackclient/tests/unit/identity/v3/test_region.py
new file mode 100644
index 00000000..e83a4e9f
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v3/test_region.py
@@ -0,0 +1,348 @@
+# 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.
+#
+
+import copy
+
+from openstackclient.identity.v3 import region
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+
+
+class TestRegion(identity_fakes.TestIdentityv3):
+
+ def setUp(self):
+ super(TestRegion, self).setUp()
+
+ # Get a shortcut to the RegionManager Mock
+ self.regions_mock = self.app.client_manager.identity.regions
+ self.regions_mock.reset_mock()
+
+
+class TestRegionCreate(TestRegion):
+
+ columns = (
+ 'description',
+ 'parent_region',
+ 'region',
+ )
+ datalist = (
+ identity_fakes.region_description,
+ identity_fakes.region_parent_region_id,
+ identity_fakes.region_id,
+ )
+
+ def setUp(self):
+ super(TestRegionCreate, self).setUp()
+
+ self.regions_mock.create.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.REGION),
+ loaded=True,
+ )
+
+ # Get the command object to test
+ self.cmd = region.CreateRegion(self.app, None)
+
+ def test_region_create_description(self):
+ arglist = [
+ identity_fakes.region_id,
+ '--description', identity_fakes.region_description,
+ ]
+ verifylist = [
+ ('region', identity_fakes.region_id),
+ ('description', identity_fakes.region_description)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'description': identity_fakes.region_description,
+ 'id': identity_fakes.region_id,
+ 'parent_region': None,
+ }
+ self.regions_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_region_create_no_options(self):
+ arglist = [
+ identity_fakes.region_id,
+ ]
+ verifylist = [
+ ('region', identity_fakes.region_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'description': None,
+ 'id': identity_fakes.region_id,
+ 'parent_region': None,
+ }
+ self.regions_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_region_create_parent_region_id(self):
+ arglist = [
+ identity_fakes.region_id,
+ '--parent-region', identity_fakes.region_parent_region_id,
+ ]
+ verifylist = [
+ ('region', identity_fakes.region_id),
+ ('parent_region', identity_fakes.region_parent_region_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'description': None,
+ 'id': identity_fakes.region_id,
+ 'parent_region': identity_fakes.region_parent_region_id,
+ }
+ self.regions_mock.create.assert_called_with(
+ **kwargs
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+
+class TestRegionDelete(TestRegion):
+
+ def setUp(self):
+ super(TestRegionDelete, self).setUp()
+
+ self.regions_mock.delete.return_value = None
+
+ # Get the command object to test
+ self.cmd = region.DeleteRegion(self.app, None)
+
+ def test_region_delete_no_options(self):
+ arglist = [
+ identity_fakes.region_id,
+ ]
+ verifylist = [
+ ('region', [identity_fakes.region_id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.regions_mock.delete.assert_called_with(
+ identity_fakes.region_id,
+ )
+ self.assertIsNone(result)
+
+
+class TestRegionList(TestRegion):
+
+ columns = (
+ 'Region',
+ 'Parent Region',
+ 'Description',
+ )
+ datalist = (
+ (
+ identity_fakes.region_id,
+ identity_fakes.region_parent_region_id,
+ identity_fakes.region_description,
+ ),
+ )
+
+ def setUp(self):
+ super(TestRegionList, self).setUp()
+
+ self.regions_mock.list.return_value = [
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.REGION),
+ loaded=True,
+ ),
+ ]
+
+ # Get the command object to test
+ self.cmd = region.ListRegion(self.app, None)
+
+ def test_region_list_no_options(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.regions_mock.list.assert_called_with()
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_region_list_parent_region_id(self):
+ arglist = [
+ '--parent-region', identity_fakes.region_parent_region_id,
+ ]
+ verifylist = [
+ ('parent_region', identity_fakes.region_parent_region_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.regions_mock.list.assert_called_with(
+ parent_region_id=identity_fakes.region_parent_region_id)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+
+class TestRegionSet(TestRegion):
+
+ def setUp(self):
+ super(TestRegionSet, self).setUp()
+
+ self.regions_mock.update.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.REGION),
+ loaded=True,
+ )
+
+ # Get the command object to test
+ self.cmd = region.SetRegion(self.app, None)
+
+ def test_region_set_no_options(self):
+ arglist = [
+ identity_fakes.region_id,
+ ]
+ verifylist = [
+ ('region', identity_fakes.region_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ kwargs = {}
+ self.regions_mock.update.assert_called_with(
+ identity_fakes.region_id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_region_set_description(self):
+ arglist = [
+ '--description', 'qwerty',
+ identity_fakes.region_id,
+ ]
+ verifylist = [
+ ('description', 'qwerty'),
+ ('region', identity_fakes.region_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'description': 'qwerty',
+ }
+ self.regions_mock.update.assert_called_with(
+ identity_fakes.region_id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_region_set_parent_region_id(self):
+ arglist = [
+ '--parent-region', 'new_parent',
+ identity_fakes.region_id,
+ ]
+ verifylist = [
+ ('parent_region', 'new_parent'),
+ ('region', identity_fakes.region_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'parent_region': 'new_parent',
+ }
+ self.regions_mock.update.assert_called_with(
+ identity_fakes.region_id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+
+class TestRegionShow(TestRegion):
+
+ def setUp(self):
+ super(TestRegionShow, self).setUp()
+
+ self.regions_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.REGION),
+ loaded=True,
+ )
+
+ # Get the command object to test
+ self.cmd = region.ShowRegion(self.app, None)
+
+ def test_region_show(self):
+ arglist = [
+ identity_fakes.region_id,
+ ]
+ verifylist = [
+ ('region', identity_fakes.region_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.regions_mock.get.assert_called_with(
+ identity_fakes.region_id,
+ )
+
+ collist = ('description', 'parent_region', 'region')
+ self.assertEqual(collist, columns)
+ datalist = (
+ identity_fakes.region_description,
+ identity_fakes.region_parent_region_id,
+ identity_fakes.region_id,
+ )
+ self.assertEqual(datalist, data)
diff --git a/openstackclient/tests/unit/identity/v3/test_role.py b/openstackclient/tests/unit/identity/v3/test_role.py
new file mode 100644
index 00000000..448e18d3
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v3/test_role.py
@@ -0,0 +1,1105 @@
+# Copyright 2013 Nebula Inc.
+#
+# 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.
+#
+
+import copy
+
+from openstackclient.identity.v3 import role
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+
+
+class TestRole(identity_fakes.TestIdentityv3):
+
+ def setUp(self):
+ super(TestRole, self).setUp()
+
+ # Get a shortcut to the UserManager Mock
+ self.users_mock = self.app.client_manager.identity.users
+ self.users_mock.reset_mock()
+
+ # Get a shortcut to the UserManager Mock
+ self.groups_mock = self.app.client_manager.identity.groups
+ self.groups_mock.reset_mock()
+
+ # Get a shortcut to the DomainManager Mock
+ self.domains_mock = self.app.client_manager.identity.domains
+ self.domains_mock.reset_mock()
+
+ # Get a shortcut to the ProjectManager Mock
+ self.projects_mock = self.app.client_manager.identity.projects
+ self.projects_mock.reset_mock()
+
+ # Get a shortcut to the RoleManager Mock
+ self.roles_mock = self.app.client_manager.identity.roles
+ self.roles_mock.reset_mock()
+
+ def _is_inheritance_testcase(self):
+ return False
+
+
+class TestRoleInherited(TestRole):
+
+ def _is_inheritance_testcase(self):
+ return True
+
+
+class TestRoleAdd(TestRole):
+
+ def setUp(self):
+ super(TestRoleAdd, self).setUp()
+
+ self.users_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.USER),
+ loaded=True,
+ )
+
+ self.groups_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.GROUP),
+ loaded=True,
+ )
+
+ self.domains_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.DOMAIN),
+ loaded=True,
+ )
+
+ self.projects_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.PROJECT),
+ loaded=True,
+ )
+
+ self.roles_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.ROLE),
+ loaded=True,
+ )
+ self.roles_mock.grant.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.ROLE),
+ loaded=True,
+ )
+
+ # Get the command object to test
+ self.cmd = role.AddRole(self.app, None)
+
+ def test_role_add_user_domain(self):
+ arglist = [
+ '--user', identity_fakes.user_name,
+ '--domain', identity_fakes.domain_name,
+ identity_fakes.role_name,
+ ]
+ if self._is_inheritance_testcase():
+ arglist.append('--inherited')
+ verifylist = [
+ ('user', identity_fakes.user_name),
+ ('group', None),
+ ('domain', identity_fakes.domain_name),
+ ('project', None),
+ ('role', identity_fakes.role_name),
+ ('inherited', self._is_inheritance_testcase()),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'user': identity_fakes.user_id,
+ 'domain': identity_fakes.domain_id,
+ 'os_inherit_extension_inherited': self._is_inheritance_testcase(),
+ }
+ # RoleManager.grant(role, user=, group=, domain=, project=)
+ self.roles_mock.grant.assert_called_with(
+ identity_fakes.role_id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_role_add_user_project(self):
+ arglist = [
+ '--user', identity_fakes.user_name,
+ '--project', identity_fakes.project_name,
+ identity_fakes.role_name,
+ ]
+ if self._is_inheritance_testcase():
+ arglist.append('--inherited')
+ verifylist = [
+ ('user', identity_fakes.user_name),
+ ('group', None),
+ ('domain', None),
+ ('project', identity_fakes.project_name),
+ ('role', identity_fakes.role_name),
+ ('inherited', self._is_inheritance_testcase()),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'user': identity_fakes.user_id,
+ 'project': identity_fakes.project_id,
+ 'os_inherit_extension_inherited': self._is_inheritance_testcase(),
+ }
+ # RoleManager.grant(role, user=, group=, domain=, project=)
+ self.roles_mock.grant.assert_called_with(
+ identity_fakes.role_id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_role_add_group_domain(self):
+ arglist = [
+ '--group', identity_fakes.group_name,
+ '--domain', identity_fakes.domain_name,
+ identity_fakes.role_name,
+ ]
+ if self._is_inheritance_testcase():
+ arglist.append('--inherited')
+ verifylist = [
+ ('user', None),
+ ('group', identity_fakes.group_name),
+ ('domain', identity_fakes.domain_name),
+ ('project', None),
+ ('role', identity_fakes.role_name),
+ ('inherited', self._is_inheritance_testcase()),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'group': identity_fakes.group_id,
+ 'domain': identity_fakes.domain_id,
+ 'os_inherit_extension_inherited': self._is_inheritance_testcase(),
+ }
+ # RoleManager.grant(role, user=, group=, domain=, project=)
+ self.roles_mock.grant.assert_called_with(
+ identity_fakes.role_id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_role_add_group_project(self):
+ arglist = [
+ '--group', identity_fakes.group_name,
+ '--project', identity_fakes.project_name,
+ identity_fakes.role_name,
+ ]
+ if self._is_inheritance_testcase():
+ arglist.append('--inherited')
+ verifylist = [
+ ('user', None),
+ ('group', identity_fakes.group_name),
+ ('domain', None),
+ ('project', identity_fakes.project_name),
+ ('role', identity_fakes.role_name),
+ ('inherited', self._is_inheritance_testcase()),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'group': identity_fakes.group_id,
+ 'project': identity_fakes.project_id,
+ 'os_inherit_extension_inherited': self._is_inheritance_testcase(),
+ }
+ # RoleManager.grant(role, user=, group=, domain=, project=)
+ self.roles_mock.grant.assert_called_with(
+ identity_fakes.role_id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_role_add_domain_role_on_user_project(self):
+ self.roles_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.ROLE_2),
+ loaded=True,
+ )
+ arglist = [
+ '--user', identity_fakes.user_name,
+ '--project', identity_fakes.project_name,
+ '--role-domain', identity_fakes.domain_name,
+ identity_fakes.ROLE_2['name'],
+ ]
+ if self._is_inheritance_testcase():
+ arglist.append('--inherited')
+ verifylist = [
+ ('user', identity_fakes.user_name),
+ ('group', None),
+ ('domain', None),
+ ('project', identity_fakes.project_name),
+ ('role', identity_fakes.ROLE_2['name']),
+ ('inherited', self._is_inheritance_testcase()),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'user': identity_fakes.user_id,
+ 'project': identity_fakes.project_id,
+ 'os_inherit_extension_inherited': self._is_inheritance_testcase(),
+ }
+ # RoleManager.grant(role, user=, group=, domain=, project=)
+ self.roles_mock.grant.assert_called_with(
+ identity_fakes.ROLE_2['id'],
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+
+class TestRoleAddInherited(TestRoleAdd, TestRoleInherited):
+ pass
+
+
+class TestRoleCreate(TestRole):
+
+ def setUp(self):
+ super(TestRoleCreate, self).setUp()
+
+ self.domains_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.DOMAIN),
+ loaded=True,
+ )
+
+ self.roles_mock.create.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.ROLE),
+ loaded=True,
+ )
+
+ # Get the command object to test
+ self.cmd = role.CreateRole(self.app, None)
+
+ def test_role_create_no_options(self):
+ arglist = [
+ identity_fakes.role_name,
+ ]
+ verifylist = [
+ ('name', identity_fakes.role_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'domain': None,
+ 'name': identity_fakes.role_name,
+ }
+
+ # RoleManager.create(name=, domain=)
+ self.roles_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ collist = ('domain', 'id', 'name')
+ self.assertEqual(collist, columns)
+ datalist = (
+ None,
+ identity_fakes.role_id,
+ identity_fakes.role_name,
+ )
+ self.assertEqual(datalist, data)
+
+ def test_role_create_with_domain(self):
+
+ self.roles_mock.create.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.ROLE_2),
+ loaded=True,
+ )
+
+ arglist = [
+ '--domain', identity_fakes.domain_name,
+ identity_fakes.ROLE_2['name'],
+ ]
+ verifylist = [
+ ('domain', identity_fakes.domain_name),
+ ('name', identity_fakes.ROLE_2['name']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'domain': identity_fakes.domain_id,
+ 'name': identity_fakes.ROLE_2['name'],
+ }
+
+ # RoleManager.create(name=, domain=)
+ self.roles_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ collist = ('domain', 'id', 'name')
+ self.assertEqual(collist, columns)
+ datalist = (
+ identity_fakes.domain_id,
+ identity_fakes.ROLE_2['id'],
+ identity_fakes.ROLE_2['name'],
+ )
+ self.assertEqual(datalist, data)
+
+
+class TestRoleDelete(TestRole):
+
+ def setUp(self):
+ super(TestRoleDelete, self).setUp()
+
+ self.roles_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.ROLE),
+ loaded=True,
+ )
+ self.roles_mock.delete.return_value = None
+
+ # Get the command object to test
+ self.cmd = role.DeleteRole(self.app, None)
+
+ def test_role_delete_no_options(self):
+ arglist = [
+ identity_fakes.role_name,
+ ]
+ verifylist = [
+ ('roles', [identity_fakes.role_name]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.roles_mock.delete.assert_called_with(
+ identity_fakes.role_id,
+ )
+ self.assertIsNone(result)
+
+ def test_role_delete_with_domain(self):
+ self.roles_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.ROLE_2),
+ loaded=True,
+ )
+ self.roles_mock.delete.return_value = None
+
+ arglist = [
+ '--domain', identity_fakes.domain_name,
+ identity_fakes.ROLE_2['name'],
+ ]
+ verifylist = [
+ ('roles', [identity_fakes.ROLE_2['name']]),
+ ('domain', identity_fakes.domain_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.roles_mock.delete.assert_called_with(
+ identity_fakes.ROLE_2['id'],
+ )
+ self.assertIsNone(result)
+
+
+class TestRoleList(TestRole):
+
+ columns = (
+ 'ID',
+ 'Name',
+ )
+ datalist = (
+ (
+ identity_fakes.role_id,
+ identity_fakes.role_name,
+ ),
+ )
+
+ def setUp(self):
+ super(TestRoleList, self).setUp()
+
+ self.roles_mock.list.return_value = [
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.ROLE),
+ loaded=True,
+ ),
+ ]
+
+ self.domains_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.DOMAIN),
+ loaded=True,
+ )
+ self.projects_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.PROJECT),
+ loaded=True,
+ )
+ self.users_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.USER),
+ loaded=True,
+ )
+ self.groups_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.GROUP),
+ loaded=True,
+ )
+
+ # Get the command object to test
+ self.cmd = role.ListRole(self.app, None)
+
+ def test_role_list_no_options(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.roles_mock.list.assert_called_with()
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_user_list_inherited(self):
+ arglist = [
+ '--user', identity_fakes.user_id,
+ '--inherited',
+ ]
+ verifylist = [
+ ('user', identity_fakes.user_id),
+ ('inherited', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'domain': 'default',
+ 'user': self.users_mock.get(),
+ 'os_inherit_extension_inherited': True,
+ }
+ # RoleManager.list(user=, group=, domain=, project=, **kwargs)
+ self.roles_mock.list.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_user_list_user(self):
+ arglist = [
+ '--user', identity_fakes.user_id,
+ ]
+ verifylist = [
+ ('user', identity_fakes.user_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'domain': 'default',
+ 'user': self.users_mock.get(),
+ 'os_inherit_extension_inherited': False
+ }
+ # RoleManager.list(user=, group=, domain=, project=, **kwargs)
+ self.roles_mock.list.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_role_list_domain_user(self):
+ arglist = [
+ '--domain', identity_fakes.domain_name,
+ '--user', identity_fakes.user_id,
+ ]
+ verifylist = [
+ ('domain', identity_fakes.domain_name),
+ ('user', identity_fakes.user_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'domain': self.domains_mock.get(),
+ 'user': self.users_mock.get(),
+ 'os_inherit_extension_inherited': False
+ }
+ # RoleManager.list(user=, group=, domain=, project=, **kwargs)
+ self.roles_mock.list.assert_called_with(
+ **kwargs
+ )
+
+ collist = ('ID', 'Name', 'Domain', 'User')
+ self.assertEqual(collist, columns)
+ datalist = ((
+ identity_fakes.role_id,
+ identity_fakes.role_name,
+ identity_fakes.domain_name,
+ identity_fakes.user_name,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_role_list_domain_group(self):
+ arglist = [
+ '--domain', identity_fakes.domain_name,
+ '--group', identity_fakes.group_id,
+ ]
+ verifylist = [
+ ('domain', identity_fakes.domain_name),
+ ('group', identity_fakes.group_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'domain': self.domains_mock.get(),
+ 'group': self.groups_mock.get(),
+ 'os_inherit_extension_inherited': False
+ }
+ # RoleManager.list(user=, group=, domain=, project=, **kwargs)
+ self.roles_mock.list.assert_called_with(
+ **kwargs
+ )
+
+ collist = ('ID', 'Name', 'Domain', 'Group')
+ self.assertEqual(collist, columns)
+ datalist = ((
+ identity_fakes.role_id,
+ identity_fakes.role_name,
+ identity_fakes.domain_name,
+ identity_fakes.group_name,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_role_list_project_user(self):
+ arglist = [
+ '--project', identity_fakes.project_name,
+ '--user', identity_fakes.user_id,
+ ]
+ verifylist = [
+ ('project', identity_fakes.project_name),
+ ('user', identity_fakes.user_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'project': self.projects_mock.get(),
+ 'user': self.users_mock.get(),
+ 'os_inherit_extension_inherited': False
+ }
+ # RoleManager.list(user=, group=, domain=, project=, **kwargs)
+ self.roles_mock.list.assert_called_with(
+ **kwargs
+ )
+
+ collist = ('ID', 'Name', 'Project', 'User')
+ self.assertEqual(collist, columns)
+ datalist = ((
+ identity_fakes.role_id,
+ identity_fakes.role_name,
+ identity_fakes.project_name,
+ identity_fakes.user_name,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_role_list_project_group(self):
+ arglist = [
+ '--project', identity_fakes.project_name,
+ '--group', identity_fakes.group_id,
+ ]
+ verifylist = [
+ ('project', identity_fakes.project_name),
+ ('group', identity_fakes.group_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'project': self.projects_mock.get(),
+ 'group': self.groups_mock.get(),
+ 'os_inherit_extension_inherited': False
+ }
+ # RoleManager.list(user=, group=, domain=, project=, **kwargs)
+ self.roles_mock.list.assert_called_with(
+ **kwargs
+ )
+
+ collist = ('ID', 'Name', 'Project', 'Group')
+ self.assertEqual(collist, columns)
+ datalist = ((
+ identity_fakes.role_id,
+ identity_fakes.role_name,
+ identity_fakes.project_name,
+ identity_fakes.group_name,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_role_list_domain_role(self):
+ self.roles_mock.list.return_value = [
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.ROLE_2),
+ loaded=True,
+ ),
+ ]
+ arglist = [
+ '--domain', identity_fakes.domain_name,
+ ]
+ verifylist = [
+ ('domain', identity_fakes.domain_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'domain_id': identity_fakes.domain_id
+ }
+ # RoleManager.list(user=, group=, domain=, project=, **kwargs)
+ self.roles_mock.list.assert_called_with(
+ **kwargs
+ )
+
+ collist = ('ID', 'Name', 'Domain')
+ self.assertEqual(collist, columns)
+ datalist = ((
+ identity_fakes.ROLE_2['id'],
+ identity_fakes.ROLE_2['name'],
+ identity_fakes.domain_name,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+
+class TestRoleRemove(TestRole):
+
+ def setUp(self):
+ super(TestRoleRemove, self).setUp()
+
+ self.users_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.USER),
+ loaded=True,
+ )
+
+ self.groups_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.GROUP),
+ loaded=True,
+ )
+
+ self.domains_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.DOMAIN),
+ loaded=True,
+ )
+
+ self.projects_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.PROJECT),
+ loaded=True,
+ )
+
+ self.roles_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.ROLE),
+ loaded=True,
+ )
+ self.roles_mock.revoke.return_value = None
+
+ # Get the command object to test
+ self.cmd = role.RemoveRole(self.app, None)
+
+ def test_role_remove_user_domain(self):
+ arglist = [
+ '--user', identity_fakes.user_name,
+ '--domain', identity_fakes.domain_name,
+ identity_fakes.role_name,
+ ]
+ if self._is_inheritance_testcase():
+ arglist.append('--inherited')
+ verifylist = [
+ ('user', identity_fakes.user_name),
+ ('group', None),
+ ('domain', identity_fakes.domain_name),
+ ('project', None),
+ ('role', identity_fakes.role_name),
+ ('inherited', self._is_inheritance_testcase()),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'user': identity_fakes.user_id,
+ 'domain': identity_fakes.domain_id,
+ 'os_inherit_extension_inherited': self._is_inheritance_testcase(),
+ }
+ # RoleManager.revoke(role, user=, group=, domain=, project=)
+ self.roles_mock.revoke.assert_called_with(
+ identity_fakes.role_id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_role_remove_user_project(self):
+ arglist = [
+ '--user', identity_fakes.user_name,
+ '--project', identity_fakes.project_name,
+ identity_fakes.role_name,
+ ]
+ if self._is_inheritance_testcase():
+ arglist.append('--inherited')
+ verifylist = [
+ ('user', identity_fakes.user_name),
+ ('group', None),
+ ('domain', None),
+ ('project', identity_fakes.project_name),
+ ('role', identity_fakes.role_name),
+ ('inherited', self._is_inheritance_testcase()),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'user': identity_fakes.user_id,
+ 'project': identity_fakes.project_id,
+ 'os_inherit_extension_inherited': self._is_inheritance_testcase(),
+ }
+ # RoleManager.revoke(role, user=, group=, domain=, project=)
+ self.roles_mock.revoke.assert_called_with(
+ identity_fakes.role_id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_role_remove_group_domain(self):
+ arglist = [
+ '--group', identity_fakes.group_name,
+ '--domain', identity_fakes.domain_name,
+ identity_fakes.role_name,
+ ]
+ if self._is_inheritance_testcase():
+ arglist.append('--inherited')
+ verifylist = [
+ ('user', None),
+ ('group', identity_fakes.group_name),
+ ('domain', identity_fakes.domain_name),
+ ('project', None),
+ ('role', identity_fakes.role_name),
+ ('role', identity_fakes.role_name),
+ ('inherited', self._is_inheritance_testcase()),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'group': identity_fakes.group_id,
+ 'domain': identity_fakes.domain_id,
+ 'os_inherit_extension_inherited': self._is_inheritance_testcase(),
+ }
+ # RoleManager.revoke(role, user=, group=, domain=, project=)
+ self.roles_mock.revoke.assert_called_with(
+ identity_fakes.role_id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_role_remove_group_project(self):
+ arglist = [
+ '--group', identity_fakes.group_name,
+ '--project', identity_fakes.project_name,
+ identity_fakes.role_name,
+ ]
+ if self._is_inheritance_testcase():
+ arglist.append('--inherited')
+ verifylist = [
+ ('user', None),
+ ('group', identity_fakes.group_name),
+ ('domain', None),
+ ('project', identity_fakes.project_name),
+ ('role', identity_fakes.role_name),
+ ('inherited', self._is_inheritance_testcase()),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'group': identity_fakes.group_id,
+ 'project': identity_fakes.project_id,
+ 'os_inherit_extension_inherited': self._is_inheritance_testcase(),
+ }
+ # RoleManager.revoke(role, user=, group=, domain=, project=)
+ self.roles_mock.revoke.assert_called_with(
+ identity_fakes.role_id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_role_remove_domain_role_on_group_domain(self):
+ self.roles_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.ROLE_2),
+ loaded=True,
+ )
+ arglist = [
+ '--group', identity_fakes.group_name,
+ '--domain', identity_fakes.domain_name,
+ identity_fakes.ROLE_2['name'],
+ ]
+ if self._is_inheritance_testcase():
+ arglist.append('--inherited')
+ verifylist = [
+ ('user', None),
+ ('group', identity_fakes.group_name),
+ ('domain', identity_fakes.domain_name),
+ ('project', None),
+ ('role', identity_fakes.ROLE_2['name']),
+ ('inherited', self._is_inheritance_testcase()),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'group': identity_fakes.group_id,
+ 'domain': identity_fakes.domain_id,
+ 'os_inherit_extension_inherited': self._is_inheritance_testcase(),
+ }
+ # RoleManager.revoke(role, user=, group=, domain=, project=)
+ self.roles_mock.revoke.assert_called_with(
+ identity_fakes.ROLE_2['id'],
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+
+class TestRoleSet(TestRole):
+
+ def setUp(self):
+ super(TestRoleSet, self).setUp()
+
+ self.roles_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.ROLE),
+ loaded=True,
+ )
+ self.roles_mock.update.return_value = None
+
+ # Get the command object to test
+ self.cmd = role.SetRole(self.app, None)
+
+ def test_role_set_no_options(self):
+ arglist = [
+ '--name', 'over',
+ identity_fakes.role_name,
+ ]
+ verifylist = [
+ ('name', 'over'),
+ ('role', identity_fakes.role_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': 'over',
+ }
+ # RoleManager.update(role, name=)
+ self.roles_mock.update.assert_called_with(
+ identity_fakes.role_id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_role_set_domain_role(self):
+ self.roles_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.ROLE_2),
+ loaded=True,
+ )
+ arglist = [
+ '--name', 'over',
+ '--domain', identity_fakes.domain_name,
+ identity_fakes.ROLE_2['name'],
+ ]
+ verifylist = [
+ ('name', 'over'),
+ ('domain', identity_fakes.domain_name),
+ ('role', identity_fakes.ROLE_2['name']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': 'over',
+ }
+ # RoleManager.update(role, name=)
+ self.roles_mock.update.assert_called_with(
+ identity_fakes.ROLE_2['id'],
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+
+class TestRoleShow(TestRole):
+
+ def setUp(self):
+ super(TestRoleShow, self).setUp()
+
+ self.roles_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.ROLE),
+ loaded=True,
+ )
+
+ # Get the command object to test
+ self.cmd = role.ShowRole(self.app, None)
+
+ def test_role_show(self):
+ arglist = [
+ identity_fakes.role_name,
+ ]
+ verifylist = [
+ ('role', identity_fakes.role_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # RoleManager.get(role)
+ self.roles_mock.get.assert_called_with(
+ identity_fakes.role_name,
+ )
+
+ collist = ('domain', 'id', 'name')
+ self.assertEqual(collist, columns)
+ datalist = (
+ None,
+ identity_fakes.role_id,
+ identity_fakes.role_name,
+ )
+ self.assertEqual(datalist, data)
+
+ def test_role_show_domain_role(self):
+ self.roles_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.ROLE_2),
+ loaded=True,
+ )
+ arglist = [
+ '--domain', identity_fakes.domain_name,
+ identity_fakes.ROLE_2['name'],
+ ]
+ verifylist = [
+ ('domain', identity_fakes.domain_name),
+ ('role', identity_fakes.ROLE_2['name']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # RoleManager.get(role). This is called from utils.find_resource().
+ # In fact, the current implementation calls the get(role) first with
+ # just the name, then with the name+domain_id. So technically we should
+ # mock this out with a call list, with the first call returning None
+ # and the second returning the object. However, if we did that we are
+ # then just testing the current sequencing within the utils method, and
+ # would become brittle to changes within that method. Hence we just
+ # check for the first call which is always lookup by name.
+ self.roles_mock.get.assert_called_with(
+ identity_fakes.ROLE_2['name'],
+ )
+
+ collist = ('domain', 'id', 'name')
+ self.assertEqual(collist, columns)
+ datalist = (
+ identity_fakes.domain_id,
+ identity_fakes.ROLE_2['id'],
+ identity_fakes.ROLE_2['name'],
+ )
+ self.assertEqual(datalist, data)
diff --git a/openstackclient/tests/unit/identity/v3/test_role_assignment.py b/openstackclient/tests/unit/identity/v3/test_role_assignment.py
new file mode 100644
index 00000000..7102a0cd
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v3/test_role_assignment.py
@@ -0,0 +1,683 @@
+# 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.
+#
+
+import copy
+import mock
+
+from openstackclient.identity.v3 import role_assignment
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+
+
+class TestRoleAssignment(identity_fakes.TestIdentityv3):
+
+ def setUp(self):
+ super(TestRoleAssignment, self).setUp()
+
+
+class TestRoleAssignmentList(TestRoleAssignment):
+
+ columns = (
+ 'Role',
+ 'User',
+ 'Group',
+ 'Project',
+ 'Domain',
+ 'Inherited',
+ )
+
+ def setUp(self):
+ super(TestRoleAssignment, self).setUp()
+
+ # Get a shortcut to the UserManager Mock
+ self.users_mock = self.app.client_manager.identity.users
+ self.users_mock.reset_mock()
+
+ # Get a shortcut to the GroupManager Mock
+ self.groups_mock = self.app.client_manager.identity.groups
+ self.groups_mock.reset_mock()
+
+ # Get a shortcut to the DomainManager Mock
+ self.domains_mock = self.app.client_manager.identity.domains
+ self.domains_mock.reset_mock()
+
+ # Get a shortcut to the ProjectManager Mock
+ self.projects_mock = self.app.client_manager.identity.projects
+ self.projects_mock.reset_mock()
+
+ # Get a shortcut to the RoleManager Mock
+ self.roles_mock = self.app.client_manager.identity.roles
+ self.roles_mock.reset_mock()
+
+ self.role_assignments_mock = self.app.client_manager.identity.\
+ role_assignments
+ self.role_assignments_mock.reset_mock()
+
+ # Get the command object to test
+ self.cmd = role_assignment.ListRoleAssignment(self.app, None)
+
+ def test_role_assignment_list_no_filters(self):
+
+ self.role_assignments_mock.list.return_value = [
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(
+ identity_fakes.ASSIGNMENT_WITH_PROJECT_ID_AND_USER_ID),
+ loaded=True,
+ ),
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(
+ identity_fakes.ASSIGNMENT_WITH_PROJECT_ID_AND_GROUP_ID),
+ loaded=True,
+ ),
+ ]
+
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.role_assignments_mock.list.assert_called_with(
+ domain=None,
+ group=None,
+ effective=False,
+ role=None,
+ user=None,
+ project=None,
+ os_inherit_extension_inherited_to=None,
+ include_names=False)
+
+ self.assertEqual(self.columns, columns)
+ datalist = ((
+ identity_fakes.role_id,
+ identity_fakes.user_id,
+ '',
+ identity_fakes.project_id,
+ '',
+ False
+ ), (identity_fakes.role_id,
+ '',
+ identity_fakes.group_id,
+ identity_fakes.project_id,
+ '',
+ False
+ ),)
+ self.assertEqual(datalist, tuple(data))
+
+ def test_role_assignment_list_user(self):
+
+ self.role_assignments_mock.list.return_value = [
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(
+ identity_fakes.ASSIGNMENT_WITH_DOMAIN_ID_AND_USER_ID),
+ loaded=True,
+ ),
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(
+ identity_fakes.ASSIGNMENT_WITH_PROJECT_ID_AND_USER_ID),
+ loaded=True,
+ ),
+ ]
+
+ arglist = [
+ '--user', identity_fakes.user_name
+ ]
+ verifylist = [
+ ('user', identity_fakes.user_name),
+ ('group', None),
+ ('domain', None),
+ ('project', None),
+ ('role', None),
+ ('effective', False),
+ ('inherited', False),
+ ('names', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.role_assignments_mock.list.assert_called_with(
+ domain=None,
+ user=self.users_mock.get(),
+ group=None,
+ project=None,
+ role=None,
+ effective=False,
+ os_inherit_extension_inherited_to=None,
+ include_names=False)
+
+ self.assertEqual(self.columns, columns)
+ datalist = ((
+ identity_fakes.role_id,
+ identity_fakes.user_id,
+ '',
+ '',
+ identity_fakes.domain_id,
+ False
+ ), (identity_fakes.role_id,
+ identity_fakes.user_id,
+ '',
+ identity_fakes.project_id,
+ '',
+ False
+ ),)
+ self.assertEqual(datalist, tuple(data))
+
+ def test_role_assignment_list_group(self):
+
+ self.role_assignments_mock.list.return_value = [
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(
+ identity_fakes.ASSIGNMENT_WITH_DOMAIN_ID_AND_GROUP_ID),
+ loaded=True,
+ ),
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(
+ identity_fakes.ASSIGNMENT_WITH_PROJECT_ID_AND_GROUP_ID),
+ loaded=True,
+ ),
+ ]
+
+ arglist = [
+ '--group', identity_fakes.group_name
+ ]
+ verifylist = [
+ ('user', None),
+ ('group', identity_fakes.group_name),
+ ('domain', None),
+ ('project', None),
+ ('role', None),
+ ('effective', False),
+ ('inherited', False),
+ ('names', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.role_assignments_mock.list.assert_called_with(
+ domain=None,
+ group=self.groups_mock.get(),
+ effective=False,
+ project=None,
+ role=None,
+ user=None,
+ os_inherit_extension_inherited_to=None,
+ include_names=False)
+
+ self.assertEqual(self.columns, columns)
+ datalist = ((
+ identity_fakes.role_id,
+ '',
+ identity_fakes.group_id,
+ '',
+ identity_fakes.domain_id,
+ False
+ ), (identity_fakes.role_id,
+ '',
+ identity_fakes.group_id,
+ identity_fakes.project_id,
+ '',
+ False
+ ),)
+ self.assertEqual(datalist, tuple(data))
+
+ def test_role_assignment_list_domain(self):
+
+ self.role_assignments_mock.list.return_value = [
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(
+ identity_fakes.ASSIGNMENT_WITH_DOMAIN_ID_AND_USER_ID),
+ loaded=True,
+ ),
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(
+ identity_fakes.ASSIGNMENT_WITH_DOMAIN_ID_AND_GROUP_ID),
+ loaded=True,
+ ),
+ ]
+
+ arglist = [
+ '--domain', identity_fakes.domain_name
+ ]
+ verifylist = [
+ ('user', None),
+ ('group', None),
+ ('domain', identity_fakes.domain_name),
+ ('project', None),
+ ('role', None),
+ ('effective', False),
+ ('inherited', False),
+ ('names', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.role_assignments_mock.list.assert_called_with(
+ domain=self.domains_mock.get(),
+ group=None,
+ effective=False,
+ project=None,
+ role=None,
+ user=None,
+ os_inherit_extension_inherited_to=None,
+ include_names=False)
+
+ self.assertEqual(self.columns, columns)
+ datalist = ((
+ identity_fakes.role_id,
+ identity_fakes.user_id,
+ '',
+ '',
+ identity_fakes.domain_id,
+ False
+ ), (identity_fakes.role_id,
+ '',
+ identity_fakes.group_id,
+ '',
+ identity_fakes.domain_id,
+ False
+ ),)
+ self.assertEqual(datalist, tuple(data))
+
+ def test_role_assignment_list_project(self):
+
+ self.role_assignments_mock.list.return_value = [
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(
+ identity_fakes.ASSIGNMENT_WITH_PROJECT_ID_AND_USER_ID),
+ loaded=True,
+ ),
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(
+ identity_fakes.ASSIGNMENT_WITH_PROJECT_ID_AND_GROUP_ID),
+ loaded=True,
+ ),
+ ]
+
+ arglist = [
+ '--project', identity_fakes.project_name
+ ]
+ verifylist = [
+ ('user', None),
+ ('group', None),
+ ('domain', None),
+ ('project', identity_fakes.project_name),
+ ('role', None),
+ ('effective', False),
+ ('inherited', False),
+ ('names', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.role_assignments_mock.list.assert_called_with(
+ domain=None,
+ group=None,
+ effective=False,
+ project=self.projects_mock.get(),
+ role=None,
+ user=None,
+ os_inherit_extension_inherited_to=None,
+ include_names=False)
+
+ self.assertEqual(self.columns, columns)
+ datalist = ((
+ identity_fakes.role_id,
+ identity_fakes.user_id,
+ '',
+ identity_fakes.project_id,
+ '',
+ False
+ ), (identity_fakes.role_id,
+ '',
+ identity_fakes.group_id,
+ identity_fakes.project_id,
+ '',
+ False
+ ),)
+ self.assertEqual(datalist, tuple(data))
+
+ def test_role_assignment_list_def_creds(self):
+
+ auth_ref = self.app.client_manager.auth_ref = mock.MagicMock()
+ auth_ref.project_id.return_value = identity_fakes.project_id
+ auth_ref.user_id.return_value = identity_fakes.user_id
+
+ self.role_assignments_mock.list.return_value = [
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(
+ identity_fakes.ASSIGNMENT_WITH_PROJECT_ID_AND_USER_ID),
+ loaded=True,
+ ),
+ ]
+
+ arglist = [
+ '--auth-user',
+ '--auth-project',
+ ]
+ verifylist = [
+ ('user', None),
+ ('group', None),
+ ('domain', None),
+ ('project', None),
+ ('role', None),
+ ('effective', False),
+ ('inherited', False),
+ ('names', False),
+ ('authuser', True),
+ ('authproject', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.role_assignments_mock.list.assert_called_with(
+ domain=None,
+ user=self.users_mock.get(),
+ group=None,
+ project=self.projects_mock.get(),
+ role=None,
+ effective=False,
+ os_inherit_extension_inherited_to=None,
+ include_names=False)
+
+ self.assertEqual(self.columns, columns)
+ datalist = ((
+ identity_fakes.role_id,
+ identity_fakes.user_id,
+ '',
+ identity_fakes.project_id,
+ '',
+ False
+ ),)
+ self.assertEqual(datalist, tuple(data))
+
+ def test_role_assignment_list_effective(self):
+
+ self.role_assignments_mock.list.return_value = [
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(
+ identity_fakes.ASSIGNMENT_WITH_PROJECT_ID_AND_USER_ID),
+ loaded=True,
+ ),
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(
+ identity_fakes.ASSIGNMENT_WITH_DOMAIN_ID_AND_USER_ID),
+ loaded=True,
+ ),
+ ]
+
+ arglist = ['--effective']
+ verifylist = [
+ ('user', None),
+ ('group', None),
+ ('domain', None),
+ ('project', None),
+ ('role', None),
+ ('effective', True),
+ ('inherited', False),
+ ('names', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.role_assignments_mock.list.assert_called_with(
+ domain=None,
+ group=None,
+ effective=True,
+ project=None,
+ role=None,
+ user=None,
+ os_inherit_extension_inherited_to=None,
+ include_names=False)
+
+ self.assertEqual(self.columns, columns)
+ datalist = ((
+ identity_fakes.role_id,
+ identity_fakes.user_id,
+ '',
+ identity_fakes.project_id,
+ '',
+ False
+ ), (identity_fakes.role_id,
+ identity_fakes.user_id,
+ '',
+ '',
+ identity_fakes.domain_id,
+ False
+ ),)
+ self.assertEqual(tuple(data), datalist)
+
+ def test_role_assignment_list_inherited(self):
+
+ self.role_assignments_mock.list.return_value = [
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(
+ (identity_fakes.
+ ASSIGNMENT_WITH_PROJECT_ID_AND_USER_ID_INHERITED)),
+ loaded=True,
+ ),
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(
+ (identity_fakes.
+ ASSIGNMENT_WITH_DOMAIN_ID_AND_USER_ID_INHERITED)),
+ loaded=True,
+ ),
+ ]
+
+ arglist = ['--inherited']
+ verifylist = [
+ ('user', None),
+ ('group', None),
+ ('domain', None),
+ ('project', None),
+ ('role', None),
+ ('effective', False),
+ ('inherited', True),
+ ('names', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.role_assignments_mock.list.assert_called_with(
+ domain=None,
+ group=None,
+ effective=False,
+ project=None,
+ role=None,
+ user=None,
+ os_inherit_extension_inherited_to='projects',
+ include_names=False)
+
+ self.assertEqual(self.columns, columns)
+ datalist = ((
+ identity_fakes.role_id,
+ identity_fakes.user_id,
+ '',
+ identity_fakes.project_id,
+ '',
+ True
+ ), (identity_fakes.role_id,
+ identity_fakes.user_id,
+ '',
+ '',
+ identity_fakes.domain_id,
+ True
+ ),)
+ self.assertEqual(datalist, tuple(data))
+
+ def test_role_assignment_list_include_names(self):
+
+ self.role_assignments_mock.list.return_value = [
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(
+ identity_fakes
+ .ASSIGNMENT_WITH_PROJECT_ID_AND_USER_ID_INCLUDE_NAMES),
+ loaded=True,
+ ),
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(
+ identity_fakes
+ .ASSIGNMENT_WITH_DOMAIN_ID_AND_USER_ID_INCLUDE_NAMES),
+ loaded=True,
+ ),
+ ]
+
+ arglist = ['--names']
+ verifylist = [
+ ('user', None),
+ ('group', None),
+ ('domain', None),
+ ('project', None),
+ ('role', None),
+ ('effective', False),
+ ('inherited', False),
+ ('names', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # DisplayCommandBase.take_action() returns two tuples
+
+ # This test will not run correctly until the patch in the python
+ # client is merged. Once that is done 'data' should return the
+ # correct information
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.role_assignments_mock.list.assert_called_with(
+ domain=None,
+ group=None,
+ effective=False,
+ project=None,
+ role=None,
+ user=None,
+ os_inherit_extension_inherited_to=None,
+ include_names=True)
+
+ collist = ('Role', 'User', 'Group', 'Project', 'Domain', 'Inherited')
+ self.assertEqual(columns, collist)
+
+ datalist1 = ((
+ identity_fakes.role_name,
+ '@'.join([identity_fakes.user_name, identity_fakes.domain_name]),
+ '',
+ '@'.join([identity_fakes.project_name,
+ identity_fakes.domain_name]),
+ '',
+ False
+ ), (identity_fakes.role_name,
+ '@'.join([identity_fakes.user_name, identity_fakes.domain_name]),
+ '',
+ '',
+ identity_fakes.domain_name,
+ False
+ ),)
+ self.assertEqual(tuple(data), datalist1)
+
+ def test_role_assignment_list_domain_role(self):
+
+ self.role_assignments_mock.list.return_value = [
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(
+ identity_fakes.ASSIGNMENT_WITH_DOMAIN_ROLE),
+ loaded=True,
+ ),
+ ]
+
+ arglist = [
+ '--role', identity_fakes.ROLE_2['name'],
+ '--role-domain', identity_fakes.domain_name
+ ]
+ verifylist = [
+ ('user', None),
+ ('group', None),
+ ('domain', None),
+ ('project', None),
+ ('role', identity_fakes.ROLE_2['name']),
+ ('effective', False),
+ ('inherited', False),
+ ('names', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.role_assignments_mock.list.assert_called_with(
+ domain=None,
+ user=None,
+ group=None,
+ project=None,
+ role=self.roles_mock.get(),
+ effective=False,
+ os_inherit_extension_inherited_to=None,
+ include_names=False)
+
+ self.assertEqual(self.columns, columns)
+ datalist = ((
+ identity_fakes.ROLE_2['id'],
+ identity_fakes.user_id,
+ '',
+ '',
+ identity_fakes.domain_id,
+ False
+ ),)
+ self.assertEqual(datalist, tuple(data))
diff --git a/openstackclient/tests/unit/identity/v3/test_service.py b/openstackclient/tests/unit/identity/v3/test_service.py
new file mode 100644
index 00000000..4cba445b
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v3/test_service.py
@@ -0,0 +1,504 @@
+# Copyright 2013 Nebula Inc.
+#
+# 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 keystoneclient import exceptions as identity_exc
+from osc_lib import exceptions
+
+from openstackclient.identity.v3 import service
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+
+
+class TestService(identity_fakes.TestIdentityv3):
+
+ def setUp(self):
+ super(TestService, self).setUp()
+
+ # Get a shortcut to the ServiceManager Mock
+ self.services_mock = self.app.client_manager.identity.services
+ self.services_mock.reset_mock()
+
+
+class TestServiceCreate(TestService):
+
+ columns = (
+ 'description',
+ 'enabled',
+ 'id',
+ 'name',
+ 'type',
+ )
+
+ def setUp(self):
+ super(TestServiceCreate, self).setUp()
+
+ self.service = identity_fakes.FakeService.create_one_service()
+ self.datalist = (
+ self.service.description,
+ True,
+ self.service.id,
+ self.service.name,
+ self.service.type,
+ )
+ self.services_mock.create.return_value = self.service
+
+ # Get the command object to test
+ self.cmd = service.CreateService(self.app, None)
+
+ def test_service_create_name(self):
+ arglist = [
+ '--name', self.service.name,
+ self.service.type,
+ ]
+ verifylist = [
+ ('name', self.service.name),
+ ('description', None),
+ ('enable', False),
+ ('disable', False),
+ ('type', self.service.type),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # ServiceManager.create(name=, type=, enabled=, **kwargs)
+ self.services_mock.create.assert_called_with(
+ name=self.service.name,
+ type=self.service.type,
+ description=None,
+ enabled=True,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_service_create_description(self):
+ arglist = [
+ '--description', self.service.description,
+ self.service.type,
+ ]
+ verifylist = [
+ ('name', None),
+ ('description', self.service.description),
+ ('enable', False),
+ ('disable', False),
+ ('type', self.service.type),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # ServiceManager.create(name=, type=, enabled=, **kwargs)
+ self.services_mock.create.assert_called_with(
+ name=None,
+ type=self.service.type,
+ description=self.service.description,
+ enabled=True,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_service_create_enable(self):
+ arglist = [
+ '--enable',
+ self.service.type,
+ ]
+ verifylist = [
+ ('name', None),
+ ('description', None),
+ ('enable', True),
+ ('disable', False),
+ ('type', self.service.type),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # ServiceManager.create(name=, type=, enabled=, **kwargs)
+ self.services_mock.create.assert_called_with(
+ name=None,
+ type=self.service.type,
+ description=None,
+ enabled=True,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_service_create_disable(self):
+ arglist = [
+ '--disable',
+ self.service.type,
+ ]
+ verifylist = [
+ ('name', None),
+ ('description', None),
+ ('enable', False),
+ ('disable', True),
+ ('type', self.service.type),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # ServiceManager.create(name=, type=, enabled=, **kwargs)
+ self.services_mock.create.assert_called_with(
+ name=None,
+ type=self.service.type,
+ description=None,
+ enabled=False,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+
+class TestServiceDelete(TestService):
+
+ service = identity_fakes.FakeService.create_one_service()
+
+ def setUp(self):
+ super(TestServiceDelete, self).setUp()
+
+ self.services_mock.get.side_effect = identity_exc.NotFound(None)
+ self.services_mock.find.return_value = self.service
+ self.services_mock.delete.return_value = None
+
+ # Get the command object to test
+ self.cmd = service.DeleteService(self.app, None)
+
+ def test_service_delete_no_options(self):
+ arglist = [
+ self.service.name,
+ ]
+ verifylist = [
+ ('service', [self.service.name]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.services_mock.delete.assert_called_with(
+ self.service.id,
+ )
+ self.assertIsNone(result)
+
+
+class TestServiceList(TestService):
+
+ service = identity_fakes.FakeService.create_one_service()
+
+ def setUp(self):
+ super(TestServiceList, self).setUp()
+
+ self.services_mock.list.return_value = [self.service]
+
+ # Get the command object to test
+ self.cmd = service.ListService(self.app, None)
+
+ def test_service_list_no_options(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.services_mock.list.assert_called_with()
+
+ collist = ('ID', 'Name', 'Type')
+ self.assertEqual(collist, columns)
+ datalist = ((
+ self.service.id,
+ self.service.name,
+ self.service.type,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_service_list_long(self):
+ arglist = [
+ '--long',
+ ]
+ verifylist = [
+ ('long', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.services_mock.list.assert_called_with()
+
+ collist = ('ID', 'Name', 'Type', 'Description', 'Enabled')
+ self.assertEqual(collist, columns)
+ datalist = ((
+ self.service.id,
+ self.service.name,
+ self.service.type,
+ self.service.description,
+ True,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+
+class TestServiceSet(TestService):
+
+ service = identity_fakes.FakeService.create_one_service()
+
+ def setUp(self):
+ super(TestServiceSet, self).setUp()
+
+ self.services_mock.get.side_effect = identity_exc.NotFound(None)
+ self.services_mock.find.return_value = self.service
+ self.services_mock.update.return_value = self.service
+
+ # Get the command object to test
+ self.cmd = service.SetService(self.app, None)
+
+ def test_service_set_no_options(self):
+ arglist = [
+ self.service.name,
+ ]
+ verifylist = [
+ ('type', None),
+ ('name', None),
+ ('description', None),
+ ('enable', False),
+ ('disable', False),
+ ('service', self.service.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.assertIsNone(result)
+
+ def test_service_set_type(self):
+ arglist = [
+ '--type', self.service.type,
+ self.service.name,
+ ]
+ verifylist = [
+ ('type', self.service.type),
+ ('name', None),
+ ('description', None),
+ ('enable', False),
+ ('disable', False),
+ ('service', self.service.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'type': self.service.type,
+ }
+ # ServiceManager.update(service, name=, type=, enabled=, **kwargs)
+ self.services_mock.update.assert_called_with(
+ self.service.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_service_set_name(self):
+ arglist = [
+ '--name', self.service.name,
+ self.service.name,
+ ]
+ verifylist = [
+ ('type', None),
+ ('name', self.service.name),
+ ('description', None),
+ ('enable', False),
+ ('disable', False),
+ ('service', self.service.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': self.service.name,
+ }
+ # ServiceManager.update(service, name=, type=, enabled=, **kwargs)
+ self.services_mock.update.assert_called_with(
+ self.service.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_service_set_description(self):
+ arglist = [
+ '--description', self.service.description,
+ self.service.name,
+ ]
+ verifylist = [
+ ('type', None),
+ ('name', None),
+ ('description', self.service.description),
+ ('enable', False),
+ ('disable', False),
+ ('service', self.service.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'description': self.service.description,
+ }
+ # ServiceManager.update(service, name=, type=, enabled=, **kwargs)
+ self.services_mock.update.assert_called_with(
+ self.service.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_service_set_enable(self):
+ arglist = [
+ '--enable',
+ self.service.name,
+ ]
+ verifylist = [
+ ('type', None),
+ ('name', None),
+ ('description', None),
+ ('enable', True),
+ ('disable', False),
+ ('service', self.service.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': True,
+ }
+ # ServiceManager.update(service, name=, type=, enabled=, **kwargs)
+ self.services_mock.update.assert_called_with(
+ self.service.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_service_set_disable(self):
+ arglist = [
+ '--disable',
+ self.service.name,
+ ]
+ verifylist = [
+ ('type', None),
+ ('name', None),
+ ('description', None),
+ ('enable', False),
+ ('disable', True),
+ ('service', self.service.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': False,
+ }
+ # ServiceManager.update(service, name=, type=, enabled=, **kwargs)
+ self.services_mock.update.assert_called_with(
+ self.service.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+
+class TestServiceShow(TestService):
+
+ service = identity_fakes.FakeService.create_one_service()
+
+ def setUp(self):
+ super(TestServiceShow, self).setUp()
+
+ self.services_mock.get.side_effect = identity_exc.NotFound(None)
+ self.services_mock.find.return_value = self.service
+
+ # Get the command object to test
+ self.cmd = service.ShowService(self.app, None)
+
+ def test_service_show(self):
+ arglist = [
+ self.service.name,
+ ]
+ verifylist = [
+ ('service', self.service.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # ServiceManager.get(id)
+ self.services_mock.find.assert_called_with(
+ name=self.service.name
+ )
+
+ collist = ('description', 'enabled', 'id', 'name', 'type')
+ self.assertEqual(collist, columns)
+ datalist = (
+ self.service.description,
+ True,
+ self.service.id,
+ self.service.name,
+ self.service.type,
+ )
+ self.assertEqual(datalist, data)
+
+ def test_service_show_nounique(self):
+ self.services_mock.find.side_effect = identity_exc.NoUniqueMatch(None)
+ arglist = [
+ 'nounique_service',
+ ]
+ verifylist = [
+ ('service', 'nounique_service'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual(
+ "Multiple service matches found for 'nounique_service',"
+ " use an ID to be more specific.", str(e))
diff --git a/openstackclient/tests/unit/identity/v3/test_service_provider.py b/openstackclient/tests/unit/identity/v3/test_service_provider.py
new file mode 100644
index 00000000..57473ef9
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v3/test_service_provider.py
@@ -0,0 +1,408 @@
+# Copyright 2014 CERN.
+#
+# 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.
+
+import copy
+
+from openstackclient.identity.v3 import service_provider
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit.identity.v3 import fakes as service_fakes
+
+
+class TestServiceProvider(service_fakes.TestFederatedIdentity):
+
+ def setUp(self):
+ super(TestServiceProvider, self).setUp()
+
+ federation_lib = self.app.client_manager.identity.federation
+ self.service_providers_mock = federation_lib.service_providers
+ self.service_providers_mock.reset_mock()
+
+
+class TestServiceProviderCreate(TestServiceProvider):
+
+ columns = (
+ 'auth_url',
+ 'description',
+ 'enabled',
+ 'id',
+ 'sp_url',
+ )
+ datalist = (
+ service_fakes.sp_auth_url,
+ service_fakes.sp_description,
+ True,
+ service_fakes.sp_id,
+ service_fakes.service_provider_url
+ )
+
+ def setUp(self):
+ super(TestServiceProviderCreate, self).setUp()
+
+ copied_sp = copy.deepcopy(service_fakes.SERVICE_PROVIDER)
+ resource = fakes.FakeResource(None, copied_sp, loaded=True)
+ self.service_providers_mock.create.return_value = resource
+ self.cmd = service_provider.CreateServiceProvider(self.app, None)
+
+ def test_create_service_provider_required_options_only(self):
+ arglist = [
+ '--auth-url', service_fakes.sp_auth_url,
+ '--service-provider-url', service_fakes.service_provider_url,
+ service_fakes.sp_id,
+ ]
+ verifylist = [
+ ('auth_url', service_fakes.sp_auth_url),
+ ('service_provider_url', service_fakes.service_provider_url),
+ ('service_provider_id', service_fakes.sp_id),
+
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': True,
+ 'description': None,
+ 'auth_url': service_fakes.sp_auth_url,
+ 'sp_url': service_fakes.service_provider_url
+ }
+
+ self.service_providers_mock.create.assert_called_with(
+ id=service_fakes.sp_id,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_create_service_provider_description(self):
+
+ arglist = [
+ '--description', service_fakes.sp_description,
+ '--auth-url', service_fakes.sp_auth_url,
+ '--service-provider-url', service_fakes.service_provider_url,
+ service_fakes.sp_id,
+ ]
+ verifylist = [
+ ('description', service_fakes.sp_description),
+ ('auth_url', service_fakes.sp_auth_url),
+ ('service_provider_url', service_fakes.service_provider_url),
+ ('service_provider_id', service_fakes.sp_id),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'description': service_fakes.sp_description,
+ 'auth_url': service_fakes.sp_auth_url,
+ 'sp_url': service_fakes.service_provider_url,
+ 'enabled': True,
+ }
+
+ self.service_providers_mock.create.assert_called_with(
+ id=service_fakes.sp_id,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_create_service_provider_disabled(self):
+
+ # Prepare FakeResource object
+ service_provider = copy.deepcopy(service_fakes.SERVICE_PROVIDER)
+ service_provider['enabled'] = False
+ service_provider['description'] = None
+
+ resource = fakes.FakeResource(None, service_provider, loaded=True)
+ self.service_providers_mock.create.return_value = resource
+
+ arglist = [
+ '--auth-url', service_fakes.sp_auth_url,
+ '--service-provider-url', service_fakes.service_provider_url,
+ '--disable',
+ service_fakes.sp_id,
+ ]
+ verifylist = [
+ ('auth_url', service_fakes.sp_auth_url),
+ ('service_provider_url', service_fakes.service_provider_url),
+ ('service_provider_id', service_fakes.sp_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+ # Set expected values
+ kwargs = {
+ 'auth_url': service_fakes.sp_auth_url,
+ 'sp_url': service_fakes.service_provider_url,
+ 'enabled': False,
+ 'description': None,
+ }
+
+ self.service_providers_mock.create.assert_called_with(
+ id=service_fakes.sp_id,
+ **kwargs
+ )
+ self.assertEqual(self.columns, columns)
+ datalist = (
+ service_fakes.sp_auth_url,
+ None,
+ False,
+ service_fakes.sp_id,
+ service_fakes.service_provider_url
+ )
+ self.assertEqual(datalist, data)
+
+
+class TestServiceProviderDelete(TestServiceProvider):
+
+ def setUp(self):
+ super(TestServiceProviderDelete, self).setUp()
+
+ # This is the return value for utils.find_resource()
+ self.service_providers_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(service_fakes.SERVICE_PROVIDER),
+ loaded=True,
+ )
+
+ self.service_providers_mock.delete.return_value = None
+ self.cmd = service_provider.DeleteServiceProvider(self.app, None)
+
+ def test_delete_service_provider(self):
+ arglist = [
+ service_fakes.sp_id,
+ ]
+ verifylist = [
+ ('service_provider', [service_fakes.sp_id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.service_providers_mock.delete.assert_called_with(
+ service_fakes.sp_id,
+ )
+ self.assertIsNone(result)
+
+
+class TestServiceProviderList(TestServiceProvider):
+
+ def setUp(self):
+ super(TestServiceProviderList, self).setUp()
+
+ self.service_providers_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(service_fakes.SERVICE_PROVIDER),
+ loaded=True,
+ )
+ self.service_providers_mock.list.return_value = [
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(service_fakes.SERVICE_PROVIDER),
+ loaded=True,
+ ),
+ ]
+
+ # Get the command object to test
+ self.cmd = service_provider.ListServiceProvider(self.app, None)
+
+ def test_service_provider_list_no_options(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.service_providers_mock.list.assert_called_with()
+
+ collist = ('ID', 'Enabled', 'Description', 'Auth URL')
+ self.assertEqual(collist, columns)
+ datalist = ((
+ service_fakes.sp_id,
+ True,
+ service_fakes.sp_description,
+ service_fakes.sp_auth_url
+ ), )
+ self.assertEqual(tuple(data), datalist)
+
+
+class TestServiceProviderSet(TestServiceProvider):
+
+ columns = (
+ 'auth_url',
+ 'description',
+ 'enabled',
+ 'id',
+ 'sp_url',
+ )
+ datalist = (
+ service_fakes.sp_auth_url,
+ service_fakes.sp_description,
+ False,
+ service_fakes.sp_id,
+ service_fakes.service_provider_url,
+ )
+
+ def setUp(self):
+ super(TestServiceProviderSet, self).setUp()
+ self.cmd = service_provider.SetServiceProvider(self.app, None)
+
+ def test_service_provider_disable(self):
+ """Disable Service Provider
+
+ Set Service Provider's ``enabled`` attribute to False.
+ """
+
+ def prepare(self):
+ """Prepare fake return objects before the test is executed"""
+ updated_sp = copy.deepcopy(service_fakes.SERVICE_PROVIDER)
+ updated_sp['enabled'] = False
+ resources = fakes.FakeResource(
+ None,
+ updated_sp,
+ loaded=True
+ )
+ self.service_providers_mock.update.return_value = resources
+
+ prepare(self)
+ arglist = [
+ '--disable', service_fakes.sp_id,
+ ]
+ verifylist = [
+ ('service_provider', service_fakes.sp_id),
+ ('enable', False),
+ ('disable', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.cmd.take_action(parsed_args)
+ self.service_providers_mock.update.assert_called_with(
+ service_fakes.sp_id,
+ enabled=False,
+ description=None,
+ auth_url=None,
+ sp_url=None
+ )
+
+ def test_service_provider_enable(self):
+ """Enable Service Provider.
+
+ Set Service Provider's ``enabled`` attribute to True.
+ """
+
+ def prepare(self):
+ """Prepare fake return objects before the test is executed"""
+ resources = fakes.FakeResource(
+ None,
+ copy.deepcopy(service_fakes.SERVICE_PROVIDER),
+ loaded=True
+ )
+ self.service_providers_mock.update.return_value = resources
+
+ prepare(self)
+ arglist = [
+ '--enable', service_fakes.sp_id,
+ ]
+ verifylist = [
+ ('service_provider', service_fakes.sp_id),
+ ('enable', True),
+ ('disable', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+ self.service_providers_mock.update.assert_called_with(
+ service_fakes.sp_id, enabled=True, description=None,
+ auth_url=None, sp_url=None)
+
+ def test_service_provider_no_options(self):
+ def prepare(self):
+ """Prepare fake return objects before the test is executed"""
+ resources = fakes.FakeResource(
+ None,
+ copy.deepcopy(service_fakes.SERVICE_PROVIDER),
+ loaded=True
+ )
+ self.service_providers_mock.get.return_value = resources
+
+ resources = fakes.FakeResource(
+ None,
+ copy.deepcopy(service_fakes.SERVICE_PROVIDER),
+ loaded=True,
+ )
+ self.service_providers_mock.update.return_value = resources
+
+ prepare(self)
+ arglist = [
+ service_fakes.sp_id,
+ ]
+ verifylist = [
+ ('service_provider', service_fakes.sp_id),
+ ('description', None),
+ ('enable', False),
+ ('disable', False),
+ ('auth_url', None),
+ ('service_provider_url', None),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+
+
+class TestServiceProviderShow(TestServiceProvider):
+
+ def setUp(self):
+ super(TestServiceProviderShow, self).setUp()
+
+ ret = fakes.FakeResource(
+ None,
+ copy.deepcopy(service_fakes.SERVICE_PROVIDER),
+ loaded=True,
+ )
+ self.service_providers_mock.get.side_effect = [Exception("Not found"),
+ ret]
+ self.service_providers_mock.get.return_value = ret
+
+ # Get the command object to test
+ self.cmd = service_provider.ShowServiceProvider(self.app, None)
+
+ def test_service_provider_show(self):
+ arglist = [
+ service_fakes.sp_id,
+ ]
+ verifylist = [
+ ('service_provider', service_fakes.sp_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.service_providers_mock.get.assert_called_with(
+ service_fakes.sp_id,
+ id='BETA'
+ )
+
+ collist = ('auth_url', 'description', 'enabled', 'id', 'sp_url')
+ self.assertEqual(collist, columns)
+ datalist = (
+ service_fakes.sp_auth_url,
+ service_fakes.sp_description,
+ True,
+ service_fakes.sp_id,
+ service_fakes.service_provider_url
+ )
+ self.assertEqual(data, datalist)
diff --git a/openstackclient/tests/unit/identity/v3/test_token.py b/openstackclient/tests/unit/identity/v3/test_token.py
new file mode 100644
index 00000000..7321909f
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v3/test_token.py
@@ -0,0 +1,138 @@
+# Copyright 2014 eBay Inc.
+#
+# 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.
+#
+
+import mock
+
+from openstackclient.identity.v3 import token
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+
+
+class TestToken(identity_fakes.TestIdentityv3):
+
+ def setUp(self):
+ super(TestToken, self).setUp()
+
+ # Get a shortcut to the Auth Ref Mock
+ self.ar_mock = mock.PropertyMock()
+ type(self.app.client_manager).auth_ref = self.ar_mock
+
+
+class TestTokenIssue(TestToken):
+
+ def setUp(self):
+ super(TestTokenIssue, self).setUp()
+
+ self.cmd = token.IssueToken(self.app, None)
+
+ def test_token_issue_with_project_id(self):
+ auth_ref = identity_fakes.fake_auth_ref(
+ identity_fakes.TOKEN_WITH_PROJECT_ID,
+ )
+ self.ar_mock = mock.PropertyMock(return_value=auth_ref)
+ type(self.app.client_manager).auth_ref = self.ar_mock
+
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ collist = ('expires', 'id', 'project_id', 'user_id')
+ self.assertEqual(collist, columns)
+ datalist = (
+ identity_fakes.token_expires,
+ identity_fakes.token_id,
+ identity_fakes.project_id,
+ identity_fakes.user_id,
+ )
+ self.assertEqual(datalist, data)
+
+ def test_token_issue_with_domain_id(self):
+ auth_ref = identity_fakes.fake_auth_ref(
+ identity_fakes.TOKEN_WITH_DOMAIN_ID,
+ )
+ self.ar_mock = mock.PropertyMock(return_value=auth_ref)
+ type(self.app.client_manager).auth_ref = self.ar_mock
+
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ collist = ('domain_id', 'expires', 'id', 'user_id')
+ self.assertEqual(collist, columns)
+ datalist = (
+ identity_fakes.domain_id,
+ identity_fakes.token_expires,
+ identity_fakes.token_id,
+ identity_fakes.user_id,
+ )
+ self.assertEqual(datalist, data)
+
+ def test_token_issue_with_unscoped(self):
+ auth_ref = identity_fakes.fake_auth_ref(
+ identity_fakes.UNSCOPED_TOKEN,
+ )
+ self.ar_mock = mock.PropertyMock(return_value=auth_ref)
+ type(self.app.client_manager).auth_ref = self.ar_mock
+
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # DisplayCommandBase.take_action() returns two tuples
+ columns, data = self.cmd.take_action(parsed_args)
+
+ collist = (
+ 'expires',
+ 'id',
+ 'user_id',
+ )
+ self.assertEqual(collist, columns)
+ datalist = (
+ identity_fakes.token_expires,
+ identity_fakes.token_id,
+ identity_fakes.user_id,
+ )
+ self.assertEqual(datalist, data)
+
+
+class TestTokenRevoke(TestToken):
+
+ TOKEN = 'fob'
+
+ def setUp(self):
+ super(TestTokenRevoke, self).setUp()
+ self.tokens_mock = self.app.client_manager.identity.tokens
+ self.tokens_mock.reset_mock()
+ self.tokens_mock.revoke_token.return_value = True
+ self.cmd = token.RevokeToken(self.app, None)
+
+ def test_token_revoke(self):
+ arglist = [self.TOKEN]
+ verifylist = [('token', self.TOKEN)]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.tokens_mock.revoke_token.assert_called_with(self.TOKEN)
+ self.assertIsNone(result)
diff --git a/openstackclient/tests/unit/identity/v3/test_trust.py b/openstackclient/tests/unit/identity/v3/test_trust.py
new file mode 100644
index 00000000..4eeb8bfe
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v3/test_trust.py
@@ -0,0 +1,236 @@
+# 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.
+#
+
+import copy
+
+from openstackclient.identity.v3 import trust
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+
+
+class TestTrust(identity_fakes.TestIdentityv3):
+
+ def setUp(self):
+ super(TestTrust, self).setUp()
+
+ self.trusts_mock = self.app.client_manager.identity.trusts
+ self.trusts_mock.reset_mock()
+ self.projects_mock = self.app.client_manager.identity.projects
+ self.projects_mock.reset_mock()
+ self.users_mock = self.app.client_manager.identity.users
+ self.users_mock.reset_mock()
+ self.roles_mock = self.app.client_manager.identity.roles
+ self.roles_mock.reset_mock()
+
+
+class TestTrustCreate(TestTrust):
+
+ def setUp(self):
+ super(TestTrustCreate, self).setUp()
+
+ self.projects_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.PROJECT),
+ loaded=True,
+ )
+
+ self.users_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.USER),
+ loaded=True,
+ )
+
+ self.roles_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.ROLE),
+ loaded=True,
+ )
+
+ self.trusts_mock.create.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.TRUST),
+ loaded=True,
+ )
+
+ # Get the command object to test
+ self.cmd = trust.CreateTrust(self.app, None)
+
+ def test_trust_create_basic(self):
+ arglist = [
+ '--project', identity_fakes.project_id,
+ '--role', identity_fakes.role_id,
+ identity_fakes.user_id,
+ identity_fakes.user_id
+ ]
+ verifylist = [
+ ('project', identity_fakes.project_id),
+ ('impersonate', False),
+ ('role', [identity_fakes.role_id]),
+ ('trustor', identity_fakes.user_id),
+ ('trustee', identity_fakes.user_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'impersonation': False,
+ 'project': identity_fakes.project_id,
+ 'role_names': [identity_fakes.role_name],
+ 'expires_at': None,
+ }
+ # TrustManager.create(trustee_id, trustor_id, impersonation=,
+ # project=, role_names=, expires_at=)
+ self.trusts_mock.create.assert_called_with(
+ identity_fakes.user_id,
+ identity_fakes.user_id,
+ **kwargs
+ )
+
+ collist = ('expires_at', 'id', 'impersonation', 'project_id',
+ 'roles', 'trustee_user_id', 'trustor_user_id')
+ self.assertEqual(collist, columns)
+ datalist = (
+ identity_fakes.trust_expires,
+ identity_fakes.trust_id,
+ identity_fakes.trust_impersonation,
+ identity_fakes.project_id,
+ identity_fakes.role_name,
+ identity_fakes.user_id,
+ identity_fakes.user_id
+ )
+ self.assertEqual(datalist, data)
+
+
+class TestTrustDelete(TestTrust):
+
+ def setUp(self):
+ super(TestTrustDelete, self).setUp()
+
+ # This is the return value for utils.find_resource()
+ self.trusts_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.TRUST),
+ loaded=True,
+ )
+ self.trusts_mock.delete.return_value = None
+
+ # Get the command object to test
+ self.cmd = trust.DeleteTrust(self.app, None)
+
+ def test_trust_delete(self):
+ arglist = [
+ identity_fakes.trust_id,
+ ]
+ verifylist = [
+ ('trust', [identity_fakes.trust_id])
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.trusts_mock.delete.assert_called_with(
+ identity_fakes.trust_id,
+ )
+ self.assertIsNone(result)
+
+
+class TestTrustList(TestTrust):
+
+ def setUp(self):
+ super(TestTrustList, self).setUp()
+
+ self.trusts_mock.list.return_value = [
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.TRUST),
+ loaded=True,
+ ),
+ ]
+
+ # Get the command object to test
+ self.cmd = trust.ListTrust(self.app, None)
+
+ def test_trust_list_no_options(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.trusts_mock.list.assert_called_with()
+
+ collist = ('ID', 'Expires At', 'Impersonation', 'Project ID',
+ 'Trustee User ID', 'Trustor User ID')
+ self.assertEqual(collist, columns)
+ datalist = ((
+ identity_fakes.trust_id,
+ identity_fakes.trust_expires,
+ identity_fakes.trust_impersonation,
+ identity_fakes.project_id,
+ identity_fakes.user_id,
+ identity_fakes.user_id
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+
+class TestTrustShow(TestTrust):
+
+ def setUp(self):
+ super(TestTrustShow, self).setUp()
+
+ self.trusts_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.TRUST),
+ loaded=True,
+ )
+
+ # Get the command object to test
+ self.cmd = trust.ShowTrust(self.app, None)
+
+ def test_trust_show(self):
+ arglist = [
+ identity_fakes.trust_id,
+ ]
+ verifylist = [
+ ('trust', identity_fakes.trust_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.trusts_mock.get.assert_called_with(identity_fakes.trust_id)
+
+ collist = ('expires_at', 'id', 'impersonation', 'project_id',
+ 'roles', 'trustee_user_id', 'trustor_user_id')
+ self.assertEqual(collist, columns)
+ datalist = (
+ identity_fakes.trust_expires,
+ identity_fakes.trust_id,
+ identity_fakes.trust_impersonation,
+ identity_fakes.project_id,
+ identity_fakes.role_name,
+ identity_fakes.user_id,
+ identity_fakes.user_id
+ )
+ self.assertEqual(datalist, data)
diff --git a/openstackclient/tests/unit/identity/v3/test_unscoped_saml.py b/openstackclient/tests/unit/identity/v3/test_unscoped_saml.py
new file mode 100644
index 00000000..9e4e1876
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v3/test_unscoped_saml.py
@@ -0,0 +1,133 @@
+# 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.
+
+import copy
+
+from osc_lib import exceptions
+
+from openstackclient.identity.v3 import unscoped_saml
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+
+
+class TestUnscopedSAML(identity_fakes.TestFederatedIdentity):
+
+ def setUp(self):
+ super(TestUnscopedSAML, self).setUp()
+
+ federation_lib = self.app.client_manager.identity.federation
+ self.projects_mock = federation_lib.projects
+ self.projects_mock.reset_mock()
+ self.domains_mock = federation_lib.domains
+ self.domains_mock.reset_mock()
+
+
+class TestDomainList(TestUnscopedSAML):
+
+ def setUp(self):
+ super(TestDomainList, self).setUp()
+
+ self.domains_mock.list.return_value = [
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.DOMAIN),
+ loaded=True,
+ ),
+ ]
+
+ # Get the command object to test
+ self.cmd = unscoped_saml.ListAccessibleDomains(self.app, None)
+
+ def test_accessible_domains_list(self):
+ self.app.client_manager.auth_plugin_name = 'v3unscopedsaml'
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.domains_mock.list.assert_called_with()
+
+ collist = ('ID', 'Enabled', 'Name', 'Description')
+ self.assertEqual(collist, columns)
+ datalist = ((
+ identity_fakes.domain_id,
+ True,
+ identity_fakes.domain_name,
+ identity_fakes.domain_description,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_accessible_domains_list_wrong_auth(self):
+ auth = identity_fakes.FakeAuth("wrong auth")
+ self.app.client_manager.identity.session.auth = auth
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
+
+
+class TestProjectList(TestUnscopedSAML):
+
+ def setUp(self):
+ super(TestProjectList, self).setUp()
+
+ self.projects_mock.list.return_value = [
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.PROJECT),
+ loaded=True,
+ ),
+ ]
+
+ # Get the command object to test
+ self.cmd = unscoped_saml.ListAccessibleProjects(self.app, None)
+
+ def test_accessible_projects_list(self):
+ self.app.client_manager.auth_plugin_name = 'v3unscopedsaml'
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.projects_mock.list.assert_called_with()
+
+ collist = ('ID', 'Domain ID', 'Enabled', 'Name')
+ self.assertEqual(collist, columns)
+ datalist = ((
+ identity_fakes.project_id,
+ identity_fakes.domain_id,
+ True,
+ identity_fakes.project_name,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_accessible_projects_list_wrong_auth(self):
+ auth = identity_fakes.FakeAuth("wrong auth")
+ self.app.client_manager.identity.session.auth = auth
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
diff --git a/openstackclient/tests/unit/identity/v3/test_user.py b/openstackclient/tests/unit/identity/v3/test_user.py
new file mode 100644
index 00000000..6150a5f3
--- /dev/null
+++ b/openstackclient/tests/unit/identity/v3/test_user.py
@@ -0,0 +1,1063 @@
+# Copyright 2013 Nebula Inc.
+#
+# 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.
+#
+
+import contextlib
+import mock
+
+from openstackclient.identity.v3 import user
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+
+
+class TestUser(identity_fakes.TestIdentityv3):
+
+ def setUp(self):
+ super(TestUser, self).setUp()
+
+ # Get a shortcut to the DomainManager Mock
+ self.domains_mock = self.app.client_manager.identity.domains
+ self.domains_mock.reset_mock()
+
+ # Get a shortcut to the ProjectManager Mock
+ self.projects_mock = self.app.client_manager.identity.projects
+ self.projects_mock.reset_mock()
+
+ # Get a shortcut to the GroupManager Mock
+ self.groups_mock = self.app.client_manager.identity.groups
+ self.groups_mock.reset_mock()
+
+ # Get a shortcut to the UserManager Mock
+ self.users_mock = self.app.client_manager.identity.users
+ self.users_mock.reset_mock()
+
+ # Shortcut for RoleAssignmentManager Mock
+ self.role_assignments_mock = self.app.client_manager.identity.\
+ role_assignments
+ self.role_assignments_mock.reset_mock()
+
+
+class TestUserCreate(TestUser):
+
+ domain = identity_fakes.FakeDomain.create_one_domain()
+ project = identity_fakes.FakeProject.create_one_project()
+
+ columns = (
+ 'default_project_id',
+ 'domain_id',
+ 'email',
+ 'enabled',
+ 'id',
+ 'name',
+ )
+
+ def setUp(self):
+ super(TestUserCreate, self).setUp()
+
+ self.user = identity_fakes.FakeUser.create_one_user(
+ attrs={'domain_id': self.domain.id,
+ 'default_project_id': self.project.id}
+ )
+ self.datalist = (
+ self.project.id,
+ self.domain.id,
+ self.user.email,
+ True,
+ self.user.id,
+ self.user.name,
+ )
+
+ self.domains_mock.get.return_value = self.domain
+ self.projects_mock.get.return_value = self.project
+ self.users_mock.create.return_value = self.user
+
+ # Get the command object to test
+ self.cmd = user.CreateUser(self.app, None)
+
+ def test_user_create_no_options(self):
+ arglist = [
+ self.user.name,
+ ]
+ verifylist = [
+ ('enable', False),
+ ('disable', False),
+ ('name', self.user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': self.user.name,
+ 'default_project': None,
+ 'description': None,
+ 'domain': None,
+ 'email': None,
+ 'enabled': True,
+ 'password': None,
+ }
+
+ # UserManager.create(name=, domain=, project=, password=, email=,
+ # description=, enabled=, default_project=)
+ self.users_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_user_create_password(self):
+ arglist = [
+ '--password', 'secret',
+ self.user.name,
+ ]
+ verifylist = [
+ ('password', 'secret'),
+ ('password_prompt', False),
+ ('enable', False),
+ ('disable', False),
+ ('name', self.user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': self.user.name,
+ 'default_project': None,
+ 'description': None,
+ 'domain': None,
+ 'email': None,
+ 'enabled': True,
+ 'password': 'secret',
+ }
+ # UserManager.create(name=, domain=, project=, password=, email=,
+ # description=, enabled=, default_project=)
+ self.users_mock.create.assert_called_with(
+ **kwargs
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_user_create_password_prompt(self):
+ arglist = [
+ '--password-prompt',
+ self.user.name,
+ ]
+ verifylist = [
+ ('password', None),
+ ('password_prompt', True),
+ ('enable', False),
+ ('disable', False),
+ ('name', self.user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ mocker = mock.Mock()
+ mocker.return_value = 'abc123'
+ with mock.patch("osc_lib.utils.get_password", mocker):
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': self.user.name,
+ 'default_project': None,
+ 'description': None,
+ 'domain': None,
+ 'email': None,
+ 'enabled': True,
+ 'password': 'abc123',
+ }
+ # UserManager.create(name=, domain=, project=, password=, email=,
+ # description=, enabled=, default_project=)
+ self.users_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_user_create_email(self):
+ arglist = [
+ '--email', 'barney@example.com',
+ self.user.name,
+ ]
+ verifylist = [
+ ('email', 'barney@example.com'),
+ ('enable', False),
+ ('disable', False),
+ ('name', self.user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': self.user.name,
+ 'default_project': None,
+ 'description': None,
+ 'domain': None,
+ 'email': 'barney@example.com',
+ 'enabled': True,
+ 'password': None,
+ }
+ # UserManager.create(name=, domain=, project=, password=, email=,
+ # description=, enabled=, default_project=)
+ self.users_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_user_create_project(self):
+ arglist = [
+ '--project', self.project.name,
+ self.user.name,
+ ]
+ verifylist = [
+ ('project', self.project.name),
+ ('enable', False),
+ ('disable', False),
+ ('name', self.user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': self.user.name,
+ 'default_project': self.project.id,
+ 'description': None,
+ 'domain': None,
+ 'email': None,
+ 'enabled': True,
+ 'password': None,
+ }
+ # UserManager.create(name=, domain=, project=, password=, email=,
+ # description=, enabled=, default_project=)
+ self.users_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ datalist = (
+ self.project.id,
+ self.domain.id,
+ self.user.email,
+ True,
+ self.user.id,
+ self.user.name,
+ )
+ self.assertEqual(datalist, data)
+
+ def test_user_create_project_domain(self):
+ arglist = [
+ '--project', self.project.name,
+ '--project-domain', self.project.domain_id,
+ self.user.name,
+ ]
+ verifylist = [
+ ('project', self.project.name),
+ ('project_domain', self.project.domain_id),
+ ('enable', False),
+ ('disable', False),
+ ('name', self.user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': self.user.name,
+ 'default_project': self.project.id,
+ 'description': None,
+ 'domain': None,
+ 'email': None,
+ 'enabled': True,
+ 'password': None,
+ }
+ # UserManager.create(name=, domain=, project=, password=, email=,
+ # description=, enabled=, default_project=)
+ self.users_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ datalist = (
+ self.project.id,
+ self.domain.id,
+ self.user.email,
+ True,
+ self.user.id,
+ self.user.name,
+ )
+ self.assertEqual(datalist, data)
+
+ def test_user_create_domain(self):
+ arglist = [
+ '--domain', self.domain.name,
+ self.user.name,
+ ]
+ verifylist = [
+ ('domain', self.domain.name),
+ ('enable', False),
+ ('disable', False),
+ ('name', self.user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': self.user.name,
+ 'default_project': None,
+ 'description': None,
+ 'domain': self.domain.id,
+ 'email': None,
+ 'enabled': True,
+ 'password': None,
+ }
+ # UserManager.create(name=, domain=, project=, password=, email=,
+ # description=, enabled=, default_project=)
+ self.users_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_user_create_enable(self):
+ arglist = [
+ '--enable',
+ self.user.name,
+ ]
+ verifylist = [
+ ('enable', True),
+ ('disable', False),
+ ('name', self.user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': self.user.name,
+ 'default_project': None,
+ 'description': None,
+ 'domain': None,
+ 'email': None,
+ 'enabled': True,
+ 'password': None,
+ }
+ # UserManager.create(name=, domain=, project=, password=, email=,
+ # description=, enabled=, default_project=)
+ self.users_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_user_create_disable(self):
+ arglist = [
+ '--disable',
+ self.user.name,
+ ]
+ verifylist = [
+ ('name', self.user.name),
+ ('enable', False),
+ ('disable', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': self.user.name,
+ 'default_project': None,
+ 'description': None,
+ 'domain': None,
+ 'email': None,
+ 'enabled': False,
+ 'password': None,
+ }
+ # users.create(name=, password, email, tenant_id=None, enabled=True)
+ self.users_mock.create.assert_called_with(
+ **kwargs
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+
+class TestUserDelete(TestUser):
+
+ user = identity_fakes.FakeUser.create_one_user()
+
+ def setUp(self):
+ super(TestUserDelete, self).setUp()
+
+ # This is the return value for utils.find_resource()
+ self.users_mock.get.return_value = self.user
+ self.users_mock.delete.return_value = None
+
+ # Get the command object to test
+ self.cmd = user.DeleteUser(self.app, None)
+
+ def test_user_delete_no_options(self):
+ arglist = [
+ self.user.id,
+ ]
+ verifylist = [
+ ('users', [self.user.id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.users_mock.delete.assert_called_with(
+ self.user.id,
+ )
+ self.assertIsNone(result)
+
+
+class TestUserList(TestUser):
+
+ domain = identity_fakes.FakeDomain.create_one_domain()
+ project = identity_fakes.FakeProject.create_one_project()
+ user = identity_fakes.FakeUser.create_one_user(
+ attrs={'domain_id': domain.id,
+ 'default_project_id': project.id}
+ )
+ group = identity_fakes.FakeGroup.create_one_group()
+ role_assignment = (
+ identity_fakes.FakeRoleAssignment.create_one_role_assignment(
+ attrs={'user': {'id': user.id}}))
+
+ columns = [
+ 'ID',
+ 'Name'
+ ]
+ datalist = (
+ (
+ user.id,
+ user.name,
+ ),
+ )
+
+ def setUp(self):
+ super(TestUserList, self).setUp()
+
+ self.users_mock.get.return_value = self.user
+ self.users_mock.list.return_value = [self.user]
+ self.domains_mock.get.return_value = self.domain
+ self.groups_mock.get.return_value = self.group
+ self.projects_mock.get.return_value = self.project
+ self.role_assignments_mock.list.return_value = [self.role_assignment]
+
+ # Get the command object to test
+ self.cmd = user.ListUser(self.app, None)
+
+ def test_user_list_no_options(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'domain': None,
+ 'group': None,
+ }
+
+ self.users_mock.list.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_user_list_domain(self):
+ arglist = [
+ '--domain', self.domain.id,
+ ]
+ verifylist = [
+ ('domain', self.domain.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'domain': self.domain.id,
+ 'group': None,
+ }
+
+ self.users_mock.list.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_user_list_group(self):
+ arglist = [
+ '--group', self.group.name,
+ ]
+ verifylist = [
+ ('group', self.group.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'domain': None,
+ 'group': self.group.id,
+ }
+
+ self.users_mock.list.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_user_list_long(self):
+ arglist = [
+ '--long',
+ ]
+ verifylist = [
+ ('long', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'domain': None,
+ 'group': None,
+ }
+
+ self.users_mock.list.assert_called_with(
+ **kwargs
+ )
+
+ collist = [
+ 'ID',
+ 'Name',
+ 'Project',
+ 'Domain',
+ 'Description',
+ 'Email',
+ 'Enabled',
+ ]
+ self.assertEqual(collist, columns)
+ datalist = (
+ (
+ self.user.id,
+ self.user.name,
+ self.project.id,
+ self.domain.id,
+ '',
+ self.user.email,
+ True,
+ ),
+ )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_user_list_project(self):
+ arglist = [
+ '--project', self.project.name,
+ ]
+ verifylist = [
+ ('project', self.project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ kwargs = {
+ 'project': self.project.id,
+ }
+
+ self.role_assignments_mock.list.assert_called_with(**kwargs)
+ self.users_mock.get.assert_called_with(self.user.id)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+
+class TestUserSet(TestUser):
+
+ project = identity_fakes.FakeProject.create_one_project()
+ user = identity_fakes.FakeUser.create_one_user(
+ attrs={'default_project_id': project.id}
+ )
+
+ def setUp(self):
+ super(TestUserSet, self).setUp()
+
+ self.projects_mock.get.return_value = self.project
+ self.users_mock.get.return_value = self.user
+ self.users_mock.update.return_value = self.user
+
+ # Get the command object to test
+ self.cmd = user.SetUser(self.app, None)
+
+ def test_user_set_no_options(self):
+ arglist = [
+ self.user.name,
+ ]
+ verifylist = [
+ ('name', None),
+ ('password', None),
+ ('email', None),
+ ('project', None),
+ ('enable', False),
+ ('disable', False),
+ ('user', self.user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.assertIsNone(result)
+
+ def test_user_set_name(self):
+ arglist = [
+ '--name', 'qwerty',
+ self.user.name,
+ ]
+ verifylist = [
+ ('name', 'qwerty'),
+ ('password', None),
+ ('email', None),
+ ('project', None),
+ ('enable', False),
+ ('disable', False),
+ ('user', self.user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': True,
+ 'name': 'qwerty',
+ }
+ # UserManager.update(user, name=, domain=, project=, password=,
+ # email=, description=, enabled=, default_project=)
+ self.users_mock.update.assert_called_with(
+ self.user.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_user_set_password(self):
+ arglist = [
+ '--password', 'secret',
+ self.user.name,
+ ]
+ verifylist = [
+ ('name', None),
+ ('password', 'secret'),
+ ('password_prompt', False),
+ ('email', None),
+ ('project', None),
+ ('enable', False),
+ ('disable', False),
+ ('user', self.user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': True,
+ 'password': 'secret',
+ }
+ # UserManager.update(user, name=, domain=, project=, password=,
+ # email=, description=, enabled=, default_project=)
+ self.users_mock.update.assert_called_with(
+ self.user.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_user_set_password_prompt(self):
+ arglist = [
+ '--password-prompt',
+ self.user.name,
+ ]
+ verifylist = [
+ ('name', None),
+ ('password', None),
+ ('password_prompt', True),
+ ('email', None),
+ ('project', None),
+ ('enable', False),
+ ('disable', False),
+ ('user', self.user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ mocker = mock.Mock()
+ mocker.return_value = 'abc123'
+ with mock.patch("osc_lib.utils.get_password", mocker):
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': True,
+ 'password': 'abc123',
+ }
+ # UserManager.update(user, name=, domain=, project=, password=,
+ # email=, description=, enabled=, default_project=)
+ self.users_mock.update.assert_called_with(
+ self.user.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_user_set_email(self):
+ arglist = [
+ '--email', 'barney@example.com',
+ self.user.name,
+ ]
+ verifylist = [
+ ('name', None),
+ ('password', None),
+ ('email', 'barney@example.com'),
+ ('project', None),
+ ('enable', False),
+ ('disable', False),
+ ('user', self.user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': True,
+ 'email': 'barney@example.com',
+ }
+ # UserManager.update(user, name=, domain=, project=, password=,
+ # email=, description=, enabled=, default_project=)
+ self.users_mock.update.assert_called_with(
+ self.user.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_user_set_project(self):
+ arglist = [
+ '--project', self.project.id,
+ self.user.name,
+ ]
+ verifylist = [
+ ('name', None),
+ ('password', None),
+ ('email', None),
+ ('project', self.project.id),
+ ('enable', False),
+ ('disable', False),
+ ('user', self.user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': True,
+ 'default_project': self.project.id,
+ }
+ # UserManager.update(user, name=, domain=, project=, password=,
+ # email=, description=, enabled=, default_project=)
+ self.users_mock.update.assert_called_with(
+ self.user.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_user_set_project_domain(self):
+ arglist = [
+ '--project', self.project.id,
+ '--project-domain', self.project.domain_id,
+ self.user.name,
+ ]
+ verifylist = [
+ ('name', None),
+ ('password', None),
+ ('email', None),
+ ('project', self.project.id),
+ ('project_domain', self.project.domain_id),
+ ('enable', False),
+ ('disable', False),
+ ('user', self.user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': True,
+ 'default_project': self.project.id,
+ }
+ # UserManager.update(user, name=, domain=, project=, password=,
+ # email=, description=, enabled=, default_project=)
+ self.users_mock.update.assert_called_with(
+ self.user.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_user_set_enable(self):
+ arglist = [
+ '--enable',
+ self.user.name,
+ ]
+ verifylist = [
+ ('name', None),
+ ('password', None),
+ ('email', None),
+ ('project', None),
+ ('enable', True),
+ ('disable', False),
+ ('user', self.user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': True,
+ }
+ # UserManager.update(user, name=, domain=, project=, password=,
+ # email=, description=, enabled=, default_project=)
+ self.users_mock.update.assert_called_with(
+ self.user.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_user_set_disable(self):
+ arglist = [
+ '--disable',
+ self.user.name,
+ ]
+ verifylist = [
+ ('name', None),
+ ('password', None),
+ ('email', None),
+ ('project', None),
+ ('enable', False),
+ ('disable', True),
+ ('user', self.user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': False,
+ }
+ # UserManager.update(user, name=, domain=, project=, password=,
+ # email=, description=, enabled=, default_project=)
+ self.users_mock.update.assert_called_with(
+ self.user.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+
+class TestUserSetPassword(TestUser):
+
+ def setUp(self):
+ super(TestUserSetPassword, self).setUp()
+ self.cmd = user.SetPasswordUser(self.app, None)
+
+ @staticmethod
+ @contextlib.contextmanager
+ def _mock_get_password(*passwords):
+ mocker = mock.Mock(side_effect=passwords)
+ with mock.patch("osc_lib.utils.get_password", mocker):
+ yield
+
+ def test_user_password_change(self):
+ current_pass = 'old_pass'
+ new_pass = 'new_pass'
+ arglist = [
+ '--password', new_pass,
+ ]
+ verifylist = [
+ ('password', new_pass),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # Mock getting user current password.
+ with self._mock_get_password(current_pass):
+ result = self.cmd.take_action(parsed_args)
+
+ self.users_mock.update_password.assert_called_with(
+ current_pass, new_pass
+ )
+ self.assertIsNone(result)
+
+ def test_user_create_password_prompt(self):
+ current_pass = 'old_pass'
+ new_pass = 'new_pass'
+ parsed_args = self.check_parser(self.cmd, [], [])
+
+ # Mock getting user current and new password.
+ with self._mock_get_password(current_pass, new_pass):
+ result = self.cmd.take_action(parsed_args)
+
+ self.users_mock.update_password.assert_called_with(
+ current_pass, new_pass
+ )
+ self.assertIsNone(result)
+
+ def test_user_password_change_no_prompt(self):
+ current_pass = 'old_pass'
+ new_pass = 'new_pass'
+ arglist = [
+ '--password', new_pass,
+ '--original-password', current_pass,
+ ]
+ verifylist = [
+ ('password', new_pass),
+ ('original_password', current_pass),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.users_mock.update_password.assert_called_with(
+ current_pass, new_pass
+ )
+ self.assertIsNone(result)
+
+
+class TestUserShow(TestUser):
+
+ user = identity_fakes.FakeUser.create_one_user()
+
+ def setUp(self):
+ super(TestUserShow, self).setUp()
+
+ self.users_mock.get.return_value = self.user
+
+ # Get the command object to test
+ self.cmd = user.ShowUser(self.app, None)
+ self.app.client_manager.identity.auth.client.get_user_id.\
+ return_value = self.user.id
+ self.app.client_manager.identity.tokens.get_token_data.return_value = \
+ {'token':
+ {'user':
+ {'domain': {},
+ 'id': self.user.id,
+ 'name': self.user.name,
+ }
+ }
+ }
+
+ def test_user_show(self):
+ arglist = [
+ self.user.id,
+ ]
+ verifylist = [
+ ('user', self.user.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.users_mock.get.assert_called_with(self.user.id)
+
+ collist = ('default_project_id', 'domain_id', 'email',
+ 'enabled', 'id', 'name')
+ self.assertEqual(collist, columns)
+ datalist = (
+ self.user.default_project_id,
+ self.user.domain_id,
+ self.user.email,
+ True,
+ self.user.id,
+ self.user.name,
+ )
+ self.assertEqual(datalist, data)
diff --git a/openstackclient/tests/unit/image/__init__.py b/openstackclient/tests/unit/image/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/unit/image/__init__.py
diff --git a/openstackclient/tests/unit/image/v1/__init__.py b/openstackclient/tests/unit/image/v1/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/unit/image/v1/__init__.py
diff --git a/openstackclient/tests/unit/image/v1/fakes.py b/openstackclient/tests/unit/image/v1/fakes.py
new file mode 100644
index 00000000..a8e52fa3
--- /dev/null
+++ b/openstackclient/tests/unit/image/v1/fakes.py
@@ -0,0 +1,76 @@
+# Copyright 2013 Nebula Inc.
+#
+# 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.
+#
+
+import mock
+
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit import utils
+from openstackclient.tests.unit.volume.v1 import fakes as volume_fakes
+
+
+image_id = 'im1'
+image_name = 'graven'
+image_owner = 'baal'
+image_protected = False
+image_public = True
+image_properties = {
+ 'Alpha': 'a',
+ 'Beta': 'b',
+ 'Gamma': 'g',
+}
+image_properties_str = "Alpha='a', Beta='b', Gamma='g'"
+image_data = 'line 1\nline 2\n'
+
+IMAGE = {
+ 'id': image_id,
+ 'name': image_name,
+ 'container_format': '',
+ 'disk_format': '',
+ 'owner': image_owner,
+ 'min_disk': 0,
+ 'min_ram': 0,
+ 'is_public': image_public,
+ 'protected': image_protected,
+ 'properties': image_properties,
+}
+
+IMAGE_columns = tuple(sorted(IMAGE))
+IMAGE_output = dict(IMAGE)
+IMAGE_output['properties'] = image_properties_str
+IMAGE_data = tuple((IMAGE_output[x] for x in sorted(IMAGE_output)))
+
+
+class FakeImagev1Client(object):
+
+ def __init__(self, **kwargs):
+ self.images = mock.Mock()
+ self.images.resource_class = fakes.FakeResource(None, {})
+ self.auth_token = kwargs['token']
+ self.management_url = kwargs['endpoint']
+
+
+class TestImagev1(utils.TestCommand):
+
+ def setUp(self):
+ super(TestImagev1, self).setUp()
+
+ self.app.client_manager.image = FakeImagev1Client(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN,
+ )
+ self.app.client_manager.volume = volume_fakes.FakeVolumev1Client(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN,
+ )
diff --git a/openstackclient/tests/unit/image/v1/test_image.py b/openstackclient/tests/unit/image/v1/test_image.py
new file mode 100644
index 00000000..c62c1ff9
--- /dev/null
+++ b/openstackclient/tests/unit/image/v1/test_image.py
@@ -0,0 +1,701 @@
+# Copyright 2013 Nebula Inc.
+#
+# 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.
+#
+
+import copy
+import mock
+
+from osc_lib import exceptions
+
+from openstackclient.image.v1 import image
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit.image.v1 import fakes as image_fakes
+
+
+class TestImage(image_fakes.TestImagev1):
+
+ def setUp(self):
+ super(TestImage, self).setUp()
+
+ # Get a shortcut to the ServerManager Mock
+ self.images_mock = self.app.client_manager.image.images
+ self.images_mock.reset_mock()
+
+
+class TestImageCreate(TestImage):
+
+ def setUp(self):
+ super(TestImageCreate, self).setUp()
+
+ self.images_mock.create.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(image_fakes.IMAGE),
+ loaded=True,
+ )
+ # This is the return value for utils.find_resource()
+ self.images_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(image_fakes.IMAGE),
+ loaded=True,
+ )
+ self.images_mock.update.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(image_fakes.IMAGE),
+ loaded=True,
+ )
+
+ # Get the command object to test
+ self.cmd = image.CreateImage(self.app, None)
+
+ def test_image_reserve_no_options(self):
+ mock_exception = {
+ 'find.side_effect': exceptions.CommandError('x'),
+ 'get.side_effect': exceptions.CommandError('x'),
+ }
+ self.images_mock.configure_mock(**mock_exception)
+ arglist = [
+ image_fakes.image_name,
+ ]
+ verifylist = [
+ ('container_format', image.DEFAULT_CONTAINER_FORMAT),
+ ('disk_format', image.DEFAULT_DISK_FORMAT),
+ ('name', image_fakes.image_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # ImageManager.create(name=, **)
+ self.images_mock.create.assert_called_with(
+ name=image_fakes.image_name,
+ container_format=image.DEFAULT_CONTAINER_FORMAT,
+ disk_format=image.DEFAULT_DISK_FORMAT,
+ data=mock.ANY,
+ )
+
+ # Verify update() was not called, if it was show the args
+ self.assertEqual(self.images_mock.update.call_args_list, [])
+
+ self.assertEqual(image_fakes.IMAGE_columns, columns)
+ self.assertEqual(image_fakes.IMAGE_data, data)
+
+ def test_image_reserve_options(self):
+ mock_exception = {
+ 'find.side_effect': exceptions.CommandError('x'),
+ 'get.side_effect': exceptions.CommandError('x'),
+ }
+ self.images_mock.configure_mock(**mock_exception)
+ arglist = [
+ '--container-format', 'ovf',
+ '--disk-format', 'fs',
+ '--min-disk', '10',
+ '--min-ram', '4',
+ '--protected',
+ '--private',
+ '--project', 'q',
+ image_fakes.image_name,
+ ]
+ verifylist = [
+ ('container_format', 'ovf'),
+ ('disk_format', 'fs'),
+ ('min_disk', 10),
+ ('min_ram', 4),
+ ('protected', True),
+ ('unprotected', False),
+ ('public', False),
+ ('private', True),
+ ('project', 'q'),
+ ('name', image_fakes.image_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # ImageManager.create(name=, **)
+ self.images_mock.create.assert_called_with(
+ name=image_fakes.image_name,
+ container_format='ovf',
+ disk_format='fs',
+ min_disk=10,
+ min_ram=4,
+ protected=True,
+ is_public=False,
+ owner='q',
+ data=mock.ANY,
+ )
+
+ # Verify update() was not called, if it was show the args
+ self.assertEqual(self.images_mock.update.call_args_list, [])
+
+ self.assertEqual(image_fakes.IMAGE_columns, columns)
+ self.assertEqual(image_fakes.IMAGE_data, data)
+
+ @mock.patch('openstackclient.image.v1.image.io.open', name='Open')
+ def test_image_create_file(self, mock_open):
+ mock_file = mock.MagicMock(name='File')
+ mock_open.return_value = mock_file
+ mock_open.read.return_value = image_fakes.image_data
+ mock_exception = {
+ 'find.side_effect': exceptions.CommandError('x'),
+ 'get.side_effect': exceptions.CommandError('x'),
+ }
+ self.images_mock.configure_mock(**mock_exception)
+
+ arglist = [
+ '--file', 'filer',
+ '--unprotected',
+ '--public',
+ '--property', 'Alpha=1',
+ '--property', 'Beta=2',
+ image_fakes.image_name,
+ ]
+ verifylist = [
+ ('file', 'filer'),
+ ('protected', False),
+ ('unprotected', True),
+ ('public', True),
+ ('private', False),
+ ('properties', {'Alpha': '1', 'Beta': '2'}),
+ ('name', image_fakes.image_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Ensure input file is opened
+ mock_open.assert_called_with('filer', 'rb')
+
+ # Ensure the input file is closed
+ mock_file.close.assert_called_with()
+
+ # ImageManager.get(name) not to be called since update action exists
+ self.images_mock.get.assert_not_called()
+
+ # ImageManager.create(name=, **)
+ self.images_mock.create.assert_called_with(
+ name=image_fakes.image_name,
+ container_format=image.DEFAULT_CONTAINER_FORMAT,
+ disk_format=image.DEFAULT_DISK_FORMAT,
+ protected=False,
+ is_public=True,
+ properties={
+ 'Alpha': '1',
+ 'Beta': '2',
+ },
+ data=mock_file,
+ )
+
+ # Verify update() was not called, if it was show the args
+ self.assertEqual(self.images_mock.update.call_args_list, [])
+
+ self.assertEqual(image_fakes.IMAGE_columns, columns)
+ self.assertEqual(image_fakes.IMAGE_data, data)
+
+
+class TestImageDelete(TestImage):
+
+ def setUp(self):
+ super(TestImageDelete, self).setUp()
+
+ # This is the return value for utils.find_resource()
+ self.images_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(image_fakes.IMAGE),
+ loaded=True,
+ )
+ self.images_mock.delete.return_value = None
+
+ # Get the command object to test
+ self.cmd = image.DeleteImage(self.app, None)
+
+ def test_image_delete_no_options(self):
+ arglist = [
+ image_fakes.image_id,
+ ]
+ verifylist = [
+ ('images', [image_fakes.image_id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.images_mock.delete.assert_called_with(image_fakes.image_id)
+ self.assertIsNone(result)
+
+
+class TestImageList(TestImage):
+
+ columns = (
+ 'ID',
+ 'Name',
+ 'Status',
+ )
+ datalist = (
+ (
+ image_fakes.image_id,
+ image_fakes.image_name,
+ '',
+ ),
+ )
+
+ def setUp(self):
+ super(TestImageList, self).setUp()
+
+ self.api_mock = mock.Mock()
+ self.api_mock.image_list.side_effect = [
+ [copy.deepcopy(image_fakes.IMAGE)], [],
+ ]
+ self.app.client_manager.image.api = self.api_mock
+
+ # Get the command object to test
+ self.cmd = image.ListImage(self.app, None)
+
+ def test_image_list_no_options(self):
+ arglist = []
+ verifylist = [
+ ('public', False),
+ ('private', False),
+ ('long', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.api_mock.image_list.assert_called_with(
+ detailed=True,
+ marker=image_fakes.image_id,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_image_list_public_option(self):
+ arglist = [
+ '--public',
+ ]
+ verifylist = [
+ ('public', True),
+ ('private', False),
+ ('long', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.api_mock.image_list.assert_called_with(
+ detailed=True,
+ public=True,
+ marker=image_fakes.image_id,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_image_list_private_option(self):
+ arglist = [
+ '--private',
+ ]
+ verifylist = [
+ ('public', False),
+ ('private', True),
+ ('long', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.api_mock.image_list.assert_called_with(
+ detailed=True,
+ private=True,
+ marker=image_fakes.image_id,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_image_list_long_option(self):
+ arglist = [
+ '--long',
+ ]
+ verifylist = [
+ ('long', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.api_mock.image_list.assert_called_with(
+ detailed=True,
+ marker=image_fakes.image_id,
+ )
+
+ collist = (
+ 'ID',
+ 'Name',
+ 'Disk Format',
+ 'Container Format',
+ 'Size',
+ 'Checksum',
+ 'Status',
+ 'Visibility',
+ 'Protected',
+ 'Project',
+ 'Properties',
+ )
+
+ self.assertEqual(collist, columns)
+ datalist = ((
+ image_fakes.image_id,
+ image_fakes.image_name,
+ '',
+ '',
+ '',
+ '',
+ '',
+ 'public',
+ False,
+ image_fakes.image_owner,
+ "Alpha='a', Beta='b', Gamma='g'",
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+ @mock.patch('openstackclient.api.utils.simple_filter')
+ def test_image_list_property_option(self, sf_mock):
+ sf_mock.side_effect = [
+ [copy.deepcopy(image_fakes.IMAGE)], [],
+ ]
+
+ arglist = [
+ '--property', 'a=1',
+ ]
+ verifylist = [
+ ('property', {'a': '1'}),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.api_mock.image_list.assert_called_with(
+ detailed=True,
+ marker=image_fakes.image_id,
+ )
+ sf_mock.assert_called_with(
+ [image_fakes.IMAGE],
+ attr='a',
+ value='1',
+ property_field='properties',
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ @mock.patch('osc_lib.utils.sort_items')
+ def test_image_list_sort_option(self, si_mock):
+ si_mock.side_effect = [
+ [copy.deepcopy(image_fakes.IMAGE)], [],
+ ]
+
+ arglist = ['--sort', 'name:asc']
+ verifylist = [('sort', 'name:asc')]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.api_mock.image_list.assert_called_with(
+ detailed=True,
+ marker=image_fakes.image_id,
+ )
+ si_mock.assert_called_with(
+ [image_fakes.IMAGE],
+ 'name:asc'
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+
+class TestImageSet(TestImage):
+
+ def setUp(self):
+ super(TestImageSet, self).setUp()
+
+ # This is the return value for utils.find_resource()
+ self.images_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(image_fakes.IMAGE),
+ loaded=True,
+ )
+ self.images_mock.update.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(image_fakes.IMAGE),
+ loaded=True,
+ )
+
+ # Get the command object to test
+ self.cmd = image.SetImage(self.app, None)
+
+ def test_image_set_no_options(self):
+ arglist = [
+ image_fakes.image_name,
+ ]
+ verifylist = [
+ ('image', image_fakes.image_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.images_mock.update.assert_called_with(image_fakes.image_id,
+ **{})
+ self.assertIsNone(result)
+
+ def test_image_set_options(self):
+ arglist = [
+ '--name', 'new-name',
+ '--min-disk', '2',
+ '--min-ram', '4',
+ '--container-format', 'ovf',
+ '--disk-format', 'vmdk',
+ '--size', '35165824',
+ '--project', 'new-owner',
+ image_fakes.image_name,
+ ]
+ verifylist = [
+ ('name', 'new-name'),
+ ('min_disk', 2),
+ ('min_ram', 4),
+ ('container_format', 'ovf'),
+ ('disk_format', 'vmdk'),
+ ('size', 35165824),
+ ('project', 'new-owner'),
+ ('image', image_fakes.image_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ kwargs = {
+ 'name': 'new-name',
+ 'owner': 'new-owner',
+ 'min_disk': 2,
+ 'min_ram': 4,
+ 'container_format': 'ovf',
+ 'disk_format': 'vmdk',
+ 'size': 35165824
+ }
+ # ImageManager.update(image, **kwargs)
+ self.images_mock.update.assert_called_with(
+ image_fakes.image_id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_image_set_bools1(self):
+ arglist = [
+ '--protected',
+ '--private',
+ image_fakes.image_name,
+ ]
+ verifylist = [
+ ('protected', True),
+ ('unprotected', False),
+ ('public', False),
+ ('private', True),
+ ('image', image_fakes.image_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ kwargs = {
+ 'protected': True,
+ 'is_public': False,
+ }
+ # ImageManager.update(image, **kwargs)
+ self.images_mock.update.assert_called_with(
+ image_fakes.image_id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_image_set_bools2(self):
+ arglist = [
+ '--unprotected',
+ '--public',
+ image_fakes.image_name,
+ ]
+ verifylist = [
+ ('protected', False),
+ ('unprotected', True),
+ ('public', True),
+ ('private', False),
+ ('image', image_fakes.image_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ kwargs = {
+ 'protected': False,
+ 'is_public': True,
+ }
+ # ImageManager.update(image, **kwargs)
+ self.images_mock.update.assert_called_with(
+ image_fakes.image_id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_image_set_properties(self):
+ arglist = [
+ '--property', 'Alpha=1',
+ '--property', 'Beta=2',
+ image_fakes.image_name,
+ ]
+ verifylist = [
+ ('properties', {'Alpha': '1', 'Beta': '2'}),
+ ('image', image_fakes.image_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ kwargs = {
+ 'properties': {
+ 'Alpha': '1',
+ 'Beta': '2',
+ 'Gamma': 'g',
+ },
+ }
+ # ImageManager.update(image, **kwargs)
+ self.images_mock.update.assert_called_with(
+ image_fakes.image_id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_image_update_volume(self):
+ # Set up VolumeManager Mock
+ volumes_mock = self.app.client_manager.volume.volumes
+ volumes_mock.reset_mock()
+ volumes_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy({'id': 'vol1', 'name': 'volly'}),
+ loaded=True,
+ )
+ response = {
+ "id": 'volume_id',
+ "updated_at": 'updated_at',
+ "status": 'uploading',
+ "display_description": 'desc',
+ "size": 'size',
+ "volume_type": 'volume_type',
+ "container_format": image.DEFAULT_CONTAINER_FORMAT,
+ "disk_format": image.DEFAULT_DISK_FORMAT,
+ "image": image_fakes.image_name,
+ }
+ full_response = {"os-volume_upload_image": response}
+ volumes_mock.upload_to_image.return_value = (201, full_response)
+
+ arglist = [
+ '--volume', 'volly',
+ '--name', 'updated_image',
+ image_fakes.image_name,
+ ]
+ verifylist = [
+ ('private', False),
+ ('protected', False),
+ ('public', False),
+ ('unprotected', False),
+ ('volume', 'volly'),
+ ('force', False),
+ ('name', 'updated_image'),
+ ('image', image_fakes.image_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # VolumeManager.upload_to_image(volume, force, image_name,
+ # container_format, disk_format)
+ volumes_mock.upload_to_image.assert_called_with(
+ 'vol1',
+ False,
+ image_fakes.image_name,
+ '',
+ '',
+ )
+ # ImageManager.update(image_id, remove_props=, **)
+ self.images_mock.update.assert_called_with(
+ image_fakes.image_id,
+ name='updated_image',
+ volume='volly',
+ )
+ self.assertIsNone(result)
+
+
+class TestImageShow(TestImage):
+
+ def setUp(self):
+ super(TestImageShow, self).setUp()
+
+ self.images_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(image_fakes.IMAGE),
+ loaded=True,
+ )
+
+ # Get the command object to test
+ self.cmd = image.ShowImage(self.app, None)
+
+ def test_image_show(self):
+ arglist = [
+ image_fakes.image_id,
+ ]
+ verifylist = [
+ ('image', image_fakes.image_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.images_mock.get.assert_called_with(
+ image_fakes.image_id,
+ )
+
+ self.assertEqual(image_fakes.IMAGE_columns, columns)
+ self.assertEqual(image_fakes.IMAGE_data, data)
diff --git a/openstackclient/tests/unit/image/v2/__init__.py b/openstackclient/tests/unit/image/v2/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/unit/image/v2/__init__.py
diff --git a/openstackclient/tests/unit/image/v2/fakes.py b/openstackclient/tests/unit/image/v2/fakes.py
new file mode 100644
index 00000000..4d9f6458
--- /dev/null
+++ b/openstackclient/tests/unit/image/v2/fakes.py
@@ -0,0 +1,309 @@
+# Copyright 2013 Nebula Inc.
+#
+# 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.
+#
+
+import copy
+import mock
+import random
+import uuid
+
+from glanceclient.v2 import schemas
+from osc_lib import utils as common_utils
+import warlock
+
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+from openstackclient.tests.unit import utils
+
+image_id = '0f41529e-7c12-4de8-be2d-181abb825b3c'
+image_name = 'graven'
+image_owner = 'baal'
+image_protected = False
+image_visibility = 'public'
+image_tags = []
+
+IMAGE = {
+ 'id': image_id,
+ 'name': image_name,
+ 'owner': image_owner,
+ 'protected': image_protected,
+ 'visibility': image_visibility,
+ 'tags': image_tags
+}
+
+IMAGE_columns = tuple(sorted(IMAGE))
+IMAGE_data = tuple((IMAGE[x] for x in sorted(IMAGE)))
+
+IMAGE_SHOW = copy.copy(IMAGE)
+IMAGE_SHOW['tags'] = ''
+IMAGE_SHOW_data = tuple((IMAGE_SHOW[x] for x in sorted(IMAGE_SHOW)))
+
+# Just enough v2 schema to do some testing
+IMAGE_schema = {
+ "additionalProperties": {
+ "type": "string"
+ },
+ "name": "image",
+ "links": [
+ {
+ "href": "{self}",
+ "rel": "self"
+ },
+ {
+ "href": "{file}",
+ "rel": "enclosure"
+ },
+ {
+ "href": "{schema}",
+ "rel": "describedby"
+ }
+ ],
+ "properties": {
+ "id": {
+ "pattern": "^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$", # noqa
+ "type": "string",
+ "description": "An identifier for the image"
+ },
+ "name": {
+ "type": [
+ "null",
+ "string"
+ ],
+ "description": "Descriptive name for the image",
+ "maxLength": 255
+ },
+ "owner": {
+ "type": [
+ "null",
+ "string"
+ ],
+ "description": "Owner of the image",
+ "maxLength": 255
+ },
+ "protected": {
+ "type": "boolean",
+ "description": "If true, image will not be deletable."
+ },
+ "self": {
+ "type": "string",
+ "description": "(READ-ONLY)"
+ },
+ "schema": {
+ "type": "string",
+ "description": "(READ-ONLY)"
+ },
+ "size": {
+ "type": [
+ "null",
+ "integer"
+ ],
+ "description": "Size of image file in bytes (READ-ONLY)"
+ },
+ "status": {
+ "enum": [
+ "queued",
+ "saving",
+ "active",
+ "killed",
+ "deleted",
+ "pending_delete"
+ ],
+ "type": "string",
+ "description": "Status of the image (READ-ONLY)"
+ },
+ "tags": {
+ "items": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "type": "array",
+ "description": "List of strings related to the image"
+ },
+ "visibility": {
+ "enum": [
+ "public",
+ "private"
+ ],
+ "type": "string",
+ "description": "Scope of image accessibility"
+ },
+ }
+}
+
+
+class FakeImagev2Client(object):
+
+ def __init__(self, **kwargs):
+ self.images = mock.Mock()
+ self.images.resource_class = fakes.FakeResource(None, {})
+ self.image_members = mock.Mock()
+ self.image_members.resource_class = fakes.FakeResource(None, {})
+ self.image_tags = mock.Mock()
+ self.image_tags.resource_class = fakes.FakeResource(None, {})
+ self.auth_token = kwargs['token']
+ self.management_url = kwargs['endpoint']
+
+
+class TestImagev2(utils.TestCommand):
+
+ def setUp(self):
+ super(TestImagev2, self).setUp()
+
+ self.app.client_manager.image = FakeImagev2Client(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN,
+ )
+
+ self.app.client_manager.identity = identity_fakes.FakeIdentityv3Client(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN,
+ )
+
+
+class FakeImage(object):
+ """Fake one or more images.
+
+ TODO(xiexs): Currently, only image API v2 is supported by this class.
+ """
+
+ @staticmethod
+ def create_one_image(attrs=None):
+ """Create a fake image.
+
+ :param Dictionary attrs:
+ A dictionary with all attrbutes of image
+ :return:
+ A FakeResource object with id, name, owner, protected,
+ visibility and tags attrs
+ """
+ attrs = attrs or {}
+
+ # Set default attribute
+ image_info = {
+ 'id': str(uuid.uuid4()),
+ 'name': 'image-name' + uuid.uuid4().hex,
+ 'owner': 'image-owner' + uuid.uuid4().hex,
+ 'protected': bool(random.choice([0, 1])),
+ 'visibility': random.choice(['public', 'private']),
+ 'tags': [uuid.uuid4().hex for r in range(2)],
+ }
+
+ # Overwrite default attributes if there are some attributes set
+ image_info.update(attrs)
+
+ # Set up the schema
+ model = warlock.model_factory(
+ IMAGE_schema,
+ schemas.SchemaBasedModel,
+ )
+
+ return model(**image_info)
+
+ @staticmethod
+ def create_images(attrs=None, count=2):
+ """Create multiple fake images.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes of image
+ :param Integer count:
+ The number of images to be faked
+ :return:
+ A list of FakeResource objects
+ """
+ images = []
+ for n in range(0, count):
+ images.append(FakeImage.create_one_image(attrs))
+
+ return images
+
+ @staticmethod
+ def get_images(images=None, count=2):
+ """Get an iterable MagicMock object with a list of faked images.
+
+ If images list is provided, then initialize the Mock object with the
+ list. Otherwise create one.
+
+ :param List images:
+ A list of FakeResource objects faking images
+ :param Integer count:
+ The number of images to be faked
+ :return
+ An iterable Mock object with side_effect set to a list of faked
+ images
+ """
+ if images is None:
+ images = FakeImage.create_images(count)
+
+ return mock.MagicMock(side_effect=images)
+
+ @staticmethod
+ def get_image_columns(image=None):
+ """Get the image columns from a faked image object.
+
+ :param image:
+ A FakeResource objects faking image
+ :return
+ A tuple which may include the following keys:
+ ('id', 'name', 'owner', 'protected', 'visibility', 'tags')
+ """
+ if image is not None:
+ return tuple(sorted(image))
+ return IMAGE_columns
+
+ @staticmethod
+ def get_image_data(image=None):
+ """Get the image data from a faked image object.
+
+ :param image:
+ A FakeResource objects faking image
+ :return
+ A tuple which may include the following values:
+ ('image-123', 'image-foo', 'admin', False, 'public', 'bar, baz')
+ """
+ data_list = []
+ if image is not None:
+ for x in sorted(image.keys()):
+ if x == 'tags':
+ # The 'tags' should be format_list
+ data_list.append(
+ common_utils.format_list(getattr(image, x)))
+ else:
+ data_list.append(getattr(image, x))
+ return tuple(data_list)
+
+ @staticmethod
+ def create_one_image_member(attrs=None):
+ """Create a fake image member.
+
+ :param Dictionary attrs:
+ A dictionary with all attrbutes of image member
+ :return:
+ A FakeResource object with member_id, image_id and so on
+ """
+ attrs = attrs or {}
+
+ # Set default attribute
+ image_member_info = {
+ 'member_id': 'member-id-' + uuid.uuid4().hex,
+ 'image_id': 'image-id-' + uuid.uuid4().hex,
+ 'status': 'pending',
+ }
+
+ # Overwrite default attributes if there are some attributes set
+ image_member_info.update(attrs)
+
+ image_member = fakes.FakeModel(
+ copy.deepcopy(image_member_info))
+
+ return image_member
diff --git a/openstackclient/tests/unit/image/v2/test_image.py b/openstackclient/tests/unit/image/v2/test_image.py
new file mode 100644
index 00000000..ebc9c3a7
--- /dev/null
+++ b/openstackclient/tests/unit/image/v2/test_image.py
@@ -0,0 +1,1316 @@
+# Copyright 2013 Nebula Inc.
+#
+# 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.
+#
+
+import copy
+import mock
+
+from glanceclient.v2 import schemas
+from osc_lib import exceptions
+from osc_lib import utils as common_utils
+import warlock
+
+from openstackclient.image.v2 import image
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+from openstackclient.tests.unit.image.v2 import fakes as image_fakes
+
+
+class TestImage(image_fakes.TestImagev2):
+
+ def setUp(self):
+ super(TestImage, self).setUp()
+
+ # Get shortcuts to the Mocks in image client
+ self.images_mock = self.app.client_manager.image.images
+ self.images_mock.reset_mock()
+ self.image_members_mock = self.app.client_manager.image.image_members
+ self.image_members_mock.reset_mock()
+ self.image_tags_mock = self.app.client_manager.image.image_tags
+ self.image_tags_mock.reset_mock()
+
+ # Get shortcut to the Mocks in identity client
+ self.project_mock = self.app.client_manager.identity.projects
+ self.project_mock.reset_mock()
+ self.domain_mock = self.app.client_manager.identity.domains
+ self.domain_mock.reset_mock()
+
+ def setup_images_mock(self, count):
+ images = image_fakes.FakeImage.create_images(count=count)
+
+ self.images_mock.get = image_fakes.FakeImage.get_images(
+ images,
+ 0)
+ return images
+
+
+class TestImageCreate(TestImage):
+
+ project = identity_fakes.FakeProject.create_one_project()
+ domain = identity_fakes.FakeDomain.create_one_domain()
+
+ def setUp(self):
+ super(TestImageCreate, self).setUp()
+
+ self.new_image = image_fakes.FakeImage.create_one_image()
+ self.images_mock.create.return_value = self.new_image
+
+ self.project_mock.get.return_value = self.project
+
+ self.domain_mock.get.return_value = self.domain
+
+ # This is the return value for utils.find_resource()
+ self.images_mock.get.return_value = copy.deepcopy(
+ self.new_image
+ )
+ self.images_mock.update.return_value = self.new_image
+
+ # Get the command object to test
+ self.cmd = image.CreateImage(self.app, None)
+
+ def test_image_reserve_no_options(self):
+ mock_exception = {
+ 'find.side_effect': exceptions.CommandError('x'),
+ }
+ self.images_mock.configure_mock(**mock_exception)
+ arglist = [
+ self.new_image.name
+ ]
+ verifylist = [
+ ('container_format', image.DEFAULT_CONTAINER_FORMAT),
+ ('disk_format', image.DEFAULT_DISK_FORMAT),
+ ('name', self.new_image.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # ImageManager.create(name=, **)
+ self.images_mock.create.assert_called_with(
+ name=self.new_image.name,
+ container_format=image.DEFAULT_CONTAINER_FORMAT,
+ disk_format=image.DEFAULT_DISK_FORMAT,
+ )
+
+ # Verify update() was not called, if it was show the args
+ self.assertEqual(self.images_mock.update.call_args_list, [])
+
+ self.images_mock.upload.assert_called_with(
+ mock.ANY, mock.ANY,
+ )
+
+ self.assertEqual(
+ image_fakes.FakeImage.get_image_columns(self.new_image),
+ columns)
+ self.assertEqual(
+ image_fakes.FakeImage.get_image_data(self.new_image),
+ data)
+
+ @mock.patch('glanceclient.common.utils.get_data_file', name='Open')
+ def test_image_reserve_options(self, mock_open):
+ mock_file = mock.MagicMock(name='File')
+ mock_open.return_value = mock_file
+ mock_open.read.return_value = None
+ mock_exception = {
+ 'find.side_effect': exceptions.CommandError('x'),
+ }
+ self.images_mock.configure_mock(**mock_exception)
+ arglist = [
+ '--container-format', 'ovf',
+ '--disk-format', 'fs',
+ '--min-disk', '10',
+ '--min-ram', '4',
+ ('--protected'
+ if self.new_image.protected else '--unprotected'),
+ ('--private'
+ if self.new_image.visibility == 'private' else '--public'),
+ '--project', self.new_image.owner,
+ '--project-domain', self.domain.id,
+ self.new_image.name,
+ ]
+ verifylist = [
+ ('container_format', 'ovf'),
+ ('disk_format', 'fs'),
+ ('min_disk', 10),
+ ('min_ram', 4),
+ ('protected', self.new_image.protected),
+ ('unprotected', not self.new_image.protected),
+ ('public', self.new_image.visibility == 'public'),
+ ('private', self.new_image.visibility == 'private'),
+ ('project', self.new_image.owner),
+ ('project_domain', self.domain.id),
+ ('name', self.new_image.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # ImageManager.create(name=, **)
+ self.images_mock.create.assert_called_with(
+ name=self.new_image.name,
+ container_format='ovf',
+ disk_format='fs',
+ min_disk=10,
+ min_ram=4,
+ owner=self.project.id,
+ protected=self.new_image.protected,
+ visibility=self.new_image.visibility,
+ )
+
+ # Verify update() was not called, if it was show the args
+ self.assertEqual(self.images_mock.update.call_args_list, [])
+
+ self.images_mock.upload.assert_called_with(
+ mock.ANY, mock.ANY,
+ )
+
+ self.assertEqual(
+ image_fakes.FakeImage.get_image_columns(self.new_image),
+ columns)
+ self.assertEqual(
+ image_fakes.FakeImage.get_image_data(self.new_image),
+ data)
+
+ def test_image_create_with_unexist_owner(self):
+ self.project_mock.get.side_effect = exceptions.NotFound(None)
+ self.project_mock.find.side_effect = exceptions.NotFound(None)
+
+ arglist = [
+ '--container-format', 'ovf',
+ '--disk-format', 'fs',
+ '--min-disk', '10',
+ '--min-ram', '4',
+ '--owner', 'unexist_owner',
+ '--protected',
+ '--private',
+ image_fakes.image_name,
+ ]
+ verifylist = [
+ ('container_format', 'ovf'),
+ ('disk_format', 'fs'),
+ ('min_disk', 10),
+ ('min_ram', 4),
+ ('owner', 'unexist_owner'),
+ ('protected', True),
+ ('unprotected', False),
+ ('public', False),
+ ('private', True),
+ ('name', image_fakes.image_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(
+ exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args,
+ )
+
+ def test_image_create_with_unexist_project(self):
+ self.project_mock.get.side_effect = exceptions.NotFound(None)
+ self.project_mock.find.side_effect = exceptions.NotFound(None)
+
+ arglist = [
+ '--container-format', 'ovf',
+ '--disk-format', 'fs',
+ '--min-disk', '10',
+ '--min-ram', '4',
+ '--protected',
+ '--private',
+ '--project', 'unexist_owner',
+ image_fakes.image_name,
+ ]
+ verifylist = [
+ ('container_format', 'ovf'),
+ ('disk_format', 'fs'),
+ ('min_disk', 10),
+ ('min_ram', 4),
+ ('protected', True),
+ ('unprotected', False),
+ ('public', False),
+ ('private', True),
+ ('project', 'unexist_owner'),
+ ('name', image_fakes.image_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(
+ exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args,
+ )
+
+ @mock.patch('glanceclient.common.utils.get_data_file', name='Open')
+ def test_image_create_file(self, mock_open):
+ mock_file = mock.MagicMock(name='File')
+ mock_open.return_value = mock_file
+ mock_open.read.return_value = (
+ image_fakes.FakeImage.get_image_data(self.new_image))
+ mock_exception = {
+ 'find.side_effect': exceptions.CommandError('x'),
+ }
+ self.images_mock.configure_mock(**mock_exception)
+
+ arglist = [
+ '--file', 'filer',
+ ('--unprotected'
+ if not self.new_image.protected else '--protected'),
+ ('--public'
+ if self.new_image.visibility == 'public' else '--private'),
+ '--property', 'Alpha=1',
+ '--property', 'Beta=2',
+ '--tag', self.new_image.tags[0],
+ '--tag', self.new_image.tags[1],
+ self.new_image.name,
+ ]
+ verifylist = [
+ ('file', 'filer'),
+ ('protected', self.new_image.protected),
+ ('unprotected', not self.new_image.protected),
+ ('public', self.new_image.visibility == 'public'),
+ ('private', self.new_image.visibility == 'private'),
+ ('properties', {'Alpha': '1', 'Beta': '2'}),
+ ('tags', self.new_image.tags),
+ ('name', self.new_image.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # ImageManager.create(name=, **)
+ self.images_mock.create.assert_called_with(
+ name=self.new_image.name,
+ container_format=image.DEFAULT_CONTAINER_FORMAT,
+ disk_format=image.DEFAULT_DISK_FORMAT,
+ protected=self.new_image.protected,
+ visibility=self.new_image.visibility,
+ Alpha='1',
+ Beta='2',
+ tags=self.new_image.tags,
+ )
+
+ # Verify update() was not called, if it was show the args
+ self.assertEqual(self.images_mock.update.call_args_list, [])
+
+ self.images_mock.upload.assert_called_with(
+ mock.ANY, mock.ANY,
+ )
+
+ self.assertEqual(
+ image_fakes.FakeImage.get_image_columns(self.new_image),
+ columns)
+ self.assertEqual(
+ image_fakes.FakeImage.get_image_data(self.new_image),
+ data)
+
+ def test_image_create_dead_options(self):
+
+ arglist = [
+ '--store', 'somewhere',
+ self.new_image.name,
+ ]
+ verifylist = [
+ ('name', self.new_image.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(
+ exceptions.CommandError,
+ self.cmd.take_action, parsed_args)
+
+
+class TestAddProjectToImage(TestImage):
+
+ project = identity_fakes.FakeProject.create_one_project()
+ domain = identity_fakes.FakeDomain.create_one_domain()
+ _image = image_fakes.FakeImage.create_one_image()
+ new_member = image_fakes.FakeImage.create_one_image_member(
+ attrs={'image_id': _image.id,
+ 'member_id': project.id}
+ )
+
+ columns = (
+ 'image_id',
+ 'member_id',
+ 'status',
+ )
+
+ datalist = (
+ _image.id,
+ new_member.member_id,
+ new_member.status,
+ )
+
+ def setUp(self):
+ super(TestAddProjectToImage, self).setUp()
+
+ # This is the return value for utils.find_resource()
+ self.images_mock.get.return_value = self._image
+
+ # Update the image_id in the MEMBER dict
+ self.image_members_mock.create.return_value = self.new_member
+ self.project_mock.get.return_value = self.project
+ self.domain_mock.get.return_value = self.domain
+ # Get the command object to test
+ self.cmd = image.AddProjectToImage(self.app, None)
+
+ def test_add_project_to_image_no_option(self):
+ arglist = [
+ self._image.id,
+ self.project.id,
+ ]
+ verifylist = [
+ ('image', self._image.id),
+ ('project', self.project.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.image_members_mock.create.assert_called_with(
+ self._image.id,
+ self.project.id
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_add_project_to_image_with_option(self):
+ arglist = [
+ self._image.id,
+ self.project.id,
+ '--project-domain', self.domain.id,
+ ]
+ verifylist = [
+ ('image', self._image.id),
+ ('project', self.project.id),
+ ('project_domain', self.domain.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.image_members_mock.create.assert_called_with(
+ self._image.id,
+ self.project.id
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+
+class TestImageDelete(TestImage):
+
+ def setUp(self):
+ super(TestImageDelete, self).setUp()
+
+ self.images_mock.delete.return_value = None
+
+ # Get the command object to test
+ self.cmd = image.DeleteImage(self.app, None)
+
+ def test_image_delete_no_options(self):
+ images = self.setup_images_mock(count=1)
+
+ arglist = [
+ images[0].id,
+ ]
+ verifylist = [
+ ('images', [images[0].id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.images_mock.delete.assert_called_with(images[0].id)
+ self.assertIsNone(result)
+
+ def test_image_delete_multi_images(self):
+ images = self.setup_images_mock(count=3)
+
+ arglist = [i.id for i in images]
+ verifylist = [
+ ('images', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ calls = [mock.call(i.id) for i in images]
+ self.images_mock.delete.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_image_delete_multi_images_exception(self):
+
+ images = image_fakes.FakeImage.create_images(count=2)
+ arglist = [
+ images[0].id,
+ images[1].id,
+ 'x-y-x',
+ ]
+ verifylist = [
+ ('images', arglist)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # Fake exception in utils.find_resource()
+ # In image v2, we use utils.find_resource() to find a network.
+ # It calls get() several times, but find() only one time. So we
+ # choose to fake get() always raise exception, then pass through.
+ # And fake find() to find the real network or not.
+ ret_find = [
+ images[0],
+ images[1],
+ exceptions.NotFound('404'),
+ ]
+
+ self.images_mock.get = Exception()
+ self.images_mock.find.side_effect = ret_find
+ self.assertRaises(exceptions.CommandError, self.cmd.take_action,
+ parsed_args)
+ calls = [mock.call(i.id) for i in images]
+ self.images_mock.delete.assert_has_calls(calls)
+
+
+class TestImageList(TestImage):
+
+ _image = image_fakes.FakeImage.create_one_image()
+
+ columns = (
+ 'ID',
+ 'Name',
+ 'Status',
+ )
+
+ datalist = (
+ _image.id,
+ _image.name,
+ '',
+ ),
+
+ def setUp(self):
+ super(TestImageList, self).setUp()
+
+ self.api_mock = mock.Mock()
+ self.api_mock.image_list.side_effect = [
+ [self._image], [],
+ ]
+ self.app.client_manager.image.api = self.api_mock
+
+ # Get the command object to test
+ self.cmd = image.ListImage(self.app, None)
+
+ def test_image_list_no_options(self):
+ arglist = []
+ verifylist = [
+ ('public', False),
+ ('private', False),
+ ('shared', False),
+ ('long', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.api_mock.image_list.assert_called_with()
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_image_list_public_option(self):
+ arglist = [
+ '--public',
+ ]
+ verifylist = [
+ ('public', True),
+ ('private', False),
+ ('shared', False),
+ ('long', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.api_mock.image_list.assert_called_with(
+ public=True,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_image_list_private_option(self):
+ arglist = [
+ '--private',
+ ]
+ verifylist = [
+ ('public', False),
+ ('private', True),
+ ('shared', False),
+ ('long', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.api_mock.image_list.assert_called_with(
+ private=True,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_image_list_shared_option(self):
+ arglist = [
+ '--shared',
+ ]
+ verifylist = [
+ ('public', False),
+ ('private', False),
+ ('shared', True),
+ ('long', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.api_mock.image_list.assert_called_with(
+ shared=True,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_image_list_long_option(self):
+ arglist = [
+ '--long',
+ ]
+ verifylist = [
+ ('long', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.api_mock.image_list.assert_called_with()
+
+ collist = (
+ 'ID',
+ 'Name',
+ 'Disk Format',
+ 'Container Format',
+ 'Size',
+ 'Checksum',
+ 'Status',
+ 'Visibility',
+ 'Protected',
+ 'Project',
+ 'Tags',
+ )
+
+ self.assertEqual(collist, columns)
+ datalist = ((
+ self._image.id,
+ self._image.name,
+ '',
+ '',
+ '',
+ '',
+ '',
+ self._image.visibility,
+ self._image.protected,
+ self._image.owner,
+ common_utils.format_list(self._image.tags),
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+ @mock.patch('openstackclient.api.utils.simple_filter')
+ def test_image_list_property_option(self, sf_mock):
+ sf_mock.return_value = [copy.deepcopy(self._image)]
+
+ arglist = [
+ '--property', 'a=1',
+ ]
+ verifylist = [
+ ('property', {'a': '1'}),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.api_mock.image_list.assert_called_with()
+ sf_mock.assert_called_with(
+ [self._image],
+ attr='a',
+ value='1',
+ property_field='properties',
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ @mock.patch('osc_lib.utils.sort_items')
+ def test_image_list_sort_option(self, si_mock):
+ si_mock.return_value = [copy.deepcopy(self._image)]
+
+ arglist = ['--sort', 'name:asc']
+ verifylist = [('sort', 'name:asc')]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.api_mock.image_list.assert_called_with()
+ si_mock.assert_called_with(
+ [self._image],
+ 'name:asc'
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_image_list_limit_option(self):
+ arglist = [
+ '--limit', str(1),
+ ]
+ verifylist = [
+ ('limit', 1),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.api_mock.image_list.assert_called_with(
+ limit=1,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(len(self.datalist), len(tuple(data)))
+
+ @mock.patch('osc_lib.utils.find_resource')
+ def test_image_list_marker_option(self, fr_mock):
+ # tangchen: Since image_fakes.IMAGE is a dict, it cannot offer a .id
+ # operation. Will fix this by using FakeImage class instead
+ # of IMAGE dict.
+ fr_mock.return_value = mock.Mock()
+ fr_mock.return_value.id = image_fakes.image_id
+
+ arglist = [
+ '--marker', image_fakes.image_name,
+ ]
+ verifylist = [
+ ('marker', image_fakes.image_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.api_mock.image_list.assert_called_with(
+ marker=image_fakes.image_id,
+ )
+
+
+class TestRemoveProjectImage(TestImage):
+
+ project = identity_fakes.FakeProject.create_one_project()
+ domain = identity_fakes.FakeDomain.create_one_domain()
+
+ def setUp(self):
+ super(TestRemoveProjectImage, self).setUp()
+
+ self._image = image_fakes.FakeImage.create_one_image()
+ # This is the return value for utils.find_resource()
+ self.images_mock.get.return_value = self._image
+
+ self.project_mock.get.return_value = self.project
+ self.domain_mock.get.return_value = self.domain
+ self.image_members_mock.delete.return_value = None
+ # Get the command object to test
+ self.cmd = image.RemoveProjectImage(self.app, None)
+
+ def test_remove_project_image_no_options(self):
+ arglist = [
+ self._image.id,
+ self.project.id,
+ ]
+ verifylist = [
+ ('image', self._image.id),
+ ('project', self.project.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.image_members_mock.delete.assert_called_with(
+ self._image.id,
+ self.project.id,
+ )
+ self.assertIsNone(result)
+
+ def test_remove_project_image_with_options(self):
+ arglist = [
+ self._image.id,
+ self.project.id,
+ '--project-domain', self.domain.id,
+ ]
+ verifylist = [
+ ('image', self._image.id),
+ ('project', self.project.id),
+ ('project_domain', self.domain.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.image_members_mock.delete.assert_called_with(
+ self._image.id,
+ self.project.id,
+ )
+ self.assertIsNone(result)
+
+
+class TestImageSet(TestImage):
+
+ project = identity_fakes.FakeProject.create_one_project()
+ domain = identity_fakes.FakeDomain.create_one_domain()
+
+ def setUp(self):
+ super(TestImageSet, self).setUp()
+ # Set up the schema
+ self.model = warlock.model_factory(
+ image_fakes.IMAGE_schema,
+ schemas.SchemaBasedModel,
+ )
+
+ self.project_mock.get.return_value = self.project
+
+ self.domain_mock.get.return_value = self.domain
+
+ self.images_mock.get.return_value = self.model(**image_fakes.IMAGE)
+ self.images_mock.update.return_value = self.model(**image_fakes.IMAGE)
+ # Get the command object to test
+ self.cmd = image.SetImage(self.app, None)
+
+ def test_image_set_no_options(self):
+ arglist = [
+ image_fakes.image_id,
+ ]
+ verifylist = [
+ ('image', image_fakes.image_id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.assertIsNone(result)
+
+ def test_image_set_options(self):
+ arglist = [
+ '--name', 'new-name',
+ '--min-disk', '2',
+ '--min-ram', '4',
+ '--container-format', 'ovf',
+ '--disk-format', 'vmdk',
+ '--project', self.project.name,
+ '--project-domain', self.domain.id,
+ image_fakes.image_id,
+ ]
+ verifylist = [
+ ('name', 'new-name'),
+ ('min_disk', 2),
+ ('min_ram', 4),
+ ('container_format', 'ovf'),
+ ('disk_format', 'vmdk'),
+ ('project', self.project.name),
+ ('project_domain', self.domain.id),
+ ('image', image_fakes.image_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ kwargs = {
+ 'name': 'new-name',
+ 'owner': self.project.id,
+ 'min_disk': 2,
+ 'min_ram': 4,
+ 'container_format': 'ovf',
+ 'disk_format': 'vmdk',
+ }
+ # ImageManager.update(image, **kwargs)
+ self.images_mock.update.assert_called_with(
+ image_fakes.image_id, **kwargs)
+ self.assertIsNone(result)
+
+ def test_image_set_with_unexist_owner(self):
+ self.project_mock.get.side_effect = exceptions.NotFound(None)
+ self.project_mock.find.side_effect = exceptions.NotFound(None)
+
+ arglist = [
+ '--owner', 'unexist_owner',
+ image_fakes.image_id,
+ ]
+ verifylist = [
+ ('owner', 'unexist_owner'),
+ ('image', image_fakes.image_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(
+ exceptions.CommandError,
+ self.cmd.take_action, parsed_args)
+
+ def test_image_set_with_unexist_project(self):
+ self.project_mock.get.side_effect = exceptions.NotFound(None)
+ self.project_mock.find.side_effect = exceptions.NotFound(None)
+
+ arglist = [
+ '--project', 'unexist_owner',
+ image_fakes.image_id,
+ ]
+ verifylist = [
+ ('project', 'unexist_owner'),
+ ('image', image_fakes.image_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(
+ exceptions.CommandError,
+ self.cmd.take_action, parsed_args)
+
+ def test_image_set_bools1(self):
+ arglist = [
+ '--protected',
+ '--private',
+ image_fakes.image_name,
+ ]
+ verifylist = [
+ ('protected', True),
+ ('unprotected', False),
+ ('public', False),
+ ('private', True),
+ ('image', image_fakes.image_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ kwargs = {
+ 'protected': True,
+ 'visibility': 'private',
+ }
+ # ImageManager.update(image, **kwargs)
+ self.images_mock.update.assert_called_with(
+ image_fakes.image_id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_image_set_bools2(self):
+ arglist = [
+ '--unprotected',
+ '--public',
+ image_fakes.image_name,
+ ]
+ verifylist = [
+ ('protected', False),
+ ('unprotected', True),
+ ('public', True),
+ ('private', False),
+ ('image', image_fakes.image_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ kwargs = {
+ 'protected': False,
+ 'visibility': 'public',
+ }
+ # ImageManager.update(image, **kwargs)
+ self.images_mock.update.assert_called_with(
+ image_fakes.image_id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_image_set_properties(self):
+ arglist = [
+ '--property', 'Alpha=1',
+ '--property', 'Beta=2',
+ image_fakes.image_name,
+ ]
+ verifylist = [
+ ('properties', {'Alpha': '1', 'Beta': '2'}),
+ ('image', image_fakes.image_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ kwargs = {
+ 'Alpha': '1',
+ 'Beta': '2',
+ }
+ # ImageManager.update(image, **kwargs)
+ self.images_mock.update.assert_called_with(
+ image_fakes.image_id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_image_set_fake_properties(self):
+ arglist = [
+ '--architecture', 'z80',
+ '--instance-id', '12345',
+ '--kernel-id', '67890',
+ '--os-distro', 'cpm',
+ '--os-version', '2.2H',
+ '--ramdisk-id', 'xyzpdq',
+ image_fakes.image_name,
+ ]
+ verifylist = [
+ ('architecture', 'z80'),
+ ('instance_id', '12345'),
+ ('kernel_id', '67890'),
+ ('os_distro', 'cpm'),
+ ('os_version', '2.2H'),
+ ('ramdisk_id', 'xyzpdq'),
+ ('image', image_fakes.image_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ kwargs = {
+ 'architecture': 'z80',
+ 'instance_id': '12345',
+ 'kernel_id': '67890',
+ 'os_distro': 'cpm',
+ 'os_version': '2.2H',
+ 'ramdisk_id': 'xyzpdq',
+ }
+ # ImageManager.update(image, **kwargs)
+ self.images_mock.update.assert_called_with(
+ image_fakes.image_id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_image_set_tag(self):
+ arglist = [
+ '--tag', 'test-tag',
+ image_fakes.image_name,
+ ]
+ verifylist = [
+ ('tags', ['test-tag']),
+ ('image', image_fakes.image_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ kwargs = {
+ 'tags': ['test-tag'],
+ }
+ # ImageManager.update(image, **kwargs)
+ self.images_mock.update.assert_called_with(
+ image_fakes.image_id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_image_set_activate(self):
+ arglist = [
+ '--tag', 'test-tag',
+ '--activate',
+ image_fakes.image_name,
+ ]
+ verifylist = [
+ ('tags', ['test-tag']),
+ ('image', image_fakes.image_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ kwargs = {
+ 'tags': ['test-tag'],
+ }
+
+ self.images_mock.reactivate.assert_called_with(
+ image_fakes.image_id,
+ )
+ # ImageManager.update(image, **kwargs)
+ self.images_mock.update.assert_called_with(
+ image_fakes.image_id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_image_set_deactivate(self):
+ arglist = [
+ '--tag', 'test-tag',
+ '--deactivate',
+ image_fakes.image_name,
+ ]
+ verifylist = [
+ ('tags', ['test-tag']),
+ ('image', image_fakes.image_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ kwargs = {
+ 'tags': ['test-tag'],
+ }
+
+ self.images_mock.deactivate.assert_called_with(
+ image_fakes.image_id,
+ )
+ # ImageManager.update(image, **kwargs)
+ self.images_mock.update.assert_called_with(
+ image_fakes.image_id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_image_set_tag_merge(self):
+ old_image = copy.copy(image_fakes.IMAGE)
+ old_image['tags'] = ['old1', 'new2']
+ self.images_mock.get.return_value = self.model(**old_image)
+ arglist = [
+ '--tag', 'test-tag',
+ image_fakes.image_name,
+ ]
+ verifylist = [
+ ('tags', ['test-tag']),
+ ('image', image_fakes.image_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ kwargs = {
+ 'tags': ['old1', 'new2', 'test-tag'],
+ }
+ # ImageManager.update(image, **kwargs)
+ a, k = self.images_mock.update.call_args
+ self.assertEqual(image_fakes.image_id, a[0])
+ self.assertIn('tags', k)
+ self.assertEqual(set(kwargs['tags']), set(k['tags']))
+ self.assertIsNone(result)
+
+ def test_image_set_tag_merge_dupe(self):
+ old_image = copy.copy(image_fakes.IMAGE)
+ old_image['tags'] = ['old1', 'new2']
+ self.images_mock.get.return_value = self.model(**old_image)
+ arglist = [
+ '--tag', 'old1',
+ image_fakes.image_name,
+ ]
+ verifylist = [
+ ('tags', ['old1']),
+ ('image', image_fakes.image_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ kwargs = {
+ 'tags': ['new2', 'old1'],
+ }
+ # ImageManager.update(image, **kwargs)
+ a, k = self.images_mock.update.call_args
+ self.assertEqual(image_fakes.image_id, a[0])
+ self.assertIn('tags', k)
+ self.assertEqual(set(kwargs['tags']), set(k['tags']))
+ self.assertIsNone(result)
+
+ def test_image_set_dead_options(self):
+
+ arglist = [
+ '--visibility', '1-mile',
+ image_fakes.image_name,
+ ]
+ verifylist = [
+ ('visibility', '1-mile'),
+ ('image', image_fakes.image_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(
+ exceptions.CommandError,
+ self.cmd.take_action, parsed_args)
+
+
+class TestImageShow(TestImage):
+
+ def setUp(self):
+ super(TestImageShow, self).setUp()
+
+ # Set up the schema
+ self.model = warlock.model_factory(
+ image_fakes.IMAGE_schema,
+ schemas.SchemaBasedModel,
+ )
+
+ self.images_mock.get.return_value = self.model(**image_fakes.IMAGE)
+
+ # Get the command object to test
+ self.cmd = image.ShowImage(self.app, None)
+
+ def test_image_show(self):
+ arglist = [
+ image_fakes.image_id,
+ ]
+ verifylist = [
+ ('image', image_fakes.image_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+ self.images_mock.get.assert_called_with(
+ image_fakes.image_id,
+ )
+
+ self.assertEqual(image_fakes.IMAGE_columns, columns)
+ self.assertEqual(image_fakes.IMAGE_SHOW_data, data)
+
+
+class TestImageUnset(TestImage):
+
+ attrs = {}
+ attrs['tags'] = ['test']
+ attrs['prop'] = 'test'
+ image = image_fakes.FakeImage.create_one_image(attrs)
+
+ def setUp(self):
+ super(TestImageUnset, self).setUp()
+
+ # Set up the schema
+ self.model = warlock.model_factory(
+ image_fakes.IMAGE_schema,
+ schemas.SchemaBasedModel,
+ )
+
+ self.images_mock.get.return_value = self.image
+ self.image_tags_mock.delete.return_value = self.image
+
+ # Get the command object to test
+ self.cmd = image.UnsetImage(self.app, None)
+
+ def test_image_unset_no_options(self):
+ arglist = [
+ image_fakes.image_id,
+ ]
+ verifylist = [
+ ('image', image_fakes.image_id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.assertIsNone(result)
+
+ def test_image_unset_tag_option(self):
+
+ arglist = [
+ '--tag', 'test',
+ self.image.id,
+ ]
+
+ verifylist = [
+ ('tags', ['test']),
+ ('image', self.image.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ self.image_tags_mock.delete.assert_called_with(
+ self.image.id, 'test'
+ )
+ self.assertIsNone(result)
+
+ def test_image_unset_property_option(self):
+
+ arglist = [
+ '--property', 'prop',
+ self.image.id,
+ ]
+
+ verifylist = [
+ ('properties', ['prop']),
+ ('image', self.image.id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ kwargs = {}
+ self.images_mock.update.assert_called_with(
+ self.image.id,
+ parsed_args.properties,
+ **kwargs)
+
+ self.assertIsNone(result)
+
+ def test_image_unset_mixed_option(self):
+
+ arglist = [
+ '--tag', 'test',
+ '--property', 'prop',
+ self.image.id,
+ ]
+
+ verifylist = [
+ ('tags', ['test']),
+ ('properties', ['prop']),
+ ('image', self.image.id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ kwargs = {}
+ self.images_mock.update.assert_called_with(
+ self.image.id,
+ parsed_args.properties,
+ **kwargs)
+
+ self.image_tags_mock.delete.assert_called_with(
+ self.image.id, 'test'
+ )
+ self.assertIsNone(result)
diff --git a/openstackclient/tests/unit/integ/__init__.py b/openstackclient/tests/unit/integ/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/unit/integ/__init__.py
diff --git a/openstackclient/tests/unit/integ/base.py b/openstackclient/tests/unit/integ/base.py
new file mode 100644
index 00000000..caed4f89
--- /dev/null
+++ b/openstackclient/tests/unit/integ/base.py
@@ -0,0 +1,121 @@
+# 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 keystoneauth1 import fixture as ksa_fixture
+from requests_mock.contrib import fixture
+
+from openstackclient.tests.unit import test_shell
+from openstackclient.tests.unit import utils
+
+
+HOST = "192.168.5.41"
+URL_BASE = "http://%s/identity" % HOST
+
+V2_AUTH_URL = URL_BASE + "/v2.0/"
+V2_VERSION_RESP = {
+ "version": {
+ "status": "stable",
+ "updated": "2014-04-17T00:00:00Z",
+ "media-types": [
+ {
+ "base": "application/json",
+ "type": "application/vnd.openstack.identity-v2.0+json",
+ },
+ ],
+ "id": "v2.0",
+ "links": [
+ {
+ "href": V2_AUTH_URL,
+ "rel": "self",
+ },
+ {
+ "href": "http://docs.openstack.org/",
+ "type": "text/html",
+ "rel": "describedby",
+ },
+ ],
+ },
+}
+
+V3_AUTH_URL = URL_BASE + "/v3/"
+V3_VERSION_RESP = {
+ "version": {
+ "status": "stable",
+ "updated": "2016-04-04T00:00:00Z",
+ "media-types": [{
+ "base": "application/json",
+ "type": "application/vnd.openstack.identity-v3+json",
+ }],
+ "id": "v3.6",
+ "links": [{
+ "href": V3_AUTH_URL,
+ "rel": "self",
+ }]
+ }
+}
+
+
+def make_v2_token(req_mock):
+ """Create an Identity v2 token and register the responses"""
+
+ token = ksa_fixture.V2Token(
+ tenant_name=test_shell.DEFAULT_PROJECT_NAME,
+ user_name=test_shell.DEFAULT_USERNAME,
+ )
+
+ # Set up the v2 auth routes
+ req_mock.register_uri(
+ 'GET',
+ V2_AUTH_URL,
+ json=V2_VERSION_RESP,
+ status_code=200,
+ )
+ req_mock.register_uri(
+ 'POST',
+ V2_AUTH_URL + 'tokens',
+ json=token,
+ status_code=200,
+ )
+ return token
+
+
+def make_v3_token(req_mock):
+ """Create an Identity v3 token and register the response"""
+
+ token = ksa_fixture.V3Token(
+ # project_domain_id=test_shell.DEFAULT_PROJECT_DOMAIN_ID,
+ user_domain_id=test_shell.DEFAULT_USER_DOMAIN_ID,
+ user_name=test_shell.DEFAULT_USERNAME,
+ )
+
+ # Set up the v3 auth routes
+ req_mock.register_uri(
+ 'GET',
+ V3_AUTH_URL,
+ json=V3_VERSION_RESP,
+ status_code=200,
+ )
+ req_mock.register_uri(
+ 'POST',
+ V3_AUTH_URL + 'auth/tokens',
+ json=token,
+ status_code=200,
+ )
+ return token
+
+
+class TestInteg(utils.TestCase):
+
+ def setUp(self):
+ super(TestInteg, self).setUp()
+
+ self.requests_mock = self.useFixture(fixture.Fixture())
diff --git a/openstackclient/tests/unit/integ/cli/__init__.py b/openstackclient/tests/unit/integ/cli/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/unit/integ/cli/__init__.py
diff --git a/openstackclient/tests/unit/integ/cli/test_project.py b/openstackclient/tests/unit/integ/cli/test_project.py
new file mode 100644
index 00000000..6a7c6d1b
--- /dev/null
+++ b/openstackclient/tests/unit/integ/cli/test_project.py
@@ -0,0 +1,257 @@
+# 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.
+
+import copy
+
+from osc_lib.tests import utils as osc_lib_utils
+
+from openstackclient import shell
+from openstackclient.tests.unit.integ import base as test_base
+from openstackclient.tests.unit import test_shell
+
+
+class TestIntegV2ProjectID(test_base.TestInteg):
+
+ def setUp(self):
+ super(TestIntegV2ProjectID, self).setUp()
+ env = {
+ "OS_AUTH_URL": test_base.V2_AUTH_URL,
+ "OS_PROJECT_ID": test_shell.DEFAULT_PROJECT_ID,
+ "OS_USERNAME": test_shell.DEFAULT_USERNAME,
+ "OS_PASSWORD": test_shell.DEFAULT_PASSWORD,
+ "OS_IDENTITY_API_VERSION": "2",
+ }
+ self.useFixture(osc_lib_utils.EnvFixture(copy.deepcopy(env)))
+
+ self.token = test_base.make_v2_token(self.requests_mock)
+
+ def test_project_id_env(self):
+ _shell = shell.OpenStackShell()
+ _shell.run("configuration show".split())
+
+ # Check general calls
+ self.assertEqual(len(self.requests_mock.request_history), 2)
+
+ # Check discovery request
+ self.assertEqual(
+ test_base.V2_AUTH_URL,
+ self.requests_mock.request_history[0].url,
+ )
+
+ # Check auth request
+ auth_req = self.requests_mock.request_history[1].json()
+
+ self.assertEqual(
+ test_shell.DEFAULT_PROJECT_ID,
+ auth_req['auth']['tenantId'],
+ )
+
+ def test_project_id_arg(self):
+ _shell = shell.OpenStackShell()
+ _shell.run("--os-project-id wsx configuration show".split())
+
+ # Check general calls
+ self.assertEqual(len(self.requests_mock.request_history), 2)
+
+ # Check discovery request
+ self.assertEqual(
+ test_base.V2_AUTH_URL,
+ self.requests_mock.request_history[0].url,
+ )
+
+ # Check auth request
+ auth_req = self.requests_mock.request_history[1].json()
+
+ self.assertEqual(
+ "wsx",
+ auth_req['auth']['tenantId'],
+ )
+
+
+class TestIntegV2ProjectName(test_base.TestInteg):
+
+ def setUp(self):
+ super(TestIntegV2ProjectName, self).setUp()
+ env = {
+ "OS_AUTH_URL": test_base.V2_AUTH_URL,
+ "OS_PROJECT_NAME": test_shell.DEFAULT_PROJECT_NAME,
+ "OS_USERNAME": test_shell.DEFAULT_USERNAME,
+ "OS_PASSWORD": test_shell.DEFAULT_PASSWORD,
+ "OS_IDENTITY_API_VERSION": "2",
+ }
+ self.useFixture(osc_lib_utils.EnvFixture(copy.deepcopy(env)))
+
+ self.token = test_base.make_v2_token(self.requests_mock)
+
+ def test_project_name_env(self):
+ _shell = shell.OpenStackShell()
+ _shell.run("configuration show".split())
+
+ # Check general calls
+ self.assertEqual(len(self.requests_mock.request_history), 2)
+
+ # Check discovery request
+ self.assertEqual(
+ test_base.V2_AUTH_URL,
+ self.requests_mock.request_history[0].url,
+ )
+
+ # Check auth request
+ auth_req = self.requests_mock.request_history[1].json()
+
+ self.assertEqual(
+ test_shell.DEFAULT_PROJECT_NAME,
+ auth_req['auth']['tenantName'],
+ )
+
+ def test_project_name_arg(self):
+ _shell = shell.OpenStackShell()
+ _shell.run("--os-project-name qaz configuration show".split())
+
+ # Check general calls
+ self.assertEqual(len(self.requests_mock.request_history), 2)
+
+ # Check discovery request
+ self.assertEqual(
+ test_base.V2_AUTH_URL,
+ self.requests_mock.request_history[0].url,
+ )
+
+ # Check auth request
+ auth_req = self.requests_mock.request_history[1].json()
+
+ self.assertEqual(
+ "qaz",
+ auth_req['auth']['tenantName'],
+ )
+
+
+class TestIntegV3ProjectID(test_base.TestInteg):
+
+ def setUp(self):
+ super(TestIntegV3ProjectID, self).setUp()
+ env = {
+ "OS_AUTH_URL": test_base.V3_AUTH_URL,
+ "OS_PROJECT_ID": test_shell.DEFAULT_PROJECT_NAME,
+ # "OS_PROJECT_DOMAIN_ID": test_shell.DEFAULT_PROJECT_DOMAIN_ID,
+ # "OS_USER_DOMAIN_ID": test_shell.DEFAULT_USER_DOMAIN_ID,
+ "OS_USERNAME": test_shell.DEFAULT_USERNAME,
+ "OS_PASSWORD": test_shell.DEFAULT_PASSWORD,
+ "OS_IDENTITY_API_VERSION": "3",
+ }
+ self.useFixture(osc_lib_utils.EnvFixture(copy.deepcopy(env)))
+
+ self.token = test_base.make_v3_token(self.requests_mock)
+
+ def test_project_id_env(self):
+ _shell = shell.OpenStackShell()
+ _shell.run("configuration show".split())
+
+ # Check general calls
+ self.assertEqual(len(self.requests_mock.request_history), 2)
+
+ # Check discovery request
+ self.assertEqual(
+ test_base.V3_AUTH_URL,
+ self.requests_mock.request_history[0].url,
+ )
+
+ # Check auth request
+ auth_req = self.requests_mock.request_history[1].json()
+
+ self.assertIsNone(auth_req['auth'].get('tenantId', None))
+ self.assertIsNone(auth_req['auth'].get('tenantName', None))
+
+ def test_project_id_arg(self):
+ _shell = shell.OpenStackShell()
+ _shell.run("--os-project-id wsx configuration show".split())
+
+ # Check general calls
+ self.assertEqual(len(self.requests_mock.request_history), 2)
+
+ # Check discovery request
+ self.assertEqual(
+ test_base.V3_AUTH_URL,
+ self.requests_mock.request_history[0].url,
+ )
+
+ # Check auth request
+ auth_req = self.requests_mock.request_history[1].json()
+
+ self.assertIsNone(auth_req['auth'].get('tenantId', None))
+ self.assertIsNone(auth_req['auth'].get('tenantName', None))
+
+
+class TestIntegV3ProjectName(test_base.TestInteg):
+
+ def setUp(self):
+ super(TestIntegV3ProjectName, self).setUp()
+ env = {
+ "OS_AUTH_URL": test_base.V3_AUTH_URL,
+ "OS_PROJECT_NAME": test_shell.DEFAULT_PROJECT_NAME,
+ # "OS_PROJECT_DOMAIN_ID": test_shell.DEFAULT_PROJECT_DOMAIN_ID,
+ # "OS_USER_DOMAIN_ID": test_shell.DEFAULT_USER_DOMAIN_ID,
+ "OS_USERNAME": test_shell.DEFAULT_USERNAME,
+ "OS_PASSWORD": test_shell.DEFAULT_PASSWORD,
+ "OS_IDENTITY_API_VERSION": "3",
+ }
+ self.useFixture(osc_lib_utils.EnvFixture(copy.deepcopy(env)))
+
+ self.token = test_base.make_v3_token(self.requests_mock)
+
+ def test_project_name_env(self):
+ _shell = shell.OpenStackShell()
+ _shell.run("configuration show".split())
+
+ # Check general calls
+ self.assertEqual(len(self.requests_mock.request_history), 2)
+
+ # Check discovery request
+ self.assertEqual(
+ test_base.V3_AUTH_URL,
+ self.requests_mock.request_history[0].url,
+ )
+
+ # Check auth request
+ auth_req = self.requests_mock.request_history[1].json()
+
+ self.assertEqual(
+ test_shell.DEFAULT_PROJECT_NAME,
+ auth_req['auth']['scope']['project']['name'],
+ )
+
+ self.assertIsNone(auth_req['auth'].get('tenantId', None))
+ self.assertIsNone(auth_req['auth'].get('tenantName', None))
+
+ def test_project_name_arg(self):
+ _shell = shell.OpenStackShell()
+ _shell.run("--os-project-name wsx configuration show".split())
+
+ # Check general calls
+ self.assertEqual(len(self.requests_mock.request_history), 2)
+
+ # Check discovery request
+ self.assertEqual(
+ test_base.V3_AUTH_URL,
+ self.requests_mock.request_history[0].url,
+ )
+
+ # Check auth request
+ auth_req = self.requests_mock.request_history[1].json()
+
+ self.assertEqual(
+ "wsx",
+ auth_req['auth']['scope']['project']['name'],
+ )
+
+ self.assertIsNone(auth_req['auth'].get('tenantId', None))
+ self.assertIsNone(auth_req['auth'].get('tenantName', None))
diff --git a/openstackclient/tests/unit/integ/cli/test_shell.py b/openstackclient/tests/unit/integ/cli/test_shell.py
new file mode 100644
index 00000000..9d819ed2
--- /dev/null
+++ b/openstackclient/tests/unit/integ/cli/test_shell.py
@@ -0,0 +1,506 @@
+# 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.
+
+import copy
+import mock
+
+from osc_lib.tests import utils as osc_lib_utils
+
+from openstackclient import shell
+from openstackclient.tests.unit.integ import base as test_base
+from openstackclient.tests.unit import test_shell
+
+
+class TestIntegShellCliV2(test_base.TestInteg):
+
+ def setUp(self):
+ super(TestIntegShellCliV2, self).setUp()
+ env = {
+ "OS_AUTH_URL": test_base.V2_AUTH_URL,
+ "OS_PROJECT_NAME": test_shell.DEFAULT_PROJECT_NAME,
+ "OS_USERNAME": test_shell.DEFAULT_USERNAME,
+ "OS_PASSWORD": test_shell.DEFAULT_PASSWORD,
+ "OS_IDENTITY_API_VERSION": "2",
+ }
+ self.useFixture(osc_lib_utils.EnvFixture(copy.deepcopy(env)))
+
+ self.token = test_base.make_v2_token(self.requests_mock)
+
+ def test_shell_args_no_options(self):
+ _shell = shell.OpenStackShell()
+ _shell.run("configuration show".split())
+
+ # Check general calls
+ self.assertEqual(len(self.requests_mock.request_history), 2)
+
+ # Check discovery request
+ self.assertEqual(
+ test_base.V2_AUTH_URL,
+ self.requests_mock.request_history[0].url,
+ )
+
+ # Check auth request
+ auth_req = self.requests_mock.request_history[1].json()
+
+ self.assertEqual(
+ test_shell.DEFAULT_PROJECT_NAME,
+ auth_req['auth']['tenantName'],
+ )
+ self.assertEqual(
+ test_shell.DEFAULT_USERNAME,
+ auth_req['auth']['passwordCredentials']['username'],
+ )
+ self.assertEqual(
+ test_shell.DEFAULT_PASSWORD,
+ auth_req['auth']['passwordCredentials']['password'],
+ )
+
+ def test_shell_args_verify(self):
+ _shell = shell.OpenStackShell()
+ _shell.run("--verify configuration show".split())
+
+ # Check general calls
+ self.assertEqual(len(self.requests_mock.request_history), 2)
+
+ # Check verify
+ self.assertTrue(self.requests_mock.request_history[0].verify)
+
+ def test_shell_args_insecure(self):
+ _shell = shell.OpenStackShell()
+ _shell.run("--insecure configuration show".split())
+
+ # Check general calls
+ self.assertEqual(len(self.requests_mock.request_history), 2)
+
+ # Check verify
+ self.assertFalse(self.requests_mock.request_history[0].verify)
+
+ def test_shell_args_cacert(self):
+ _shell = shell.OpenStackShell()
+ _shell.run("--os-cacert xyzpdq configuration show".split())
+
+ # Check general calls
+ self.assertEqual(len(self.requests_mock.request_history), 2)
+
+ # Check verify
+ self.assertEqual(
+ 'xyzpdq',
+ self.requests_mock.request_history[0].verify,
+ )
+
+ def test_shell_args_cacert_insecure(self):
+ _shell = shell.OpenStackShell()
+ _shell.run("--os-cacert xyzpdq --insecure configuration show".split())
+
+ # Check general calls
+ self.assertEqual(len(self.requests_mock.request_history), 2)
+
+ # Check verify
+ self.assertFalse(self.requests_mock.request_history[0].verify)
+
+
+class TestIntegShellCliV2Ignore(test_base.TestInteg):
+
+ def setUp(self):
+ super(TestIntegShellCliV2Ignore, self).setUp()
+ env = {
+ "OS_AUTH_URL": test_base.V2_AUTH_URL,
+ "OS_PROJECT_NAME": test_shell.DEFAULT_PROJECT_NAME,
+ "OS_USERNAME": test_shell.DEFAULT_USERNAME,
+ "OS_PASSWORD": test_shell.DEFAULT_PASSWORD,
+ "OS_PROJECT_DOMAIN_ID": test_shell.DEFAULT_PROJECT_DOMAIN_ID,
+ "OS_USER_DOMAIN_ID": test_shell.DEFAULT_USER_DOMAIN_ID,
+ "OS_IDENTITY_API_VERSION": "2",
+ }
+ self.useFixture(osc_lib_utils.EnvFixture(copy.deepcopy(env)))
+
+ self.token = test_base.make_v2_token(self.requests_mock)
+
+ def test_shell_args_ignore_v3(self):
+ _shell = shell.OpenStackShell()
+ _shell.run("configuration show".split())
+
+ # Check general calls
+ self.assertEqual(len(self.requests_mock.request_history), 2)
+
+ # Check discovery request
+ self.assertEqual(
+ test_base.V2_AUTH_URL,
+ self.requests_mock.request_history[0].url,
+ )
+
+ # Check auth request
+ auth_req = self.requests_mock.request_history[1].json()
+
+ self.assertEqual(
+ test_shell.DEFAULT_PROJECT_NAME,
+ auth_req['auth']['tenantName'],
+ )
+ self.assertEqual(
+ test_shell.DEFAULT_USERNAME,
+ auth_req['auth']['passwordCredentials']['username'],
+ )
+ self.assertEqual(
+ test_shell.DEFAULT_PASSWORD,
+ auth_req['auth']['passwordCredentials']['password'],
+ )
+
+
+class TestIntegShellCliV3(test_base.TestInteg):
+
+ def setUp(self):
+ super(TestIntegShellCliV3, self).setUp()
+ env = {
+ "OS_AUTH_URL": test_base.V3_AUTH_URL,
+ "OS_PROJECT_DOMAIN_ID": test_shell.DEFAULT_PROJECT_DOMAIN_ID,
+ "OS_USER_DOMAIN_ID": test_shell.DEFAULT_USER_DOMAIN_ID,
+ "OS_USERNAME": test_shell.DEFAULT_USERNAME,
+ "OS_PASSWORD": test_shell.DEFAULT_PASSWORD,
+ "OS_IDENTITY_API_VERSION": "3",
+ }
+ self.useFixture(osc_lib_utils.EnvFixture(copy.deepcopy(env)))
+
+ self.token = test_base.make_v3_token(self.requests_mock)
+
+ def test_shell_args_no_options(self):
+ _shell = shell.OpenStackShell()
+ _shell.run("configuration show".split())
+
+ # Check general calls
+ self.assertEqual(len(self.requests_mock.request_history), 2)
+
+ # Check discovery request
+ self.assertEqual(
+ test_base.V3_AUTH_URL,
+ self.requests_mock.request_history[0].url,
+ )
+
+ # Check auth request
+ auth_req = self.requests_mock.request_history[1].json()
+
+ self.assertEqual(
+ test_shell.DEFAULT_PROJECT_DOMAIN_ID,
+ auth_req['auth']['identity']['password']['user']['domain']['id'],
+ )
+ self.assertEqual(
+ test_shell.DEFAULT_USERNAME,
+ auth_req['auth']['identity']['password']['user']['name'],
+ )
+ self.assertEqual(
+ test_shell.DEFAULT_PASSWORD,
+ auth_req['auth']['identity']['password']['user']['password'],
+ )
+
+ def test_shell_args_verify(self):
+ _shell = shell.OpenStackShell()
+ _shell.run("--verify configuration show".split())
+
+ # Check general calls
+ self.assertEqual(len(self.requests_mock.request_history), 2)
+
+ # Check verify
+ self.assertTrue(self.requests_mock.request_history[0].verify)
+
+ def test_shell_args_insecure(self):
+ _shell = shell.OpenStackShell()
+ _shell.run("--insecure configuration show".split())
+
+ # Check general calls
+ self.assertEqual(len(self.requests_mock.request_history), 2)
+
+ # Check verify
+ self.assertFalse(self.requests_mock.request_history[0].verify)
+
+ def test_shell_args_cacert(self):
+ _shell = shell.OpenStackShell()
+ _shell.run("--os-cacert xyzpdq configuration show".split())
+
+ # Check general calls
+ self.assertEqual(len(self.requests_mock.request_history), 2)
+
+ # Check verify
+ self.assertEqual(
+ 'xyzpdq',
+ self.requests_mock.request_history[0].verify,
+ )
+
+ def test_shell_args_cacert_insecure(self):
+ # This test verifies the outcome of bug 1447784
+ # https://bugs.launchpad.net/python-openstackclient/+bug/1447784
+ _shell = shell.OpenStackShell()
+ _shell.run("--os-cacert xyzpdq --insecure configuration show".split())
+
+ # Check general calls
+ self.assertEqual(len(self.requests_mock.request_history), 2)
+
+ # Check verify
+ self.assertFalse(self.requests_mock.request_history[0].verify)
+
+
+class TestIntegShellCliV3Prompt(test_base.TestInteg):
+
+ def setUp(self):
+ super(TestIntegShellCliV3Prompt, self).setUp()
+ env = {
+ "OS_AUTH_URL": test_base.V3_AUTH_URL,
+ "OS_PROJECT_DOMAIN_ID": test_shell.DEFAULT_PROJECT_DOMAIN_ID,
+ "OS_USER_DOMAIN_ID": test_shell.DEFAULT_USER_DOMAIN_ID,
+ "OS_USERNAME": test_shell.DEFAULT_USERNAME,
+ "OS_IDENTITY_API_VERSION": "3",
+ }
+ self.useFixture(osc_lib_utils.EnvFixture(copy.deepcopy(env)))
+
+ self.token = test_base.make_v3_token(self.requests_mock)
+
+ @mock.patch("osc_lib.shell.prompt_for_password")
+ def test_shell_callback(self, mock_prompt):
+ mock_prompt.return_value = "qaz"
+ _shell = shell.OpenStackShell()
+ _shell.run("configuration show".split())
+
+ # Check general calls
+ self.assertEqual(len(self.requests_mock.request_history), 2)
+
+ # Check password callback set correctly
+ self.assertEqual(
+ mock_prompt,
+ _shell.cloud._openstack_config._pw_callback
+ )
+
+ # Check auth request
+ auth_req = self.requests_mock.request_history[1].json()
+
+ # Check returned password from prompt function
+ self.assertEqual(
+ "qaz",
+ auth_req['auth']['identity']['password']['user']['password'],
+ )
+
+
+class TestIntegShellCliPrecedence(test_base.TestInteg):
+ """Validate option precedence rules without clouds.yaml
+
+ Global option values may be set in three places:
+ * command line options
+ * environment variables
+ * clouds.yaml
+
+ Verify that the above order is the precedence used,
+ i.e. a command line option overrides all others, etc
+ """
+
+ def setUp(self):
+ super(TestIntegShellCliPrecedence, self).setUp()
+ env = {
+ "OS_AUTH_URL": test_base.V3_AUTH_URL,
+ "OS_PROJECT_DOMAIN_ID": test_shell.DEFAULT_PROJECT_DOMAIN_ID,
+ "OS_USER_DOMAIN_ID": test_shell.DEFAULT_USER_DOMAIN_ID,
+ "OS_USERNAME": test_shell.DEFAULT_USERNAME,
+ "OS_IDENTITY_API_VERSION": "3",
+ }
+ self.useFixture(osc_lib_utils.EnvFixture(copy.deepcopy(env)))
+
+ self.token = test_base.make_v3_token(self.requests_mock)
+
+ # Patch a v3 auth URL into the o-c-c data
+ test_shell.PUBLIC_1['public-clouds']['megadodo']['auth']['auth_url'] \
+ = test_base.V3_AUTH_URL
+
+ def test_shell_args_options(self):
+ """Verify command line options override environment variables"""
+
+ _shell = shell.OpenStackShell()
+ _shell.run(
+ "--os-username zarquon --os-password qaz "
+ "configuration show".split(),
+ )
+
+ # Check general calls
+ self.assertEqual(len(self.requests_mock.request_history), 2)
+
+ # Check discovery request
+ self.assertEqual(
+ test_base.V3_AUTH_URL,
+ self.requests_mock.request_history[0].url,
+ )
+
+ # Check auth request
+ auth_req = self.requests_mock.request_history[1].json()
+
+ # -env, -cli
+ # No test, everything not specified tests this
+
+ # -env, +cli
+ self.assertEqual(
+ 'qaz',
+ auth_req['auth']['identity']['password']['user']['password'],
+ )
+
+ # +env, -cli
+ self.assertEqual(
+ test_shell.DEFAULT_PROJECT_DOMAIN_ID,
+ auth_req['auth']['identity']['password']['user']['domain']['id'],
+ )
+
+ # +env, +cli
+ self.assertEqual(
+ 'zarquon',
+ auth_req['auth']['identity']['password']['user']['name'],
+ )
+
+
+class TestIntegShellCliPrecedenceOCC(test_base.TestInteg):
+ """Validate option precedence rules with clouds.yaml
+
+ Global option values may be set in three places:
+ * command line options
+ * environment variables
+ * clouds.yaml
+
+ Verify that the above order is the precedence used,
+ i.e. a command line option overrides all others, etc
+ """
+
+ def setUp(self):
+ super(TestIntegShellCliPrecedenceOCC, self).setUp()
+ env = {
+ "OS_CLOUD": "megacloud",
+ "OS_AUTH_URL": test_base.V3_AUTH_URL,
+ "OS_PROJECT_DOMAIN_ID": test_shell.DEFAULT_PROJECT_DOMAIN_ID,
+ "OS_USER_DOMAIN_ID": test_shell.DEFAULT_USER_DOMAIN_ID,
+ "OS_USERNAME": test_shell.DEFAULT_USERNAME,
+ "OS_IDENTITY_API_VERSION": "3",
+ "OS_CLOUD_NAME": "qaz",
+ }
+ self.useFixture(osc_lib_utils.EnvFixture(copy.deepcopy(env)))
+
+ self.token = test_base.make_v3_token(self.requests_mock)
+
+ # Patch a v3 auth URL into the o-c-c data
+ test_shell.PUBLIC_1['public-clouds']['megadodo']['auth']['auth_url'] \
+ = test_base.V3_AUTH_URL
+
+ @mock.patch("os_client_config.config.OpenStackConfig._load_vendor_file")
+ @mock.patch("os_client_config.config.OpenStackConfig._load_config_file")
+ def test_shell_args_precedence_1(self, config_mock, vendor_mock):
+ """Precedence run 1
+
+ Run 1 has --os-password on CLI
+ """
+
+ config_mock.return_value = (
+ 'file.yaml',
+ copy.deepcopy(test_shell.CLOUD_2),
+ )
+ vendor_mock.return_value = (
+ 'file.yaml',
+ copy.deepcopy(test_shell.PUBLIC_1),
+ )
+ _shell = shell.OpenStackShell()
+ _shell.run(
+ "--os-password qaz configuration show".split(),
+ )
+
+ # Check general calls
+ self.assertEqual(len(self.requests_mock.request_history), 2)
+
+ # Check discovery request
+ self.assertEqual(
+ test_base.V3_AUTH_URL,
+ self.requests_mock.request_history[0].url,
+ )
+
+ # Check auth request
+ auth_req = self.requests_mock.request_history[1].json()
+
+ # -env, -cli, -occ
+ # No test, everything not specified tests this
+
+ # -env, -cli, +occ
+ self.assertEqual(
+ "heart-o-gold",
+ auth_req['auth']['scope']['project']['name'],
+ )
+
+ # -env, +cli, -occ
+ self.assertEqual(
+ 'qaz',
+ auth_req['auth']['identity']['password']['user']['password'],
+ )
+
+ # -env, +cli, +occ
+
+ # +env, -cli, -occ
+ self.assertEqual(
+ test_shell.DEFAULT_USER_DOMAIN_ID,
+ auth_req['auth']['identity']['password']['user']['domain']['id'],
+ )
+
+ # +env, -cli, +occ
+ print("auth_req: %s" % auth_req['auth'])
+ self.assertEqual(
+ test_shell.DEFAULT_USERNAME,
+ auth_req['auth']['identity']['password']['user']['name'],
+ )
+
+ # +env, +cli, -occ
+ # see test_shell_args_precedence_2()
+
+ # +env, +cli, +occ
+ # see test_shell_args_precedence_2()
+
+ @mock.patch("os_client_config.config.OpenStackConfig._load_vendor_file")
+ @mock.patch("os_client_config.config.OpenStackConfig._load_config_file")
+ def test_shell_args_precedence_2(self, config_mock, vendor_mock):
+ """Precedence run 2
+
+ Run 2 has --os-username, --os-password, --os-project-domain-id on CLI
+ """
+
+ config_mock.return_value = (
+ 'file.yaml',
+ copy.deepcopy(test_shell.CLOUD_2),
+ )
+ vendor_mock.return_value = (
+ 'file.yaml',
+ copy.deepcopy(test_shell.PUBLIC_1),
+ )
+ _shell = shell.OpenStackShell()
+ _shell.run(
+ "--os-username zarquon --os-password qaz "
+ "--os-project-domain-id 5678 configuration show".split(),
+ )
+
+ # Check general calls
+ self.assertEqual(len(self.requests_mock.request_history), 2)
+
+ # Check discovery request
+ self.assertEqual(
+ test_base.V3_AUTH_URL,
+ self.requests_mock.request_history[0].url,
+ )
+
+ # Check auth request
+ auth_req = self.requests_mock.request_history[1].json()
+
+ # +env, +cli, -occ
+ self.assertEqual(
+ '5678',
+ auth_req['auth']['scope']['project']['domain']['id'],
+ )
+
+ # +env, +cli, +occ
+ print("auth_req: %s" % auth_req['auth'])
+ self.assertEqual(
+ 'zarquon',
+ auth_req['auth']['identity']['password']['user']['name'],
+ )
diff --git a/openstackclient/tests/unit/network/__init__.py b/openstackclient/tests/unit/network/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/unit/network/__init__.py
diff --git a/openstackclient/tests/unit/network/test_common.py b/openstackclient/tests/unit/network/test_common.py
new file mode 100644
index 00000000..325aad2a
--- /dev/null
+++ b/openstackclient/tests/unit/network/test_common.py
@@ -0,0 +1,174 @@
+# 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.
+#
+
+import argparse
+import mock
+
+from openstackclient.network import common
+from openstackclient.tests.unit import utils
+
+
+def _add_common_argument(parser):
+ parser.add_argument(
+ 'common',
+ metavar='<common>',
+ help='Common argument',
+ )
+ return parser
+
+
+def _add_network_argument(parser):
+ parser.add_argument(
+ 'network',
+ metavar='<network>',
+ help='Network argument',
+ )
+ return parser
+
+
+def _add_compute_argument(parser):
+ parser.add_argument(
+ 'compute',
+ metavar='<compute>',
+ help='Compute argument',
+ )
+ return parser
+
+
+class FakeNetworkAndComputeCommand(common.NetworkAndComputeCommand):
+
+ def update_parser_common(self, parser):
+ return _add_common_argument(parser)
+
+ def update_parser_network(self, parser):
+ return _add_network_argument(parser)
+
+ def update_parser_compute(self, parser):
+ return _add_compute_argument(parser)
+
+ def take_action_network(self, client, parsed_args):
+ return client.network_action(parsed_args)
+
+ def take_action_compute(self, client, parsed_args):
+ return client.compute_action(parsed_args)
+
+
+class FakeNetworkAndComputeLister(common.NetworkAndComputeLister):
+
+ def update_parser_common(self, parser):
+ return _add_common_argument(parser)
+
+ def update_parser_network(self, parser):
+ return _add_network_argument(parser)
+
+ def update_parser_compute(self, parser):
+ return _add_compute_argument(parser)
+
+ def take_action_network(self, client, parsed_args):
+ return client.network_action(parsed_args)
+
+ def take_action_compute(self, client, parsed_args):
+ return client.compute_action(parsed_args)
+
+
+class FakeNetworkAndComputeShowOne(common.NetworkAndComputeShowOne):
+
+ def update_parser_common(self, parser):
+ return _add_common_argument(parser)
+
+ def update_parser_network(self, parser):
+ return _add_network_argument(parser)
+
+ def update_parser_compute(self, parser):
+ return _add_compute_argument(parser)
+
+ def take_action_network(self, client, parsed_args):
+ return client.network_action(parsed_args)
+
+ def take_action_compute(self, client, parsed_args):
+ return client.compute_action(parsed_args)
+
+
+class TestNetworkAndCompute(utils.TestCommand):
+
+ def setUp(self):
+ super(TestNetworkAndCompute, self).setUp()
+
+ self.namespace = argparse.Namespace()
+
+ # Create network client mocks.
+ self.app.client_manager.network = mock.Mock()
+ self.network = self.app.client_manager.network
+ self.network.network_action = mock.Mock(
+ return_value='take_action_network')
+
+ # Create compute client mocks.
+ self.app.client_manager.compute = mock.Mock()
+ self.compute = self.app.client_manager.compute
+ self.compute.compute_action = mock.Mock(
+ return_value='take_action_compute')
+
+ # Subclasses can override the command object to test.
+ self.cmd = FakeNetworkAndComputeCommand(self.app, self.namespace)
+
+ def test_take_action_network(self):
+ arglist = [
+ 'common',
+ 'network'
+ ]
+ verifylist = [
+ ('common', 'common'),
+ ('network', 'network')
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.network.network_action.assert_called_with(parsed_args)
+ self.assertEqual('take_action_network', result)
+
+ def test_take_action_compute(self):
+ arglist = [
+ 'common',
+ 'compute'
+ ]
+ verifylist = [
+ ('common', 'common'),
+ ('compute', 'compute')
+ ]
+
+ self.app.client_manager.network_endpoint_enabled = False
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.compute.compute_action.assert_called_with(parsed_args)
+ self.assertEqual('take_action_compute', result)
+
+
+class TestNetworkAndComputeCommand(TestNetworkAndCompute):
+
+ def setUp(self):
+ super(TestNetworkAndComputeCommand, self).setUp()
+ self.cmd = FakeNetworkAndComputeCommand(self.app, self.namespace)
+
+
+class TestNetworkAndComputeLister(TestNetworkAndCompute):
+
+ def setUp(self):
+ super(TestNetworkAndComputeLister, self).setUp()
+ self.cmd = FakeNetworkAndComputeLister(self.app, self.namespace)
+
+
+class TestNetworkAndComputeShowOne(TestNetworkAndCompute):
+
+ def setUp(self):
+ super(TestNetworkAndComputeShowOne, self).setUp()
+ self.cmd = FakeNetworkAndComputeShowOne(self.app, self.namespace)
diff --git a/openstackclient/tests/unit/network/v2/__init__.py b/openstackclient/tests/unit/network/v2/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/unit/network/v2/__init__.py
diff --git a/openstackclient/tests/unit/network/v2/fakes.py b/openstackclient/tests/unit/network/v2/fakes.py
new file mode 100644
index 00000000..ed30bad3
--- /dev/null
+++ b/openstackclient/tests/unit/network/v2/fakes.py
@@ -0,0 +1,1100 @@
+# 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.
+#
+
+import argparse
+import copy
+import mock
+import uuid
+
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes_v3
+from openstackclient.tests.unit import utils
+
+
+QUOTA = {
+ "subnet": 10,
+ "network": 10,
+ "floatingip": 50,
+ "subnetpool": -1,
+ "security_group_rule": 100,
+ "security_group": 10,
+ "router": 10,
+ "rbac_policy": -1,
+ "port": 50,
+ "vip": 10,
+ "member": 10,
+ "health_monitor": 10,
+}
+
+
+class FakeNetworkV2Client(object):
+
+ def __init__(self, **kwargs):
+ self.extensions = mock.Mock()
+ self.extensions.resource_class = fakes.FakeResource(None, {})
+
+
+class TestNetworkV2(utils.TestCommand):
+
+ def setUp(self):
+ super(TestNetworkV2, self).setUp()
+
+ self.namespace = argparse.Namespace()
+
+ self.app.client_manager.session = mock.Mock()
+
+ self.app.client_manager.network = FakeNetworkV2Client(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN,
+ )
+
+ self.app.client_manager.identity = (
+ identity_fakes_v3.FakeIdentityv3Client(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN,
+ )
+ )
+
+
+class FakeAddressScope(object):
+ """Fake one or more address scopes."""
+
+ @staticmethod
+ def create_one_address_scope(attrs=None):
+ """Create a fake address scope.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object with name, id, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ address_scope_attrs = {
+ 'name': 'address-scope-name-' + uuid.uuid4().hex,
+ 'id': 'address-scope-id-' + uuid.uuid4().hex,
+ 'tenant_id': 'project-id-' + uuid.uuid4().hex,
+ 'shared': False,
+ 'ip_version': 4,
+ }
+
+ # Overwrite default attributes.
+ address_scope_attrs.update(attrs)
+
+ address_scope = fakes.FakeResource(
+ info=copy.deepcopy(address_scope_attrs),
+ loaded=True)
+
+ # Set attributes with special mapping in OpenStack SDK.
+ address_scope.project_id = address_scope_attrs['tenant_id']
+
+ return address_scope
+
+ @staticmethod
+ def create_address_scopes(attrs=None, count=2):
+ """Create multiple fake address scopes.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of address scopes to fake
+ :return:
+ A list of FakeResource objects faking the address scopes
+ """
+ address_scopes = []
+ for i in range(0, count):
+ address_scopes.append(
+ FakeAddressScope.create_one_address_scope(attrs))
+
+ return address_scopes
+
+ @staticmethod
+ def get_address_scopes(address_scopes=None, count=2):
+ """Get an iterable MagicMock object with a list of faked address scopes.
+
+ If address scopes list is provided, then initialize the Mock object
+ with the list. Otherwise create one.
+
+ :param List address scopes:
+ A list of FakeResource objects faking address scopes
+ :param int count:
+ The number of address scopes to fake
+ :return:
+ An iterable Mock object with side_effect set to a list of faked
+ address scopes
+ """
+ if address_scopes is None:
+ address_scopes = FakeAddressScope.create_address_scopes(count)
+ return mock.MagicMock(side_effect=address_scopes)
+
+
+class FakeAvailabilityZone(object):
+ """Fake one or more network availability zones (AZs)."""
+
+ @staticmethod
+ def create_one_availability_zone(attrs=None):
+ """Create a fake AZ.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object with name, state, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ availability_zone = {
+ 'name': uuid.uuid4().hex,
+ 'state': 'available',
+ 'resource': 'network',
+ }
+
+ # Overwrite default attributes.
+ availability_zone.update(attrs)
+
+ availability_zone = fakes.FakeResource(
+ info=copy.deepcopy(availability_zone),
+ loaded=True)
+ return availability_zone
+
+ @staticmethod
+ def create_availability_zones(attrs=None, count=2):
+ """Create multiple fake AZs.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of AZs to fake
+ :return:
+ A list of FakeResource objects faking the AZs
+ """
+ availability_zones = []
+ for i in range(0, count):
+ availability_zone = \
+ FakeAvailabilityZone.create_one_availability_zone(attrs)
+ availability_zones.append(availability_zone)
+
+ return availability_zones
+
+
+class FakeIPAvailability(object):
+ """Fake one or more network ip availabilities."""
+
+ @staticmethod
+ def create_one_ip_availability():
+ """Create a fake list with ip availability stats of a network.
+
+ :return:
+ A FakeResource object with network_name, network_id, etc.
+ """
+
+ # Set default attributes.
+ network_ip_availability = {
+ 'network_id': 'network-id-' + uuid.uuid4().hex,
+ 'network_name': 'network-name-' + uuid.uuid4().hex,
+ 'tenant_id': '',
+ 'subnet_ip_availability': [],
+ 'total_ips': 254,
+ 'used_ips': 6,
+ }
+
+ network_ip_availability = fakes.FakeResource(
+ info=copy.deepcopy(network_ip_availability),
+ loaded=True)
+ return network_ip_availability
+
+ @staticmethod
+ def create_ip_availability(count=2):
+ """Create fake list of ip availability stats of multiple networks.
+
+ :param int count:
+ The number of networks to fake
+ :return:
+ A list of FakeResource objects faking network ip availability stats
+ """
+ network_ip_availabilities = []
+ for i in range(0, count):
+ network_ip_availability = \
+ FakeIPAvailability.create_one_ip_availability()
+ network_ip_availabilities.append(network_ip_availability)
+
+ return network_ip_availabilities
+
+
+class FakeExtension(object):
+ """Fake one or more extension."""
+
+ @staticmethod
+ def create_one_extension(attrs=None):
+ """Create a fake extension.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object with name, namespace, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ extension_info = {
+ 'name': 'name-' + uuid.uuid4().hex,
+ 'namespace': 'http://docs.openstack.org/network/',
+ 'description': 'description-' + uuid.uuid4().hex,
+ 'updated': '2013-07-09T12:00:0-00:00',
+ 'alias': 'Dystopian',
+ 'links': '[{"href":''"https://github.com/os/network", "type"}]',
+ }
+
+ # Overwrite default attributes.
+ extension_info.update(attrs)
+
+ extension = fakes.FakeResource(
+ info=copy.deepcopy(extension_info),
+ loaded=True)
+ return extension
+
+
+class FakeNetwork(object):
+ """Fake one or more networks."""
+
+ @staticmethod
+ def create_one_network(attrs=None):
+ """Create a fake network.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, name, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ network_attrs = {
+ 'id': 'network-id-' + uuid.uuid4().hex,
+ 'name': 'network-name-' + uuid.uuid4().hex,
+ 'status': 'ACTIVE',
+ 'tenant_id': 'project-id-' + uuid.uuid4().hex,
+ 'admin_state_up': True,
+ 'shared': False,
+ 'subnets': ['a', 'b'],
+ 'provider_network_type': 'vlan',
+ 'router:external': True,
+ 'availability_zones': [],
+ 'availability_zone_hints': [],
+ 'is_default': False,
+ 'port_security_enabled': True,
+ }
+
+ # Overwrite default attributes.
+ network_attrs.update(attrs)
+
+ network = fakes.FakeResource(info=copy.deepcopy(network_attrs),
+ loaded=True)
+
+ # Set attributes with special mapping in OpenStack SDK.
+ network.project_id = network_attrs['tenant_id']
+ network.is_router_external = network_attrs['router:external']
+ network.is_port_security_enabled = \
+ network_attrs['port_security_enabled']
+
+ return network
+
+ @staticmethod
+ def create_networks(attrs=None, count=2):
+ """Create multiple fake networks.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of networks to fake
+ :return:
+ A list of FakeResource objects faking the networks
+ """
+ networks = []
+ for i in range(0, count):
+ networks.append(FakeNetwork.create_one_network(attrs))
+
+ return networks
+
+ @staticmethod
+ def get_networks(networks=None, count=2):
+ """Get an iterable MagicMock object with a list of faked networks.
+
+ If networks list is provided, then initialize the Mock object with the
+ list. Otherwise create one.
+
+ :param List networks:
+ A list of FakeResource objects faking networks
+ :param int count:
+ The number of networks to fake
+ :return:
+ An iterable Mock object with side_effect set to a list of faked
+ networks
+ """
+ if networks is None:
+ networks = FakeNetwork.create_networks(count)
+ return mock.MagicMock(side_effect=networks)
+
+
+class FakeNetworkSegment(object):
+ """Fake one or more network segments."""
+
+ @staticmethod
+ def create_one_network_segment(attrs=None):
+ """Create a fake network segment.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object faking the network segment
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ network_segment_attrs = {
+ 'id': 'network-segment-id-' + uuid.uuid4().hex,
+ 'network_id': 'network-id-' + uuid.uuid4().hex,
+ 'network_type': 'vlan',
+ 'physical_network': 'physical-network-name-' + uuid.uuid4().hex,
+ 'segmentation_id': 1024,
+ }
+
+ # Overwrite default attributes.
+ network_segment_attrs.update(attrs)
+
+ network_segment = fakes.FakeResource(
+ info=copy.deepcopy(network_segment_attrs),
+ loaded=True
+ )
+
+ return network_segment
+
+ @staticmethod
+ def create_network_segments(attrs=None, count=2):
+ """Create multiple fake network segments.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of network segments to fake
+ :return:
+ A list of FakeResource objects faking the network segments
+ """
+ network_segments = []
+ for i in range(0, count):
+ network_segments.append(
+ FakeNetworkSegment.create_one_network_segment(attrs)
+ )
+ return network_segments
+
+
+class FakePort(object):
+ """Fake one or more ports."""
+
+ @staticmethod
+ def create_one_port(attrs=None):
+ """Create a fake port.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, name, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ port_attrs = {
+ 'admin_state_up': True,
+ 'allowed_address_pairs': [{}],
+ 'binding:host_id': 'binding-host-id-' + uuid.uuid4().hex,
+ 'binding:profile': {},
+ 'binding:vif_details': {},
+ 'binding:vif_type': 'ovs',
+ 'binding:vnic_type': 'normal',
+ 'device_id': 'device-id-' + uuid.uuid4().hex,
+ 'device_owner': 'compute:nova',
+ 'dns_assignment': [{}],
+ 'dns_name': 'dns-name-' + uuid.uuid4().hex,
+ 'extra_dhcp_opts': [{}],
+ 'fixed_ips': [{}],
+ 'id': 'port-id-' + uuid.uuid4().hex,
+ 'mac_address': 'fa:16:3e:a9:4e:72',
+ 'name': 'port-name-' + uuid.uuid4().hex,
+ 'network_id': 'network-id-' + uuid.uuid4().hex,
+ 'port_security_enabled': True,
+ 'security_groups': [],
+ 'status': 'ACTIVE',
+ 'tenant_id': 'project-id-' + uuid.uuid4().hex,
+ }
+
+ # Overwrite default attributes.
+ port_attrs.update(attrs)
+
+ port = fakes.FakeResource(info=copy.deepcopy(port_attrs),
+ loaded=True)
+
+ # Set attributes with special mappings in OpenStack SDK.
+ port.project_id = port_attrs['tenant_id']
+ port.binding_host_id = port_attrs['binding:host_id']
+ port.binding_profile = port_attrs['binding:profile']
+ port.binding_vif_details = port_attrs['binding:vif_details']
+ port.binding_vif_type = port_attrs['binding:vif_type']
+ port.binding_vnic_type = port_attrs['binding:vnic_type']
+
+ return port
+
+ @staticmethod
+ def create_ports(attrs=None, count=2):
+ """Create multiple fake ports.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of ports to fake
+ :return:
+ A list of FakeResource objects faking the ports
+ """
+ ports = []
+ for i in range(0, count):
+ ports.append(FakePort.create_one_port(attrs))
+
+ return ports
+
+ @staticmethod
+ def get_ports(ports=None, count=2):
+ """Get an iterable MagicMock object with a list of faked ports.
+
+ If ports list is provided, then initialize the Mock object with the
+ list. Otherwise create one.
+
+ :param List ports:
+ A list of FakeResource objects faking ports
+ :param int count:
+ The number of ports to fake
+ :return:
+ An iterable Mock object with side_effect set to a list of faked
+ ports
+ """
+ if ports is None:
+ ports = FakePort.create_ports(count)
+ return mock.MagicMock(side_effect=ports)
+
+
+class FakeNetworkAgent(object):
+ """Fake one or more network agents."""
+
+ @staticmethod
+ def create_one_network_agent(attrs=None):
+ """Create a fake network agent
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, agent_type, and so on.
+ """
+ attrs = attrs or {}
+
+ # Set default attributes
+ agent_attrs = {
+ 'id': 'agent-id-' + uuid.uuid4().hex,
+ 'agent_type': 'agent-type-' + uuid.uuid4().hex,
+ 'host': 'host-' + uuid.uuid4().hex,
+ 'availability_zone': 'zone-' + uuid.uuid4().hex,
+ 'alive': True,
+ 'admin_state_up': True,
+ 'binary': 'binary-' + uuid.uuid4().hex,
+ 'configurations': {'subnet': 2, 'networks': 1},
+ }
+ agent_attrs.update(attrs)
+ agent = fakes.FakeResource(info=copy.deepcopy(agent_attrs),
+ loaded=True)
+ return agent
+
+ @staticmethod
+ def create_network_agents(attrs=None, count=2):
+ """Create multiple fake network agents.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of network agents to fake
+ :return:
+ A list of FakeResource objects faking the network agents
+ """
+ agents = []
+ for i in range(0, count):
+ agents.append(FakeNetworkAgent.create_one_network_agent(attrs))
+
+ return agents
+
+ @staticmethod
+ def get_network_agents(agents=None, count=2):
+ """Get an iterable MagicMock object with a list of faked network agents.
+
+ If network agents list is provided, then initialize the Mock object
+ with the list. Otherwise create one.
+
+ :param List agents:
+ A list of FakeResource objects faking network agents
+ :param int count:
+ The number of network agents to fake
+ :return:
+ An iterable Mock object with side_effect set to a list of faked
+ network agents
+ """
+ if agents is None:
+ agents = FakeNetworkAgent.create_network_agents(count)
+ return mock.MagicMock(side_effect=agents)
+
+
+class FakeNetworkRBAC(object):
+ """Fake one or more network rbac policies."""
+
+ @staticmethod
+ def create_one_network_rbac(attrs=None):
+ """Create a fake network rbac
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, action, target_tenant,
+ tenant_id, type
+ """
+ attrs = attrs or {}
+
+ # Set default attributes
+ rbac_attrs = {
+ 'id': 'rbac-id-' + uuid.uuid4().hex,
+ 'object_type': 'network',
+ 'object_id': 'object-id-' + uuid.uuid4().hex,
+ 'action': 'access_as_shared',
+ 'target_tenant': 'target-tenant-' + uuid.uuid4().hex,
+ 'tenant_id': 'tenant-id-' + uuid.uuid4().hex,
+ }
+ rbac_attrs.update(attrs)
+ rbac = fakes.FakeResource(info=copy.deepcopy(rbac_attrs),
+ loaded=True)
+ # Set attributes with special mapping in OpenStack SDK.
+ rbac.project_id = rbac_attrs['tenant_id']
+ rbac.target_project_id = rbac_attrs['target_tenant']
+ return rbac
+
+ @staticmethod
+ def create_network_rbacs(attrs=None, count=2):
+ """Create multiple fake network rbac policies.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of rbac policies to fake
+ :return:
+ A list of FakeResource objects faking the rbac policies
+ """
+ rbac_policies = []
+ for i in range(0, count):
+ rbac_policies.append(FakeNetworkRBAC.
+ create_one_network_rbac(attrs))
+
+ return rbac_policies
+
+ @staticmethod
+ def get_network_rbacs(rbac_policies=None, count=2):
+ """Get an iterable MagicMock object with a list of faked rbac policies.
+
+ If rbac policies list is provided, then initialize the Mock object
+ with the list. Otherwise create one.
+
+ :param List rbac_policies:
+ A list of FakeResource objects faking rbac policies
+ :param int count:
+ The number of rbac policies to fake
+ :return:
+ An iterable Mock object with side_effect set to a list of faked
+ rbac policies
+ """
+ if rbac_policies is None:
+ rbac_policies = FakeNetworkRBAC.create_network_rbacs(count)
+ return mock.MagicMock(side_effect=rbac_policies)
+
+
+class FakeRouter(object):
+ """Fake one or more routers."""
+
+ @staticmethod
+ def create_one_router(attrs=None):
+ """Create a fake router.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, name, admin_state_up,
+ status, tenant_id
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ router_attrs = {
+ 'id': 'router-id-' + uuid.uuid4().hex,
+ 'name': 'router-name-' + uuid.uuid4().hex,
+ 'status': 'ACTIVE',
+ 'admin_state_up': True,
+ 'distributed': False,
+ 'ha': False,
+ 'tenant_id': 'project-id-' + uuid.uuid4().hex,
+ 'routes': [],
+ 'external_gateway_info': {},
+ 'availability_zone_hints': [],
+ 'availability_zones': [],
+ }
+
+ # Overwrite default attributes.
+ router_attrs.update(attrs)
+
+ router = fakes.FakeResource(info=copy.deepcopy(router_attrs),
+ loaded=True)
+
+ # Set attributes with special mapping in OpenStack SDK.
+ router.project_id = router_attrs['tenant_id']
+
+ return router
+
+ @staticmethod
+ def create_routers(attrs=None, count=2):
+ """Create multiple fake routers.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of routers to fake
+ :return:
+ A list of FakeResource objects faking the routers
+ """
+ routers = []
+ for i in range(0, count):
+ routers.append(FakeRouter.create_one_router(attrs))
+
+ return routers
+
+ @staticmethod
+ def get_routers(routers=None, count=2):
+ """Get an iterable MagicMock object with a list of faked routers.
+
+ If routers list is provided, then initialize the Mock object with the
+ list. Otherwise create one.
+
+ :param List routers:
+ A list of FakeResource objects faking routers
+ :param int count:
+ The number of routers to fake
+ :return:
+ An iterable Mock object with side_effect set to a list of faked
+ routers
+ """
+ if routers is None:
+ routers = FakeRouter.create_routers(count)
+ return mock.MagicMock(side_effect=routers)
+
+
+class FakeSecurityGroup(object):
+ """Fake one or more security groups."""
+
+ @staticmethod
+ def create_one_security_group(attrs=None):
+ """Create a fake security group.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, name, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ security_group_attrs = {
+ 'id': 'security-group-id-' + uuid.uuid4().hex,
+ 'name': 'security-group-name-' + uuid.uuid4().hex,
+ 'description': 'security-group-description-' + uuid.uuid4().hex,
+ 'tenant_id': 'project-id-' + uuid.uuid4().hex,
+ 'security_group_rules': [],
+ }
+
+ # Overwrite default attributes.
+ security_group_attrs.update(attrs)
+
+ security_group = fakes.FakeResource(
+ info=copy.deepcopy(security_group_attrs),
+ loaded=True)
+
+ # Set attributes with special mapping in OpenStack SDK.
+ security_group.project_id = security_group_attrs['tenant_id']
+
+ return security_group
+
+ @staticmethod
+ def create_security_groups(attrs=None, count=2):
+ """Create multiple fake security groups.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of security groups to fake
+ :return:
+ A list of FakeResource objects faking the security groups
+ """
+ security_groups = []
+ for i in range(0, count):
+ security_groups.append(
+ FakeSecurityGroup.create_one_security_group(attrs))
+
+ return security_groups
+
+ @staticmethod
+ def get_security_groups(security_groups=None, count=2):
+ """Get an iterable MagicMock object with a list of faked security groups.
+
+ If security groups list is provided, then initialize the Mock object
+ with the list. Otherwise create one.
+
+ :param List security groups:
+ A list of FakeResource objects faking security groups
+ :param int count:
+ The number of security groups to fake
+ :return:
+ An iterable Mock object with side_effect set to a list of faked
+ security groups
+ """
+ if security_groups is None:
+ security_groups = FakeSecurityGroup.create_security_groups(count)
+ return mock.MagicMock(side_effect=security_groups)
+
+
+class FakeSecurityGroupRule(object):
+ """Fake one or more security group rules."""
+
+ @staticmethod
+ def create_one_security_group_rule(attrs=None):
+ """Create a fake security group rule.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ security_group_rule_attrs = {
+ 'direction': 'ingress',
+ 'ethertype': 'IPv4',
+ 'id': 'security-group-rule-id-' + uuid.uuid4().hex,
+ 'port_range_max': None,
+ 'port_range_min': None,
+ 'protocol': 'tcp',
+ 'remote_group_id': None,
+ 'remote_ip_prefix': '0.0.0.0/0',
+ 'security_group_id': 'security-group-id-' + uuid.uuid4().hex,
+ 'tenant_id': 'project-id-' + uuid.uuid4().hex,
+ }
+
+ # Overwrite default attributes.
+ security_group_rule_attrs.update(attrs)
+
+ security_group_rule = fakes.FakeResource(
+ info=copy.deepcopy(security_group_rule_attrs),
+ loaded=True)
+
+ # Set attributes with special mapping in OpenStack SDK.
+ security_group_rule.project_id = security_group_rule_attrs['tenant_id']
+
+ return security_group_rule
+
+ @staticmethod
+ def create_security_group_rules(attrs=None, count=2):
+ """Create multiple fake security group rules.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of security group rules to fake
+ :return:
+ A list of FakeResource objects faking the security group rules
+ """
+ security_group_rules = []
+ for i in range(0, count):
+ security_group_rules.append(
+ FakeSecurityGroupRule.create_one_security_group_rule(attrs))
+
+ return security_group_rules
+
+ @staticmethod
+ def get_security_group_rules(security_group_rules=None, count=2):
+ """Get an iterable MagicMock object with a list of faked security group rules.
+
+ If security group rules list is provided, then initialize the Mock
+ object with the list. Otherwise create one.
+
+ :param List security group rules:
+ A list of FakeResource objects faking security group rules
+ :param int count:
+ The number of security group rules to fake
+ :return:
+ An iterable Mock object with side_effect set to a list of faked
+ security group rules
+ """
+ if security_group_rules is None:
+ security_group_rules = (
+ FakeSecurityGroupRule.create_security_group_rules(count))
+ return mock.MagicMock(side_effect=security_group_rules)
+
+
+class FakeSubnet(object):
+ """Fake one or more subnets."""
+
+ @staticmethod
+ def create_one_subnet(attrs=None):
+ """Create a fake subnet.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object faking the subnet
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ project_id = 'project-id-' + uuid.uuid4().hex
+ subnet_attrs = {
+ 'id': 'subnet-id-' + uuid.uuid4().hex,
+ 'name': 'subnet-name-' + uuid.uuid4().hex,
+ 'network_id': 'network-id-' + uuid.uuid4().hex,
+ 'cidr': '10.10.10.0/24',
+ 'tenant_id': project_id,
+ 'enable_dhcp': True,
+ 'dns_nameservers': [],
+ 'allocation_pools': [],
+ 'host_routes': [],
+ 'ip_version': 4,
+ 'gateway_ip': '10.10.10.1',
+ 'ipv6_address_mode': None,
+ 'ipv6_ra_mode': None,
+ 'segment_id': None,
+ 'service_types': [],
+ 'subnetpool_id': None,
+ }
+
+ # Overwrite default attributes.
+ subnet_attrs.update(attrs)
+
+ subnet = fakes.FakeResource(info=copy.deepcopy(subnet_attrs),
+ loaded=True)
+
+ # Set attributes with special mappings in OpenStack SDK.
+ subnet.project_id = subnet_attrs['tenant_id']
+
+ return subnet
+
+ @staticmethod
+ def create_subnets(attrs=None, count=2):
+ """Create multiple fake subnets.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of subnets to fake
+ :return:
+ A list of FakeResource objects faking the subnets
+ """
+ subnets = []
+ for i in range(0, count):
+ subnets.append(FakeSubnet.create_one_subnet(attrs))
+
+ return subnets
+
+ @staticmethod
+ def get_subnets(subnets=None, count=2):
+ """Get an iterable MagicMock object with a list of faked subnets.
+
+ If subnets list is provided, then initialize the Mock object
+ with the list. Otherwise create one.
+
+ :param List subnets:
+ A list of FakeResource objects faking subnets
+ :param int count:
+ The number of subnets to fake
+ :return:
+ An iterable Mock object with side_effect set to a list of faked
+ subnets
+ """
+ if subnets is None:
+ subnets = FakeSubnet.create_subnets(count)
+ return mock.MagicMock(side_effect=subnets)
+
+
+class FakeFloatingIP(object):
+ """Fake one or more floating ip."""
+
+ @staticmethod
+ def create_one_floating_ip(attrs=None):
+ """Create a fake floating ip.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, ip, and so on
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ floating_ip_attrs = {
+ 'id': 'floating-ip-id-' + uuid.uuid4().hex,
+ 'floating_ip_address': '1.0.9.0',
+ 'fixed_ip_address': '2.0.9.0',
+ 'dns_domain': None,
+ 'dns_name': None,
+ 'status': 'DOWN',
+ 'floating_network_id': 'network-id-' + uuid.uuid4().hex,
+ 'router_id': 'router-id-' + uuid.uuid4().hex,
+ 'port_id': 'port-id-' + uuid.uuid4().hex,
+ 'tenant_id': 'project-id-' + uuid.uuid4().hex,
+ }
+
+ # Overwrite default attributes.
+ floating_ip_attrs.update(attrs)
+
+ floating_ip = fakes.FakeResource(
+ info=copy.deepcopy(floating_ip_attrs),
+ loaded=True
+ )
+
+ # Set attributes with special mappings in OpenStack SDK.
+ floating_ip.project_id = floating_ip_attrs['tenant_id']
+
+ return floating_ip
+
+ @staticmethod
+ def create_floating_ips(attrs=None, count=2):
+ """Create multiple fake floating ips.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of floating ips to fake
+ :return:
+ A list of FakeResource objects faking the floating ips
+ """
+ floating_ips = []
+ for i in range(0, count):
+ floating_ips.append(FakeFloatingIP.create_one_floating_ip(attrs))
+ return floating_ips
+
+ @staticmethod
+ def get_floating_ips(floating_ips=None, count=2):
+ """Get an iterable MagicMock object with a list of faked floating ips.
+
+ If floating_ips list is provided, then initialize the Mock object
+ with the list. Otherwise create one.
+
+ :param List floating ips:
+ A list of FakeResource objects faking floating ips
+ :param int count:
+ The number of floating ips to fake
+ :return:
+ An iterable Mock object with side_effect set to a list of faked
+ floating ips
+ """
+ if floating_ips is None:
+ floating_ips = FakeFloatingIP.create_floating_ips(count)
+ return mock.MagicMock(side_effect=floating_ips)
+
+
+class FakeSubnetPool(object):
+ """Fake one or more subnet pools."""
+
+ @staticmethod
+ def create_one_subnet_pool(attrs=None):
+ """Create a fake subnet pool.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object faking the subnet pool
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ subnet_pool_attrs = {
+ 'id': 'subnet-pool-id-' + uuid.uuid4().hex,
+ 'name': 'subnet-pool-name-' + uuid.uuid4().hex,
+ 'prefixes': ['10.0.0.0/24', '10.1.0.0/24'],
+ 'default_prefixlen': '8',
+ 'address_scope_id': 'address-scope-id-' + uuid.uuid4().hex,
+ 'tenant_id': 'project-id-' + uuid.uuid4().hex,
+ 'is_default': False,
+ 'shared': False,
+ 'max_prefixlen': '32',
+ 'min_prefixlen': '8',
+ 'default_quota': None,
+ 'ip_version': '4',
+ }
+
+ # Overwrite default attributes.
+ subnet_pool_attrs.update(attrs)
+
+ subnet_pool = fakes.FakeResource(
+ info=copy.deepcopy(subnet_pool_attrs),
+ loaded=True
+ )
+
+ # Set attributes with special mapping in OpenStack SDK.
+ subnet_pool.project_id = subnet_pool_attrs['tenant_id']
+
+ return subnet_pool
+
+ @staticmethod
+ def create_subnet_pools(attrs=None, count=2):
+ """Create multiple fake subnet pools.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of subnet pools to fake
+ :return:
+ A list of FakeResource objects faking the subnet pools
+ """
+ subnet_pools = []
+ for i in range(0, count):
+ subnet_pools.append(
+ FakeSubnetPool.create_one_subnet_pool(attrs)
+ )
+
+ return subnet_pools
+
+ @staticmethod
+ def get_subnet_pools(subnet_pools=None, count=2):
+ """Get an iterable MagicMock object with a list of faked subnet pools.
+
+ If subnet_pools list is provided, then initialize the Mock object
+ with the list. Otherwise create one.
+
+ :param List subnet pools:
+ A list of FakeResource objects faking subnet pools
+ :param int count:
+ The number of subnet pools to fake
+ :return:
+ An iterable Mock object with side_effect set to a list of faked
+ subnet pools
+ """
+ if subnet_pools is None:
+ subnet_pools = FakeSubnetPool.create_subnet_pools(count)
+ return mock.MagicMock(side_effect=subnet_pools)
diff --git a/openstackclient/tests/unit/network/v2/test_address_scope.py b/openstackclient/tests/unit/network/v2/test_address_scope.py
new file mode 100644
index 00000000..6d3f4011
--- /dev/null
+++ b/openstackclient/tests/unit/network/v2/test_address_scope.py
@@ -0,0 +1,399 @@
+# 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.
+#
+
+import mock
+from mock import call
+
+from osc_lib import exceptions
+
+from openstackclient.network.v2 import address_scope
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes_v3
+from openstackclient.tests.unit.network.v2 import fakes as network_fakes
+from openstackclient.tests.unit import utils as tests_utils
+
+
+class TestAddressScope(network_fakes.TestNetworkV2):
+
+ def setUp(self):
+ super(TestAddressScope, self).setUp()
+
+ # Get a shortcut to the network client
+ self.network = self.app.client_manager.network
+ # Get a shortcut to the ProjectManager Mock
+ self.projects_mock = self.app.client_manager.identity.projects
+ # Get a shortcut to the DomainManager Mock
+ self.domains_mock = self.app.client_manager.identity.domains
+
+
+class TestCreateAddressScope(TestAddressScope):
+
+ project = identity_fakes_v3.FakeProject.create_one_project()
+ domain = identity_fakes_v3.FakeDomain.create_one_domain()
+ # The new address scope created.
+ new_address_scope = (
+ network_fakes.FakeAddressScope.create_one_address_scope(
+ attrs={
+ 'tenant_id': project.id,
+ }
+ ))
+ columns = (
+ 'id',
+ 'ip_version',
+ 'name',
+ 'project_id',
+ 'shared'
+ )
+ data = (
+ new_address_scope.id,
+ new_address_scope.ip_version,
+ new_address_scope.name,
+ new_address_scope.project_id,
+ new_address_scope.shared,
+ )
+
+ def setUp(self):
+ super(TestCreateAddressScope, self).setUp()
+ self.network.create_address_scope = mock.Mock(
+ return_value=self.new_address_scope)
+
+ # Get the command object to test
+ self.cmd = address_scope.CreateAddressScope(self.app, self.namespace)
+
+ self.projects_mock.get.return_value = self.project
+ self.domains_mock.get.return_value = self.domain
+
+ def test_create_no_options(self):
+ arglist = []
+ verifylist = []
+
+ # Missing required args should bail here
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_create_default_options(self):
+ arglist = [
+ self.new_address_scope.name,
+ ]
+ verifylist = [
+ ('project', None),
+ ('ip_version', self.new_address_scope.ip_version),
+ ('name', self.new_address_scope.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = (self.cmd.take_action(parsed_args))
+
+ self.network.create_address_scope.assert_called_once_with(**{
+ 'ip_version': self.new_address_scope.ip_version,
+ 'name': self.new_address_scope.name,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_create_all_options(self):
+ arglist = [
+ '--ip-version', str(self.new_address_scope.ip_version),
+ '--share',
+ '--project', self.project.name,
+ '--project-domain', self.domain.name,
+ self.new_address_scope.name,
+ ]
+ verifylist = [
+ ('ip_version', self.new_address_scope.ip_version),
+ ('share', True),
+ ('project', self.project.name),
+ ('project_domain', self.domain.name),
+ ('name', self.new_address_scope.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = (self.cmd.take_action(parsed_args))
+
+ self.network.create_address_scope.assert_called_once_with(**{
+ 'ip_version': self.new_address_scope.ip_version,
+ 'shared': True,
+ 'tenant_id': self.project.id,
+ 'name': self.new_address_scope.name,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_create_no_share(self):
+ arglist = [
+ '--no-share',
+ self.new_address_scope.name,
+ ]
+ verifylist = [
+ ('no_share', True),
+ ('name', self.new_address_scope.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_address_scope.assert_called_once_with(**{
+ 'ip_version': self.new_address_scope.ip_version,
+ 'shared': False,
+ 'name': self.new_address_scope.name,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestDeleteAddressScope(TestAddressScope):
+
+ # The address scope to delete.
+ _address_scopes = (
+ network_fakes.FakeAddressScope.create_address_scopes(count=2))
+
+ def setUp(self):
+ super(TestDeleteAddressScope, self).setUp()
+ self.network.delete_address_scope = mock.Mock(return_value=None)
+ self.network.find_address_scope = (
+ network_fakes.FakeAddressScope.get_address_scopes(
+ address_scopes=self._address_scopes)
+ )
+
+ # Get the command object to test
+ self.cmd = address_scope.DeleteAddressScope(self.app, self.namespace)
+
+ def test_address_scope_delete(self):
+ arglist = [
+ self._address_scopes[0].name,
+ ]
+ verifylist = [
+ ('address_scope', [self._address_scopes[0].name]),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.network.find_address_scope.assert_called_once_with(
+ self._address_scopes[0].name, ignore_missing=False)
+ self.network.delete_address_scope.assert_called_once_with(
+ self._address_scopes[0])
+ self.assertIsNone(result)
+
+ def test_multi_address_scopes_delete(self):
+ arglist = []
+ verifylist = []
+
+ for a in self._address_scopes:
+ arglist.append(a.name)
+ verifylist = [
+ ('address_scope', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for a in self._address_scopes:
+ calls.append(call(a))
+ self.network.delete_address_scope.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_multi_address_scopes_delete_with_exception(self):
+ arglist = [
+ self._address_scopes[0].name,
+ 'unexist_address_scope',
+ ]
+ verifylist = [
+ ('address_scope',
+ [self._address_scopes[0].name, 'unexist_address_scope']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [self._address_scopes[0], exceptions.CommandError]
+ self.network.find_address_scope = (
+ mock.MagicMock(side_effect=find_mock_result)
+ )
+
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 address scopes failed to delete.', str(e))
+
+ self.network.find_address_scope.assert_any_call(
+ self._address_scopes[0].name, ignore_missing=False)
+ self.network.find_address_scope.assert_any_call(
+ 'unexist_address_scope', ignore_missing=False)
+ self.network.delete_address_scope.assert_called_once_with(
+ self._address_scopes[0]
+ )
+
+
+class TestListAddressScope(TestAddressScope):
+
+ # The address scopes to list up.
+ address_scopes = (
+ network_fakes.FakeAddressScope.create_address_scopes(count=3))
+ columns = (
+ 'ID',
+ 'Name',
+ 'IP Version',
+ 'Shared',
+ 'Project',
+ )
+ data = []
+ for scope in address_scopes:
+ data.append((
+ scope.id,
+ scope.name,
+ scope.ip_version,
+ scope.shared,
+ scope.project_id,
+ ))
+
+ def setUp(self):
+ super(TestListAddressScope, self).setUp()
+ self.network.address_scopes = mock.Mock(
+ return_value=self.address_scopes)
+
+ # Get the command object to test
+ self.cmd = address_scope.ListAddressScope(self.app, self.namespace)
+
+ def test_address_scope_list(self):
+ arglist = []
+ verifylist = []
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.address_scopes.assert_called_once_with(**{})
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+
+class TestSetAddressScope(TestAddressScope):
+
+ # The address scope to set.
+ _address_scope = network_fakes.FakeAddressScope.create_one_address_scope()
+
+ def setUp(self):
+ super(TestSetAddressScope, self).setUp()
+ self.network.update_address_scope = mock.Mock(return_value=None)
+ self.network.find_address_scope = mock.Mock(
+ return_value=self._address_scope)
+
+ # Get the command object to test
+ self.cmd = address_scope.SetAddressScope(self.app, self.namespace)
+
+ def test_set_nothing(self):
+ arglist = [self._address_scope.name, ]
+ verifylist = [
+ ('address_scope', self._address_scope.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {}
+ self.network.update_address_scope.assert_called_with(
+ self._address_scope, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_name_and_share(self):
+ arglist = [
+ '--name', 'new_address_scope',
+ '--share',
+ self._address_scope.name,
+ ]
+ verifylist = [
+ ('name', 'new_address_scope'),
+ ('share', True),
+ ('address_scope', self._address_scope.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ attrs = {
+ 'name': "new_address_scope",
+ 'shared': True,
+ }
+ self.network.update_address_scope.assert_called_with(
+ self._address_scope, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_no_share(self):
+ arglist = [
+ '--no-share',
+ self._address_scope.name,
+ ]
+ verifylist = [
+ ('no_share', True),
+ ('address_scope', self._address_scope.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ attrs = {
+ 'shared': False,
+ }
+ self.network.update_address_scope.assert_called_with(
+ self._address_scope, **attrs)
+ self.assertIsNone(result)
+
+
+class TestShowAddressScope(TestAddressScope):
+
+ # The address scope to show.
+ _address_scope = (
+ network_fakes.FakeAddressScope.create_one_address_scope())
+ columns = (
+ 'id',
+ 'ip_version',
+ 'name',
+ 'project_id',
+ 'shared',
+ )
+ data = (
+ _address_scope.id,
+ _address_scope.ip_version,
+ _address_scope.name,
+ _address_scope.project_id,
+ _address_scope.shared,
+ )
+
+ def setUp(self):
+ super(TestShowAddressScope, self).setUp()
+ self.network.find_address_scope = mock.Mock(
+ return_value=self._address_scope)
+
+ # Get the command object to test
+ self.cmd = address_scope.ShowAddressScope(self.app, self.namespace)
+
+ def test_show_no_options(self):
+ arglist = []
+ verifylist = []
+
+ # Missing required args should bail here
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_show_all_options(self):
+ arglist = [
+ self._address_scope.name,
+ ]
+ verifylist = [
+ ('address_scope', self._address_scope.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.find_address_scope.assert_called_once_with(
+ self._address_scope.name, ignore_missing=False)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(list(self.data), list(data))
diff --git a/openstackclient/tests/unit/network/v2/test_floating_ip.py b/openstackclient/tests/unit/network/v2/test_floating_ip.py
new file mode 100644
index 00000000..a40e48f4
--- /dev/null
+++ b/openstackclient/tests/unit/network/v2/test_floating_ip.py
@@ -0,0 +1,565 @@
+# 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.
+#
+
+import mock
+from mock import call
+
+from osc_lib import exceptions
+
+from openstackclient.network.v2 import floating_ip
+from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
+from openstackclient.tests.unit.network.v2 import fakes as network_fakes
+from openstackclient.tests.unit import utils as tests_utils
+
+
+# Tests for Neutron network
+#
+class TestFloatingIPNetwork(network_fakes.TestNetworkV2):
+
+ def setUp(self):
+ super(TestFloatingIPNetwork, self).setUp()
+
+ # Get a shortcut to the network client
+ self.network = self.app.client_manager.network
+
+
+class TestCreateFloatingIPNetwork(TestFloatingIPNetwork):
+
+ # Fake data for option tests.
+ floating_network = network_fakes.FakeNetwork.create_one_network()
+ subnet = network_fakes.FakeSubnet.create_one_subnet()
+ port = network_fakes.FakePort.create_one_port()
+
+ # The floating ip to be deleted.
+ floating_ip = network_fakes.FakeFloatingIP.create_one_floating_ip(
+ attrs={
+ 'floating_network_id': floating_network.id,
+ 'port_id': port.id,
+ }
+ )
+
+ columns = (
+ 'dns_domain',
+ 'dns_name',
+ 'fixed_ip_address',
+ 'floating_ip_address',
+ 'floating_network_id',
+ 'id',
+ 'port_id',
+ 'project_id',
+ 'router_id',
+ 'status',
+ )
+
+ data = (
+ floating_ip.dns_domain,
+ floating_ip.dns_name,
+ floating_ip.fixed_ip_address,
+ floating_ip.floating_ip_address,
+ floating_ip.floating_network_id,
+ floating_ip.id,
+ floating_ip.port_id,
+ floating_ip.project_id,
+ floating_ip.router_id,
+ floating_ip.status,
+ )
+
+ def setUp(self):
+ super(TestCreateFloatingIPNetwork, self).setUp()
+
+ self.network.create_ip = mock.Mock(return_value=self.floating_ip)
+
+ self.network.find_network = mock.Mock(
+ return_value=self.floating_network)
+ self.network.find_subnet = mock.Mock(return_value=self.subnet)
+ self.network.find_port = mock.Mock(return_value=self.port)
+
+ # Get the command object to test
+ self.cmd = floating_ip.CreateFloatingIP(self.app, self.namespace)
+
+ def test_create_no_options(self):
+ arglist = []
+ verifylist = []
+
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_create_default_options(self):
+ arglist = [
+ self.floating_ip.floating_network_id,
+ ]
+ verifylist = [
+ ('network', self.floating_ip.floating_network_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_ip.assert_called_once_with(**{
+ 'floating_network_id': self.floating_ip.floating_network_id,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_create_all_options(self):
+ arglist = [
+ '--subnet', self.subnet.id,
+ '--port', self.floating_ip.port_id,
+ '--floating-ip-address', self.floating_ip.floating_ip_address,
+ '--fixed-ip-address', self.floating_ip.fixed_ip_address,
+ self.floating_ip.floating_network_id,
+ ]
+ verifylist = [
+ ('subnet', self.subnet.id),
+ ('port', self.floating_ip.port_id),
+ ('floating_ip_address', self.floating_ip.floating_ip_address),
+ ('fixed_ip_address', self.floating_ip.fixed_ip_address),
+ ('network', self.floating_ip.floating_network_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_ip.assert_called_once_with(**{
+ 'subnet_id': self.subnet.id,
+ 'port_id': self.floating_ip.port_id,
+ 'floating_ip_address': self.floating_ip.floating_ip_address,
+ 'fixed_ip_address': self.floating_ip.fixed_ip_address,
+ 'floating_network_id': self.floating_ip.floating_network_id,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestDeleteFloatingIPNetwork(TestFloatingIPNetwork):
+
+ # The floating ips to be deleted.
+ floating_ips = network_fakes.FakeFloatingIP.create_floating_ips(count=2)
+
+ def setUp(self):
+ super(TestDeleteFloatingIPNetwork, self).setUp()
+
+ self.network.delete_ip = mock.Mock(return_value=None)
+ self.network.find_ip = (
+ network_fakes.FakeFloatingIP.get_floating_ips(self.floating_ips))
+
+ # Get the command object to test
+ self.cmd = floating_ip.DeleteFloatingIP(self.app, self.namespace)
+
+ def test_floating_ip_delete(self):
+ arglist = [
+ self.floating_ips[0].id,
+ ]
+ verifylist = [
+ ('floating_ip', [self.floating_ips[0].id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.network.find_ip.assert_called_once_with(
+ self.floating_ips[0].id, ignore_missing=False)
+ self.network.delete_ip.assert_called_once_with(self.floating_ips[0])
+ self.assertIsNone(result)
+
+ def test_multi_floating_ips_delete(self):
+ arglist = []
+ verifylist = []
+
+ for f in self.floating_ips:
+ arglist.append(f.id)
+ verifylist = [
+ ('floating_ip', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for f in self.floating_ips:
+ calls.append(call(f))
+ self.network.delete_ip.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_multi_floating_ips_delete_with_exception(self):
+ arglist = [
+ self.floating_ips[0].id,
+ 'unexist_floating_ip',
+ ]
+ verifylist = [
+ ('floating_ip',
+ [self.floating_ips[0].id, 'unexist_floating_ip']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [self.floating_ips[0], exceptions.CommandError]
+ self.network.find_ip = (
+ mock.MagicMock(side_effect=find_mock_result)
+ )
+
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 floating_ips failed to delete.', str(e))
+
+ self.network.find_ip.assert_any_call(
+ self.floating_ips[0].id, ignore_missing=False)
+ self.network.find_ip.assert_any_call(
+ 'unexist_floating_ip', ignore_missing=False)
+ self.network.delete_ip.assert_called_once_with(
+ self.floating_ips[0]
+ )
+
+
+class TestListFloatingIPNetwork(TestFloatingIPNetwork):
+
+ # The floating ips to list up
+ floating_ips = network_fakes.FakeFloatingIP.create_floating_ips(count=3)
+
+ columns = (
+ 'ID',
+ 'Floating IP Address',
+ 'Fixed IP Address',
+ 'Port',
+ )
+
+ data = []
+ for ip in floating_ips:
+ data.append((
+ ip.id,
+ ip.floating_ip_address,
+ ip.fixed_ip_address,
+ ip.port_id,
+ ))
+
+ def setUp(self):
+ super(TestListFloatingIPNetwork, self).setUp()
+
+ self.network.ips = mock.Mock(return_value=self.floating_ips)
+
+ # Get the command object to test
+ self.cmd = floating_ip.ListFloatingIP(self.app, self.namespace)
+
+ def test_floating_ip_list(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.ips.assert_called_once_with(**{})
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+
+class TestShowFloatingIPNetwork(TestFloatingIPNetwork):
+
+ # The floating ip to display.
+ floating_ip = network_fakes.FakeFloatingIP.create_one_floating_ip()
+
+ columns = (
+ 'dns_domain',
+ 'dns_name',
+ 'fixed_ip_address',
+ 'floating_ip_address',
+ 'floating_network_id',
+ 'id',
+ 'port_id',
+ 'project_id',
+ 'router_id',
+ 'status',
+ )
+
+ data = (
+ floating_ip.dns_domain,
+ floating_ip.dns_name,
+ floating_ip.fixed_ip_address,
+ floating_ip.floating_ip_address,
+ floating_ip.floating_network_id,
+ floating_ip.id,
+ floating_ip.port_id,
+ floating_ip.tenant_id,
+ floating_ip.router_id,
+ floating_ip.status,
+ )
+
+ def setUp(self):
+ super(TestShowFloatingIPNetwork, self).setUp()
+
+ self.network.find_ip = mock.Mock(return_value=self.floating_ip)
+
+ # Get the command object to test
+ self.cmd = floating_ip.ShowFloatingIP(self.app, self.namespace)
+
+ def test_floating_ip_show(self):
+ arglist = [
+ self.floating_ip.id,
+ ]
+ verifylist = [
+ ('floating_ip', self.floating_ip.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.find_ip.assert_called_once_with(
+ self.floating_ip.id,
+ ignore_missing=False
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+# Tests for Nova network
+#
+class TestFloatingIPCompute(compute_fakes.TestComputev2):
+
+ def setUp(self):
+ super(TestFloatingIPCompute, self).setUp()
+
+ # Get a shortcut to the compute client
+ self.compute = self.app.client_manager.compute
+
+
+class TestCreateFloatingIPCompute(TestFloatingIPCompute):
+
+ # The floating ip to be deleted.
+ floating_ip = compute_fakes.FakeFloatingIP.create_one_floating_ip()
+
+ columns = (
+ 'fixed_ip',
+ 'id',
+ 'instance_id',
+ 'ip',
+ 'pool',
+ )
+
+ data = (
+ floating_ip.fixed_ip,
+ floating_ip.id,
+ floating_ip.instance_id,
+ floating_ip.ip,
+ floating_ip.pool,
+ )
+
+ def setUp(self):
+ super(TestCreateFloatingIPCompute, self).setUp()
+
+ self.app.client_manager.network_endpoint_enabled = False
+
+ self.compute.floating_ips.create.return_value = self.floating_ip
+
+ # Get the command object to test
+ self.cmd = floating_ip.CreateFloatingIP(self.app, None)
+
+ def test_create_no_options(self):
+ arglist = []
+ verifylist = []
+
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_create_default_options(self):
+ arglist = [
+ self.floating_ip.pool,
+ ]
+ verifylist = [
+ ('network', self.floating_ip.pool),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.compute.floating_ips.create.assert_called_once_with(
+ self.floating_ip.pool)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestDeleteFloatingIPCompute(TestFloatingIPCompute):
+
+ # The floating ips to be deleted.
+ floating_ips = compute_fakes.FakeFloatingIP.create_floating_ips(count=2)
+
+ def setUp(self):
+ super(TestDeleteFloatingIPCompute, self).setUp()
+
+ self.app.client_manager.network_endpoint_enabled = False
+
+ self.compute.floating_ips.delete.return_value = None
+
+ # Return value of utils.find_resource()
+ self.compute.floating_ips.get = (
+ compute_fakes.FakeFloatingIP.get_floating_ips(self.floating_ips))
+
+ # Get the command object to test
+ self.cmd = floating_ip.DeleteFloatingIP(self.app, None)
+
+ def test_floating_ip_delete(self):
+ arglist = [
+ self.floating_ips[0].id,
+ ]
+ verifylist = [
+ ('floating_ip', [self.floating_ips[0].id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.compute.floating_ips.delete.assert_called_once_with(
+ self.floating_ips[0].id
+ )
+ self.assertIsNone(result)
+
+ def test_multi_floating_ips_delete(self):
+ arglist = []
+ verifylist = []
+
+ for f in self.floating_ips:
+ arglist.append(f.id)
+ verifylist = [
+ ('floating_ip', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for f in self.floating_ips:
+ calls.append(call(f.id))
+ self.compute.floating_ips.delete.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_multi_floating_ips_delete_with_exception(self):
+ arglist = [
+ self.floating_ips[0].id,
+ 'unexist_floating_ip',
+ ]
+ verifylist = [
+ ('floating_ip',
+ [self.floating_ips[0].id, 'unexist_floating_ip']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [self.floating_ips[0], exceptions.CommandError]
+ self.compute.floating_ips.get = (
+ mock.MagicMock(side_effect=find_mock_result)
+ )
+ self.compute.floating_ips.find.side_effect = exceptions.NotFound(None)
+
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 floating_ips failed to delete.', str(e))
+
+ self.compute.floating_ips.get.assert_any_call(
+ self.floating_ips[0].id)
+ self.compute.floating_ips.get.assert_any_call(
+ 'unexist_floating_ip')
+ self.compute.floating_ips.delete.assert_called_once_with(
+ self.floating_ips[0].id
+ )
+
+
+class TestListFloatingIPCompute(TestFloatingIPCompute):
+
+ # The floating ips to be list up
+ floating_ips = compute_fakes.FakeFloatingIP.create_floating_ips(count=3)
+
+ columns = (
+ 'ID',
+ 'Floating IP Address',
+ 'Fixed IP Address',
+ 'Server',
+ 'Pool',
+ )
+
+ data = []
+ for ip in floating_ips:
+ data.append((
+ ip.id,
+ ip.ip,
+ ip.fixed_ip,
+ ip.instance_id,
+ ip.pool,
+ ))
+
+ def setUp(self):
+ super(TestListFloatingIPCompute, self).setUp()
+
+ self.app.client_manager.network_endpoint_enabled = False
+
+ self.compute.floating_ips.list.return_value = self.floating_ips
+
+ # Get the command object to test
+ self.cmd = floating_ip.ListFloatingIP(self.app, None)
+
+ def test_floating_ip_list(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.compute.floating_ips.list.assert_called_once_with()
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+
+class TestShowFloatingIPCompute(TestFloatingIPCompute):
+
+ # The floating ip to display.
+ floating_ip = compute_fakes.FakeFloatingIP.create_one_floating_ip()
+
+ columns = (
+ 'fixed_ip',
+ 'id',
+ 'instance_id',
+ 'ip',
+ 'pool',
+ )
+
+ data = (
+ floating_ip.fixed_ip,
+ floating_ip.id,
+ floating_ip.instance_id,
+ floating_ip.ip,
+ floating_ip.pool,
+ )
+
+ def setUp(self):
+ super(TestShowFloatingIPCompute, self).setUp()
+
+ self.app.client_manager.network_endpoint_enabled = False
+
+ # Return value of utils.find_resource()
+ self.compute.floating_ips.get.return_value = self.floating_ip
+
+ # Get the command object to test
+ self.cmd = floating_ip.ShowFloatingIP(self.app, None)
+
+ def test_floating_ip_show(self):
+ arglist = [
+ self.floating_ip.id,
+ ]
+ verifylist = [
+ ('floating_ip', self.floating_ip.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
diff --git a/openstackclient/tests/unit/network/v2/test_floating_ip_pool.py b/openstackclient/tests/unit/network/v2/test_floating_ip_pool.py
new file mode 100644
index 00000000..11d01d36
--- /dev/null
+++ b/openstackclient/tests/unit/network/v2/test_floating_ip_pool.py
@@ -0,0 +1,97 @@
+# 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 osc_lib import exceptions
+
+from openstackclient.network.v2 import floating_ip_pool
+from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
+from openstackclient.tests.unit.network.v2 import fakes as network_fakes
+
+
+# Tests for Network API v2
+#
+class TestFloatingIPPoolNetwork(network_fakes.TestNetworkV2):
+
+ def setUp(self):
+ super(TestFloatingIPPoolNetwork, self).setUp()
+
+ # Get a shortcut to the network client
+ self.network = self.app.client_manager.network
+
+
+class TestListFloatingIPPoolNetwork(TestFloatingIPPoolNetwork):
+
+ def setUp(self):
+ super(TestListFloatingIPPoolNetwork, self).setUp()
+
+ # Get the command object to test
+ self.cmd = floating_ip_pool.ListFloatingIPPool(self.app,
+ self.namespace)
+
+ def test_floating_ip_list(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(exceptions.CommandError, self.cmd.take_action,
+ parsed_args)
+
+
+# Tests for Compute network
+#
+class TestFloatingIPPoolCompute(compute_fakes.TestComputev2):
+
+ def setUp(self):
+ super(TestFloatingIPPoolCompute, self).setUp()
+
+ # Get a shortcut to the compute client
+ self.compute = self.app.client_manager.compute
+
+
+class TestListFloatingIPPoolCompute(TestFloatingIPPoolCompute):
+
+ # The floating ip pools to list up
+ floating_ip_pools = \
+ compute_fakes.FakeFloatingIPPool.create_floating_ip_pools(count=3)
+
+ columns = (
+ 'Name',
+ )
+
+ data = []
+ for pool in floating_ip_pools:
+ data.append((
+ pool.name,
+ ))
+
+ def setUp(self):
+ super(TestListFloatingIPPoolCompute, self).setUp()
+
+ self.app.client_manager.network_endpoint_enabled = False
+
+ self.compute.floating_ip_pools.list.return_value = \
+ self.floating_ip_pools
+
+ # Get the command object to test
+ self.cmd = floating_ip_pool.ListFloatingIPPool(self.app, None)
+
+ def test_floating_ip_list(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.compute.floating_ip_pools.list.assert_called_once_with()
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
diff --git a/openstackclient/tests/unit/network/v2/test_ip_availability.py b/openstackclient/tests/unit/network/v2/test_ip_availability.py
new file mode 100644
index 00000000..c929ab82
--- /dev/null
+++ b/openstackclient/tests/unit/network/v2/test_ip_availability.py
@@ -0,0 +1,172 @@
+# 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.
+#
+
+import mock
+
+from osc_lib import utils as common_utils
+
+from openstackclient.network.v2 import ip_availability
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+from openstackclient.tests.unit.network.v2 import fakes as network_fakes
+from openstackclient.tests.unit import utils as tests_utils
+
+
+class TestIPAvailability(network_fakes.TestNetworkV2):
+
+ def setUp(self):
+ super(TestIPAvailability, self).setUp()
+
+ # Get a shortcut to the network client
+ self.network = self.app.client_manager.network
+
+ # Get a shortcut to the ProjectManager Mock
+ self.projects_mock = self.app.client_manager.identity.projects
+
+ self.project = identity_fakes.FakeProject.create_one_project()
+ self.projects_mock.get.return_value = self.project
+
+
+class TestListIPAvailability(TestIPAvailability):
+
+ _ip_availability = \
+ network_fakes.FakeIPAvailability.create_ip_availability(count=3)
+ columns = (
+ 'Network ID',
+ 'Network Name',
+ 'Total IPs',
+ 'Used IPs',
+ )
+ data = []
+ for net in _ip_availability:
+ data.append((
+ net.network_id,
+ net.network_name,
+ net.total_ips,
+ net.used_ips,
+ ))
+
+ def setUp(self):
+ super(TestListIPAvailability, self).setUp()
+
+ self.cmd = ip_availability.ListIPAvailability(
+ self.app, self.namespace)
+ self.network.network_ip_availabilities = mock.Mock(
+ return_value=self._ip_availability)
+
+ def test_list_no_options(self):
+ arglist = []
+ verifylist = []
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {'ip_version': 4}
+
+ self.network.network_ip_availabilities.assert_called_once_with(
+ **filters)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_list_ip_version(self):
+ arglist = [
+ '--ip-version', str(4),
+ ]
+ verifylist = [
+ ('ip_version', 4)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {'ip_version': 4}
+
+ self.network.network_ip_availabilities.assert_called_once_with(
+ **filters)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_list_project(self):
+ arglist = [
+ '--project', self.project.name
+ ]
+ verifylist = [
+ ('project', self.project.name)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {'tenant_id': self.project.id,
+ 'ip_version': 4}
+
+ self.network.network_ip_availabilities.assert_called_once_with(
+ **filters)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+
+class TestShowIPAvailability(TestIPAvailability):
+
+ _ip_availability = \
+ network_fakes.FakeIPAvailability.create_one_ip_availability()
+
+ columns = (
+ 'network_id',
+ 'network_name',
+ 'project_id',
+ 'subnet_ip_availability',
+ 'total_ips',
+ 'used_ips',
+ )
+ data = (
+ _ip_availability.network_id,
+ _ip_availability.network_name,
+ _ip_availability.tenant_id,
+ common_utils.format_list(
+ _ip_availability.subnet_ip_availability),
+ _ip_availability.total_ips,
+ _ip_availability.used_ips,
+ )
+
+ def setUp(self):
+ super(TestShowIPAvailability, self).setUp()
+
+ self.network.find_network_ip_availability = mock.Mock(
+ return_value=self._ip_availability)
+
+ # Get the command object to test
+ self.cmd = ip_availability.ShowIPAvailability(
+ self.app, self.namespace)
+
+ def test_show_no_option(self):
+ arglist = []
+ verifylist = []
+
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, arglist, verifylist)
+
+ def test_show_all_options(self):
+ arglist = [
+ self._ip_availability.network_name,
+ ]
+ verifylist = [
+ ('network', self._ip_availability.network_name)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+ self.network.find_network_ip_availability.assert_called_once_with(
+ self._ip_availability.network_name,
+ ignore_missing=False)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
diff --git a/openstackclient/tests/unit/network/v2/test_network.py b/openstackclient/tests/unit/network/v2/test_network.py
new file mode 100644
index 00000000..84ead093
--- /dev/null
+++ b/openstackclient/tests/unit/network/v2/test_network.py
@@ -0,0 +1,1059 @@
+# 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.
+#
+
+import mock
+from mock import call
+
+from osc_lib import exceptions
+from osc_lib import utils
+
+from openstackclient.network.v2 import network
+from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit.identity.v2_0 import fakes as identity_fakes_v2
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes_v3
+from openstackclient.tests.unit.network.v2 import fakes as network_fakes
+from openstackclient.tests.unit import utils as tests_utils
+
+
+# Tests for Neutron network
+#
+class TestNetwork(network_fakes.TestNetworkV2):
+
+ def setUp(self):
+ super(TestNetwork, self).setUp()
+
+ # Get a shortcut to the network client
+ self.network = self.app.client_manager.network
+ # Get a shortcut to the ProjectManager Mock
+ self.projects_mock = self.app.client_manager.identity.projects
+ # Get a shortcut to the DomainManager Mock
+ self.domains_mock = self.app.client_manager.identity.domains
+
+
+class TestCreateNetworkIdentityV3(TestNetwork):
+
+ project = identity_fakes_v3.FakeProject.create_one_project()
+ domain = identity_fakes_v3.FakeDomain.create_one_domain()
+ # The new network created.
+ _network = network_fakes.FakeNetwork.create_one_network(
+ attrs={
+ 'tenant_id': project.id,
+ 'availability_zone_hints': ["nova"],
+ }
+ )
+
+ columns = (
+ 'admin_state_up',
+ 'availability_zone_hints',
+ 'availability_zones',
+ 'id',
+ 'is_default',
+ 'name',
+ 'port_security_enabled',
+ 'project_id',
+ 'provider_network_type',
+ 'router:external',
+ 'shared',
+ 'status',
+ 'subnets',
+ )
+
+ data = (
+ network._format_admin_state(_network.admin_state_up),
+ utils.format_list(_network.availability_zone_hints),
+ utils.format_list(_network.availability_zones),
+ _network.id,
+ _network.is_default,
+ _network.name,
+ _network.is_port_security_enabled,
+ _network.project_id,
+ _network.provider_network_type,
+ network._format_router_external(_network.is_router_external),
+ _network.shared,
+ _network.status,
+ utils.format_list(_network.subnets),
+ )
+
+ def setUp(self):
+ super(TestCreateNetworkIdentityV3, self).setUp()
+
+ self.network.create_network = mock.Mock(return_value=self._network)
+
+ # Get the command object to test
+ self.cmd = network.CreateNetwork(self.app, self.namespace)
+
+ self.projects_mock.get.return_value = self.project
+ self.domains_mock.get.return_value = self.domain
+
+ def test_create_no_options(self):
+ arglist = []
+ verifylist = []
+
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_create_default_options(self):
+ arglist = [
+ self._network.name,
+ ]
+ verifylist = [
+ ('name', self._network.name),
+ ('enable', True),
+ ('share', None),
+ ('project', None),
+ ('external', False),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_network.assert_called_once_with(**{
+ 'admin_state_up': True,
+ 'name': self._network.name,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_create_all_options(self):
+ arglist = [
+ "--disable",
+ "--share",
+ "--project", self.project.name,
+ "--project-domain", self.domain.name,
+ "--availability-zone-hint", "nova",
+ "--external", "--default",
+ "--provider-network-type", "vlan",
+ "--provider-physical-network", "physnet1",
+ "--provider-segment", "400",
+ "--transparent-vlan",
+ "--enable-port-security",
+ self._network.name,
+ ]
+ verifylist = [
+ ('disable', True),
+ ('share', True),
+ ('project', self.project.name),
+ ('project_domain', self.domain.name),
+ ('availability_zone_hints', ["nova"]),
+ ('external', True),
+ ('default', True),
+ ('provider_network_type', 'vlan'),
+ ('physical_network', 'physnet1'),
+ ('segmentation_id', '400'),
+ ('transparent_vlan', True),
+ ('enable_port_security', True),
+ ('name', self._network.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = (self.cmd.take_action(parsed_args))
+
+ self.network.create_network.assert_called_once_with(**{
+ 'admin_state_up': False,
+ 'availability_zone_hints': ["nova"],
+ 'name': self._network.name,
+ 'shared': True,
+ 'tenant_id': self.project.id,
+ 'is_default': True,
+ 'router:external': True,
+ 'provider:network_type': 'vlan',
+ 'provider:physical_network': 'physnet1',
+ 'provider:segmentation_id': '400',
+ 'vlan_transparent': True,
+ 'port_security_enabled': True,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_create_other_options(self):
+ arglist = [
+ "--enable",
+ "--no-share",
+ "--disable-port-security",
+ self._network.name,
+ ]
+ verifylist = [
+ ('enable', True),
+ ('no_share', True),
+ ('name', self._network.name),
+ ('external', False),
+ ('disable_port_security', True),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_network.assert_called_once_with(**{
+ 'admin_state_up': True,
+ 'name': self._network.name,
+ 'shared': False,
+ 'port_security_enabled': False,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestCreateNetworkIdentityV2(TestNetwork):
+
+ project = identity_fakes_v2.FakeProject.create_one_project()
+ # The new network created.
+ _network = network_fakes.FakeNetwork.create_one_network(
+ attrs={'tenant_id': project.id}
+ )
+
+ columns = (
+ 'admin_state_up',
+ 'availability_zone_hints',
+ 'availability_zones',
+ 'id',
+ 'is_default',
+ 'name',
+ 'port_security_enabled',
+ 'project_id',
+ 'provider_network_type',
+ 'router:external',
+ 'shared',
+ 'status',
+ 'subnets',
+ )
+
+ data = (
+ network._format_admin_state(_network.admin_state_up),
+ utils.format_list(_network.availability_zone_hints),
+ utils.format_list(_network.availability_zones),
+ _network.id,
+ _network.is_default,
+ _network.name,
+ _network.is_port_security_enabled,
+ _network.project_id,
+ _network.provider_network_type,
+ network._format_router_external(_network.is_router_external),
+ _network.shared,
+ _network.status,
+ utils.format_list(_network.subnets),
+ )
+
+ def setUp(self):
+ super(TestCreateNetworkIdentityV2, self).setUp()
+
+ self.network.create_network = mock.Mock(return_value=self._network)
+
+ # Get the command object to test
+ self.cmd = network.CreateNetwork(self.app, self.namespace)
+
+ # Set identity client v2. And get a shortcut to Identity client.
+ identity_client = identity_fakes_v2.FakeIdentityv2Client(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN,
+ )
+ self.app.client_manager.identity = identity_client
+ self.identity = self.app.client_manager.identity
+
+ # Get a shortcut to the ProjectManager Mock
+ self.projects_mock = self.identity.tenants
+ self.projects_mock.get.return_value = self.project
+
+ # There is no DomainManager Mock in fake identity v2.
+
+ def test_create_with_project_identityv2(self):
+ arglist = [
+ "--project", self.project.name,
+ self._network.name,
+ ]
+ verifylist = [
+ ('enable', True),
+ ('share', None),
+ ('name', self._network.name),
+ ('project', self.project.name),
+ ('external', False),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_network.assert_called_once_with(**{
+ 'admin_state_up': True,
+ 'name': self._network.name,
+ 'tenant_id': self.project.id,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_create_with_domain_identityv2(self):
+ arglist = [
+ "--project", self.project.name,
+ "--project-domain", "domain-name",
+ self._network.name,
+ ]
+ verifylist = [
+ ('enable', True),
+ ('share', None),
+ ('project', self.project.name),
+ ('project_domain', "domain-name"),
+ ('name', self._network.name),
+ ('external', False),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(
+ AttributeError,
+ self.cmd.take_action,
+ parsed_args,
+ )
+
+
+class TestDeleteNetwork(TestNetwork):
+
+ def setUp(self):
+ super(TestDeleteNetwork, self).setUp()
+
+ # The networks to delete
+ self._networks = network_fakes.FakeNetwork.create_networks(count=3)
+
+ self.network.delete_network = mock.Mock(return_value=None)
+
+ self.network.find_network = network_fakes.FakeNetwork.get_networks(
+ networks=self._networks)
+
+ # Get the command object to test
+ self.cmd = network.DeleteNetwork(self.app, self.namespace)
+
+ def test_delete_one_network(self):
+ arglist = [
+ self._networks[0].name,
+ ]
+ verifylist = [
+ ('network', [self._networks[0].name]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.network.delete_network.assert_called_once_with(self._networks[0])
+ self.assertIsNone(result)
+
+ def test_delete_multiple_networks(self):
+ arglist = []
+ for n in self._networks:
+ arglist.append(n.id)
+ verifylist = [
+ ('network', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for n in self._networks:
+ calls.append(call(n))
+ self.network.delete_network.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_delete_multiple_networks_exception(self):
+ arglist = [
+ self._networks[0].id,
+ 'xxxx-yyyy-zzzz',
+ self._networks[1].id,
+ ]
+ verifylist = [
+ ('network', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # Fake exception in find_network()
+ ret_find = [
+ self._networks[0],
+ exceptions.NotFound('404'),
+ self._networks[1],
+ ]
+ self.network.find_network = mock.Mock(side_effect=ret_find)
+
+ # Fake exception in delete_network()
+ ret_delete = [
+ None,
+ exceptions.NotFound('404'),
+ ]
+ self.network.delete_network = mock.Mock(side_effect=ret_delete)
+
+ self.assertRaises(exceptions.CommandError, self.cmd.take_action,
+ parsed_args)
+
+ # The second call of find_network() should fail. So delete_network()
+ # was only called twice.
+ calls = [
+ call(self._networks[0]),
+ call(self._networks[1]),
+ ]
+ self.network.delete_network.assert_has_calls(calls)
+
+
+class TestListNetwork(TestNetwork):
+
+ # The networks going to be listed up.
+ _network = network_fakes.FakeNetwork.create_networks(count=3)
+
+ columns = (
+ 'ID',
+ 'Name',
+ 'Subnets',
+ )
+ columns_long = (
+ 'ID',
+ 'Name',
+ 'Status',
+ 'Project',
+ 'State',
+ 'Shared',
+ 'Subnets',
+ 'Network Type',
+ 'Router Type',
+ 'Availability Zones',
+ )
+
+ data = []
+ for net in _network:
+ data.append((
+ net.id,
+ net.name,
+ utils.format_list(net.subnets),
+ ))
+
+ data_long = []
+ for net in _network:
+ data_long.append((
+ net.id,
+ net.name,
+ net.status,
+ net.project_id,
+ network._format_admin_state(net.admin_state_up),
+ net.shared,
+ utils.format_list(net.subnets),
+ net.provider_network_type,
+ network._format_router_external(net.is_router_external),
+ utils.format_list(net.availability_zones),
+ ))
+
+ def setUp(self):
+ super(TestListNetwork, self).setUp()
+
+ # Get the command object to test
+ self.cmd = network.ListNetwork(self.app, self.namespace)
+
+ self.network.networks = mock.Mock(return_value=self._network)
+
+ def test_network_list_no_options(self):
+ arglist = []
+ verifylist = [
+ ('external', False),
+ ('long', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.networks.assert_called_once_with()
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_list_external(self):
+ arglist = [
+ '--external',
+ ]
+ verifylist = [
+ ('external', True),
+ ('long', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.networks.assert_called_once_with(
+ **{'router:external': True}
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_network_list_long(self):
+ arglist = [
+ '--long',
+ ]
+ verifylist = [
+ ('long', True),
+ ('external', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.networks.assert_called_once_with()
+ self.assertEqual(self.columns_long, columns)
+ self.assertEqual(self.data_long, list(data))
+
+
+class TestSetNetwork(TestNetwork):
+
+ # The network to set.
+ _network = network_fakes.FakeNetwork.create_one_network()
+
+ def setUp(self):
+ super(TestSetNetwork, self).setUp()
+
+ self.network.update_network = mock.Mock(return_value=None)
+
+ self.network.find_network = mock.Mock(return_value=self._network)
+
+ # Get the command object to test
+ self.cmd = network.SetNetwork(self.app, self.namespace)
+
+ def test_set_this(self):
+ arglist = [
+ self._network.name,
+ '--enable',
+ '--name', 'noob',
+ '--share',
+ '--external',
+ '--default',
+ '--provider-network-type', 'vlan',
+ '--provider-physical-network', 'physnet1',
+ '--provider-segment', '400',
+ '--no-transparent-vlan',
+ '--enable-port-security',
+ ]
+ verifylist = [
+ ('network', self._network.name),
+ ('enable', True),
+ ('name', 'noob'),
+ ('share', True),
+ ('external', True),
+ ('default', True),
+ ('provider_network_type', 'vlan'),
+ ('physical_network', 'physnet1'),
+ ('segmentation_id', '400'),
+ ('no_transparent_vlan', True),
+ ('enable_port_security', True),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'name': 'noob',
+ 'admin_state_up': True,
+ 'shared': True,
+ 'router:external': True,
+ 'is_default': True,
+ 'provider:network_type': 'vlan',
+ 'provider:physical_network': 'physnet1',
+ 'provider:segmentation_id': '400',
+ 'vlan_transparent': False,
+ 'port_security_enabled': True,
+ }
+ self.network.update_network.assert_called_once_with(
+ self._network, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_that(self):
+ arglist = [
+ self._network.name,
+ '--disable',
+ '--no-share',
+ '--internal',
+ '--disable-port-security',
+ ]
+ verifylist = [
+ ('network', self._network.name),
+ ('disable', True),
+ ('no_share', True),
+ ('internal', True),
+ ('disable_port_security', True),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'admin_state_up': False,
+ 'shared': False,
+ 'router:external': False,
+ 'port_security_enabled': False,
+ }
+ self.network.update_network.assert_called_once_with(
+ self._network, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_nothing(self):
+ arglist = [self._network.name, ]
+ verifylist = [('network', self._network.name), ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {}
+ self.network.update_network.assert_called_once_with(
+ self._network, **attrs)
+ self.assertIsNone(result)
+
+
+class TestShowNetwork(TestNetwork):
+
+ # The network to show.
+ _network = network_fakes.FakeNetwork.create_one_network()
+
+ columns = (
+ 'admin_state_up',
+ 'availability_zone_hints',
+ 'availability_zones',
+ 'id',
+ 'is_default',
+ 'name',
+ 'port_security_enabled',
+ 'project_id',
+ 'provider_network_type',
+ 'router:external',
+ 'shared',
+ 'status',
+ 'subnets',
+ )
+
+ data = (
+ network._format_admin_state(_network.admin_state_up),
+ utils.format_list(_network.availability_zone_hints),
+ utils.format_list(_network.availability_zones),
+ _network.id,
+ _network.is_default,
+ _network.name,
+ _network.is_port_security_enabled,
+ _network.project_id,
+ _network.provider_network_type,
+ network._format_router_external(_network.is_router_external),
+ _network.shared,
+ _network.status,
+ utils.format_list(_network.subnets),
+ )
+
+ def setUp(self):
+ super(TestShowNetwork, self).setUp()
+
+ self.network.find_network = mock.Mock(return_value=self._network)
+
+ # Get the command object to test
+ self.cmd = network.ShowNetwork(self.app, self.namespace)
+
+ def test_show_no_options(self):
+ arglist = []
+ verifylist = []
+
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_show_all_options(self):
+ arglist = [
+ self._network.name,
+ ]
+ verifylist = [
+ ('network', self._network.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.find_network.assert_called_once_with(
+ self._network.name, ignore_missing=False)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+# Tests for Nova network
+#
+class TestNetworkCompute(compute_fakes.TestComputev2):
+
+ def setUp(self):
+ super(TestNetworkCompute, self).setUp()
+
+ # Get a shortcut to the compute client
+ self.compute = self.app.client_manager.compute
+
+
+class TestCreateNetworkCompute(TestNetworkCompute):
+
+ # The network to create.
+ _network = compute_fakes.FakeNetwork.create_one_network()
+
+ columns = (
+ 'bridge',
+ 'bridge_interface',
+ 'broadcast',
+ 'cidr',
+ 'cidr_v6',
+ 'created_at',
+ 'deleted',
+ 'deleted_at',
+ 'dhcp_server',
+ 'dhcp_start',
+ 'dns1',
+ 'dns2',
+ 'enable_dhcp',
+ 'gateway',
+ 'gateway_v6',
+ 'host',
+ 'id',
+ 'injected',
+ 'label',
+ 'mtu',
+ 'multi_host',
+ 'netmask',
+ 'netmask_v6',
+ 'priority',
+ 'project_id',
+ 'rxtx_base',
+ 'share_address',
+ 'updated_at',
+ 'vlan',
+ 'vpn_private_address',
+ 'vpn_public_address',
+ 'vpn_public_port',
+ )
+
+ data = (
+ _network.bridge,
+ _network.bridge_interface,
+ _network.broadcast,
+ _network.cidr,
+ _network.cidr_v6,
+ _network.created_at,
+ _network.deleted,
+ _network.deleted_at,
+ _network.dhcp_server,
+ _network.dhcp_start,
+ _network.dns1,
+ _network.dns2,
+ _network.enable_dhcp,
+ _network.gateway,
+ _network.gateway_v6,
+ _network.host,
+ _network.id,
+ _network.injected,
+ _network.label,
+ _network.mtu,
+ _network.multi_host,
+ _network.netmask,
+ _network.netmask_v6,
+ _network.priority,
+ _network.project_id,
+ _network.rxtx_base,
+ _network.share_address,
+ _network.updated_at,
+ _network.vlan,
+ _network.vpn_private_address,
+ _network.vpn_public_address,
+ _network.vpn_public_port,
+ )
+
+ def setUp(self):
+ super(TestCreateNetworkCompute, self).setUp()
+
+ self.app.client_manager.network_endpoint_enabled = False
+
+ self.compute.networks.create.return_value = self._network
+
+ # Get the command object to test
+ self.cmd = network.CreateNetwork(self.app, None)
+
+ def test_create_no_options(self):
+ arglist = []
+ verifylist = []
+
+ # Missing required args should raise exception here
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_create_default_options(self):
+ arglist = [
+ "--subnet", self._network.cidr,
+ self._network.label,
+ ]
+ verifylist = [
+ ('subnet', self._network.cidr),
+ ('name', self._network.label),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.compute.networks.create.assert_called_once_with(**{
+ 'cidr': self._network.cidr,
+ 'label': self._network.label,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestDeleteNetworkCompute(TestNetworkCompute):
+
+ def setUp(self):
+ super(TestDeleteNetworkCompute, self).setUp()
+
+ self.app.client_manager.network_endpoint_enabled = False
+
+ # The networks to delete
+ self._networks = compute_fakes.FakeNetwork.create_networks(count=3)
+
+ self.compute.networks.delete.return_value = None
+
+ # Return value of utils.find_resource()
+ self.compute.networks.get = \
+ compute_fakes.FakeNetwork.get_networks(networks=self._networks)
+
+ # Get the command object to test
+ self.cmd = network.DeleteNetwork(self.app, None)
+
+ def test_delete_one_network(self):
+ arglist = [
+ self._networks[0].label,
+ ]
+ verifylist = [
+ ('network', [self._networks[0].label]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.compute.networks.delete.assert_called_once_with(
+ self._networks[0].id)
+ self.assertIsNone(result)
+
+ def test_delete_multiple_networks(self):
+ arglist = []
+ for n in self._networks:
+ arglist.append(n.label)
+ verifylist = [
+ ('network', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for n in self._networks:
+ calls.append(call(n.id))
+ self.compute.networks.delete.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_delete_multiple_networks_exception(self):
+ arglist = [
+ self._networks[0].id,
+ 'xxxx-yyyy-zzzz',
+ self._networks[1].id,
+ ]
+ verifylist = [
+ ('network', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # Fake exception in utils.find_resource()
+ # In compute v2, we use utils.find_resource() to find a network.
+ # It calls get() several times, but find() only one time. So we
+ # choose to fake get() always raise exception, then pass through.
+ # And fake find() to find the real network or not.
+ self.compute.networks.get.side_effect = Exception()
+ ret_find = [
+ self._networks[0],
+ Exception(),
+ self._networks[1],
+ ]
+ self.compute.networks.find.side_effect = ret_find
+
+ # Fake exception in delete()
+ ret_delete = [
+ None,
+ Exception(),
+ ]
+ self.compute.networks.delete = mock.Mock(side_effect=ret_delete)
+
+ self.assertRaises(exceptions.CommandError, self.cmd.take_action,
+ parsed_args)
+
+ # The second call of utils.find_resource() should fail. So delete()
+ # was only called twice.
+ calls = [
+ call(self._networks[0].id),
+ call(self._networks[1].id),
+ ]
+ self.compute.networks.delete.assert_has_calls(calls)
+
+
+class TestListNetworkCompute(TestNetworkCompute):
+
+ # The networks going to be listed up.
+ _networks = compute_fakes.FakeNetwork.create_networks(count=3)
+
+ columns = (
+ 'ID',
+ 'Name',
+ 'Subnet',
+ )
+
+ data = []
+ for net in _networks:
+ data.append((
+ net.id,
+ net.label,
+ net.cidr,
+ ))
+
+ def setUp(self):
+ super(TestListNetworkCompute, self).setUp()
+
+ self.app.client_manager.network_endpoint_enabled = False
+
+ self.compute.networks.list.return_value = self._networks
+
+ # Get the command object to test
+ self.cmd = network.ListNetwork(self.app, None)
+
+ def test_network_list_no_options(self):
+ arglist = []
+ verifylist = [
+ ('external', False),
+ ('long', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.compute.networks.list.assert_called_once_with()
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+
+class TestShowNetworkCompute(TestNetworkCompute):
+
+ # The network to show.
+ _network = compute_fakes.FakeNetwork.create_one_network()
+
+ columns = (
+ 'bridge',
+ 'bridge_interface',
+ 'broadcast',
+ 'cidr',
+ 'cidr_v6',
+ 'created_at',
+ 'deleted',
+ 'deleted_at',
+ 'dhcp_server',
+ 'dhcp_start',
+ 'dns1',
+ 'dns2',
+ 'enable_dhcp',
+ 'gateway',
+ 'gateway_v6',
+ 'host',
+ 'id',
+ 'injected',
+ 'label',
+ 'mtu',
+ 'multi_host',
+ 'netmask',
+ 'netmask_v6',
+ 'priority',
+ 'project_id',
+ 'rxtx_base',
+ 'share_address',
+ 'updated_at',
+ 'vlan',
+ 'vpn_private_address',
+ 'vpn_public_address',
+ 'vpn_public_port',
+ )
+
+ data = (
+ _network.bridge,
+ _network.bridge_interface,
+ _network.broadcast,
+ _network.cidr,
+ _network.cidr_v6,
+ _network.created_at,
+ _network.deleted,
+ _network.deleted_at,
+ _network.dhcp_server,
+ _network.dhcp_start,
+ _network.dns1,
+ _network.dns2,
+ _network.enable_dhcp,
+ _network.gateway,
+ _network.gateway_v6,
+ _network.host,
+ _network.id,
+ _network.injected,
+ _network.label,
+ _network.mtu,
+ _network.multi_host,
+ _network.netmask,
+ _network.netmask_v6,
+ _network.priority,
+ _network.project_id,
+ _network.rxtx_base,
+ _network.share_address,
+ _network.updated_at,
+ _network.vlan,
+ _network.vpn_private_address,
+ _network.vpn_public_address,
+ _network.vpn_public_port,
+ )
+
+ def setUp(self):
+ super(TestShowNetworkCompute, self).setUp()
+
+ self.app.client_manager.network_endpoint_enabled = False
+
+ # Return value of utils.find_resource()
+ self.compute.networks.get.return_value = self._network
+
+ # Get the command object to test
+ self.cmd = network.ShowNetwork(self.app, None)
+
+ def test_show_no_options(self):
+ arglist = []
+ verifylist = []
+
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_show_all_options(self):
+ arglist = [
+ self._network.label,
+ ]
+ verifylist = [
+ ('network', self._network.label),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
diff --git a/openstackclient/tests/unit/network/v2/test_network_agent.py b/openstackclient/tests/unit/network/v2/test_network_agent.py
new file mode 100644
index 00000000..2f17f41b
--- /dev/null
+++ b/openstackclient/tests/unit/network/v2/test_network_agent.py
@@ -0,0 +1,294 @@
+# 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.
+#
+
+import mock
+from mock import call
+
+from osc_lib import exceptions
+from osc_lib import utils
+
+from openstackclient.network.v2 import network_agent
+from openstackclient.tests.unit.network.v2 import fakes as network_fakes
+from openstackclient.tests.unit import utils as tests_utils
+
+
+class TestNetworkAgent(network_fakes.TestNetworkV2):
+
+ def setUp(self):
+ super(TestNetworkAgent, self).setUp()
+
+ # Get a shortcut to the network client
+ self.network = self.app.client_manager.network
+
+
+class TestDeleteNetworkAgent(TestNetworkAgent):
+
+ network_agents = (
+ network_fakes.FakeNetworkAgent.create_network_agents(count=2))
+
+ def setUp(self):
+ super(TestDeleteNetworkAgent, self).setUp()
+ self.network.delete_agent = mock.Mock(return_value=None)
+ self.network.get_agent = (
+ network_fakes.FakeNetworkAgent.get_network_agents(
+ agents=self.network_agents)
+ )
+
+ # Get the command object to test
+ self.cmd = network_agent.DeleteNetworkAgent(self.app, self.namespace)
+
+ def test_network_agent_delete(self):
+ arglist = [
+ self.network_agents[0].id,
+ ]
+ verifylist = [
+ ('network_agent', [self.network_agents[0].id]),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.network.get_agent.assert_called_once_with(
+ self.network_agents[0].id, ignore_missing=False)
+ self.network.delete_agent.assert_called_once_with(
+ self.network_agents[0])
+ self.assertIsNone(result)
+
+ def test_multi_network_agents_delete(self):
+ arglist = []
+ verifylist = []
+
+ for n in self.network_agents:
+ arglist.append(n.id)
+ verifylist = [
+ ('network_agent', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for n in self.network_agents:
+ calls.append(call(n))
+ self.network.delete_agent.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_multi_network_agents_delete_with_exception(self):
+ arglist = [
+ self.network_agents[0].id,
+ 'unexist_network_agent',
+ ]
+ verifylist = [
+ ('network_agent',
+ [self.network_agents[0].id, 'unexist_network_agent']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [self.network_agents[0], exceptions.CommandError]
+ self.network.get_agent = (
+ mock.MagicMock(side_effect=find_mock_result)
+ )
+
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 network agents failed to delete.', str(e))
+
+ self.network.get_agent.assert_any_call(
+ self.network_agents[0].id, ignore_missing=False)
+ self.network.get_agent.assert_any_call(
+ 'unexist_network_agent', ignore_missing=False)
+ self.network.delete_agent.assert_called_once_with(
+ self.network_agents[0]
+ )
+
+
+class TestListNetworkAgent(TestNetworkAgent):
+
+ network_agents = (
+ network_fakes.FakeNetworkAgent.create_network_agents(count=3))
+
+ columns = (
+ 'ID',
+ 'Agent Type',
+ 'Host',
+ 'Availability Zone',
+ 'Alive',
+ 'State',
+ 'Binary'
+ )
+ data = []
+ for agent in network_agents:
+ data.append((
+ agent.id,
+ agent.agent_type,
+ agent.host,
+ agent.availability_zone,
+ agent.alive,
+ network_agent._format_admin_state(agent.admin_state_up),
+ agent.binary,
+ ))
+
+ def setUp(self):
+ super(TestListNetworkAgent, self).setUp()
+ self.network.agents = mock.Mock(
+ return_value=self.network_agents)
+
+ # Get the command object to test
+ self.cmd = network_agent.ListNetworkAgent(self.app, self.namespace)
+
+ def test_network_agents_list(self):
+ arglist = []
+ verifylist = []
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.agents.assert_called_once_with(**{})
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+
+class TestSetNetworkAgent(TestNetworkAgent):
+
+ _network_agent = (
+ network_fakes.FakeNetworkAgent.create_one_network_agent())
+
+ def setUp(self):
+ super(TestSetNetworkAgent, self).setUp()
+ self.network.update_agent = mock.Mock(return_value=None)
+ self.network.get_agent = mock.Mock(return_value=self._network_agent)
+
+ # Get the command object to test
+ self.cmd = network_agent.SetNetworkAgent(self.app, self.namespace)
+
+ def test_set_nothing(self):
+ arglist = [
+ self._network_agent.id,
+ ]
+ verifylist = [
+ ('network_agent', self._network_agent.id),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {}
+ self.network.update_agent.assert_called_once_with(
+ self._network_agent, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_all(self):
+ arglist = [
+ '--description', 'new_description',
+ '--enable',
+ self._network_agent.id,
+ ]
+ verifylist = [
+ ('description', 'new_description'),
+ ('enable', True),
+ ('disable', False),
+ ('network_agent', self._network_agent.id),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'description': 'new_description',
+ 'admin_state_up': True,
+ }
+ self.network.update_agent.assert_called_once_with(
+ self._network_agent, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_with_disable(self):
+ arglist = [
+ '--disable',
+ self._network_agent.id,
+ ]
+ verifylist = [
+ ('enable', False),
+ ('disable', True),
+ ('network_agent', self._network_agent.id),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'admin_state_up': False,
+ }
+ self.network.update_agent.assert_called_once_with(
+ self._network_agent, **attrs)
+ self.assertIsNone(result)
+
+
+class TestShowNetworkAgent(TestNetworkAgent):
+
+ _network_agent = (
+ network_fakes.FakeNetworkAgent.create_one_network_agent())
+
+ columns = (
+ 'admin_state_up',
+ 'agent_type',
+ 'alive',
+ 'availability_zone',
+ 'binary',
+ 'configurations',
+ 'host',
+ 'id',
+ )
+ data = (
+ network_agent._format_admin_state(_network_agent.admin_state_up),
+ _network_agent.agent_type,
+ _network_agent.alive,
+ _network_agent.availability_zone,
+ _network_agent.binary,
+ utils.format_dict(_network_agent.configurations),
+ _network_agent.host,
+ _network_agent.id,
+ )
+
+ def setUp(self):
+ super(TestShowNetworkAgent, self).setUp()
+ self.network.get_agent = mock.Mock(
+ return_value=self._network_agent)
+
+ # Get the command object to test
+ self.cmd = network_agent.ShowNetworkAgent(self.app, self.namespace)
+
+ def test_show_no_options(self):
+ arglist = []
+ verifylist = []
+
+ # Missing required args should bail here
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_show_all_options(self):
+ arglist = [
+ self._network_agent.id,
+ ]
+ verifylist = [
+ ('network_agent', self._network_agent.id),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.get_agent.assert_called_once_with(
+ self._network_agent.id, ignore_missing=False)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(list(self.data), list(data))
diff --git a/openstackclient/tests/unit/network/v2/test_network_rbac.py b/openstackclient/tests/unit/network/v2/test_network_rbac.py
new file mode 100644
index 00000000..1cd18a09
--- /dev/null
+++ b/openstackclient/tests/unit/network/v2/test_network_rbac.py
@@ -0,0 +1,430 @@
+# 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.
+#
+
+import mock
+from mock import call
+
+from osc_lib import exceptions
+
+from openstackclient.network.v2 import network_rbac
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes_v3
+from openstackclient.tests.unit.network.v2 import fakes as network_fakes
+from openstackclient.tests.unit import utils as tests_utils
+
+
+class TestNetworkRBAC(network_fakes.TestNetworkV2):
+
+ def setUp(self):
+ super(TestNetworkRBAC, self).setUp()
+
+ # Get a shortcut to the network client
+ self.network = self.app.client_manager.network
+ # Get a shortcut to the ProjectManager Mock
+ self.projects_mock = self.app.client_manager.identity.projects
+
+
+class TestCreateNetworkRBAC(TestNetworkRBAC):
+
+ network_object = network_fakes.FakeNetwork.create_one_network()
+ project = identity_fakes_v3.FakeProject.create_one_project()
+ rbac_policy = network_fakes.FakeNetworkRBAC.create_one_network_rbac(
+ attrs={'tenant_id': project.id,
+ 'target_tenant': project.id,
+ 'object_id': network_object.id}
+ )
+
+ columns = (
+ 'action',
+ 'id',
+ 'object_id',
+ 'object_type',
+ 'project_id',
+ 'target_project_id',
+ )
+
+ data = [
+ rbac_policy.action,
+ rbac_policy.id,
+ rbac_policy.object_id,
+ rbac_policy.object_type,
+ rbac_policy.tenant_id,
+ rbac_policy.target_tenant,
+ ]
+
+ def setUp(self):
+ super(TestCreateNetworkRBAC, self).setUp()
+
+ # Get the command object to test
+ self.cmd = network_rbac.CreateNetworkRBAC(self.app, self.namespace)
+
+ self.network.create_rbac_policy = mock.Mock(
+ return_value=self.rbac_policy)
+ self.network.find_network = mock.Mock(
+ return_value=self.network_object)
+ self.projects_mock.get.return_value = self.project
+
+ def test_network_rbac_create_no_type(self):
+ arglist = [
+ '--action', self.rbac_policy.action,
+ self.rbac_policy.object_id,
+ ]
+ verifylist = [
+ ('action', self.rbac_policy.action),
+ ('rbac_policy', self.rbac_policy.id),
+ ]
+
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_network_rbac_create_no_action(self):
+ arglist = [
+ '--type', self.rbac_policy.object_type,
+ self.rbac_policy.object_id,
+ ]
+ verifylist = [
+ ('type', self.rbac_policy.object_type),
+ ('rbac_policy', self.rbac_policy.id),
+ ]
+
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_network_rbac_create_invalid_type(self):
+ arglist = [
+ '--action', self.rbac_policy.action,
+ '--type', 'invalid_type',
+ '--target-project', self.rbac_policy.target_tenant,
+ self.rbac_policy.object_id,
+ ]
+ verifylist = [
+ ('action', self.rbac_policy.action),
+ ('type', 'invalid_type'),
+ ('target-project', self.rbac_policy.target_tenant),
+ ('rbac_policy', self.rbac_policy.id),
+ ]
+
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_network_rbac_create_invalid_action(self):
+ arglist = [
+ '--type', self.rbac_policy.object_type,
+ '--action', 'invalid_action',
+ '--target-project', self.rbac_policy.target_tenant,
+ self.rbac_policy.object_id,
+ ]
+ verifylist = [
+ ('type', self.rbac_policy.object_type),
+ ('action', 'invalid_action'),
+ ('target-project', self.rbac_policy.target_tenant),
+ ('rbac_policy', self.rbac_policy.id),
+ ]
+
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_network_rbac_create(self):
+ arglist = [
+ '--type', self.rbac_policy.object_type,
+ '--action', self.rbac_policy.action,
+ '--target-project', self.rbac_policy.target_tenant,
+ self.rbac_policy.object_id,
+ ]
+ verifylist = [
+ ('type', self.rbac_policy.object_type),
+ ('action', self.rbac_policy.action),
+ ('target_project', self.rbac_policy.target_tenant),
+ ('rbac_object', self.rbac_policy.object_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # DisplayCommandBase.take_action() returns two tuples
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_rbac_policy.assert_called_with(**{
+ 'object_id': self.rbac_policy.object_id,
+ 'object_type': self.rbac_policy.object_type,
+ 'action': self.rbac_policy.action,
+ 'target_tenant': self.rbac_policy.target_tenant,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_network_rbac_create_all_options(self):
+ arglist = [
+ '--type', self.rbac_policy.object_type,
+ '--action', self.rbac_policy.action,
+ '--target-project', self.rbac_policy.target_tenant,
+ '--project', self.rbac_policy.tenant_id,
+ '--project-domain', self.project.domain_id,
+ '--target-project-domain', self.project.domain_id,
+ self.rbac_policy.object_id,
+ ]
+ verifylist = [
+ ('type', self.rbac_policy.object_type),
+ ('action', self.rbac_policy.action),
+ ('target_project', self.rbac_policy.target_tenant),
+ ('project', self.rbac_policy.tenant_id),
+ ('project_domain', self.project.domain_id),
+ ('target_project_domain', self.project.domain_id),
+ ('rbac_object', self.rbac_policy.object_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # DisplayCommandBase.take_action() returns two tuples
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_rbac_policy.assert_called_with(**{
+ 'object_id': self.rbac_policy.object_id,
+ 'object_type': self.rbac_policy.object_type,
+ 'action': self.rbac_policy.action,
+ 'target_tenant': self.rbac_policy.target_tenant,
+ 'tenant_id': self.rbac_policy.tenant_id,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+
+class TestDeleteNetworkRBAC(TestNetworkRBAC):
+
+ rbac_policies = network_fakes.FakeNetworkRBAC.create_network_rbacs(count=2)
+
+ def setUp(self):
+ super(TestDeleteNetworkRBAC, self).setUp()
+ self.network.delete_rbac_policy = mock.Mock(return_value=None)
+ self.network.find_rbac_policy = (
+ network_fakes.FakeNetworkRBAC.get_network_rbacs(
+ rbac_policies=self.rbac_policies)
+ )
+
+ # Get the command object to test
+ self.cmd = network_rbac.DeleteNetworkRBAC(self.app, self.namespace)
+
+ def test_network_rbac_delete(self):
+ arglist = [
+ self.rbac_policies[0].id,
+ ]
+ verifylist = [
+ ('rbac_policy', [self.rbac_policies[0].id]),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.network.find_rbac_policy.assert_called_once_with(
+ self.rbac_policies[0].id, ignore_missing=False)
+ self.network.delete_rbac_policy.assert_called_once_with(
+ self.rbac_policies[0])
+ self.assertIsNone(result)
+
+ def test_multi_network_rbacs_delete(self):
+ arglist = []
+ verifylist = []
+
+ for r in self.rbac_policies:
+ arglist.append(r.id)
+ verifylist = [
+ ('rbac_policy', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for r in self.rbac_policies:
+ calls.append(call(r))
+ self.network.delete_rbac_policy.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_multi_network_policies_delete_with_exception(self):
+ arglist = [
+ self.rbac_policies[0].id,
+ 'unexist_rbac_policy',
+ ]
+ verifylist = [
+ ('rbac_policy',
+ [self.rbac_policies[0].id, 'unexist_rbac_policy']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [self.rbac_policies[0], exceptions.CommandError]
+ self.network.find_rbac_policy = (
+ mock.MagicMock(side_effect=find_mock_result)
+ )
+
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 RBAC policies failed to delete.', str(e))
+
+ self.network.find_rbac_policy.assert_any_call(
+ self.rbac_policies[0].id, ignore_missing=False)
+ self.network.find_rbac_policy.assert_any_call(
+ 'unexist_rbac_policy', ignore_missing=False)
+ self.network.delete_rbac_policy.assert_called_once_with(
+ self.rbac_policies[0]
+ )
+
+
+class TestListNetworkRABC(TestNetworkRBAC):
+
+ # The network rbac policies going to be listed up.
+ rbac_policies = network_fakes.FakeNetworkRBAC.create_network_rbacs(count=3)
+
+ columns = (
+ 'ID',
+ 'Object Type',
+ 'Object ID',
+ )
+
+ data = []
+ for r in rbac_policies:
+ data.append((
+ r.id,
+ r.object_type,
+ r.object_id,
+ ))
+
+ def setUp(self):
+ super(TestListNetworkRABC, self).setUp()
+
+ # Get the command object to test
+ self.cmd = network_rbac.ListNetworkRBAC(self.app, self.namespace)
+
+ self.network.rbac_policies = mock.Mock(return_value=self.rbac_policies)
+
+ def test_network_rbac_list(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # DisplayCommandBase.take_action() returns two tuples
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.rbac_policies.assert_called_with()
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+
+class TestSetNetworkRBAC(TestNetworkRBAC):
+
+ project = identity_fakes_v3.FakeProject.create_one_project()
+ rbac_policy = network_fakes.FakeNetworkRBAC.create_one_network_rbac(
+ attrs={'target_tenant': project.id})
+
+ def setUp(self):
+ super(TestSetNetworkRBAC, self).setUp()
+
+ # Get the command object to test
+ self.cmd = network_rbac.SetNetworkRBAC(self.app, self.namespace)
+
+ self.network.find_rbac_policy = mock.Mock(
+ return_value=self.rbac_policy)
+ self.network.update_rbac_policy = mock.Mock(return_value=None)
+ self.projects_mock.get.return_value = self.project
+
+ def test_network_rbac_set_nothing(self):
+ arglist = [
+ self.rbac_policy.id,
+ ]
+ verifylist = [
+ ('rbac_policy', self.rbac_policy.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.network.find_rbac_policy.assert_called_once_with(
+ self.rbac_policy.id, ignore_missing=False
+ )
+ attrs = {}
+ self.network.update_rbac_policy.assert_called_once_with(
+ self.rbac_policy, **attrs)
+ self.assertIsNone(result)
+
+ def test_network_rbac_set(self):
+ arglist = [
+ '--target-project', self.project.id,
+ self.rbac_policy.id,
+ ]
+ verifylist = [
+ ('target_project', self.project.id),
+ ('rbac_policy', self.rbac_policy.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.network.find_rbac_policy.assert_called_once_with(
+ self.rbac_policy.id, ignore_missing=False
+ )
+ attrs = {'target_tenant': self.project.id}
+ self.network.update_rbac_policy.assert_called_once_with(
+ self.rbac_policy, **attrs)
+ self.assertIsNone(result)
+
+
+class TestShowNetworkRBAC(TestNetworkRBAC):
+
+ rbac_policy = network_fakes.FakeNetworkRBAC.create_one_network_rbac()
+
+ columns = (
+ 'action',
+ 'id',
+ 'object_id',
+ 'object_type',
+ 'project_id',
+ 'target_project_id',
+ )
+
+ data = [
+ rbac_policy.action,
+ rbac_policy.id,
+ rbac_policy.object_id,
+ rbac_policy.object_type,
+ rbac_policy.tenant_id,
+ rbac_policy.target_tenant,
+ ]
+
+ def setUp(self):
+ super(TestShowNetworkRBAC, self).setUp()
+
+ # Get the command object to test
+ self.cmd = network_rbac.ShowNetworkRBAC(self.app, self.namespace)
+
+ self.network.find_rbac_policy = mock.Mock(
+ return_value=self.rbac_policy)
+
+ def test_show_no_options(self):
+ arglist = []
+ verifylist = []
+
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_network_rbac_show_all_options(self):
+ arglist = [
+ self.rbac_policy.id,
+ ]
+ verifylist = [
+ ('rbac_policy', self.rbac_policy.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # DisplayCommandBase.take_action() returns two tuples
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.find_rbac_policy.assert_called_with(
+ self.rbac_policy.id, ignore_missing=False
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
diff --git a/openstackclient/tests/unit/network/v2/test_network_segment.py b/openstackclient/tests/unit/network/v2/test_network_segment.py
new file mode 100644
index 00000000..b9fce078
--- /dev/null
+++ b/openstackclient/tests/unit/network/v2/test_network_segment.py
@@ -0,0 +1,200 @@
+# 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.
+#
+
+import mock
+
+from osc_lib import exceptions
+
+from openstackclient.network.v2 import network_segment
+from openstackclient.tests.unit.network.v2 import fakes as network_fakes
+from openstackclient.tests.unit import utils as tests_utils
+
+
+class TestNetworkSegment(network_fakes.TestNetworkV2):
+
+ def setUp(self):
+ super(TestNetworkSegment, self).setUp()
+
+ # Enable beta commands.
+ self.app.options.os_beta_command = True
+
+ # Get a shortcut to the network client
+ self.network = self.app.client_manager.network
+
+
+class TestListNetworkSegment(TestNetworkSegment):
+ _network = network_fakes.FakeNetwork.create_one_network()
+ _network_segments = \
+ network_fakes.FakeNetworkSegment.create_network_segments(count=3)
+
+ columns = (
+ 'ID',
+ 'Network',
+ 'Network Type',
+ 'Segment',
+ )
+ columns_long = columns + (
+ 'Physical Network',
+ )
+
+ data = []
+ for _network_segment in _network_segments:
+ data.append((
+ _network_segment.id,
+ _network_segment.network_id,
+ _network_segment.network_type,
+ _network_segment.segmentation_id,
+ ))
+
+ data_long = []
+ for _network_segment in _network_segments:
+ data_long.append((
+ _network_segment.id,
+ _network_segment.network_id,
+ _network_segment.network_type,
+ _network_segment.segmentation_id,
+ _network_segment.physical_network,
+ ))
+
+ def setUp(self):
+ super(TestListNetworkSegment, self).setUp()
+
+ # Get the command object to test
+ self.cmd = network_segment.ListNetworkSegment(self.app, self.namespace)
+
+ self.network.find_network = mock.Mock(return_value=self._network)
+ self.network.segments = mock.Mock(return_value=self._network_segments)
+
+ def test_list_no_option(self):
+ arglist = []
+ verifylist = [
+ ('long', False),
+ ('network', None),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.segments.assert_called_once_with()
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_list_no_beta_commands(self):
+ self.app.options.os_beta_command = False
+ parsed_args = self.check_parser(self.cmd, [], [])
+ self.assertRaises(exceptions.CommandError, self.cmd.take_action,
+ parsed_args)
+
+ def test_list_long(self):
+ arglist = [
+ '--long',
+ ]
+ verifylist = [
+ ('long', True),
+ ('network', None),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.segments.assert_called_once_with()
+ self.assertEqual(self.columns_long, columns)
+ self.assertEqual(self.data_long, list(data))
+
+ def test_list_network(self):
+ arglist = [
+ '--network',
+ self._network.id,
+ ]
+ verifylist = [
+ ('long', False),
+ ('network', self._network.id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.segments.assert_called_once_with(
+ **{'network_id': self._network.id}
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+
+class TestShowNetworkSegment(TestNetworkSegment):
+
+ # The network segment to show.
+ _network_segment = \
+ network_fakes.FakeNetworkSegment.create_one_network_segment()
+
+ columns = (
+ 'id',
+ 'network_id',
+ 'network_type',
+ 'physical_network',
+ 'segmentation_id',
+ )
+
+ data = (
+ _network_segment.id,
+ _network_segment.network_id,
+ _network_segment.network_type,
+ _network_segment.physical_network,
+ _network_segment.segmentation_id,
+ )
+
+ def setUp(self):
+ super(TestShowNetworkSegment, self).setUp()
+
+ self.network.find_segment = mock.Mock(
+ return_value=self._network_segment
+ )
+
+ # Get the command object to test
+ self.cmd = network_segment.ShowNetworkSegment(self.app, self.namespace)
+
+ def test_show_no_options(self):
+ # Missing required args should bail here
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, [], [])
+
+ def test_show_no_beta_commands(self):
+ arglist = [
+ self._network_segment.id,
+ ]
+ verifylist = [
+ ('network_segment', self._network_segment.id),
+ ]
+ self.app.options.os_beta_command = False
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.assertRaises(exceptions.CommandError, self.cmd.take_action,
+ parsed_args)
+
+ def test_show_all_options(self):
+ arglist = [
+ self._network_segment.id,
+ ]
+ verifylist = [
+ ('network_segment', self._network_segment.id),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.find_segment.assert_called_once_with(
+ self._network_segment.id,
+ ignore_missing=False
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
diff --git a/openstackclient/tests/unit/network/v2/test_port.py b/openstackclient/tests/unit/network/v2/test_port.py
new file mode 100644
index 00000000..d5d7f330
--- /dev/null
+++ b/openstackclient/tests/unit/network/v2/test_port.py
@@ -0,0 +1,696 @@
+# 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.
+#
+
+import argparse
+import mock
+
+from mock import call
+from osc_lib import exceptions
+from osc_lib import utils
+
+from openstackclient.network.v2 import port
+from openstackclient.tests.unit.network.v2 import fakes as network_fakes
+from openstackclient.tests.unit import utils as tests_utils
+
+
+class TestPort(network_fakes.TestNetworkV2):
+
+ def setUp(self):
+ super(TestPort, self).setUp()
+
+ # Get a shortcut to the network client
+ self.network = self.app.client_manager.network
+
+ def _get_common_cols_data(self, fake_port):
+ columns = (
+ 'admin_state_up',
+ 'allowed_address_pairs',
+ 'binding_host_id',
+ 'binding_profile',
+ 'binding_vif_details',
+ 'binding_vif_type',
+ 'binding_vnic_type',
+ 'device_id',
+ 'device_owner',
+ 'dns_assignment',
+ 'dns_name',
+ 'extra_dhcp_opts',
+ 'fixed_ips',
+ 'id',
+ 'mac_address',
+ 'name',
+ 'network_id',
+ 'port_security_enabled',
+ 'project_id',
+ 'security_groups',
+ 'status',
+ )
+
+ data = (
+ port._format_admin_state(fake_port.admin_state_up),
+ utils.format_list_of_dicts(fake_port.allowed_address_pairs),
+ fake_port.binding_host_id,
+ utils.format_dict(fake_port.binding_profile),
+ utils.format_dict(fake_port.binding_vif_details),
+ fake_port.binding_vif_type,
+ fake_port.binding_vnic_type,
+ fake_port.device_id,
+ fake_port.device_owner,
+ utils.format_list_of_dicts(fake_port.dns_assignment),
+ fake_port.dns_name,
+ utils.format_list_of_dicts(fake_port.extra_dhcp_opts),
+ utils.format_list_of_dicts(fake_port.fixed_ips),
+ fake_port.id,
+ fake_port.mac_address,
+ fake_port.name,
+ fake_port.network_id,
+ fake_port.port_security_enabled,
+ fake_port.project_id,
+ utils.format_list(fake_port.security_groups),
+ fake_port.status,
+ )
+
+ return columns, data
+
+
+class TestCreatePort(TestPort):
+
+ _port = network_fakes.FakePort.create_one_port()
+
+ def setUp(self):
+ super(TestCreatePort, self).setUp()
+
+ self.network.create_port = mock.Mock(return_value=self._port)
+ fake_net = network_fakes.FakeNetwork.create_one_network({
+ 'id': self._port.network_id,
+ })
+ self.network.find_network = mock.Mock(return_value=fake_net)
+ self.fake_subnet = network_fakes.FakeSubnet.create_one_subnet()
+ self.network.find_subnet = mock.Mock(return_value=self.fake_subnet)
+ # Get the command object to test
+ self.cmd = port.CreatePort(self.app, self.namespace)
+
+ def test_create_default_options(self):
+ arglist = [
+ '--network', self._port.network_id,
+ 'test-port',
+ ]
+ verifylist = [
+ ('network', self._port.network_id,),
+ ('enable', True),
+ ('name', 'test-port'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = (self.cmd.take_action(parsed_args))
+
+ self.network.create_port.assert_called_once_with(**{
+ 'admin_state_up': True,
+ 'network_id': self._port.network_id,
+ 'name': 'test-port',
+ })
+
+ ref_columns, ref_data = self._get_common_cols_data(self._port)
+ self.assertEqual(ref_columns, columns)
+ self.assertEqual(ref_data, data)
+
+ def test_create_full_options(self):
+ arglist = [
+ '--mac-address', 'aa:aa:aa:aa:aa:aa',
+ '--fixed-ip', 'subnet=%s,ip-address=10.0.0.2'
+ % self.fake_subnet.id,
+ '--device', 'deviceid',
+ '--device-owner', 'fakeowner',
+ '--disable',
+ '--vnic-type', 'macvtap',
+ '--binding-profile', 'foo=bar',
+ '--binding-profile', 'foo2=bar2',
+ '--network', self._port.network_id,
+ 'test-port',
+
+ ]
+ verifylist = [
+ ('mac_address', 'aa:aa:aa:aa:aa:aa'),
+ (
+ 'fixed_ip',
+ [{'subnet': self.fake_subnet.id, 'ip-address': '10.0.0.2'}]
+ ),
+ ('device', 'deviceid'),
+ ('device_owner', 'fakeowner'),
+ ('disable', True),
+ ('vnic_type', 'macvtap'),
+ ('binding_profile', {'foo': 'bar', 'foo2': 'bar2'}),
+ ('network', self._port.network_id),
+ ('name', 'test-port'),
+
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = (self.cmd.take_action(parsed_args))
+
+ self.network.create_port.assert_called_once_with(**{
+ 'mac_address': 'aa:aa:aa:aa:aa:aa',
+ 'fixed_ips': [{'subnet_id': self.fake_subnet.id,
+ 'ip_address': '10.0.0.2'}],
+ 'device_id': 'deviceid',
+ 'device_owner': 'fakeowner',
+ 'admin_state_up': False,
+ 'binding:vnic_type': 'macvtap',
+ 'binding:profile': {'foo': 'bar', 'foo2': 'bar2'},
+ 'network_id': self._port.network_id,
+ 'name': 'test-port',
+ })
+
+ ref_columns, ref_data = self._get_common_cols_data(self._port)
+ self.assertEqual(ref_columns, columns)
+ self.assertEqual(ref_data, data)
+
+ def test_create_invalid_json_binding_profile(self):
+ arglist = [
+ '--network', self._port.network_id,
+ '--binding-profile', '{"parent_name":"fake_parent"',
+ 'test-port',
+ ]
+ self.assertRaises(argparse.ArgumentTypeError,
+ self.check_parser,
+ self.cmd,
+ arglist,
+ None)
+
+ def test_create_invalid_key_value_binding_profile(self):
+ arglist = [
+ '--network', self._port.network_id,
+ '--binding-profile', 'key',
+ 'test-port',
+ ]
+ self.assertRaises(argparse.ArgumentTypeError,
+ self.check_parser,
+ self.cmd,
+ arglist,
+ None)
+
+ def test_create_json_binding_profile(self):
+ arglist = [
+ '--network', self._port.network_id,
+ '--binding-profile', '{"parent_name":"fake_parent"}',
+ '--binding-profile', '{"tag":42}',
+ 'test-port',
+ ]
+ verifylist = [
+ ('network', self._port.network_id,),
+ ('enable', True),
+ ('binding_profile', {'parent_name': 'fake_parent', 'tag': 42}),
+ ('name', 'test-port'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = (self.cmd.take_action(parsed_args))
+
+ self.network.create_port.assert_called_once_with(**{
+ 'admin_state_up': True,
+ 'network_id': self._port.network_id,
+ 'binding:profile': {'parent_name': 'fake_parent', 'tag': 42},
+ 'name': 'test-port',
+ })
+
+ ref_columns, ref_data = self._get_common_cols_data(self._port)
+ self.assertEqual(ref_columns, columns)
+ self.assertEqual(ref_data, data)
+
+
+class TestDeletePort(TestPort):
+
+ # Ports to delete.
+ _ports = network_fakes.FakePort.create_ports(count=2)
+
+ def setUp(self):
+ super(TestDeletePort, self).setUp()
+
+ self.network.delete_port = mock.Mock(return_value=None)
+ self.network.find_port = network_fakes.FakePort.get_ports(
+ ports=self._ports)
+ # Get the command object to test
+ self.cmd = port.DeletePort(self.app, self.namespace)
+
+ def test_port_delete(self):
+ arglist = [
+ self._ports[0].name,
+ ]
+ verifylist = [
+ ('port', [self._ports[0].name]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.network.find_port.assert_called_once_with(
+ self._ports[0].name, ignore_missing=False)
+ self.network.delete_port.assert_called_once_with(self._ports[0])
+ self.assertIsNone(result)
+
+ def test_multi_ports_delete(self):
+ arglist = []
+ verifylist = []
+
+ for p in self._ports:
+ arglist.append(p.name)
+ verifylist = [
+ ('port', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for p in self._ports:
+ calls.append(call(p))
+ self.network.delete_port.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_multi_ports_delete_with_exception(self):
+ arglist = [
+ self._ports[0].name,
+ 'unexist_port',
+ ]
+ verifylist = [
+ ('port',
+ [self._ports[0].name, 'unexist_port']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [self._ports[0], exceptions.CommandError]
+ self.network.find_port = (
+ mock.MagicMock(side_effect=find_mock_result)
+ )
+
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 ports failed to delete.', str(e))
+
+ self.network.find_port.assert_any_call(
+ self._ports[0].name, ignore_missing=False)
+ self.network.find_port.assert_any_call(
+ 'unexist_port', ignore_missing=False)
+ self.network.delete_port.assert_called_once_with(
+ self._ports[0]
+ )
+
+
+class TestListPort(TestPort):
+
+ _ports = network_fakes.FakePort.create_ports(count=3)
+
+ columns = (
+ 'ID',
+ 'Name',
+ 'MAC Address',
+ 'Fixed IP Addresses',
+ )
+
+ data = []
+ for prt in _ports:
+ data.append((
+ prt.id,
+ prt.name,
+ prt.mac_address,
+ utils.format_list_of_dicts(prt.fixed_ips),
+ ))
+
+ def setUp(self):
+ super(TestListPort, self).setUp()
+
+ # Get the command object to test
+ self.cmd = port.ListPort(self.app, self.namespace)
+ self.network.ports = mock.Mock(return_value=self._ports)
+ fake_router = network_fakes.FakeRouter.create_one_router({
+ 'id': 'fake-router-id',
+ })
+ self.network.find_router = mock.Mock(return_value=fake_router)
+
+ def test_port_list_no_options(self):
+ arglist = []
+ verifylist = []
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.ports.assert_called_once_with()
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_port_list_router_opt(self):
+ arglist = [
+ '--router', 'fake-router-name',
+ ]
+
+ verifylist = [
+ ('router', 'fake-router-name')
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.ports.assert_called_once_with(**{
+ 'device_id': 'fake-router-id'
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_port_list_device_owner_opt(self):
+ arglist = [
+ '--device-owner', self._ports[0].device_owner,
+ ]
+
+ verifylist = [
+ ('device_owner', self._ports[0].device_owner)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.ports.assert_called_once_with(**{
+ 'device_owner': self._ports[0].device_owner
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_port_list_all_opt(self):
+ arglist = [
+ '--device-owner', self._ports[0].device_owner,
+ '--router', 'fake-router-name',
+ ]
+
+ verifylist = [
+ ('device_owner', self._ports[0].device_owner),
+ ('router', 'fake-router-name')
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.ports.assert_called_once_with(**{
+ 'device_owner': self._ports[0].device_owner,
+ 'device_id': 'fake-router-id'
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+
+class TestSetPort(TestPort):
+
+ _port = network_fakes.FakePort.create_one_port()
+
+ def setUp(self):
+ super(TestSetPort, self).setUp()
+ self.fake_subnet = network_fakes.FakeSubnet.create_one_subnet()
+ self.network.find_subnet = mock.Mock(return_value=self.fake_subnet)
+ self.network.find_port = mock.Mock(return_value=self._port)
+ self.network.update_port = mock.Mock(return_value=None)
+
+ # Get the command object to test
+ self.cmd = port.SetPort(self.app, self.namespace)
+
+ def test_set_fixed_ip(self):
+ arglist = [
+ '--fixed-ip', 'ip-address=10.0.0.11',
+ self._port.name,
+ ]
+ verifylist = [
+ ('fixed_ip', [{'ip-address': '10.0.0.11'}]),
+ ('port', self._port.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'fixed_ips': [{'ip_address': '10.0.0.11'}],
+ }
+ self.network.update_port.assert_called_once_with(self._port, **attrs)
+ self.assertIsNone(result)
+
+ def test_append_fixed_ip(self):
+ _testport = network_fakes.FakePort.create_one_port(
+ {'fixed_ips': [{'ip_address': '0.0.0.1'}]})
+ self.network.find_port = mock.Mock(return_value=_testport)
+ arglist = [
+ '--fixed-ip', 'ip-address=10.0.0.12',
+ _testport.name,
+ ]
+ verifylist = [
+ ('fixed_ip', [{'ip-address': '10.0.0.12'}]),
+ ('port', _testport.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ attrs = {
+ 'fixed_ips': [
+ {'ip_address': '10.0.0.12'}, {'ip_address': '0.0.0.1'}],
+ }
+ self.network.update_port.assert_called_once_with(_testport, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_this(self):
+ arglist = [
+ '--disable',
+ '--no-fixed-ip',
+ '--no-binding-profile',
+ self._port.name,
+ ]
+ verifylist = [
+ ('disable', True),
+ ('no_binding_profile', True),
+ ('no_fixed_ip', True),
+ ('port', self._port.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'admin_state_up': False,
+ 'binding:profile': {},
+ 'fixed_ips': [],
+ }
+ self.network.update_port.assert_called_once_with(self._port, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_that(self):
+ arglist = [
+ '--enable',
+ '--vnic-type', 'macvtap',
+ '--binding-profile', 'foo=bar',
+ '--host', 'binding-host-id-xxxx',
+ '--name', 'newName',
+ self._port.name,
+ ]
+ verifylist = [
+ ('enable', True),
+ ('vnic_type', 'macvtap'),
+ ('binding_profile', {'foo': 'bar'}),
+ ('host', 'binding-host-id-xxxx'),
+ ('name', 'newName'),
+ ('port', self._port.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'admin_state_up': True,
+ 'binding:vnic_type': 'macvtap',
+ 'binding:profile': {'foo': 'bar'},
+ 'binding:host_id': 'binding-host-id-xxxx',
+ 'name': 'newName',
+ }
+ self.network.update_port.assert_called_once_with(self._port, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_nothing(self):
+ arglist = [
+ self._port.name,
+ ]
+ verifylist = [
+ ('port', self._port.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {}
+ self.network.update_port.assert_called_once_with(self._port, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_invalid_json_binding_profile(self):
+ arglist = [
+ '--binding-profile', '{"parent_name"}',
+ 'test-port',
+ ]
+ self.assertRaises(argparse.ArgumentTypeError,
+ self.check_parser,
+ self.cmd,
+ arglist,
+ None)
+
+ def test_set_invalid_key_value_binding_profile(self):
+ arglist = [
+ '--binding-profile', 'key',
+ 'test-port',
+ ]
+ self.assertRaises(argparse.ArgumentTypeError,
+ self.check_parser,
+ self.cmd,
+ arglist,
+ None)
+
+ def test_set_mixed_binding_profile(self):
+ arglist = [
+ '--binding-profile', 'foo=bar',
+ '--binding-profile', '{"foo2": "bar2"}',
+ self._port.name,
+ ]
+ verifylist = [
+ ('binding_profile', {'foo': 'bar', 'foo2': 'bar2'}),
+ ('port', self._port.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'binding:profile': {'foo': 'bar', 'foo2': 'bar2'},
+ }
+ self.network.update_port.assert_called_once_with(self._port, **attrs)
+ self.assertIsNone(result)
+
+
+class TestShowPort(TestPort):
+
+ # The port to show.
+ _port = network_fakes.FakePort.create_one_port()
+
+ def setUp(self):
+ super(TestShowPort, self).setUp()
+
+ self.network.find_port = mock.Mock(return_value=self._port)
+
+ # Get the command object to test
+ self.cmd = port.ShowPort(self.app, self.namespace)
+
+ def test_show_no_options(self):
+ arglist = []
+ verifylist = []
+
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, arglist, verifylist)
+
+ def test_show_all_options(self):
+ arglist = [
+ self._port.name,
+ ]
+ verifylist = [
+ ('port', self._port.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.find_port.assert_called_once_with(
+ self._port.name, ignore_missing=False)
+
+ ref_columns, ref_data = self._get_common_cols_data(self._port)
+ self.assertEqual(ref_columns, columns)
+ self.assertEqual(ref_data, data)
+
+
+class TestUnsetPort(TestPort):
+
+ def setUp(self):
+ super(TestUnsetPort, self).setUp()
+ self._testport = network_fakes.FakePort.create_one_port(
+ {'fixed_ips': [{'subnet_id': '042eb10a-3a18-4658-ab-cf47c8d03152',
+ 'ip_address': '0.0.0.1'},
+ {'subnet_id': '042eb10a-3a18-4658-ab-cf47c8d03152',
+ 'ip_address': '1.0.0.0'}],
+ 'binding:profile': {'batman': 'Joker', 'Superman': 'LexLuthor'}})
+ self.fake_subnet = network_fakes.FakeSubnet.create_one_subnet(
+ {'id': '042eb10a-3a18-4658-ab-cf47c8d03152'})
+ self.network.find_subnet = mock.Mock(return_value=self.fake_subnet)
+ self.network.find_port = mock.Mock(return_value=self._testport)
+ self.network.update_port = mock.Mock(return_value=None)
+ # Get the command object to test
+ self.cmd = port.UnsetPort(self.app, self.namespace)
+
+ def test_unset_port_parameters(self):
+ arglist = [
+ '--fixed-ip',
+ 'subnet=042eb10a-3a18-4658-ab-cf47c8d03152,ip-address=1.0.0.0',
+ '--binding-profile', 'Superman',
+ self._testport.name,
+ ]
+ verifylist = [
+ ('fixed_ip', [{
+ 'subnet': '042eb10a-3a18-4658-ab-cf47c8d03152',
+ 'ip-address': '1.0.0.0'}]),
+ ('binding_profile', ['Superman']),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'fixed_ips': [{
+ 'subnet_id': '042eb10a-3a18-4658-ab-cf47c8d03152',
+ 'ip_address': '0.0.0.1'}],
+ 'binding:profile': {'batman': 'Joker'}
+ }
+ self.network.update_port.assert_called_once_with(
+ self._testport, **attrs)
+ self.assertIsNone(result)
+
+ def test_unset_port_fixed_ip_not_existent(self):
+ arglist = [
+ '--fixed-ip', 'ip-address=1.0.0.1',
+ '--binding-profile', 'Superman',
+ self._testport.name,
+ ]
+ verifylist = [
+ ('fixed_ip', [{'ip-address': '1.0.0.1'}]),
+ ('binding_profile', ['Superman']),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.assertRaises(exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
+
+ def test_unset_port_binding_profile_not_existent(self):
+ arglist = [
+ '--fixed-ip', 'ip-address=1.0.0.0',
+ '--binding-profile', 'Neo',
+ self._testport.name,
+ ]
+ verifylist = [
+ ('fixed_ip', [{'ip-address': '1.0.0.0'}]),
+ ('binding_profile', ['Neo']),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.assertRaises(exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
diff --git a/openstackclient/tests/unit/network/v2/test_router.py b/openstackclient/tests/unit/network/v2/test_router.py
new file mode 100644
index 00000000..26fe655e
--- /dev/null
+++ b/openstackclient/tests/unit/network/v2/test_router.py
@@ -0,0 +1,751 @@
+# 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.
+#
+
+import mock
+from mock import call
+
+from osc_lib import exceptions
+from osc_lib import utils as osc_utils
+
+from openstackclient.network.v2 import router
+from openstackclient.tests.unit.network.v2 import fakes as network_fakes
+from openstackclient.tests.unit import utils as tests_utils
+
+
+class TestRouter(network_fakes.TestNetworkV2):
+
+ def setUp(self):
+ super(TestRouter, self).setUp()
+
+ # Get a shortcut to the network client
+ self.network = self.app.client_manager.network
+
+
+class TestAddPortToRouter(TestRouter):
+ '''Add port to Router '''
+
+ _port = network_fakes.FakePort.create_one_port()
+ _router = network_fakes.FakeRouter.create_one_router(
+ attrs={'port': _port.id})
+
+ def setUp(self):
+ super(TestAddPortToRouter, self).setUp()
+ self.network.router_add_interface = mock.Mock()
+ self.cmd = router.AddPortToRouter(self.app, self.namespace)
+ self.network.find_router = mock.Mock(return_value=self._router)
+ self.network.find_port = mock.Mock(return_value=self._port)
+
+ def test_add_port_no_option(self):
+ arglist = []
+ verifylist = []
+
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_add_port_required_options(self):
+ arglist = [
+ self._router.id,
+ self._router.port,
+ ]
+ verifylist = [
+ ('router', self._router.id),
+ ('port', self._router.port),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.network.router_add_interface.assert_called_with(self._router, **{
+ 'port_id': self._router.port,
+ })
+ self.assertIsNone(result)
+
+
+class TestAddSubnetToRouter(TestRouter):
+ '''Add subnet to Router '''
+
+ _subnet = network_fakes.FakeSubnet.create_one_subnet()
+ _router = network_fakes.FakeRouter.create_one_router(
+ attrs={'subnet': _subnet.id})
+
+ def setUp(self):
+ super(TestAddSubnetToRouter, self).setUp()
+ self.network.router_add_interface = mock.Mock()
+ self.cmd = router.AddSubnetToRouter(self.app, self.namespace)
+ self.network.find_router = mock.Mock(return_value=self._router)
+ self.network.find_subnet = mock.Mock(return_value=self._subnet)
+
+ def test_add_subnet_no_option(self):
+ arglist = []
+ verifylist = []
+
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_add_subnet_required_options(self):
+ arglist = [
+ self._router.id,
+ self._router.subnet,
+ ]
+ verifylist = [
+ ('router', self._router.id),
+ ('subnet', self._router.subnet),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.network.router_add_interface.assert_called_with(
+ self._router, **{'subnet_id': self._router.subnet})
+
+ self.assertIsNone(result)
+
+
+class TestCreateRouter(TestRouter):
+
+ # The new router created.
+ new_router = network_fakes.FakeRouter.create_one_router()
+
+ columns = (
+ 'admin_state_up',
+ 'availability_zone_hints',
+ 'availability_zones',
+ 'distributed',
+ 'external_gateway_info',
+ 'ha',
+ 'id',
+ 'name',
+ 'project_id',
+ 'routes',
+ 'status',
+ )
+ data = (
+ router._format_admin_state(new_router.admin_state_up),
+ osc_utils.format_list(new_router.availability_zone_hints),
+ osc_utils.format_list(new_router.availability_zones),
+ new_router.distributed,
+ router._format_external_gateway_info(new_router.external_gateway_info),
+ new_router.ha,
+ new_router.id,
+ new_router.name,
+ new_router.tenant_id,
+ router._format_routes(new_router.routes),
+ new_router.status,
+ )
+
+ def setUp(self):
+ super(TestCreateRouter, self).setUp()
+
+ self.network.create_router = mock.Mock(return_value=self.new_router)
+
+ # Get the command object to test
+ self.cmd = router.CreateRouter(self.app, self.namespace)
+
+ def test_create_no_options(self):
+ arglist = []
+ verifylist = []
+
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_create_default_options(self):
+ arglist = [
+ self.new_router.name,
+ ]
+ verifylist = [
+ ('name', self.new_router.name),
+ ('enable', True),
+ ('distributed', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = (self.cmd.take_action(parsed_args))
+
+ self.network.create_router.assert_called_once_with(**{
+ 'admin_state_up': True,
+ 'name': self.new_router.name,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_create_with_AZ_hints(self):
+ arglist = [
+ self.new_router.name,
+ '--availability-zone-hint', 'fake-az',
+ '--availability-zone-hint', 'fake-az2',
+ ]
+ verifylist = [
+ ('name', self.new_router.name),
+ ('availability_zone_hints', ['fake-az', 'fake-az2']),
+ ('enable', True),
+ ('distributed', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = (self.cmd.take_action(parsed_args))
+ self.network.create_router.assert_called_once_with(**{
+ 'admin_state_up': True,
+ 'name': self.new_router.name,
+ 'availability_zone_hints': ['fake-az', 'fake-az2'],
+ })
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestDeleteRouter(TestRouter):
+
+ # The routers to delete.
+ _routers = network_fakes.FakeRouter.create_routers(count=2)
+
+ def setUp(self):
+ super(TestDeleteRouter, self).setUp()
+
+ self.network.delete_router = mock.Mock(return_value=None)
+
+ self.network.find_router = (
+ network_fakes.FakeRouter.get_routers(self._routers))
+
+ # Get the command object to test
+ self.cmd = router.DeleteRouter(self.app, self.namespace)
+
+ def test_router_delete(self):
+ arglist = [
+ self._routers[0].name,
+ ]
+ verifylist = [
+ ('router', [self._routers[0].name]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.network.delete_router.assert_called_once_with(self._routers[0])
+ self.assertIsNone(result)
+
+ def test_multi_routers_delete(self):
+ arglist = []
+ verifylist = []
+
+ for r in self._routers:
+ arglist.append(r.name)
+ verifylist = [
+ ('router', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for r in self._routers:
+ calls.append(call(r))
+ self.network.delete_router.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_multi_routers_delete_with_exception(self):
+ arglist = [
+ self._routers[0].name,
+ 'unexist_router',
+ ]
+ verifylist = [
+ ('router',
+ [self._routers[0].name, 'unexist_router']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [self._routers[0], exceptions.CommandError]
+ self.network.find_router = (
+ mock.MagicMock(side_effect=find_mock_result)
+ )
+
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 routers failed to delete.', str(e))
+
+ self.network.find_router.assert_any_call(
+ self._routers[0].name, ignore_missing=False)
+ self.network.find_router.assert_any_call(
+ 'unexist_router', ignore_missing=False)
+ self.network.delete_router.assert_called_once_with(
+ self._routers[0]
+ )
+
+
+class TestListRouter(TestRouter):
+
+ # The routers going to be listed up.
+ routers = network_fakes.FakeRouter.create_routers(count=3)
+
+ columns = (
+ 'ID',
+ 'Name',
+ 'Status',
+ 'State',
+ 'Distributed',
+ 'HA',
+ 'Project',
+ )
+ columns_long = columns + (
+ 'Routes',
+ 'External gateway info',
+ 'Availability zones'
+ )
+
+ data = []
+ for r in routers:
+ data.append((
+ r.id,
+ r.name,
+ r.status,
+ router._format_admin_state(r.admin_state_up),
+ r.distributed,
+ r.ha,
+ r.tenant_id,
+ ))
+ data_long = []
+ for i in range(0, len(routers)):
+ r = routers[i]
+ data_long.append(
+ data[i] + (
+ router._format_routes(r.routes),
+ router._format_external_gateway_info(r.external_gateway_info),
+ osc_utils.format_list(r.availability_zones),
+ )
+ )
+
+ def setUp(self):
+ super(TestListRouter, self).setUp()
+
+ # Get the command object to test
+ self.cmd = router.ListRouter(self.app, self.namespace)
+
+ self.network.routers = mock.Mock(return_value=self.routers)
+
+ def test_router_list_no_options(self):
+ arglist = []
+ verifylist = [
+ ('long', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.routers.assert_called_once_with()
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_router_list_long(self):
+ arglist = [
+ '--long',
+ ]
+ verifylist = [
+ ('long', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.routers.assert_called_once_with()
+ self.assertEqual(self.columns_long, columns)
+ self.assertEqual(self.data_long, list(data))
+
+
+class TestRemovePortFromRouter(TestRouter):
+ '''Remove port from a Router '''
+
+ _port = network_fakes.FakePort.create_one_port()
+ _router = network_fakes.FakeRouter.create_one_router(
+ attrs={'port': _port.id})
+
+ def setUp(self):
+ super(TestRemovePortFromRouter, self).setUp()
+ self.network.router_remove_interface = mock.Mock()
+ self.cmd = router.RemovePortFromRouter(self.app, self.namespace)
+ self.network.find_router = mock.Mock(return_value=self._router)
+ self.network.find_port = mock.Mock(return_value=self._port)
+
+ def test_remove_port_no_option(self):
+ arglist = []
+ verifylist = []
+
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_remove_port_required_options(self):
+ arglist = [
+ self._router.id,
+ self._router.port,
+ ]
+ verifylist = [
+ ('router', self._router.id),
+ ('port', self._router.port),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.network.router_remove_interface.assert_called_with(
+ self._router, **{'port_id': self._router.port})
+ self.assertIsNone(result)
+
+
+class TestRemoveSubnetFromRouter(TestRouter):
+ '''Remove subnet from Router '''
+
+ _subnet = network_fakes.FakeSubnet.create_one_subnet()
+ _router = network_fakes.FakeRouter.create_one_router(
+ attrs={'subnet': _subnet.id})
+
+ def setUp(self):
+ super(TestRemoveSubnetFromRouter, self).setUp()
+ self.network.router_remove_interface = mock.Mock()
+ self.cmd = router.RemoveSubnetFromRouter(self.app, self.namespace)
+ self.network.find_router = mock.Mock(return_value=self._router)
+ self.network.find_subnet = mock.Mock(return_value=self._subnet)
+
+ def test_remove_subnet_no_option(self):
+ arglist = []
+ verifylist = []
+
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_remove_subnet_required_options(self):
+ arglist = [
+ self._router.id,
+ self._router.subnet,
+ ]
+ verifylist = [
+ ('subnet', self._router.subnet),
+ ('router', self._router.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.network.router_remove_interface.assert_called_with(
+ self._router, **{'subnet_id': self._router.subnet})
+ self.assertIsNone(result)
+
+
+class TestSetRouter(TestRouter):
+
+ # The router to set.
+ _default_route = {'destination': '10.20.20.0/24', 'nexthop': '10.20.30.1'}
+ _router = network_fakes.FakeRouter.create_one_router(
+ attrs={'routes': [_default_route]}
+ )
+
+ def setUp(self):
+ super(TestSetRouter, self).setUp()
+
+ self.network.update_router = mock.Mock(return_value=None)
+
+ self.network.find_router = mock.Mock(return_value=self._router)
+
+ # Get the command object to test
+ self.cmd = router.SetRouter(self.app, self.namespace)
+
+ def test_set_this(self):
+ arglist = [
+ self._router.name,
+ '--enable',
+ '--distributed',
+ '--name', 'noob',
+ ]
+ verifylist = [
+ ('router', self._router.name),
+ ('enable', True),
+ ('distributed', True),
+ ('name', 'noob'),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'admin_state_up': True,
+ 'distributed': True,
+ 'name': 'noob',
+ }
+ self.network.update_router.assert_called_once_with(
+ self._router, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_that(self):
+ arglist = [
+ self._router.name,
+ '--disable',
+ '--centralized',
+ ]
+ verifylist = [
+ ('router', self._router.name),
+ ('disable', True),
+ ('centralized', True),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'admin_state_up': False,
+ 'distributed': False,
+ }
+ self.network.update_router.assert_called_once_with(
+ self._router, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_distributed_centralized(self):
+ arglist = [
+ self._router.name,
+ '--distributed',
+ '--centralized',
+ ]
+ verifylist = [
+ ('router', self._router.name),
+ ('distributed', True),
+ ('distributed', False),
+ ]
+
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_set_route(self):
+ arglist = [
+ self._router.name,
+ '--route', 'destination=10.20.30.0/24,gateway=10.20.30.1',
+ ]
+ verifylist = [
+ ('router', self._router.name),
+ ('routes', [{'destination': '10.20.30.0/24',
+ 'gateway': '10.20.30.1'}]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'routes': self._router.routes + [{'destination': '10.20.30.0/24',
+ 'nexthop': '10.20.30.1'}],
+ }
+ self.network.update_router.assert_called_once_with(
+ self._router, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_no_route(self):
+ arglist = [
+ self._router.name,
+ '--no-route',
+ ]
+ verifylist = [
+ ('router', self._router.name),
+ ('no_route', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'routes': [],
+ }
+ self.network.update_router.assert_called_once_with(
+ self._router, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_route_no_route(self):
+ arglist = [
+ self._router.name,
+ '--route', 'destination=10.20.30.0/24,gateway=10.20.30.1',
+ '--no-route',
+ ]
+ verifylist = [
+ ('router', self._router.name),
+ ('routes', [{'destination': '10.20.30.0/24',
+ 'gateway': '10.20.30.1'}]),
+ ('no_route', True),
+ ]
+
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_set_clear_routes(self):
+ arglist = [
+ self._router.name,
+ '--clear-routes',
+ ]
+ verifylist = [
+ ('router', self._router.name),
+ ('clear_routes', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'routes': [],
+ }
+ self.network.update_router.assert_called_once_with(
+ self._router, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_route_clear_routes(self):
+ arglist = [
+ self._router.name,
+ '--route', 'destination=10.20.30.0/24,gateway=10.20.30.1',
+ '--clear-routes',
+ ]
+ verifylist = [
+ ('router', self._router.name),
+ ('routes', [{'destination': '10.20.30.0/24',
+ 'gateway': '10.20.30.1'}]),
+ ('clear_routes', True),
+ ]
+
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_set_nothing(self):
+ arglist = [
+ self._router.name,
+ ]
+ verifylist = [
+ ('router', self._router.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {}
+ self.network.update_router.assert_called_once_with(
+ self._router, **attrs)
+ self.assertIsNone(result)
+
+
+class TestShowRouter(TestRouter):
+
+ # The router to set.
+ _router = network_fakes.FakeRouter.create_one_router()
+
+ columns = (
+ 'admin_state_up',
+ 'availability_zone_hints',
+ 'availability_zones',
+ 'distributed',
+ 'external_gateway_info',
+ 'ha',
+ 'id',
+ 'name',
+ 'project_id',
+ 'routes',
+ 'status',
+ )
+ data = (
+ router._format_admin_state(_router.admin_state_up),
+ osc_utils.format_list(_router.availability_zone_hints),
+ osc_utils.format_list(_router.availability_zones),
+ _router.distributed,
+ router._format_external_gateway_info(_router.external_gateway_info),
+ _router.ha,
+ _router.id,
+ _router.name,
+ _router.tenant_id,
+ router._format_routes(_router.routes),
+ _router.status,
+ )
+
+ def setUp(self):
+ super(TestShowRouter, self).setUp()
+
+ self.network.find_router = mock.Mock(return_value=self._router)
+
+ # Get the command object to test
+ self.cmd = router.ShowRouter(self.app, self.namespace)
+
+ def test_show_no_options(self):
+ arglist = []
+ verifylist = []
+
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_show_all_options(self):
+ arglist = [
+ self._router.name,
+ ]
+ verifylist = [
+ ('router', self._router.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.find_router.assert_called_once_with(
+ self._router.name, ignore_missing=False)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestUnsetRouter(TestRouter):
+
+ def setUp(self):
+ super(TestUnsetRouter, self).setUp()
+ self._testrouter = network_fakes.FakeRouter.create_one_router(
+ {'routes': [{"destination": "192.168.101.1/24",
+ "gateway": "172.24.4.3"},
+ {"destination": "192.168.101.2/24",
+ "gateway": "172.24.4.3"}], })
+ self.fake_subnet = network_fakes.FakeSubnet.create_one_subnet()
+ self.network.find_router = mock.Mock(return_value=self._testrouter)
+ self.network.update_router = mock.Mock(return_value=None)
+ # Get the command object to test
+ self.cmd = router.UnsetRouter(self.app, self.namespace)
+
+ def test_unset_router_params(self):
+ arglist = [
+ '--route', 'destination=192.168.101.1/24,gateway=172.24.4.3',
+ self._testrouter.name,
+ ]
+ verifylist = [
+ ('routes', [
+ {"destination": "192.168.101.1/24", "gateway": "172.24.4.3"}]),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'routes': [{"destination": "192.168.101.2/24",
+ "nexthop": "172.24.4.3"}],
+ }
+ self.network.update_router.assert_called_once_with(
+ self._testrouter, **attrs)
+ self.assertIsNone(result)
+
+ def test_unset_router_wrong_routes(self):
+ arglist = [
+ '--route', 'destination=192.168.101.1/24,gateway=172.24.4.2',
+ self._testrouter.name,
+ ]
+ verifylist = [
+ ('routes', [
+ {"destination": "192.168.101.1/24", "gateway": "172.24.4.2"}]),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.assertRaises(exceptions.CommandError,
+ self.cmd.take_action, parsed_args)
diff --git a/openstackclient/tests/unit/network/v2/test_security_group.py b/openstackclient/tests/unit/network/v2/test_security_group.py
new file mode 100644
index 00000000..4c5b2972
--- /dev/null
+++ b/openstackclient/tests/unit/network/v2/test_security_group.py
@@ -0,0 +1,770 @@
+# 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.
+#
+
+import mock
+from mock import call
+
+from osc_lib import exceptions
+
+from openstackclient.network.v2 import security_group
+from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+from openstackclient.tests.unit.network.v2 import fakes as network_fakes
+from openstackclient.tests.unit import utils as tests_utils
+
+
+class TestSecurityGroupNetwork(network_fakes.TestNetworkV2):
+
+ def setUp(self):
+ super(TestSecurityGroupNetwork, self).setUp()
+
+ # Get a shortcut to the network client
+ self.network = self.app.client_manager.network
+ # Get a shortcut to the ProjectManager Mock
+ self.projects_mock = self.app.client_manager.identity.projects
+ # Get a shortcut to the DomainManager Mock
+ self.domains_mock = self.app.client_manager.identity.domains
+
+
+class TestSecurityGroupCompute(compute_fakes.TestComputev2):
+
+ def setUp(self):
+ super(TestSecurityGroupCompute, self).setUp()
+
+ # Get a shortcut to the compute client
+ self.compute = self.app.client_manager.compute
+
+
+class TestCreateSecurityGroupNetwork(TestSecurityGroupNetwork):
+
+ project = identity_fakes.FakeProject.create_one_project()
+ domain = identity_fakes.FakeDomain.create_one_domain()
+ # The security group to be created.
+ _security_group = \
+ network_fakes.FakeSecurityGroup.create_one_security_group()
+
+ columns = (
+ 'description',
+ 'id',
+ 'name',
+ 'project_id',
+ 'rules',
+ )
+
+ data = (
+ _security_group.description,
+ _security_group.id,
+ _security_group.name,
+ _security_group.project_id,
+ '',
+ )
+
+ def setUp(self):
+ super(TestCreateSecurityGroupNetwork, self).setUp()
+
+ self.network.create_security_group = mock.Mock(
+ return_value=self._security_group)
+
+ self.projects_mock.get.return_value = self.project
+ self.domains_mock.get.return_value = self.domain
+
+ # Get the command object to test
+ self.cmd = security_group.CreateSecurityGroup(self.app, self.namespace)
+
+ def test_create_no_options(self):
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, [], [])
+
+ def test_create_min_options(self):
+ arglist = [
+ self._security_group.name,
+ ]
+ verifylist = [
+ ('name', self._security_group.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_security_group.assert_called_once_with(**{
+ 'description': self._security_group.name,
+ 'name': self._security_group.name,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_create_all_options(self):
+ arglist = [
+ '--description', self._security_group.description,
+ '--project', self.project.name,
+ '--project-domain', self.domain.name,
+ self._security_group.name,
+ ]
+ verifylist = [
+ ('description', self._security_group.description),
+ ('name', self._security_group.name),
+ ('project', self.project.name),
+ ('project_domain', self.domain.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_security_group.assert_called_once_with(**{
+ 'description': self._security_group.description,
+ 'name': self._security_group.name,
+ 'tenant_id': self.project.id,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestCreateSecurityGroupCompute(TestSecurityGroupCompute):
+
+ project = identity_fakes.FakeProject.create_one_project()
+ domain = identity_fakes.FakeDomain.create_one_domain()
+ # The security group to be shown.
+ _security_group = \
+ compute_fakes.FakeSecurityGroup.create_one_security_group()
+
+ columns = (
+ 'description',
+ 'id',
+ 'name',
+ 'project_id',
+ 'rules',
+ )
+
+ data = (
+ _security_group.description,
+ _security_group.id,
+ _security_group.name,
+ _security_group.tenant_id,
+ '',
+ )
+
+ def setUp(self):
+ super(TestCreateSecurityGroupCompute, self).setUp()
+
+ self.app.client_manager.network_endpoint_enabled = False
+
+ self.compute.security_groups.create.return_value = self._security_group
+
+ # Get the command object to test
+ self.cmd = security_group.CreateSecurityGroup(self.app, None)
+
+ def test_create_no_options(self):
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, [], [])
+
+ def test_create_network_options(self):
+ arglist = [
+ '--project', self.project.name,
+ '--project-domain', self.domain.name,
+ self._security_group.name,
+ ]
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, arglist, [])
+
+ def test_create_min_options(self):
+ arglist = [
+ self._security_group.name,
+ ]
+ verifylist = [
+ ('name', self._security_group.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.compute.security_groups.create.assert_called_once_with(
+ self._security_group.name,
+ self._security_group.name)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_create_all_options(self):
+ arglist = [
+ '--description', self._security_group.description,
+ self._security_group.name,
+ ]
+ verifylist = [
+ ('description', self._security_group.description),
+ ('name', self._security_group.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.compute.security_groups.create.assert_called_once_with(
+ self._security_group.name,
+ self._security_group.description)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestDeleteSecurityGroupNetwork(TestSecurityGroupNetwork):
+
+ # The security groups to be deleted.
+ _security_groups = \
+ network_fakes.FakeSecurityGroup.create_security_groups()
+
+ def setUp(self):
+ super(TestDeleteSecurityGroupNetwork, self).setUp()
+
+ self.network.delete_security_group = mock.Mock(return_value=None)
+
+ self.network.find_security_group = (
+ network_fakes.FakeSecurityGroup.get_security_groups(
+ self._security_groups)
+ )
+
+ # Get the command object to test
+ self.cmd = security_group.DeleteSecurityGroup(self.app, self.namespace)
+
+ def test_security_group_delete(self):
+ arglist = [
+ self._security_groups[0].name,
+ ]
+ verifylist = [
+ ('group', [self._security_groups[0].name]),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ self.network.delete_security_group.assert_called_once_with(
+ self._security_groups[0])
+ self.assertIsNone(result)
+
+ def test_multi_security_groups_delete(self):
+ arglist = []
+ verifylist = []
+
+ for s in self._security_groups:
+ arglist.append(s.name)
+ verifylist = [
+ ('group', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for s in self._security_groups:
+ calls.append(call(s))
+ self.network.delete_security_group.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_multi_security_groups_delete_with_exception(self):
+ arglist = [
+ self._security_groups[0].name,
+ 'unexist_security_group',
+ ]
+ verifylist = [
+ ('group',
+ [self._security_groups[0].name, 'unexist_security_group']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [self._security_groups[0], exceptions.CommandError]
+ self.network.find_security_group = (
+ mock.MagicMock(side_effect=find_mock_result)
+ )
+
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 groups failed to delete.', str(e))
+
+ self.network.find_security_group.assert_any_call(
+ self._security_groups[0].name, ignore_missing=False)
+ self.network.find_security_group.assert_any_call(
+ 'unexist_security_group', ignore_missing=False)
+ self.network.delete_security_group.assert_called_once_with(
+ self._security_groups[0]
+ )
+
+
+class TestDeleteSecurityGroupCompute(TestSecurityGroupCompute):
+
+ # The security groups to be deleted.
+ _security_groups = \
+ compute_fakes.FakeSecurityGroup.create_security_groups()
+
+ def setUp(self):
+ super(TestDeleteSecurityGroupCompute, self).setUp()
+
+ self.app.client_manager.network_endpoint_enabled = False
+
+ self.compute.security_groups.delete = mock.Mock(return_value=None)
+
+ self.compute.security_groups.get = (
+ compute_fakes.FakeSecurityGroup.get_security_groups(
+ self._security_groups)
+ )
+
+ # Get the command object to test
+ self.cmd = security_group.DeleteSecurityGroup(self.app, None)
+
+ def test_security_group_delete(self):
+ arglist = [
+ self._security_groups[0].id,
+ ]
+ verifylist = [
+ ('group', [self._security_groups[0].id]),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ self.compute.security_groups.delete.assert_called_once_with(
+ self._security_groups[0].id)
+ self.assertIsNone(result)
+
+ def test_multi_security_groups_delete(self):
+ arglist = []
+ verifylist = []
+
+ for s in self._security_groups:
+ arglist.append(s.id)
+ verifylist = [
+ ('group', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for s in self._security_groups:
+ calls.append(call(s.id))
+ self.compute.security_groups.delete.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_multi_security_groups_delete_with_exception(self):
+ arglist = [
+ self._security_groups[0].id,
+ 'unexist_security_group',
+ ]
+ verifylist = [
+ ('group',
+ [self._security_groups[0].id, 'unexist_security_group']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [self._security_groups[0], exceptions.CommandError]
+ self.compute.security_groups.get = (
+ mock.MagicMock(side_effect=find_mock_result)
+ )
+ self.compute.security_groups.find.side_effect = (
+ exceptions.NotFound(None))
+
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 groups failed to delete.', str(e))
+
+ self.compute.security_groups.get.assert_any_call(
+ self._security_groups[0].id)
+ self.compute.security_groups.get.assert_any_call(
+ 'unexist_security_group')
+ self.compute.security_groups.delete.assert_called_once_with(
+ self._security_groups[0].id
+ )
+
+
+class TestListSecurityGroupNetwork(TestSecurityGroupNetwork):
+
+ # The security group to be listed.
+ _security_groups = \
+ network_fakes.FakeSecurityGroup.create_security_groups(count=3)
+
+ columns = (
+ 'ID',
+ 'Name',
+ 'Description',
+ 'Project',
+ )
+
+ data = []
+ for grp in _security_groups:
+ data.append((
+ grp.id,
+ grp.name,
+ grp.description,
+ grp.tenant_id,
+ ))
+
+ def setUp(self):
+ super(TestListSecurityGroupNetwork, self).setUp()
+
+ self.network.security_groups = mock.Mock(
+ return_value=self._security_groups)
+
+ # Get the command object to test
+ self.cmd = security_group.ListSecurityGroup(self.app, self.namespace)
+
+ def test_security_group_list_no_options(self):
+ arglist = []
+ verifylist = [
+ ('all_projects', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.security_groups.assert_called_once_with()
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_security_group_list_all_projects(self):
+ arglist = [
+ '--all-projects',
+ ]
+ verifylist = [
+ ('all_projects', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.security_groups.assert_called_once_with()
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+
+class TestListSecurityGroupCompute(TestSecurityGroupCompute):
+
+ # The security group to be listed.
+ _security_groups = \
+ compute_fakes.FakeSecurityGroup.create_security_groups(count=3)
+
+ columns = (
+ 'ID',
+ 'Name',
+ 'Description',
+ )
+ columns_all_projects = (
+ 'ID',
+ 'Name',
+ 'Description',
+ 'Project',
+ )
+
+ data = []
+ for grp in _security_groups:
+ data.append((
+ grp.id,
+ grp.name,
+ grp.description,
+ ))
+ data_all_projects = []
+ for grp in _security_groups:
+ data_all_projects.append((
+ grp.id,
+ grp.name,
+ grp.description,
+ grp.tenant_id,
+ ))
+
+ def setUp(self):
+ super(TestListSecurityGroupCompute, self).setUp()
+
+ self.app.client_manager.network_endpoint_enabled = False
+ self.compute.security_groups.list.return_value = self._security_groups
+
+ # Get the command object to test
+ self.cmd = security_group.ListSecurityGroup(self.app, None)
+
+ def test_security_group_list_no_options(self):
+ arglist = []
+ verifylist = [
+ ('all_projects', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ kwargs = {'search_opts': {'all_tenants': False}}
+ self.compute.security_groups.list.assert_called_once_with(**kwargs)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_security_group_list_all_projects(self):
+ arglist = [
+ '--all-projects',
+ ]
+ verifylist = [
+ ('all_projects', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ kwargs = {'search_opts': {'all_tenants': True}}
+ self.compute.security_groups.list.assert_called_once_with(**kwargs)
+ self.assertEqual(self.columns_all_projects, columns)
+ self.assertEqual(self.data_all_projects, list(data))
+
+
+class TestSetSecurityGroupNetwork(TestSecurityGroupNetwork):
+
+ # The security group to be set.
+ _security_group = \
+ network_fakes.FakeSecurityGroup.create_one_security_group()
+
+ def setUp(self):
+ super(TestSetSecurityGroupNetwork, self).setUp()
+
+ self.network.update_security_group = mock.Mock(return_value=None)
+
+ self.network.find_security_group = mock.Mock(
+ return_value=self._security_group)
+
+ # Get the command object to test
+ self.cmd = security_group.SetSecurityGroup(self.app, self.namespace)
+
+ def test_set_no_options(self):
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, [], [])
+
+ def test_set_no_updates(self):
+ arglist = [
+ self._security_group.name,
+ ]
+ verifylist = [
+ ('group', self._security_group.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ self.network.update_security_group.assert_called_once_with(
+ self._security_group,
+ **{}
+ )
+ self.assertIsNone(result)
+
+ def test_set_all_options(self):
+ new_name = 'new-' + self._security_group.name
+ new_description = 'new-' + self._security_group.description
+ arglist = [
+ '--name', new_name,
+ '--description', new_description,
+ self._security_group.name,
+ ]
+ verifylist = [
+ ('description', new_description),
+ ('group', self._security_group.name),
+ ('name', new_name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'description': new_description,
+ 'name': new_name,
+ }
+ self.network.update_security_group.assert_called_once_with(
+ self._security_group,
+ **attrs
+ )
+ self.assertIsNone(result)
+
+
+class TestSetSecurityGroupCompute(TestSecurityGroupCompute):
+
+ # The security group to be set.
+ _security_group = \
+ compute_fakes.FakeSecurityGroup.create_one_security_group()
+
+ def setUp(self):
+ super(TestSetSecurityGroupCompute, self).setUp()
+
+ self.app.client_manager.network_endpoint_enabled = False
+
+ self.compute.security_groups.update = mock.Mock(return_value=None)
+
+ self.compute.security_groups.get = mock.Mock(
+ return_value=self._security_group)
+
+ # Get the command object to test
+ self.cmd = security_group.SetSecurityGroup(self.app, None)
+
+ def test_set_no_options(self):
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, [], [])
+
+ def test_set_no_updates(self):
+ arglist = [
+ self._security_group.name,
+ ]
+ verifylist = [
+ ('group', self._security_group.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ self.compute.security_groups.update.assert_called_once_with(
+ self._security_group,
+ self._security_group.name,
+ self._security_group.description
+ )
+ self.assertIsNone(result)
+
+ def test_set_all_options(self):
+ new_name = 'new-' + self._security_group.name
+ new_description = 'new-' + self._security_group.description
+ arglist = [
+ '--name', new_name,
+ '--description', new_description,
+ self._security_group.name,
+ ]
+ verifylist = [
+ ('description', new_description),
+ ('group', self._security_group.name),
+ ('name', new_name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ self.compute.security_groups.update.assert_called_once_with(
+ self._security_group,
+ new_name,
+ new_description
+ )
+ self.assertIsNone(result)
+
+
+class TestShowSecurityGroupNetwork(TestSecurityGroupNetwork):
+
+ # The security group rule to be shown with the group.
+ _security_group_rule = \
+ network_fakes.FakeSecurityGroupRule.create_one_security_group_rule()
+
+ # The security group to be shown.
+ _security_group = \
+ network_fakes.FakeSecurityGroup.create_one_security_group(
+ attrs={'security_group_rules': [_security_group_rule._info]}
+ )
+
+ columns = (
+ 'description',
+ 'id',
+ 'name',
+ 'project_id',
+ 'rules',
+ )
+
+ data = (
+ _security_group.description,
+ _security_group.id,
+ _security_group.name,
+ _security_group.project_id,
+ security_group._format_network_security_group_rules(
+ [_security_group_rule._info]),
+ )
+
+ def setUp(self):
+ super(TestShowSecurityGroupNetwork, self).setUp()
+
+ self.network.find_security_group = mock.Mock(
+ return_value=self._security_group)
+
+ # Get the command object to test
+ self.cmd = security_group.ShowSecurityGroup(self.app, self.namespace)
+
+ def test_show_no_options(self):
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, [], [])
+
+ def test_show_all_options(self):
+ arglist = [
+ self._security_group.id,
+ ]
+ verifylist = [
+ ('group', self._security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.find_security_group.assert_called_once_with(
+ self._security_group.id, ignore_missing=False)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestShowSecurityGroupCompute(TestSecurityGroupCompute):
+
+ # The security group rule to be shown with the group.
+ _security_group_rule = \
+ compute_fakes.FakeSecurityGroupRule.create_one_security_group_rule()
+
+ # The security group to be shown.
+ _security_group = \
+ compute_fakes.FakeSecurityGroup.create_one_security_group(
+ attrs={'rules': [_security_group_rule._info]}
+ )
+
+ columns = (
+ 'description',
+ 'id',
+ 'name',
+ 'project_id',
+ 'rules',
+ )
+
+ data = (
+ _security_group.description,
+ _security_group.id,
+ _security_group.name,
+ _security_group.tenant_id,
+ security_group._format_compute_security_group_rules(
+ [_security_group_rule._info]),
+ )
+
+ def setUp(self):
+ super(TestShowSecurityGroupCompute, self).setUp()
+
+ self.app.client_manager.network_endpoint_enabled = False
+
+ self.compute.security_groups.get.return_value = self._security_group
+
+ # Get the command object to test
+ self.cmd = security_group.ShowSecurityGroup(self.app, None)
+
+ def test_show_no_options(self):
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, [], [])
+
+ def test_show_all_options(self):
+ arglist = [
+ self._security_group.id,
+ ]
+ verifylist = [
+ ('group', self._security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.compute.security_groups.get.assert_called_once_with(
+ self._security_group.id)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
diff --git a/openstackclient/tests/unit/network/v2/test_security_group_rule.py b/openstackclient/tests/unit/network/v2/test_security_group_rule.py
new file mode 100644
index 00000000..51e18a65
--- /dev/null
+++ b/openstackclient/tests/unit/network/v2/test_security_group_rule.py
@@ -0,0 +1,1177 @@
+# 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.
+#
+
+import copy
+import mock
+from mock import call
+
+from osc_lib import exceptions
+
+from openstackclient.network import utils as network_utils
+from openstackclient.network.v2 import security_group_rule
+from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+from openstackclient.tests.unit.network.v2 import fakes as network_fakes
+from openstackclient.tests.unit import utils as tests_utils
+
+
+class TestSecurityGroupRuleNetwork(network_fakes.TestNetworkV2):
+
+ def setUp(self):
+ super(TestSecurityGroupRuleNetwork, self).setUp()
+
+ # Get a shortcut to the network client
+ self.network = self.app.client_manager.network
+ # Get a shortcut to the ProjectManager Mock
+ self.projects_mock = self.app.client_manager.identity.projects
+ # Get a shortcut to the DomainManager Mock
+ self.domains_mock = self.app.client_manager.identity.domains
+
+
+class TestSecurityGroupRuleCompute(compute_fakes.TestComputev2):
+
+ def setUp(self):
+ super(TestSecurityGroupRuleCompute, self).setUp()
+
+ # Get a shortcut to the network client
+ self.compute = self.app.client_manager.compute
+
+
+class TestCreateSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork):
+
+ project = identity_fakes.FakeProject.create_one_project()
+ domain = identity_fakes.FakeDomain.create_one_domain()
+ # The security group rule to be created.
+ _security_group_rule = None
+
+ # The security group that will contain the rule created.
+ _security_group = \
+ network_fakes.FakeSecurityGroup.create_one_security_group()
+
+ expected_columns = (
+ 'direction',
+ 'ethertype',
+ 'id',
+ 'port_range_max',
+ 'port_range_min',
+ 'project_id',
+ 'protocol',
+ 'remote_group_id',
+ 'remote_ip_prefix',
+ 'security_group_id',
+ )
+
+ expected_data = None
+
+ def _setup_security_group_rule(self, attrs=None):
+ self._security_group_rule = \
+ network_fakes.FakeSecurityGroupRule.create_one_security_group_rule(
+ attrs)
+ self.network.create_security_group_rule = mock.Mock(
+ return_value=self._security_group_rule)
+ self.expected_data = (
+ self._security_group_rule.direction,
+ self._security_group_rule.ethertype,
+ self._security_group_rule.id,
+ self._security_group_rule.port_range_max,
+ self._security_group_rule.port_range_min,
+ self._security_group_rule.project_id,
+ self._security_group_rule.protocol,
+ self._security_group_rule.remote_group_id,
+ self._security_group_rule.remote_ip_prefix,
+ self._security_group_rule.security_group_id,
+ )
+
+ def setUp(self):
+ super(TestCreateSecurityGroupRuleNetwork, self).setUp()
+
+ self.network.find_security_group = mock.Mock(
+ return_value=self._security_group)
+
+ self.projects_mock.get.return_value = self.project
+ self.domains_mock.get.return_value = self.domain
+
+ # Get the command object to test
+ self.cmd = security_group_rule.CreateSecurityGroupRule(
+ self.app, self.namespace)
+
+ def test_create_no_options(self):
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, [], [])
+
+ def test_create_all_source_options(self):
+ arglist = [
+ '--src-ip', '10.10.0.0/24',
+ '--src-group', self._security_group.id,
+ self._security_group.id,
+ ]
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, arglist, [])
+
+ def test_create_bad_ethertype(self):
+ arglist = [
+ '--ethertype', 'foo',
+ self._security_group.id,
+ ]
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, arglist, [])
+
+ def test_create_all_protocol_options(self):
+ arglist = [
+ '--protocol', 'tcp',
+ '--proto', 'tcp',
+ self._security_group.id,
+ ]
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, arglist, [])
+
+ def test_create_all_port_range_options(self):
+ arglist = [
+ '--dst-port', '80:80',
+ '--icmp-type', '3',
+ '--icmp-code', '1',
+ self._security_group.id,
+ ]
+ verifylist = [
+ ('dst_port', (80, 80)),
+ ('icmp_type', 3),
+ ('icmp_code', 1),
+ ('group', self._security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.assertRaises(exceptions.CommandError, self.cmd.take_action,
+ parsed_args)
+
+ def test_create_default_rule(self):
+ self._setup_security_group_rule({
+ 'port_range_max': 443,
+ 'port_range_min': 443,
+ })
+ arglist = [
+ '--dst-port', str(self._security_group_rule.port_range_min),
+ self._security_group.id,
+ ]
+ verifylist = [
+ ('dst_port', (self._security_group_rule.port_range_min,
+ self._security_group_rule.port_range_max)),
+ ('group', self._security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_security_group_rule.assert_called_once_with(**{
+ 'direction': self._security_group_rule.direction,
+ 'ethertype': self._security_group_rule.ethertype,
+ 'port_range_max': self._security_group_rule.port_range_max,
+ 'port_range_min': self._security_group_rule.port_range_min,
+ 'protocol': self._security_group_rule.protocol,
+ 'remote_ip_prefix': self._security_group_rule.remote_ip_prefix,
+ 'security_group_id': self._security_group.id,
+ })
+ self.assertEqual(self.expected_columns, columns)
+ self.assertEqual(self.expected_data, data)
+
+ def test_create_proto_option(self):
+ self._setup_security_group_rule({
+ 'protocol': 'icmp',
+ 'remote_ip_prefix': '10.0.2.0/24',
+ })
+ arglist = [
+ '--proto', self._security_group_rule.protocol,
+ '--src-ip', self._security_group_rule.remote_ip_prefix,
+ self._security_group.id,
+ ]
+ verifylist = [
+ ('proto', self._security_group_rule.protocol),
+ ('protocol', None),
+ ('src_ip', self._security_group_rule.remote_ip_prefix),
+ ('group', self._security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_security_group_rule.assert_called_once_with(**{
+ 'direction': self._security_group_rule.direction,
+ 'ethertype': self._security_group_rule.ethertype,
+ 'protocol': self._security_group_rule.protocol,
+ 'remote_ip_prefix': self._security_group_rule.remote_ip_prefix,
+ 'security_group_id': self._security_group.id,
+ })
+ self.assertEqual(self.expected_columns, columns)
+ self.assertEqual(self.expected_data, data)
+
+ def test_create_source_group(self):
+ self._setup_security_group_rule({
+ 'port_range_max': 22,
+ 'port_range_min': 22,
+ 'remote_group_id': self._security_group.id,
+ })
+ arglist = [
+ '--dst-port', str(self._security_group_rule.port_range_min),
+ '--ingress',
+ '--src-group', self._security_group.name,
+ self._security_group.id,
+ ]
+ verifylist = [
+ ('dst_port', (self._security_group_rule.port_range_min,
+ self._security_group_rule.port_range_max)),
+ ('ingress', True),
+ ('src_group', self._security_group.name),
+ ('group', self._security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_security_group_rule.assert_called_once_with(**{
+ 'direction': self._security_group_rule.direction,
+ 'ethertype': self._security_group_rule.ethertype,
+ 'port_range_max': self._security_group_rule.port_range_max,
+ 'port_range_min': self._security_group_rule.port_range_min,
+ 'protocol': self._security_group_rule.protocol,
+ 'remote_group_id': self._security_group_rule.remote_group_id,
+ 'security_group_id': self._security_group.id,
+ })
+ self.assertEqual(self.expected_columns, columns)
+ self.assertEqual(self.expected_data, data)
+
+ def test_create_source_ip(self):
+ self._setup_security_group_rule({
+ 'protocol': 'icmp',
+ 'remote_ip_prefix': '10.0.2.0/24',
+ })
+ arglist = [
+ '--protocol', self._security_group_rule.protocol,
+ '--src-ip', self._security_group_rule.remote_ip_prefix,
+ self._security_group.id,
+ ]
+ verifylist = [
+ ('protocol', self._security_group_rule.protocol),
+ ('src_ip', self._security_group_rule.remote_ip_prefix),
+ ('group', self._security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_security_group_rule.assert_called_once_with(**{
+ 'direction': self._security_group_rule.direction,
+ 'ethertype': self._security_group_rule.ethertype,
+ 'protocol': self._security_group_rule.protocol,
+ 'remote_ip_prefix': self._security_group_rule.remote_ip_prefix,
+ 'security_group_id': self._security_group.id,
+ })
+ self.assertEqual(self.expected_columns, columns)
+ self.assertEqual(self.expected_data, data)
+
+ def test_create_network_options(self):
+ self._setup_security_group_rule({
+ 'direction': 'egress',
+ 'ethertype': 'IPv6',
+ 'port_range_max': 443,
+ 'port_range_min': 443,
+ 'protocol': '6',
+ 'remote_group_id': None,
+ 'remote_ip_prefix': None,
+ })
+ arglist = [
+ '--dst-port', str(self._security_group_rule.port_range_min),
+ '--egress',
+ '--ethertype', self._security_group_rule.ethertype,
+ '--project', self.project.name,
+ '--project-domain', self.domain.name,
+ '--protocol', self._security_group_rule.protocol,
+ self._security_group.id,
+ ]
+ verifylist = [
+ ('dst_port', (self._security_group_rule.port_range_min,
+ self._security_group_rule.port_range_max)),
+ ('egress', True),
+ ('ethertype', self._security_group_rule.ethertype),
+ ('project', self.project.name),
+ ('project_domain', self.domain.name),
+ ('protocol', self._security_group_rule.protocol),
+ ('group', self._security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_security_group_rule.assert_called_once_with(**{
+ 'direction': self._security_group_rule.direction,
+ 'ethertype': self._security_group_rule.ethertype,
+ 'port_range_max': self._security_group_rule.port_range_max,
+ 'port_range_min': self._security_group_rule.port_range_min,
+ 'protocol': self._security_group_rule.protocol,
+ 'security_group_id': self._security_group.id,
+ 'tenant_id': self.project.id,
+ })
+ self.assertEqual(self.expected_columns, columns)
+ self.assertEqual(self.expected_data, data)
+
+ def test_create_tcp_with_icmp_type(self):
+ arglist = [
+ '--protocol', 'tcp',
+ '--icmp-type', '15',
+ self._security_group.id,
+ ]
+ verifylist = [
+ ('protocol', 'tcp'),
+ ('icmp_type', 15),
+ ('group', self._security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.assertRaises(exceptions.CommandError, self.cmd.take_action,
+ parsed_args)
+
+ def test_create_icmp_code(self):
+ arglist = [
+ '--protocol', '1',
+ '--icmp-code', '1',
+ self._security_group.id,
+ ]
+ verifylist = [
+ ('protocol', '1'),
+ ('icmp_code', 1),
+ ('group', self._security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.assertRaises(exceptions.CommandError, self.cmd.take_action,
+ parsed_args)
+
+ def test_create_icmp_type(self):
+ self._setup_security_group_rule({
+ 'port_range_min': 15,
+ 'protocol': 'icmp',
+ 'remote_ip_prefix': '0.0.0.0/0',
+ })
+ arglist = [
+ '--icmp-type', str(self._security_group_rule.port_range_min),
+ '--protocol', self._security_group_rule.protocol,
+ self._security_group.id,
+ ]
+ verifylist = [
+ ('dst_port', None),
+ ('icmp_type', self._security_group_rule.port_range_min),
+ ('icmp_code', None),
+ ('protocol', self._security_group_rule.protocol),
+ ('group', self._security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_security_group_rule.assert_called_once_with(**{
+ 'direction': self._security_group_rule.direction,
+ 'ethertype': self._security_group_rule.ethertype,
+ 'port_range_min': self._security_group_rule.port_range_min,
+ 'protocol': self._security_group_rule.protocol,
+ 'remote_ip_prefix': self._security_group_rule.remote_ip_prefix,
+ 'security_group_id': self._security_group.id,
+ })
+ self.assertEqual(self.expected_columns, columns)
+ self.assertEqual(self.expected_data, data)
+
+ def test_create_ipv6_icmp_type_code(self):
+ self._setup_security_group_rule({
+ 'ethertype': 'IPv6',
+ 'port_range_min': 139,
+ 'port_range_max': 2,
+ 'protocol': 'ipv6-icmp',
+ })
+ arglist = [
+ '--icmp-type', str(self._security_group_rule.port_range_min),
+ '--icmp-code', str(self._security_group_rule.port_range_max),
+ '--protocol', self._security_group_rule.protocol,
+ self._security_group.id,
+ ]
+ verifylist = [
+ ('dst_port', None),
+ ('icmp_type', self._security_group_rule.port_range_min),
+ ('icmp_code', self._security_group_rule.port_range_max),
+ ('protocol', self._security_group_rule.protocol),
+ ('group', self._security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_security_group_rule.assert_called_once_with(**{
+ 'direction': self._security_group_rule.direction,
+ 'ethertype': self._security_group_rule.ethertype,
+ 'port_range_min': self._security_group_rule.port_range_min,
+ 'port_range_max': self._security_group_rule.port_range_max,
+ 'protocol': self._security_group_rule.protocol,
+ 'security_group_id': self._security_group.id,
+ })
+ self.assertEqual(self.expected_columns, columns)
+ self.assertEqual(self.expected_data, data)
+
+ def test_create_icmpv6_type(self):
+ self._setup_security_group_rule({
+ 'ethertype': 'IPv6',
+ 'port_range_min': 139,
+ 'protocol': 'icmpv6',
+ })
+ arglist = [
+ '--icmp-type', str(self._security_group_rule.port_range_min),
+ '--protocol', self._security_group_rule.protocol,
+ self._security_group.id,
+ ]
+ verifylist = [
+ ('dst_port', None),
+ ('icmp_type', self._security_group_rule.port_range_min),
+ ('icmp_code', None),
+ ('protocol', self._security_group_rule.protocol),
+ ('group', self._security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_security_group_rule.assert_called_once_with(**{
+ 'direction': self._security_group_rule.direction,
+ 'ethertype': self._security_group_rule.ethertype,
+ 'port_range_min': self._security_group_rule.port_range_min,
+ 'protocol': self._security_group_rule.protocol,
+ 'security_group_id': self._security_group.id,
+ })
+ self.assertEqual(self.expected_columns, columns)
+ self.assertEqual(self.expected_data, data)
+
+
+class TestCreateSecurityGroupRuleCompute(TestSecurityGroupRuleCompute):
+
+ project = identity_fakes.FakeProject.create_one_project()
+ domain = identity_fakes.FakeDomain.create_one_domain()
+ # The security group rule to be created.
+ _security_group_rule = None
+
+ # The security group that will contain the rule created.
+ _security_group = \
+ compute_fakes.FakeSecurityGroup.create_one_security_group()
+
+ def _setup_security_group_rule(self, attrs=None):
+ self._security_group_rule = \
+ compute_fakes.FakeSecurityGroupRule.create_one_security_group_rule(
+ attrs)
+ self.compute.security_group_rules.create.return_value = \
+ self._security_group_rule
+ expected_columns, expected_data = \
+ security_group_rule._format_security_group_rule_show(
+ self._security_group_rule._info)
+ return expected_columns, expected_data
+
+ def setUp(self):
+ super(TestCreateSecurityGroupRuleCompute, self).setUp()
+
+ self.app.client_manager.network_endpoint_enabled = False
+
+ self.compute.security_groups.get.return_value = self._security_group
+
+ # Get the command object to test
+ self.cmd = security_group_rule.CreateSecurityGroupRule(self.app, None)
+
+ def test_create_no_options(self):
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, [], [])
+
+ def test_create_all_source_options(self):
+ arglist = [
+ '--src-ip', '10.10.0.0/24',
+ '--src-group', self._security_group.id,
+ self._security_group.id,
+ ]
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, arglist, [])
+
+ def test_create_bad_protocol(self):
+ arglist = [
+ '--protocol', 'foo',
+ self._security_group.id,
+ ]
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, arglist, [])
+
+ def test_create_all_protocol_options(self):
+ arglist = [
+ '--protocol', 'tcp',
+ '--proto', 'tcp',
+ self._security_group.id,
+ ]
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, arglist, [])
+
+ def test_create_network_options(self):
+ arglist = [
+ '--ingress',
+ '--ethertype', 'IPv4',
+ '--icmp-type', '3',
+ '--icmp-code', '11',
+ '--project', self.project.name,
+ '--project-domain', self.domain.name,
+ self._security_group.id,
+ ]
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, arglist, [])
+
+ def test_create_default_rule(self):
+ expected_columns, expected_data = self._setup_security_group_rule()
+ dst_port = str(self._security_group_rule.from_port) + ':' + \
+ str(self._security_group_rule.to_port)
+ arglist = [
+ '--dst-port', dst_port,
+ self._security_group.id,
+ ]
+ verifylist = [
+ ('dst_port', (self._security_group_rule.from_port,
+ self._security_group_rule.to_port)),
+ ('group', self._security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.compute.security_group_rules.create.assert_called_once_with(
+ self._security_group.id,
+ self._security_group_rule.ip_protocol,
+ self._security_group_rule.from_port,
+ self._security_group_rule.to_port,
+ self._security_group_rule.ip_range['cidr'],
+ None,
+ )
+ self.assertEqual(expected_columns, columns)
+ self.assertEqual(expected_data, data)
+
+ def test_create_source_group(self):
+ expected_columns, expected_data = self._setup_security_group_rule({
+ 'from_port': 22,
+ 'to_port': 22,
+ 'group': {'name': self._security_group.name},
+ })
+ arglist = [
+ '--dst-port', str(self._security_group_rule.from_port),
+ '--src-group', self._security_group.name,
+ self._security_group.id,
+ ]
+ verifylist = [
+ ('dst_port', (self._security_group_rule.from_port,
+ self._security_group_rule.to_port)),
+ ('src_group', self._security_group.name),
+ ('group', self._security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.compute.security_group_rules.create.assert_called_once_with(
+ self._security_group.id,
+ self._security_group_rule.ip_protocol,
+ self._security_group_rule.from_port,
+ self._security_group_rule.to_port,
+ self._security_group_rule.ip_range['cidr'],
+ self._security_group.id,
+ )
+ self.assertEqual(expected_columns, columns)
+ self.assertEqual(expected_data, data)
+
+ def test_create_source_ip(self):
+ expected_columns, expected_data = self._setup_security_group_rule({
+ 'ip_protocol': 'icmp',
+ 'from_port': -1,
+ 'to_port': -1,
+ 'ip_range': {'cidr': '10.0.2.0/24'},
+ })
+ arglist = [
+ '--protocol', self._security_group_rule.ip_protocol,
+ '--src-ip', self._security_group_rule.ip_range['cidr'],
+ self._security_group.id,
+ ]
+ verifylist = [
+ ('protocol', self._security_group_rule.ip_protocol),
+ ('src_ip', self._security_group_rule.ip_range['cidr']),
+ ('group', self._security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.compute.security_group_rules.create.assert_called_once_with(
+ self._security_group.id,
+ self._security_group_rule.ip_protocol,
+ self._security_group_rule.from_port,
+ self._security_group_rule.to_port,
+ self._security_group_rule.ip_range['cidr'],
+ None,
+ )
+ self.assertEqual(expected_columns, columns)
+ self.assertEqual(expected_data, data)
+
+ def test_create_proto_option(self):
+ expected_columns, expected_data = self._setup_security_group_rule({
+ 'ip_protocol': 'icmp',
+ 'from_port': -1,
+ 'to_port': -1,
+ 'ip_range': {'cidr': '10.0.2.0/24'},
+ })
+ arglist = [
+ '--proto', self._security_group_rule.ip_protocol,
+ '--src-ip', self._security_group_rule.ip_range['cidr'],
+ self._security_group.id,
+ ]
+ verifylist = [
+ ('proto', self._security_group_rule.ip_protocol),
+ ('protocol', None),
+ ('src_ip', self._security_group_rule.ip_range['cidr']),
+ ('group', self._security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.compute.security_group_rules.create.assert_called_once_with(
+ self._security_group.id,
+ self._security_group_rule.ip_protocol,
+ self._security_group_rule.from_port,
+ self._security_group_rule.to_port,
+ self._security_group_rule.ip_range['cidr'],
+ None,
+ )
+ self.assertEqual(expected_columns, columns)
+ self.assertEqual(expected_data, data)
+
+
+class TestDeleteSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork):
+
+ # The security group rules to be deleted.
+ _security_group_rules = \
+ network_fakes.FakeSecurityGroupRule.create_security_group_rules(
+ count=2)
+
+ def setUp(self):
+ super(TestDeleteSecurityGroupRuleNetwork, self).setUp()
+
+ self.network.delete_security_group_rule = mock.Mock(return_value=None)
+
+ self.network.find_security_group_rule = (
+ network_fakes.FakeSecurityGroupRule.get_security_group_rules(
+ self._security_group_rules)
+ )
+
+ # Get the command object to test
+ self.cmd = security_group_rule.DeleteSecurityGroupRule(
+ self.app, self.namespace)
+
+ def test_security_group_rule_delete(self):
+ arglist = [
+ self._security_group_rules[0].id,
+ ]
+ verifylist = [
+ ('rule', [self._security_group_rules[0].id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.network.delete_security_group_rule.assert_called_once_with(
+ self._security_group_rules[0])
+ self.assertIsNone(result)
+
+ def test_multi_security_group_rules_delete(self):
+ arglist = []
+ verifylist = []
+
+ for s in self._security_group_rules:
+ arglist.append(s.id)
+ verifylist = [
+ ('rule', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for s in self._security_group_rules:
+ calls.append(call(s))
+ self.network.delete_security_group_rule.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_multi_security_group_rules_delete_with_exception(self):
+ arglist = [
+ self._security_group_rules[0].id,
+ 'unexist_rule',
+ ]
+ verifylist = [
+ ('rule',
+ [self._security_group_rules[0].id, 'unexist_rule']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [
+ self._security_group_rules[0], exceptions.CommandError]
+ self.network.find_security_group_rule = (
+ mock.MagicMock(side_effect=find_mock_result)
+ )
+
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 rules failed to delete.', str(e))
+
+ self.network.find_security_group_rule.assert_any_call(
+ self._security_group_rules[0].id, ignore_missing=False)
+ self.network.find_security_group_rule.assert_any_call(
+ 'unexist_rule', ignore_missing=False)
+ self.network.delete_security_group_rule.assert_called_once_with(
+ self._security_group_rules[0]
+ )
+
+
+class TestDeleteSecurityGroupRuleCompute(TestSecurityGroupRuleCompute):
+
+ # The security group rule to be deleted.
+ _security_group_rules = \
+ compute_fakes.FakeSecurityGroupRule.create_security_group_rules(
+ count=2)
+
+ def setUp(self):
+ super(TestDeleteSecurityGroupRuleCompute, self).setUp()
+
+ self.app.client_manager.network_endpoint_enabled = False
+
+ # Get the command object to test
+ self.cmd = security_group_rule.DeleteSecurityGroupRule(self.app, None)
+
+ def test_security_group_rule_delete(self):
+ arglist = [
+ self._security_group_rules[0].id,
+ ]
+ verifylist = [
+ ('rule', [self._security_group_rules[0].id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.compute.security_group_rules.delete.assert_called_once_with(
+ self._security_group_rules[0].id)
+ self.assertIsNone(result)
+
+ def test_multi_security_group_rules_delete(self):
+ arglist = []
+ verifylist = []
+
+ for s in self._security_group_rules:
+ arglist.append(s.id)
+ verifylist = [
+ ('rule', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for s in self._security_group_rules:
+ calls.append(call(s.id))
+ self.compute.security_group_rules.delete.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_multi_security_group_rules_delete_with_exception(self):
+ arglist = [
+ self._security_group_rules[0].id,
+ 'unexist_rule',
+ ]
+ verifylist = [
+ ('rule',
+ [self._security_group_rules[0].id, 'unexist_rule']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [None, exceptions.CommandError]
+ self.compute.security_group_rules.delete = (
+ mock.MagicMock(side_effect=find_mock_result)
+ )
+
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 rules failed to delete.', str(e))
+
+ self.compute.security_group_rules.delete.assert_any_call(
+ self._security_group_rules[0].id)
+ self.compute.security_group_rules.delete.assert_any_call(
+ 'unexist_rule')
+
+
+class TestListSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork):
+
+ # The security group to hold the rules.
+ _security_group = \
+ network_fakes.FakeSecurityGroup.create_one_security_group()
+
+ # The security group rule to be listed.
+ _security_group_rule_tcp = \
+ network_fakes.FakeSecurityGroupRule.create_one_security_group_rule({
+ 'protocol': 'tcp',
+ 'port_range_max': 80,
+ 'port_range_min': 80,
+ 'security_group_id': _security_group.id,
+ })
+ _security_group_rule_icmp = \
+ network_fakes.FakeSecurityGroupRule.create_one_security_group_rule({
+ 'protocol': 'icmp',
+ 'remote_ip_prefix': '10.0.2.0/24',
+ 'security_group_id': _security_group.id,
+ })
+ _security_group.security_group_rules = [_security_group_rule_tcp._info,
+ _security_group_rule_icmp._info]
+ _security_group_rules = [_security_group_rule_tcp,
+ _security_group_rule_icmp]
+
+ expected_columns_with_group_and_long = (
+ 'ID',
+ 'IP Protocol',
+ 'IP Range',
+ 'Port Range',
+ 'Direction',
+ 'Ethertype',
+ 'Remote Security Group',
+ )
+ expected_columns_no_group = (
+ 'ID',
+ 'IP Protocol',
+ 'IP Range',
+ 'Port Range',
+ 'Remote Security Group',
+ 'Security Group',
+ )
+
+ expected_data_with_group_and_long = []
+ expected_data_no_group = []
+ for _security_group_rule in _security_group_rules:
+ expected_data_with_group_and_long.append((
+ _security_group_rule.id,
+ _security_group_rule.protocol,
+ _security_group_rule.remote_ip_prefix,
+ security_group_rule._format_network_port_range(
+ _security_group_rule),
+ _security_group_rule.direction,
+ _security_group_rule.ethertype,
+ _security_group_rule.remote_group_id,
+ ))
+ expected_data_no_group.append((
+ _security_group_rule.id,
+ _security_group_rule.protocol,
+ _security_group_rule.remote_ip_prefix,
+ security_group_rule._format_network_port_range(
+ _security_group_rule),
+ _security_group_rule.remote_group_id,
+ _security_group_rule.security_group_id,
+ ))
+
+ def setUp(self):
+ super(TestListSecurityGroupRuleNetwork, self).setUp()
+
+ self.network.find_security_group = mock.Mock(
+ return_value=self._security_group)
+ self.network.security_group_rules = mock.Mock(
+ return_value=self._security_group_rules)
+
+ # Get the command object to test
+ self.cmd = security_group_rule.ListSecurityGroupRule(
+ self.app, self.namespace)
+
+ def test_list_default(self):
+ self._security_group_rule_tcp.port_range_min = 80
+ parsed_args = self.check_parser(self.cmd, [], [])
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.security_group_rules.assert_called_once_with(**{})
+ self.assertEqual(self.expected_columns_no_group, columns)
+ self.assertEqual(self.expected_data_no_group, list(data))
+
+ def test_list_with_group_and_long(self):
+ self._security_group_rule_tcp.port_range_min = 80
+ arglist = [
+ '--long',
+ self._security_group.id,
+ ]
+ verifylist = [
+ ('long', True),
+ ('group', self._security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.security_group_rules.assert_called_once_with(**{
+ 'security_group_id': self._security_group.id,
+ })
+ self.assertEqual(self.expected_columns_with_group_and_long, columns)
+ self.assertEqual(self.expected_data_with_group_and_long, list(data))
+
+ def test_list_with_ignored_options(self):
+ self._security_group_rule_tcp.port_range_min = 80
+ arglist = [
+ '--all-projects',
+ ]
+ verifylist = [
+ ('all_projects', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.security_group_rules.assert_called_once_with(**{})
+ self.assertEqual(self.expected_columns_no_group, columns)
+ self.assertEqual(self.expected_data_no_group, list(data))
+
+
+class TestListSecurityGroupRuleCompute(TestSecurityGroupRuleCompute):
+
+ # The security group to hold the rules.
+ _security_group = \
+ compute_fakes.FakeSecurityGroup.create_one_security_group()
+
+ # The security group rule to be listed.
+ _security_group_rule_tcp = \
+ compute_fakes.FakeSecurityGroupRule.create_one_security_group_rule({
+ 'ip_protocol': 'tcp',
+ 'from_port': 80,
+ 'to_port': 80,
+ 'group': {'name': _security_group.name},
+ })
+ _security_group_rule_icmp = \
+ compute_fakes.FakeSecurityGroupRule.create_one_security_group_rule({
+ 'ip_protocol': 'icmp',
+ 'from_port': -1,
+ 'to_port': -1,
+ 'ip_range': {'cidr': '10.0.2.0/24'},
+ 'group': {'name': _security_group.name},
+ })
+ _security_group.rules = [_security_group_rule_tcp._info,
+ _security_group_rule_icmp._info]
+
+ expected_columns_with_group = (
+ 'ID',
+ 'IP Protocol',
+ 'IP Range',
+ 'Port Range',
+ 'Remote Security Group',
+ )
+ expected_columns_no_group = \
+ expected_columns_with_group + ('Security Group',)
+
+ expected_data_with_group = []
+ expected_data_no_group = []
+ for _security_group_rule in _security_group.rules:
+ rule = network_utils.transform_compute_security_group_rule(
+ _security_group_rule
+ )
+ expected_rule_with_group = (
+ rule['id'],
+ rule['ip_protocol'],
+ rule['ip_range'],
+ rule['port_range'],
+ rule['remote_security_group'],
+ )
+ expected_rule_no_group = expected_rule_with_group + \
+ (_security_group_rule['parent_group_id'],)
+ expected_data_with_group.append(expected_rule_with_group)
+ expected_data_no_group.append(expected_rule_no_group)
+
+ def setUp(self):
+ super(TestListSecurityGroupRuleCompute, self).setUp()
+
+ self.app.client_manager.network_endpoint_enabled = False
+
+ self.compute.security_groups.get.return_value = \
+ self._security_group
+ self.compute.security_groups.list.return_value = \
+ [self._security_group]
+
+ # Get the command object to test
+ self.cmd = security_group_rule.ListSecurityGroupRule(self.app, None)
+
+ def test_list_default(self):
+ parsed_args = self.check_parser(self.cmd, [], [])
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.compute.security_groups.list.assert_called_once_with(
+ search_opts={'all_tenants': False}
+ )
+ self.assertEqual(self.expected_columns_no_group, columns)
+ self.assertEqual(self.expected_data_no_group, list(data))
+
+ def test_list_with_group(self):
+ arglist = [
+ self._security_group.id,
+ ]
+ verifylist = [
+ ('group', self._security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.compute.security_groups.get.assert_called_once_with(
+ self._security_group.id
+ )
+ self.assertEqual(self.expected_columns_with_group, columns)
+ self.assertEqual(self.expected_data_with_group, list(data))
+
+ def test_list_all_projects(self):
+ arglist = [
+ '--all-projects',
+ ]
+ verifylist = [
+ ('all_projects', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.compute.security_groups.list.assert_called_once_with(
+ search_opts={'all_tenants': True}
+ )
+ self.assertEqual(self.expected_columns_no_group, columns)
+ self.assertEqual(self.expected_data_no_group, list(data))
+
+ def test_list_with_ignored_options(self):
+ arglist = [
+ '--long',
+ ]
+ verifylist = [
+ ('long', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.compute.security_groups.list.assert_called_once_with(
+ search_opts={'all_tenants': False}
+ )
+ self.assertEqual(self.expected_columns_no_group, columns)
+ self.assertEqual(self.expected_data_no_group, list(data))
+
+
+class TestShowSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork):
+
+ # The security group rule to be shown.
+ _security_group_rule = \
+ network_fakes.FakeSecurityGroupRule.create_one_security_group_rule()
+
+ columns = (
+ 'direction',
+ 'ethertype',
+ 'id',
+ 'port_range_max',
+ 'port_range_min',
+ 'project_id',
+ 'protocol',
+ 'remote_group_id',
+ 'remote_ip_prefix',
+ 'security_group_id',
+ )
+
+ data = (
+ _security_group_rule.direction,
+ _security_group_rule.ethertype,
+ _security_group_rule.id,
+ _security_group_rule.port_range_max,
+ _security_group_rule.port_range_min,
+ _security_group_rule.project_id,
+ _security_group_rule.protocol,
+ _security_group_rule.remote_group_id,
+ _security_group_rule.remote_ip_prefix,
+ _security_group_rule.security_group_id,
+ )
+
+ def setUp(self):
+ super(TestShowSecurityGroupRuleNetwork, self).setUp()
+
+ self.network.find_security_group_rule = mock.Mock(
+ return_value=self._security_group_rule)
+
+ # Get the command object to test
+ self.cmd = security_group_rule.ShowSecurityGroupRule(
+ self.app, self.namespace)
+
+ def test_show_no_options(self):
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, [], [])
+
+ def test_show_all_options(self):
+ arglist = [
+ self._security_group_rule.id,
+ ]
+ verifylist = [
+ ('rule', self._security_group_rule.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.find_security_group_rule.assert_called_once_with(
+ self._security_group_rule.id, ignore_missing=False)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestShowSecurityGroupRuleCompute(TestSecurityGroupRuleCompute):
+
+ # The security group rule to be shown.
+ _security_group_rule = \
+ compute_fakes.FakeSecurityGroupRule.create_one_security_group_rule()
+
+ columns, data = \
+ security_group_rule._format_security_group_rule_show(
+ _security_group_rule._info)
+
+ def setUp(self):
+ super(TestShowSecurityGroupRuleCompute, self).setUp()
+
+ self.app.client_manager.network_endpoint_enabled = False
+
+ # Build a security group fake customized for this test.
+ security_group_rules = [self._security_group_rule._info]
+ security_group = fakes.FakeResource(
+ info=copy.deepcopy({'rules': security_group_rules}),
+ loaded=True)
+ security_group.rules = security_group_rules
+ self.compute.security_groups.list.return_value = [security_group]
+
+ # Get the command object to test
+ self.cmd = security_group_rule.ShowSecurityGroupRule(self.app, None)
+
+ def test_show_no_options(self):
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, [], [])
+
+ def test_show_all_options(self):
+ arglist = [
+ self._security_group_rule.id,
+ ]
+ verifylist = [
+ ('rule', self._security_group_rule.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.compute.security_groups.list.assert_called_once_with()
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
diff --git a/openstackclient/tests/unit/network/v2/test_subnet.py b/openstackclient/tests/unit/network/v2/test_subnet.py
new file mode 100644
index 00000000..e31db469
--- /dev/null
+++ b/openstackclient/tests/unit/network/v2/test_subnet.py
@@ -0,0 +1,978 @@
+# 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.
+#
+
+import mock
+from mock import call
+
+from osc_lib import exceptions
+from osc_lib import utils
+
+from openstackclient.network.v2 import subnet as subnet_v2
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes_v3
+from openstackclient.tests.unit.network.v2 import fakes as network_fakes
+from openstackclient.tests.unit import utils as tests_utils
+
+
+class TestSubnet(network_fakes.TestNetworkV2):
+
+ def setUp(self):
+ super(TestSubnet, self).setUp()
+
+ # Get a shortcut to the network client
+ self.network = self.app.client_manager.network
+ # Get a shortcut to the ProjectManager Mock
+ self.projects_mock = self.app.client_manager.identity.projects
+ # Get a shortcut to the DomainManager Mock
+ self.domains_mock = self.app.client_manager.identity.domains
+
+
+class TestCreateSubnet(TestSubnet):
+
+ project = identity_fakes_v3.FakeProject.create_one_project()
+ domain = identity_fakes_v3.FakeDomain.create_one_domain()
+ # An IPv4 subnet to be created with mostly default values
+ _subnet = network_fakes.FakeSubnet.create_one_subnet(
+ attrs={
+ 'tenant_id': project.id,
+ }
+ )
+
+ # Subnet pool to be used to create a subnet from a pool
+ _subnet_pool = network_fakes.FakeSubnetPool.create_one_subnet_pool()
+
+ # An IPv4 subnet to be created using a specific subnet pool
+ _subnet_from_pool = network_fakes.FakeSubnet.create_one_subnet(
+ attrs={
+ 'tenant_id': project.id,
+ 'subnetpool_id': _subnet_pool.id,
+ 'dns_nameservers': ['8.8.8.8',
+ '8.8.4.4'],
+ 'host_routes': [{'destination': '10.20.20.0/24',
+ 'nexthop': '10.20.20.1'},
+ {'destination': '10.30.30.0/24',
+ 'nexthop': '10.30.30.1'}],
+ 'service_types': ['network:router_gateway',
+ 'network:floatingip_agent_gateway'],
+ }
+ )
+
+ # An IPv6 subnet to be created with most options specified
+ _subnet_ipv6 = network_fakes.FakeSubnet.create_one_subnet(
+ attrs={
+ 'tenant_id': project.id,
+ 'cidr': 'fe80:0:0:a00a::/64',
+ 'enable_dhcp': True,
+ 'dns_nameservers': ['fe80:27ff:a00a:f00f::ffff',
+ 'fe80:37ff:a00a:f00f::ffff'],
+ 'allocation_pools': [{'start': 'fe80::a00a:0:c0de:0:100',
+ 'end': 'fe80::a00a:0:c0de:0:f000'},
+ {'start': 'fe80::a00a:0:c0de:1:100',
+ 'end': 'fe80::a00a:0:c0de:1:f000'}],
+ 'host_routes': [{'destination': 'fe80:27ff:a00a:f00f::/64',
+ 'nexthop': 'fe80:27ff:a00a:f00f::1'},
+ {'destination': 'fe80:37ff:a00a:f00f::/64',
+ 'nexthop': 'fe80:37ff:a00a:f00f::1'}],
+ 'ip_version': 6,
+ 'gateway_ip': 'fe80::a00a:0:c0de:0:1',
+ 'ipv6_address_mode': 'slaac',
+ 'ipv6_ra_mode': 'slaac',
+ 'subnetpool_id': 'None',
+ 'service_types': ['network:router_gateway',
+ 'network:floatingip_agent_gateway'],
+ }
+ )
+
+ # The network to be returned from find_network
+ _network = network_fakes.FakeNetwork.create_one_network(
+ attrs={
+ 'id': _subnet.network_id,
+ }
+ )
+
+ # The network segment to be returned from find_segment
+ _network_segment = \
+ network_fakes.FakeNetworkSegment.create_one_network_segment(
+ attrs={
+ 'network_id': _subnet.network_id,
+ }
+ )
+
+ columns = (
+ 'allocation_pools',
+ 'cidr',
+ 'dns_nameservers',
+ 'enable_dhcp',
+ 'gateway_ip',
+ 'host_routes',
+ 'id',
+ 'ip_version',
+ 'ipv6_address_mode',
+ 'ipv6_ra_mode',
+ 'name',
+ 'network_id',
+ 'project_id',
+ 'segment_id',
+ 'service_types',
+ 'subnetpool_id',
+ )
+
+ data = (
+ subnet_v2._format_allocation_pools(_subnet.allocation_pools),
+ _subnet.cidr,
+ utils.format_list(_subnet.dns_nameservers),
+ _subnet.enable_dhcp,
+ _subnet.gateway_ip,
+ subnet_v2._format_host_routes(_subnet.host_routes),
+ _subnet.id,
+ _subnet.ip_version,
+ _subnet.ipv6_address_mode,
+ _subnet.ipv6_ra_mode,
+ _subnet.name,
+ _subnet.network_id,
+ _subnet.project_id,
+ _subnet.segment_id,
+ utils.format_list(_subnet.service_types),
+ _subnet.subnetpool_id,
+ )
+
+ data_subnet_pool = (
+ subnet_v2._format_allocation_pools(_subnet_from_pool.allocation_pools),
+ _subnet_from_pool.cidr,
+ utils.format_list(_subnet_from_pool.dns_nameservers),
+ _subnet_from_pool.enable_dhcp,
+ _subnet_from_pool.gateway_ip,
+ subnet_v2._format_host_routes(_subnet_from_pool.host_routes),
+ _subnet_from_pool.id,
+ _subnet_from_pool.ip_version,
+ _subnet_from_pool.ipv6_address_mode,
+ _subnet_from_pool.ipv6_ra_mode,
+ _subnet_from_pool.name,
+ _subnet_from_pool.network_id,
+ _subnet_from_pool.project_id,
+ _subnet_from_pool.segment_id,
+ utils.format_list(_subnet_from_pool.service_types),
+ _subnet_from_pool.subnetpool_id,
+ )
+
+ data_ipv6 = (
+ subnet_v2._format_allocation_pools(_subnet_ipv6.allocation_pools),
+ _subnet_ipv6.cidr,
+ utils.format_list(_subnet_ipv6.dns_nameservers),
+ _subnet_ipv6.enable_dhcp,
+ _subnet_ipv6.gateway_ip,
+ subnet_v2._format_host_routes(_subnet_ipv6.host_routes),
+ _subnet_ipv6.id,
+ _subnet_ipv6.ip_version,
+ _subnet_ipv6.ipv6_address_mode,
+ _subnet_ipv6.ipv6_ra_mode,
+ _subnet_ipv6.name,
+ _subnet_ipv6.network_id,
+ _subnet_ipv6.project_id,
+ _subnet_ipv6.segment_id,
+ utils.format_list(_subnet_ipv6.service_types),
+ _subnet_ipv6.subnetpool_id,
+ )
+
+ def setUp(self):
+ super(TestCreateSubnet, self).setUp()
+
+ # Get the command object to test
+ self.cmd = subnet_v2.CreateSubnet(self.app, self.namespace)
+
+ self.projects_mock.get.return_value = self.project
+ self.domains_mock.get.return_value = self.domain
+
+ # Mock SDK calls for all tests.
+ self.network.find_network = mock.Mock(return_value=self._network)
+ self.network.find_segment = mock.Mock(
+ return_value=self._network_segment
+ )
+ self.network.find_subnet_pool = mock.Mock(
+ return_value=self._subnet_pool
+ )
+
+ def test_create_no_options(self):
+ arglist = []
+ verifylist = []
+
+ # Testing that a call without the required argument will fail and
+ # throw a "ParserExecption"
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, arglist, verifylist)
+
+ def test_create_default_options(self):
+ # Mock SDK calls for this test.
+ self.network.create_subnet = mock.Mock(return_value=self._subnet)
+ self._network.id = self._subnet.network_id
+
+ arglist = [
+ "--subnet-range", self._subnet.cidr,
+ "--network", self._subnet.network_id,
+ self._subnet.name,
+ ]
+ verifylist = [
+ ('name', self._subnet.name),
+ ('subnet_range', self._subnet.cidr),
+ ('network', self._subnet.network_id),
+ ('ip_version', self._subnet.ip_version),
+ ('gateway', 'auto'),
+
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_subnet.assert_called_once_with(**{
+ 'cidr': self._subnet.cidr,
+ 'ip_version': self._subnet.ip_version,
+ 'name': self._subnet.name,
+ 'network_id': self._subnet.network_id,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_create_from_subnet_pool_options(self):
+ # Mock SDK calls for this test.
+ self.network.create_subnet = \
+ mock.Mock(return_value=self._subnet_from_pool)
+ self._network.id = self._subnet_from_pool.network_id
+
+ arglist = [
+ self._subnet_from_pool.name,
+ "--subnet-pool", self._subnet_from_pool.subnetpool_id,
+ "--prefix-length", '24',
+ "--network", self._subnet_from_pool.network_id,
+ "--ip-version", str(self._subnet_from_pool.ip_version),
+ "--gateway", self._subnet_from_pool.gateway_ip,
+ "--dhcp",
+ ]
+
+ for dns_addr in self._subnet_from_pool.dns_nameservers:
+ arglist.append('--dns-nameserver')
+ arglist.append(dns_addr)
+
+ for host_route in self._subnet_from_pool.host_routes:
+ arglist.append('--host-route')
+ value = 'gateway=' + host_route.get('nexthop', '') + \
+ ',destination=' + host_route.get('destination', '')
+ arglist.append(value)
+
+ for service_type in self._subnet_from_pool.service_types:
+ arglist.append('--service-type')
+ arglist.append(service_type)
+
+ verifylist = [
+ ('name', self._subnet_from_pool.name),
+ ('prefix_length', '24'),
+ ('network', self._subnet_from_pool.network_id),
+ ('ip_version', self._subnet_from_pool.ip_version),
+ ('gateway', self._subnet_from_pool.gateway_ip),
+ ('dns_nameservers', self._subnet_from_pool.dns_nameservers),
+ ('dhcp', self._subnet_from_pool.enable_dhcp),
+ ('host_routes', subnet_v2.convert_entries_to_gateway(
+ self._subnet_from_pool.host_routes)),
+ ('subnet_pool', self._subnet_from_pool.subnetpool_id),
+ ('service_types', self._subnet_from_pool.service_types),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_subnet.assert_called_once_with(**{
+ 'dns_nameservers': self._subnet_from_pool.dns_nameservers,
+ 'enable_dhcp': self._subnet_from_pool.enable_dhcp,
+ 'gateway_ip': self._subnet_from_pool.gateway_ip,
+ 'host_routes': self._subnet_from_pool.host_routes,
+ 'ip_version': self._subnet_from_pool.ip_version,
+ 'name': self._subnet_from_pool.name,
+ 'network_id': self._subnet_from_pool.network_id,
+ 'prefixlen': '24',
+ 'subnetpool_id': self._subnet_from_pool.subnetpool_id,
+ 'service_types': self._subnet_from_pool.service_types,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data_subnet_pool, data)
+
+ def test_create_options_subnet_range_ipv6(self):
+ # Mock SDK calls for this test.
+ self.network.create_subnet = mock.Mock(return_value=self._subnet_ipv6)
+ self._network.id = self._subnet_ipv6.network_id
+
+ arglist = [
+ self._subnet_ipv6.name,
+ "--subnet-range", self._subnet_ipv6.cidr,
+ "--network", self._subnet_ipv6.network_id,
+ "--ip-version", str(self._subnet_ipv6.ip_version),
+ "--ipv6-ra-mode", self._subnet_ipv6.ipv6_ra_mode,
+ "--ipv6-address-mode", self._subnet_ipv6.ipv6_address_mode,
+ "--gateway", self._subnet_ipv6.gateway_ip,
+ "--dhcp",
+ ]
+
+ for dns_addr in self._subnet_ipv6.dns_nameservers:
+ arglist.append('--dns-nameserver')
+ arglist.append(dns_addr)
+
+ for host_route in self._subnet_ipv6.host_routes:
+ arglist.append('--host-route')
+ value = 'gateway=' + host_route.get('nexthop', '') + \
+ ',destination=' + host_route.get('destination', '')
+ arglist.append(value)
+
+ for pool in self._subnet_ipv6.allocation_pools:
+ arglist.append('--allocation-pool')
+ value = 'start=' + pool.get('start', '') + \
+ ',end=' + pool.get('end', '')
+ arglist.append(value)
+
+ for service_type in self._subnet_ipv6.service_types:
+ arglist.append('--service-type')
+ arglist.append(service_type)
+
+ verifylist = [
+ ('name', self._subnet_ipv6.name),
+ ('subnet_range', self._subnet_ipv6.cidr),
+ ('network', self._subnet_ipv6.network_id),
+ ('ip_version', self._subnet_ipv6.ip_version),
+ ('ipv6_ra_mode', self._subnet_ipv6.ipv6_ra_mode),
+ ('ipv6_address_mode', self._subnet_ipv6.ipv6_address_mode),
+ ('gateway', self._subnet_ipv6.gateway_ip),
+ ('dns_nameservers', self._subnet_ipv6.dns_nameservers),
+ ('dhcp', self._subnet_ipv6.enable_dhcp),
+ ('host_routes', subnet_v2.convert_entries_to_gateway(
+ self._subnet_ipv6.host_routes)),
+ ('allocation_pools', self._subnet_ipv6.allocation_pools),
+ ('service_types', self._subnet_ipv6.service_types),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_subnet.assert_called_once_with(**{
+ 'cidr': self._subnet_ipv6.cidr,
+ 'dns_nameservers': self._subnet_ipv6.dns_nameservers,
+ 'enable_dhcp': self._subnet_ipv6.enable_dhcp,
+ 'gateway_ip': self._subnet_ipv6.gateway_ip,
+ 'host_routes': self._subnet_ipv6.host_routes,
+ 'ip_version': self._subnet_ipv6.ip_version,
+ 'ipv6_address_mode': self._subnet_ipv6.ipv6_address_mode,
+ 'ipv6_ra_mode': self._subnet_ipv6.ipv6_ra_mode,
+ 'name': self._subnet_ipv6.name,
+ 'network_id': self._subnet_ipv6.network_id,
+ 'allocation_pools': self._subnet_ipv6.allocation_pools,
+ 'service_types': self._subnet_ipv6.service_types,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data_ipv6, data)
+
+ def test_create_no_beta_command_options(self):
+ arglist = [
+ "--subnet-range", self._subnet.cidr,
+ "--network-segment", self._network_segment.id,
+ "--network", self._subnet.network_id,
+ self._subnet.name,
+ ]
+ verifylist = [
+ ('name', self._subnet.name),
+ ('subnet_range', self._subnet.cidr),
+ ('network-segment', self._network_segment.id),
+ ('network', self._subnet.network_id),
+ ]
+ self.app.options.os_beta_command = False
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, arglist, verifylist)
+
+ def test_create_with_network_segment(self):
+ # Mock SDK calls for this test.
+ self.network.create_subnet = mock.Mock(return_value=self._subnet)
+ self._network.id = self._subnet.network_id
+
+ arglist = [
+ "--subnet-range", self._subnet.cidr,
+ "--network-segment", self._network_segment.id,
+ "--network", self._subnet.network_id,
+ self._subnet.name,
+ ]
+ verifylist = [
+ ('name', self._subnet.name),
+ ('subnet_range', self._subnet.cidr),
+ ('network_segment', self._network_segment.id),
+ ('network', self._subnet.network_id),
+ ('ip_version', self._subnet.ip_version),
+ ('gateway', 'auto'),
+
+ ]
+
+ self.app.options.os_beta_command = True
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.create_subnet.assert_called_once_with(**{
+ 'cidr': self._subnet.cidr,
+ 'ip_version': self._subnet.ip_version,
+ 'name': self._subnet.name,
+ 'network_id': self._subnet.network_id,
+ 'segment_id': self._network_segment.id,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestDeleteSubnet(TestSubnet):
+
+ # The subnets to delete.
+ _subnets = network_fakes.FakeSubnet.create_subnets(count=2)
+
+ def setUp(self):
+ super(TestDeleteSubnet, self).setUp()
+
+ self.network.delete_subnet = mock.Mock(return_value=None)
+
+ self.network.find_subnet = (
+ network_fakes.FakeSubnet.get_subnets(self._subnets))
+
+ # Get the command object to test
+ self.cmd = subnet_v2.DeleteSubnet(self.app, self.namespace)
+
+ def test_subnet_delete(self):
+ arglist = [
+ self._subnets[0].name,
+ ]
+ verifylist = [
+ ('subnet', [self._subnets[0].name]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.network.delete_subnet.assert_called_once_with(self._subnets[0])
+ self.assertIsNone(result)
+
+ def test_multi_subnets_delete(self):
+ arglist = []
+ verifylist = []
+
+ for s in self._subnets:
+ arglist.append(s.name)
+ verifylist = [
+ ('subnet', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for s in self._subnets:
+ calls.append(call(s))
+ self.network.delete_subnet.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_multi_subnets_delete_with_exception(self):
+ arglist = [
+ self._subnets[0].name,
+ 'unexist_subnet',
+ ]
+ verifylist = [
+ ('subnet',
+ [self._subnets[0].name, 'unexist_subnet']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [self._subnets[0], exceptions.CommandError]
+ self.network.find_subnet = (
+ mock.MagicMock(side_effect=find_mock_result)
+ )
+
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 subnets failed to delete.', str(e))
+
+ self.network.find_subnet.assert_any_call(
+ self._subnets[0].name, ignore_missing=False)
+ self.network.find_subnet.assert_any_call(
+ 'unexist_subnet', ignore_missing=False)
+ self.network.delete_subnet.assert_called_once_with(
+ self._subnets[0]
+ )
+
+
+class TestListSubnet(TestSubnet):
+ # The subnets going to be listed up.
+ _subnet = network_fakes.FakeSubnet.create_subnets(count=3)
+
+ columns = (
+ 'ID',
+ 'Name',
+ 'Network',
+ 'Subnet',
+ )
+ columns_long = columns + (
+ 'Project',
+ 'DHCP',
+ 'Name Servers',
+ 'Allocation Pools',
+ 'Host Routes',
+ 'IP Version',
+ 'Gateway',
+ 'Service Types',
+ )
+
+ data = []
+ for subnet in _subnet:
+ data.append((
+ subnet.id,
+ subnet.name,
+ subnet.network_id,
+ subnet.cidr,
+ ))
+
+ data_long = []
+ for subnet in _subnet:
+ data_long.append((
+ subnet.id,
+ subnet.name,
+ subnet.network_id,
+ subnet.cidr,
+ subnet.tenant_id,
+ subnet.enable_dhcp,
+ utils.format_list(subnet.dns_nameservers),
+ subnet_v2._format_allocation_pools(subnet.allocation_pools),
+ utils.format_list(subnet.host_routes),
+ subnet.ip_version,
+ subnet.gateway_ip,
+ utils.format_list(subnet.service_types),
+ ))
+
+ def setUp(self):
+ super(TestListSubnet, self).setUp()
+
+ # Get the command object to test
+ self.cmd = subnet_v2.ListSubnet(self.app, self.namespace)
+
+ self.network.subnets = mock.Mock(return_value=self._subnet)
+
+ def test_subnet_list_no_options(self):
+ arglist = []
+ verifylist = [
+ ('long', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.subnets.assert_called_once_with()
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_subnet_list_long(self):
+ arglist = [
+ '--long',
+ ]
+ verifylist = [
+ ('long', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.subnets.assert_called_once_with()
+ self.assertEqual(self.columns_long, columns)
+ self.assertEqual(self.data_long, list(data))
+
+ def test_subnet_list_ip_version(self):
+ arglist = [
+ '--ip-version', str(4),
+ ]
+ verifylist = [
+ ('ip_version', 4),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {'ip_version': 4}
+
+ self.network.subnets.assert_called_once_with(**filters)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_subnet_list_dhcp(self):
+ arglist = [
+ '--dhcp',
+ ]
+ verifylist = [
+ ('dhcp', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {'enable_dhcp': True}
+
+ self.network.subnets.assert_called_once_with(**filters)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_subnet_list_no_dhcp(self):
+ arglist = [
+ '--no-dhcp',
+ ]
+ verifylist = [
+ ('no_dhcp', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {'enable_dhcp': False}
+
+ self.network.subnets.assert_called_once_with(**filters)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_subnet_list_service_type(self):
+ arglist = [
+ '--service-type', 'network:router_gateway',
+ ]
+ verifylist = [
+ ('service_types', ['network:router_gateway']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {'service_types': ['network:router_gateway']}
+
+ self.network.subnets.assert_called_once_with(**filters)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_subnet_list_service_type_multiple(self):
+ arglist = [
+ '--service-type', 'network:router_gateway',
+ '--service-type', 'network:floatingip_agent_gateway',
+ ]
+ verifylist = [
+ ('service_types', ['network:router_gateway',
+ 'network:floatingip_agent_gateway']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {'service_types': ['network:router_gateway',
+ 'network:floatingip_agent_gateway']}
+
+ self.network.subnets.assert_called_once_with(**filters)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+
+class TestSetSubnet(TestSubnet):
+
+ _subnet = network_fakes.FakeSubnet.create_one_subnet()
+
+ def setUp(self):
+ super(TestSetSubnet, self).setUp()
+ self.network.update_subnet = mock.Mock(return_value=None)
+ self.network.find_subnet = mock.Mock(return_value=self._subnet)
+ self.cmd = subnet_v2.SetSubnet(self.app, self.namespace)
+
+ def test_set_this(self):
+ arglist = [
+ "--name", "new_subnet",
+ "--dhcp",
+ "--gateway", self._subnet.gateway_ip,
+ self._subnet.name,
+ ]
+ verifylist = [
+ ('name', "new_subnet"),
+ ('dhcp', True),
+ ('gateway', self._subnet.gateway_ip),
+ ('subnet', self._subnet.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ attrs = {
+ 'enable_dhcp': True,
+ 'gateway_ip': self._subnet.gateway_ip,
+ 'name': "new_subnet",
+ }
+ self.network.update_subnet.assert_called_with(self._subnet, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_that(self):
+ arglist = [
+ "--name", "new_subnet",
+ "--no-dhcp",
+ "--gateway", "none",
+ self._subnet.name,
+ ]
+ verifylist = [
+ ('name', "new_subnet"),
+ ('no_dhcp', True),
+ ('gateway', "none"),
+ ('subnet', self._subnet.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ attrs = {
+ 'enable_dhcp': False,
+ 'gateway_ip': None,
+ 'name': "new_subnet",
+ }
+ self.network.update_subnet.assert_called_with(self._subnet, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_nothing(self):
+ arglist = [self._subnet.name, ]
+ verifylist = [('subnet', self._subnet.name)]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {}
+ self.network.update_subnet.assert_called_with(self._subnet, **attrs)
+ self.assertIsNone(result)
+
+ def test_append_options(self):
+ _testsubnet = network_fakes.FakeSubnet.create_one_subnet(
+ {'dns_nameservers': ["10.0.0.1"],
+ 'service_types': ["network:router_gateway"]})
+ self.network.find_subnet = mock.Mock(return_value=_testsubnet)
+ arglist = [
+ '--dns-nameserver', '10.0.0.2',
+ '--service-type', 'network:floatingip_agent_gateway',
+ _testsubnet.name,
+ ]
+ verifylist = [
+ ('dns_nameservers', ['10.0.0.2']),
+ ('service_types', ['network:floatingip_agent_gateway']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ attrs = {
+ 'dns_nameservers': ['10.0.0.2', '10.0.0.1'],
+ 'service_types': ['network:floatingip_agent_gateway',
+ 'network:router_gateway'],
+ }
+ self.network.update_subnet.assert_called_once_with(
+ _testsubnet, **attrs)
+ self.assertIsNone(result)
+
+
+class TestShowSubnet(TestSubnet):
+ # The subnets to be shown
+ _subnet = network_fakes.FakeSubnet.create_one_subnet()
+
+ columns = (
+ 'allocation_pools',
+ 'cidr',
+ 'dns_nameservers',
+ 'enable_dhcp',
+ 'gateway_ip',
+ 'host_routes',
+ 'id',
+ 'ip_version',
+ 'ipv6_address_mode',
+ 'ipv6_ra_mode',
+ 'name',
+ 'network_id',
+ 'project_id',
+ 'segment_id',
+ 'service_types',
+ 'subnetpool_id',
+ )
+
+ data = (
+ subnet_v2._format_allocation_pools(_subnet.allocation_pools),
+ _subnet.cidr,
+ utils.format_list(_subnet.dns_nameservers),
+ _subnet.enable_dhcp,
+ _subnet.gateway_ip,
+ utils.format_list(_subnet.host_routes),
+ _subnet.id,
+ _subnet.ip_version,
+ _subnet.ipv6_address_mode,
+ _subnet.ipv6_ra_mode,
+ _subnet.name,
+ _subnet.network_id,
+ _subnet.tenant_id,
+ _subnet.segment_id,
+ utils.format_list(_subnet.service_types),
+ _subnet.subnetpool_id,
+ )
+
+ def setUp(self):
+ super(TestShowSubnet, self).setUp()
+
+ # Get the command object to test
+ self.cmd = subnet_v2.ShowSubnet(self.app, self.namespace)
+
+ self.network.find_subnet = mock.Mock(return_value=self._subnet)
+
+ def test_show_no_options(self):
+ arglist = []
+ verifylist = []
+
+ # Testing that a call without the required argument will fail and
+ # throw a "ParserExecption"
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, arglist, verifylist)
+
+ def test_show_all_options(self):
+ arglist = [
+ self._subnet.name,
+ ]
+ verifylist = [
+ ('subnet', self._subnet.name),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.find_subnet.assert_called_once_with(
+ self._subnet.name, ignore_missing=False)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestUnsetSubnet(TestSubnet):
+
+ def setUp(self):
+ super(TestUnsetSubnet, self).setUp()
+ self._testsubnet = network_fakes.FakeSubnet.create_one_subnet(
+ {'dns_nameservers': ['8.8.8.8',
+ '8.8.8.4'],
+ 'host_routes': [{'destination': '10.20.20.0/24',
+ 'nexthop': '10.20.20.1'},
+ {'destination': '10.30.30.30/24',
+ 'nexthop': '10.30.30.1'}],
+ 'allocation_pools': [{'start': '8.8.8.100',
+ 'end': '8.8.8.150'},
+ {'start': '8.8.8.160',
+ 'end': '8.8.8.170'}],
+ 'service_types': ['network:router_gateway',
+ 'network:floatingip_agent_gateway'], })
+ self.network.find_subnet = mock.Mock(return_value=self._testsubnet)
+ self.network.update_subnet = mock.Mock(return_value=None)
+ # Get the command object to test
+ self.cmd = subnet_v2.UnsetSubnet(self.app, self.namespace)
+
+ def test_unset_subnet_params(self):
+ arglist = [
+ '--dns-nameserver', '8.8.8.8',
+ '--host-route', 'destination=10.30.30.30/24,gateway=10.30.30.1',
+ '--allocation-pool', 'start=8.8.8.100,end=8.8.8.150',
+ '--service-type', 'network:router_gateway',
+ self._testsubnet.name,
+ ]
+ verifylist = [
+ ('dns_nameservers', ['8.8.8.8']),
+ ('host_routes', [{
+ "destination": "10.30.30.30/24", "gateway": "10.30.30.1"}]),
+ ('allocation_pools', [{
+ 'start': '8.8.8.100', 'end': '8.8.8.150'}]),
+ ('service_types', ['network:router_gateway']),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'dns_nameservers': ['8.8.8.4'],
+ 'host_routes': [{
+ "destination": "10.20.20.0/24", "nexthop": "10.20.20.1"}],
+ 'allocation_pools': [{'start': '8.8.8.160', 'end': '8.8.8.170'}],
+ 'service_types': ['network:floatingip_agent_gateway'],
+ }
+ self.network.update_subnet.assert_called_once_with(
+ self._testsubnet, **attrs)
+ self.assertIsNone(result)
+
+ def test_unset_subnet_wrong_host_routes(self):
+ arglist = [
+ '--dns-nameserver', '8.8.8.8',
+ '--host-route', 'destination=10.30.30.30/24,gateway=10.30.30.2',
+ '--allocation-pool', 'start=8.8.8.100,end=8.8.8.150',
+ self._testsubnet.name,
+ ]
+ verifylist = [
+ ('dns_nameservers', ['8.8.8.8']),
+ ('host_routes', [{
+ "destination": "10.30.30.30/24", "gateway": "10.30.30.2"}]),
+ ('allocation_pools', [{
+ 'start': '8.8.8.100', 'end': '8.8.8.150'}]),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.assertRaises(exceptions.CommandError,
+ self.cmd.take_action, parsed_args)
+
+ def test_unset_subnet_wrong_allocation_pool(self):
+ arglist = [
+ '--dns-nameserver', '8.8.8.8',
+ '--host-route', 'destination=10.30.30.30/24,gateway=10.30.30.1',
+ '--allocation-pool', 'start=8.8.8.100,end=8.8.8.156',
+ self._testsubnet.name,
+ ]
+ verifylist = [
+ ('dns_nameservers', ['8.8.8.8']),
+ ('host_routes', [{
+ "destination": "10.30.30.30/24", "gateway": "10.30.30.1"}]),
+ ('allocation_pools', [{
+ 'start': '8.8.8.100', 'end': '8.8.8.156'}]),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.assertRaises(exceptions.CommandError,
+ self.cmd.take_action, parsed_args)
+
+ def test_unset_subnet_wrong_dns_nameservers(self):
+ arglist = [
+ '--dns-nameserver', '8.8.8.1',
+ '--host-route', 'destination=10.30.30.30/24,gateway=10.30.30.1',
+ '--allocation-pool', 'start=8.8.8.100,end=8.8.8.150',
+ self._testsubnet.name,
+ ]
+ verifylist = [
+ ('dns_nameservers', ['8.8.8.1']),
+ ('host_routes', [{
+ "destination": "10.30.30.30/24", "gateway": "10.30.30.1"}]),
+ ('allocation_pools', [{
+ 'start': '8.8.8.100', 'end': '8.8.8.150'}]),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.assertRaises(exceptions.CommandError,
+ self.cmd.take_action, parsed_args)
+
+ def test_unset_subnet_wrong_service_type(self):
+ arglist = [
+ '--dns-nameserver', '8.8.8.8',
+ '--host-route', 'destination=10.30.30.30/24,gateway=10.30.30.1',
+ '--allocation-pool', 'start=8.8.8.100,end=8.8.8.150',
+ '--service-type', 'network:dhcp',
+ self._testsubnet.name,
+ ]
+ verifylist = [
+ ('dns_nameservers', ['8.8.8.8']),
+ ('host_routes', [{
+ "destination": "10.30.30.30/24", "gateway": "10.30.30.1"}]),
+ ('allocation_pools', [{
+ 'start': '8.8.8.100', 'end': '8.8.8.150'}]),
+ ('service_types', ['network:dhcp']),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.assertRaises(exceptions.CommandError,
+ self.cmd.take_action, parsed_args)
diff --git a/openstackclient/tests/unit/network/v2/test_subnet_pool.py b/openstackclient/tests/unit/network/v2/test_subnet_pool.py
new file mode 100644
index 00000000..0d9494c0
--- /dev/null
+++ b/openstackclient/tests/unit/network/v2/test_subnet_pool.py
@@ -0,0 +1,722 @@
+# 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.
+#
+
+import argparse
+import mock
+from mock import call
+
+from osc_lib import exceptions
+from osc_lib import utils
+
+from openstackclient.network.v2 import subnet_pool
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes_v3
+from openstackclient.tests.unit.network.v2 import fakes as network_fakes
+from openstackclient.tests.unit import utils as tests_utils
+
+
+class TestSubnetPool(network_fakes.TestNetworkV2):
+
+ def setUp(self):
+ super(TestSubnetPool, self).setUp()
+
+ # Get a shortcut to the network client
+ self.network = self.app.client_manager.network
+ # Get a shortcut to the ProjectManager Mock
+ self.projects_mock = self.app.client_manager.identity.projects
+ # Get a shortcut to the DomainManager Mock
+ self.domains_mock = self.app.client_manager.identity.domains
+
+
+class TestCreateSubnetPool(TestSubnetPool):
+
+ project = identity_fakes_v3.FakeProject.create_one_project()
+ domain = identity_fakes_v3.FakeDomain.create_one_domain()
+ # The new subnet pool to create.
+ _subnet_pool = network_fakes.FakeSubnetPool.create_one_subnet_pool()
+
+ _address_scope = network_fakes.FakeAddressScope.create_one_address_scope()
+
+ columns = (
+ 'address_scope_id',
+ 'default_prefixlen',
+ 'default_quota',
+ 'id',
+ 'ip_version',
+ 'is_default',
+ 'max_prefixlen',
+ 'min_prefixlen',
+ 'name',
+ 'prefixes',
+ 'project_id',
+ 'shared',
+ )
+ data = (
+ _subnet_pool.address_scope_id,
+ _subnet_pool.default_prefixlen,
+ _subnet_pool.default_quota,
+ _subnet_pool.id,
+ _subnet_pool.ip_version,
+ _subnet_pool.is_default,
+ _subnet_pool.max_prefixlen,
+ _subnet_pool.min_prefixlen,
+ _subnet_pool.name,
+ utils.format_list(_subnet_pool.prefixes),
+ _subnet_pool.project_id,
+ _subnet_pool.shared,
+ )
+
+ def setUp(self):
+ super(TestCreateSubnetPool, self).setUp()
+
+ self.network.create_subnet_pool = mock.Mock(
+ return_value=self._subnet_pool)
+
+ # Get the command object to test
+ self.cmd = subnet_pool.CreateSubnetPool(self.app, self.namespace)
+
+ self.network.find_address_scope = mock.Mock(
+ return_value=self._address_scope)
+
+ self.projects_mock.get.return_value = self.project
+ self.domains_mock.get.return_value = self.domain
+
+ def test_create_no_options(self):
+ arglist = []
+ verifylist = []
+
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_create_no_pool_prefix(self):
+ """Make sure --pool-prefix is a required argument"""
+ arglist = [
+ self._subnet_pool.name,
+ ]
+ verifylist = [
+ ('name', self._subnet_pool.name),
+ ]
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_create_default_options(self):
+ arglist = [
+ '--pool-prefix', '10.0.10.0/24',
+ self._subnet_pool.name,
+ ]
+ verifylist = [
+ ('prefixes', ['10.0.10.0/24']),
+ ('name', self._subnet_pool.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = (self.cmd.take_action(parsed_args))
+
+ self.network.create_subnet_pool.assert_called_once_with(**{
+ 'prefixes': ['10.0.10.0/24'],
+ 'name': self._subnet_pool.name,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_create_prefixlen_options(self):
+ arglist = [
+ '--default-prefix-length', self._subnet_pool.default_prefixlen,
+ '--max-prefix-length', self._subnet_pool.max_prefixlen,
+ '--min-prefix-length', self._subnet_pool.min_prefixlen,
+ '--pool-prefix', '10.0.10.0/24',
+ self._subnet_pool.name,
+ ]
+ verifylist = [
+ ('default_prefix_length',
+ int(self._subnet_pool.default_prefixlen)),
+ ('max_prefix_length', int(self._subnet_pool.max_prefixlen)),
+ ('min_prefix_length', int(self._subnet_pool.min_prefixlen)),
+ ('name', self._subnet_pool.name),
+ ('prefixes', ['10.0.10.0/24']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = (self.cmd.take_action(parsed_args))
+
+ self.network.create_subnet_pool.assert_called_once_with(**{
+ 'default_prefixlen': int(self._subnet_pool.default_prefixlen),
+ 'max_prefixlen': int(self._subnet_pool.max_prefixlen),
+ 'min_prefixlen': int(self._subnet_pool.min_prefixlen),
+ 'prefixes': ['10.0.10.0/24'],
+ 'name': self._subnet_pool.name,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_create_len_negative(self):
+ arglist = [
+ self._subnet_pool.name,
+ '--min-prefix-length', '-16',
+ ]
+ verifylist = [
+ ('subnet_pool', self._subnet_pool.name),
+ ('min_prefix_length', '-16'),
+ ]
+
+ self.assertRaises(argparse.ArgumentTypeError, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_create_project_domain(self):
+ arglist = [
+ '--pool-prefix', '10.0.10.0/24',
+ "--project", self.project.name,
+ "--project-domain", self.domain.name,
+ self._subnet_pool.name,
+ ]
+ verifylist = [
+ ('prefixes', ['10.0.10.0/24']),
+ ('project', self.project.name),
+ ('project_domain', self.domain.name),
+ ('name', self._subnet_pool.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = (self.cmd.take_action(parsed_args))
+
+ self.network.create_subnet_pool.assert_called_once_with(**{
+ 'prefixes': ['10.0.10.0/24'],
+ 'tenant_id': self.project.id,
+ 'name': self._subnet_pool.name,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_create_address_scope_option(self):
+ arglist = [
+ '--pool-prefix', '10.0.10.0/24',
+ '--address-scope', self._address_scope.id,
+ self._subnet_pool.name,
+ ]
+ verifylist = [
+ ('prefixes', ['10.0.10.0/24']),
+ ('address_scope', self._address_scope.id),
+ ('name', self._subnet_pool.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = (self.cmd.take_action(parsed_args))
+
+ self.network.create_subnet_pool.assert_called_once_with(**{
+ 'prefixes': ['10.0.10.0/24'],
+ 'address_scope_id': self._address_scope.id,
+ 'name': self._subnet_pool.name,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_create_default_and_shared_options(self):
+ arglist = [
+ '--pool-prefix', '10.0.10.0/24',
+ '--default',
+ '--share',
+ self._subnet_pool.name,
+ ]
+ verifylist = [
+ ('prefixes', ['10.0.10.0/24']),
+ ('default', True),
+ ('share', True),
+ ('name', self._subnet_pool.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = (self.cmd.take_action(parsed_args))
+
+ self.network.create_subnet_pool.assert_called_once_with(**{
+ 'is_default': True,
+ 'name': self._subnet_pool.name,
+ 'prefixes': ['10.0.10.0/24'],
+ 'shared': True,
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestDeleteSubnetPool(TestSubnetPool):
+
+ # The subnet pools to delete.
+ _subnet_pools = network_fakes.FakeSubnetPool.create_subnet_pools(count=2)
+
+ def setUp(self):
+ super(TestDeleteSubnetPool, self).setUp()
+
+ self.network.delete_subnet_pool = mock.Mock(return_value=None)
+
+ self.network.find_subnet_pool = (
+ network_fakes.FakeSubnetPool.get_subnet_pools(self._subnet_pools)
+ )
+
+ # Get the command object to test
+ self.cmd = subnet_pool.DeleteSubnetPool(self.app, self.namespace)
+
+ def test_subnet_pool_delete(self):
+ arglist = [
+ self._subnet_pools[0].name,
+ ]
+ verifylist = [
+ ('subnet_pool', [self._subnet_pools[0].name]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.network.delete_subnet_pool.assert_called_once_with(
+ self._subnet_pools[0])
+ self.assertIsNone(result)
+
+ def test_multi_subnet_pools_delete(self):
+ arglist = []
+ verifylist = []
+
+ for s in self._subnet_pools:
+ arglist.append(s.name)
+ verifylist = [
+ ('subnet_pool', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for s in self._subnet_pools:
+ calls.append(call(s))
+ self.network.delete_subnet_pool.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_multi_subnet_pools_delete_with_exception(self):
+ arglist = [
+ self._subnet_pools[0].name,
+ 'unexist_subnet_pool',
+ ]
+ verifylist = [
+ ('subnet_pool',
+ [self._subnet_pools[0].name, 'unexist_subnet_pool']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [self._subnet_pools[0], exceptions.CommandError]
+ self.network.find_subnet_pool = (
+ mock.MagicMock(side_effect=find_mock_result)
+ )
+
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 subnet pools failed to delete.', str(e))
+
+ self.network.find_subnet_pool.assert_any_call(
+ self._subnet_pools[0].name, ignore_missing=False)
+ self.network.find_subnet_pool.assert_any_call(
+ 'unexist_subnet_pool', ignore_missing=False)
+ self.network.delete_subnet_pool.assert_called_once_with(
+ self._subnet_pools[0]
+ )
+
+
+class TestListSubnetPool(TestSubnetPool):
+ # The subnet pools going to be listed up.
+ _subnet_pools = network_fakes.FakeSubnetPool.create_subnet_pools(count=3)
+
+ columns = (
+ 'ID',
+ 'Name',
+ 'Prefixes',
+ )
+ columns_long = columns + (
+ 'Default Prefix Length',
+ 'Address Scope',
+ 'Default Subnet Pool',
+ 'Shared',
+ )
+
+ data = []
+ for pool in _subnet_pools:
+ data.append((
+ pool.id,
+ pool.name,
+ utils.format_list(pool.prefixes),
+ ))
+
+ data_long = []
+ for pool in _subnet_pools:
+ data_long.append((
+ pool.id,
+ pool.name,
+ utils.format_list(pool.prefixes),
+ pool.default_prefixlen,
+ pool.address_scope_id,
+ pool.is_default,
+ pool.shared,
+ ))
+
+ def setUp(self):
+ super(TestListSubnetPool, self).setUp()
+
+ # Get the command object to test
+ self.cmd = subnet_pool.ListSubnetPool(self.app, self.namespace)
+
+ self.network.subnet_pools = mock.Mock(return_value=self._subnet_pools)
+
+ def test_subnet_pool_list_no_option(self):
+ arglist = []
+ verifylist = [
+ ('long', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.subnet_pools.assert_called_once_with()
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_subnet_pool_list_long(self):
+ arglist = [
+ '--long',
+ ]
+ verifylist = [
+ ('long', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.subnet_pools.assert_called_once_with()
+ self.assertEqual(self.columns_long, columns)
+ self.assertEqual(self.data_long, list(data))
+
+
+class TestSetSubnetPool(TestSubnetPool):
+
+ # The subnet_pool to set.
+ _subnet_pool = network_fakes.FakeSubnetPool.create_one_subnet_pool()
+
+ _address_scope = network_fakes.FakeAddressScope.create_one_address_scope()
+
+ def setUp(self):
+ super(TestSetSubnetPool, self).setUp()
+
+ self.network.update_subnet_pool = mock.Mock(return_value=None)
+
+ self.network.find_subnet_pool = mock.Mock(
+ return_value=self._subnet_pool)
+
+ self.network.find_address_scope = mock.Mock(
+ return_value=self._address_scope)
+
+ # Get the command object to test
+ self.cmd = subnet_pool.SetSubnetPool(self.app, self.namespace)
+
+ def test_set_this(self):
+ arglist = [
+ '--name', 'noob',
+ '--default-prefix-length', '8',
+ '--min-prefix-length', '8',
+ self._subnet_pool.name,
+ ]
+ verifylist = [
+ ('name', 'noob'),
+ ('default_prefix_length', 8),
+ ('min_prefix_length', 8),
+ ('subnet_pool', self._subnet_pool.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'name': 'noob',
+ 'default_prefixlen': 8,
+ 'min_prefixlen': 8,
+ }
+ self.network.update_subnet_pool.assert_called_once_with(
+ self._subnet_pool, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_that(self):
+ arglist = [
+ '--pool-prefix', '10.0.1.0/24',
+ '--pool-prefix', '10.0.2.0/24',
+ '--max-prefix-length', '16',
+ self._subnet_pool.name,
+ ]
+ verifylist = [
+ ('prefixes', ['10.0.1.0/24', '10.0.2.0/24']),
+ ('max_prefix_length', 16),
+ ('subnet_pool', self._subnet_pool.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ prefixes = ['10.0.1.0/24', '10.0.2.0/24']
+ prefixes.extend(self._subnet_pool.prefixes)
+ attrs = {
+ 'prefixes': prefixes,
+ 'max_prefixlen': 16,
+ }
+ self.network.update_subnet_pool.assert_called_once_with(
+ self._subnet_pool, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_nothing(self):
+ arglist = [self._subnet_pool.name, ]
+ verifylist = [('subnet_pool', self._subnet_pool.name), ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {}
+ self.network.update_subnet_pool.assert_called_once_with(
+ self._subnet_pool, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_len_negative(self):
+ arglist = [
+ '--max-prefix-length', '-16',
+ self._subnet_pool.name,
+ ]
+ verifylist = [
+ ('max_prefix_length', '-16'),
+ ('subnet_pool', self._subnet_pool.name),
+ ]
+
+ self.assertRaises(argparse.ArgumentTypeError, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_set_address_scope(self):
+ arglist = [
+ '--address-scope', self._address_scope.id,
+ self._subnet_pool.name,
+ ]
+ verifylist = [
+ ('address_scope', self._address_scope.id),
+ ('subnet_pool', self._subnet_pool.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'address_scope_id': self._address_scope.id,
+ }
+ self.network.update_subnet_pool.assert_called_once_with(
+ self._subnet_pool, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_no_address_scope(self):
+ arglist = [
+ '--no-address-scope',
+ self._subnet_pool.name,
+ ]
+ verifylist = [
+ ('no_address_scope', True),
+ ('subnet_pool', self._subnet_pool.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'address_scope_id': None,
+ }
+ self.network.update_subnet_pool.assert_called_once_with(
+ self._subnet_pool, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_no_address_scope_conflict(self):
+ arglist = [
+ '--address-scope', self._address_scope.id,
+ '--no-address-scope',
+ self._subnet_pool.name,
+ ]
+ verifylist = [
+ ('address_scope', self._address_scope.id),
+ ('no_address_scope', True),
+ ('subnet_pool', self._subnet_pool.name),
+ ]
+
+ # Exclusive arguments will conflict here.
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_set_default(self):
+ arglist = [
+ '--default',
+ self._subnet_pool.name,
+ ]
+ verifylist = [
+ ('default', True),
+ ('subnet_pool', self._subnet_pool.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'is_default': True
+ }
+ self.network.update_subnet_pool.assert_called_once_with(
+ self._subnet_pool, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_no_default(self):
+ arglist = [
+ '--no-default',
+ self._subnet_pool.name,
+ ]
+ verifylist = [
+ ('no_default', True),
+ ('subnet_pool', self._subnet_pool.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'is_default': False,
+ }
+ self.network.update_subnet_pool.assert_called_once_with(
+ self._subnet_pool, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_no_default_conflict(self):
+ arglist = [
+ '--default',
+ '--no-default',
+ self._subnet_pool.name,
+ ]
+ verifylist = [
+ ('default', True),
+ ('no_default', True),
+ ('subnet_pool', self._subnet_pool.name),
+ ]
+
+ # Exclusive arguments will conflict here.
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+
+class TestShowSubnetPool(TestSubnetPool):
+
+ # The subnet_pool to set.
+ _subnet_pool = network_fakes.FakeSubnetPool.create_one_subnet_pool()
+
+ columns = (
+ 'address_scope_id',
+ 'default_prefixlen',
+ 'default_quota',
+ 'id',
+ 'ip_version',
+ 'is_default',
+ 'max_prefixlen',
+ 'min_prefixlen',
+ 'name',
+ 'prefixes',
+ 'project_id',
+ 'shared',
+ )
+
+ data = (
+ _subnet_pool.address_scope_id,
+ _subnet_pool.default_prefixlen,
+ _subnet_pool.default_quota,
+ _subnet_pool.id,
+ _subnet_pool.ip_version,
+ _subnet_pool.is_default,
+ _subnet_pool.max_prefixlen,
+ _subnet_pool.min_prefixlen,
+ _subnet_pool.name,
+ utils.format_list(_subnet_pool.prefixes),
+ _subnet_pool.tenant_id,
+ _subnet_pool.shared,
+ )
+
+ def setUp(self):
+ super(TestShowSubnetPool, self).setUp()
+
+ self.network.find_subnet_pool = mock.Mock(
+ return_value=self._subnet_pool
+ )
+
+ # Get the command object to test
+ self.cmd = subnet_pool.ShowSubnetPool(self.app, self.namespace)
+
+ def test_show_no_options(self):
+ arglist = []
+ verifylist = []
+
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_show_all_options(self):
+ arglist = [
+ self._subnet_pool.name,
+ ]
+ verifylist = [
+ ('subnet_pool', self._subnet_pool.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.find_subnet_pool.assert_called_once_with(
+ self._subnet_pool.name,
+ ignore_missing=False
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestUnsetSubnetPool(TestSubnetPool):
+
+ def setUp(self):
+ super(TestUnsetSubnetPool, self).setUp()
+ self._subnetpool = network_fakes.FakeSubnetPool.create_one_subnet_pool(
+ {'prefixes': ['10.0.10.0/24', '10.1.10.0/24',
+ '10.2.10.0/24'], })
+ self.network.find_subnet_pool = mock.Mock(
+ return_value=self._subnetpool)
+ self.network.update_subnet_pool = mock.Mock(return_value=None)
+ # Get the command object to test
+ self.cmd = subnet_pool.UnsetSubnetPool(self.app, self.namespace)
+
+ def test_unset_subnet_pool(self):
+ arglist = [
+ '--pool-prefix', '10.0.10.0/24',
+ '--pool-prefix', '10.1.10.0/24',
+ self._subnetpool.name,
+ ]
+ verifylist = [('prefixes', ['10.0.10.0/24', '10.1.10.0/24'])]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ attrs = {'prefixes': ['10.2.10.0/24']}
+ self.network.update_subnet_pool.assert_called_once_with(
+ self._subnetpool, **attrs)
+ self.assertIsNone(result)
+
+ def test_unset_subnet_pool_prefix_not_existent(self):
+ arglist = [
+ '--pool-prefix', '10.100.1.1/25',
+ self._subnetpool.name,
+ ]
+ verifylist = [('prefixes', ['10.100.1.1/25'])]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.assertRaises(exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
diff --git a/openstackclient/tests/unit/object/__init__.py b/openstackclient/tests/unit/object/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/unit/object/__init__.py
diff --git a/openstackclient/tests/unit/object/v1/__init__.py b/openstackclient/tests/unit/object/v1/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/unit/object/v1/__init__.py
diff --git a/openstackclient/tests/unit/object/v1/fakes.py b/openstackclient/tests/unit/object/v1/fakes.py
new file mode 100644
index 00000000..0ff594bc
--- /dev/null
+++ b/openstackclient/tests/unit/object/v1/fakes.py
@@ -0,0 +1,88 @@
+# Copyright 2013 Nebula Inc.
+#
+# 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 keystoneauth1 import session
+
+from openstackclient.api import object_store_v1 as object_store
+from openstackclient.tests.unit import utils
+
+
+ACCOUNT_ID = 'tqbfjotld'
+ENDPOINT = 'https://0.0.0.0:6482/v1/' + ACCOUNT_ID
+
+container_name = 'bit-bucket'
+container_bytes = 1024
+container_count = 1
+
+container_name_2 = 'archive'
+container_name_3 = 'bit-blit'
+
+CONTAINER = {
+ 'name': container_name,
+ 'bytes': container_bytes,
+ 'count': container_count,
+}
+
+CONTAINER_2 = {
+ 'name': container_name_2,
+ 'bytes': container_bytes * 2,
+ 'count': container_count * 2,
+}
+
+CONTAINER_3 = {
+ 'name': container_name_3,
+ 'bytes': container_bytes * 3,
+ 'count': container_count * 3,
+}
+
+object_name_1 = 'punch-card'
+object_bytes_1 = 80
+object_hash_1 = '1234567890'
+object_content_type_1 = 'text'
+object_modified_1 = 'today'
+
+object_name_2 = 'floppy-disk'
+object_bytes_2 = 1440000
+object_hash_2 = '0987654321'
+object_content_type_2 = 'text'
+object_modified_2 = 'today'
+
+OBJECT = {
+ 'name': object_name_1,
+ 'bytes': object_bytes_1,
+ 'hash': object_hash_1,
+ 'content_type': object_content_type_1,
+ 'last_modified': object_modified_1,
+}
+
+OBJECT_2 = {
+ 'name': object_name_2,
+ 'bytes': object_bytes_2,
+ 'hash': object_hash_2,
+ 'content_type': object_content_type_2,
+ 'last_modified': object_modified_2,
+}
+
+
+class TestObjectv1(utils.TestCommand):
+
+ def setUp(self):
+ super(TestObjectv1, self).setUp()
+
+ self.app.client_manager.session = session.Session()
+ self.app.client_manager.object_store = object_store.APIv1(
+ session=self.app.client_manager.session,
+ endpoint=ENDPOINT,
+ )
diff --git a/openstackclient/tests/unit/object/v1/test_container.py b/openstackclient/tests/unit/object/v1/test_container.py
new file mode 100644
index 00000000..37b8c705
--- /dev/null
+++ b/openstackclient/tests/unit/object/v1/test_container.py
@@ -0,0 +1,407 @@
+# Copyright 2013 OpenStack Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+import copy
+import mock
+
+from openstackclient.api import object_store_v1 as object_store
+from openstackclient.object.v1 import container
+from openstackclient.tests.unit.object.v1 import fakes as object_fakes
+
+
+AUTH_TOKEN = "foobar"
+AUTH_URL = "http://0.0.0.0"
+
+
+class FakeClient(object):
+
+ def __init__(self, endpoint=None, **kwargs):
+ self.endpoint = AUTH_URL
+ self.token = AUTH_TOKEN
+
+
+class TestContainer(object_fakes.TestObjectv1):
+
+ columns = ('Name',)
+
+ def setUp(self):
+ super(TestContainer, self).setUp()
+ self.app.client_manager.object_store = object_store.APIv1(
+ session=mock.Mock(),
+ service_type="object-store",
+ )
+ self.api = self.app.client_manager.object_store
+
+
+@mock.patch('openstackclient.api.object_store_v1.APIv1.object_delete')
+@mock.patch('openstackclient.api.object_store_v1.APIv1.object_list')
+@mock.patch('openstackclient.api.object_store_v1.APIv1.container_delete')
+class TestContainerDelete(TestContainer):
+
+ def setUp(self):
+ super(TestContainerDelete, self).setUp()
+
+ # Get the command object to test
+ self.cmd = container.DeleteContainer(self.app, None)
+
+ def test_container_delete(self, c_mock, o_list_mock, o_delete_mock):
+ c_mock.return_value = None
+
+ arglist = [
+ object_fakes.container_name,
+ ]
+ verifylist = [
+ ('containers', [object_fakes.container_name]),
+ ('recursive', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertIsNone(self.cmd.take_action(parsed_args))
+
+ kwargs = {}
+ c_mock.assert_called_with(
+ container=object_fakes.container_name,
+ **kwargs
+ )
+ self.assertFalse(o_list_mock.called)
+ self.assertFalse(o_delete_mock.called)
+
+ def test_recursive_delete(self, c_mock, o_list_mock, o_delete_mock):
+ c_mock.return_value = None
+ o_list_mock.return_value = [object_fakes.OBJECT]
+ o_delete_mock.return_value = None
+
+ arglist = [
+ '--recursive',
+ object_fakes.container_name,
+ ]
+ verifylist = [
+ ('containers', [object_fakes.container_name]),
+ ('recursive', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertIsNone(self.cmd.take_action(parsed_args))
+
+ kwargs = {}
+ c_mock.assert_called_with(
+ container=object_fakes.container_name,
+ **kwargs
+ )
+ o_list_mock.assert_called_with(container=object_fakes.container_name)
+ o_delete_mock.assert_called_with(
+ container=object_fakes.container_name,
+ object=object_fakes.OBJECT['name'],
+ )
+
+ def test_r_delete(self, c_mock, o_list_mock, o_delete_mock):
+ c_mock.return_value = None
+ o_list_mock.return_value = [object_fakes.OBJECT]
+ o_delete_mock.return_value = None
+
+ arglist = [
+ '-r',
+ object_fakes.container_name,
+ ]
+ verifylist = [
+ ('containers', [object_fakes.container_name]),
+ ('recursive', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertIsNone(self.cmd.take_action(parsed_args))
+
+ kwargs = {}
+ c_mock.assert_called_with(
+ container=object_fakes.container_name,
+ **kwargs
+ )
+ o_list_mock.assert_called_with(container=object_fakes.container_name)
+ o_delete_mock.assert_called_with(
+ container=object_fakes.container_name,
+ object=object_fakes.OBJECT['name'],
+ )
+
+
+@mock.patch(
+ 'openstackclient.api.object_store_v1.APIv1.container_list'
+)
+class TestContainerList(TestContainer):
+
+ def setUp(self):
+ super(TestContainerList, self).setUp()
+
+ # Get the command object to test
+ self.cmd = container.ListContainer(self.app, None)
+
+ def test_object_list_containers_no_options(self, c_mock):
+ c_mock.return_value = [
+ copy.deepcopy(object_fakes.CONTAINER),
+ copy.deepcopy(object_fakes.CONTAINER_3),
+ copy.deepcopy(object_fakes.CONTAINER_2),
+ ]
+
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ }
+ c_mock.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ datalist = (
+ (object_fakes.container_name, ),
+ (object_fakes.container_name_3, ),
+ (object_fakes.container_name_2, ),
+ )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_object_list_containers_prefix(self, c_mock):
+ c_mock.return_value = [
+ copy.deepcopy(object_fakes.CONTAINER),
+ copy.deepcopy(object_fakes.CONTAINER_3),
+ ]
+
+ arglist = [
+ '--prefix', 'bit',
+ ]
+ verifylist = [
+ ('prefix', 'bit'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'prefix': 'bit',
+ }
+ c_mock.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ datalist = (
+ (object_fakes.container_name, ),
+ (object_fakes.container_name_3, ),
+ )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_object_list_containers_marker(self, c_mock):
+ c_mock.return_value = [
+ copy.deepcopy(object_fakes.CONTAINER),
+ copy.deepcopy(object_fakes.CONTAINER_3),
+ ]
+
+ arglist = [
+ '--marker', object_fakes.container_name,
+ '--end-marker', object_fakes.container_name_3,
+ ]
+ verifylist = [
+ ('marker', object_fakes.container_name),
+ ('end_marker', object_fakes.container_name_3),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'marker': object_fakes.container_name,
+ 'end_marker': object_fakes.container_name_3,
+ }
+ c_mock.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ datalist = (
+ (object_fakes.container_name, ),
+ (object_fakes.container_name_3, ),
+ )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_object_list_containers_limit(self, c_mock):
+ c_mock.return_value = [
+ copy.deepcopy(object_fakes.CONTAINER),
+ copy.deepcopy(object_fakes.CONTAINER_3),
+ ]
+
+ arglist = [
+ '--limit', '2',
+ ]
+ verifylist = [
+ ('limit', 2),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'limit': 2,
+ }
+ c_mock.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ datalist = (
+ (object_fakes.container_name, ),
+ (object_fakes.container_name_3, ),
+ )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_object_list_containers_long(self, c_mock):
+ c_mock.return_value = [
+ copy.deepcopy(object_fakes.CONTAINER),
+ copy.deepcopy(object_fakes.CONTAINER_3),
+ ]
+
+ arglist = [
+ '--long',
+ ]
+ verifylist = [
+ ('long', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ }
+ c_mock.assert_called_with(
+ **kwargs
+ )
+
+ collist = ('Name', 'Bytes', 'Count')
+ self.assertEqual(collist, columns)
+ datalist = (
+ (
+ object_fakes.container_name,
+ object_fakes.container_bytes,
+ object_fakes.container_count,
+ ),
+ (
+ object_fakes.container_name_3,
+ object_fakes.container_bytes * 3,
+ object_fakes.container_count * 3,
+ ),
+ )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_object_list_containers_all(self, c_mock):
+ c_mock.return_value = [
+ copy.deepcopy(object_fakes.CONTAINER),
+ copy.deepcopy(object_fakes.CONTAINER_2),
+ copy.deepcopy(object_fakes.CONTAINER_3),
+ ]
+
+ arglist = [
+ '--all',
+ ]
+ verifylist = [
+ ('all', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'full_listing': True,
+ }
+ c_mock.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ datalist = (
+ (object_fakes.container_name, ),
+ (object_fakes.container_name_2, ),
+ (object_fakes.container_name_3, ),
+ )
+ self.assertEqual(datalist, tuple(data))
+
+
+@mock.patch(
+ 'openstackclient.api.object_store_v1.APIv1.container_show'
+)
+class TestContainerShow(TestContainer):
+
+ def setUp(self):
+ super(TestContainerShow, self).setUp()
+
+ # Get the command object to test
+ self.cmd = container.ShowContainer(self.app, None)
+
+ def test_container_show(self, c_mock):
+ c_mock.return_value = copy.deepcopy(object_fakes.CONTAINER)
+
+ arglist = [
+ object_fakes.container_name,
+ ]
+ verifylist = [
+ ('container', object_fakes.container_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ }
+ # lib.container.show_container(api, url, container)
+ c_mock.assert_called_with(
+ container=object_fakes.container_name,
+ **kwargs
+ )
+
+ collist = ('bytes', 'count', 'name')
+ self.assertEqual(collist, columns)
+ datalist = (
+ object_fakes.container_bytes,
+ object_fakes.container_count,
+ object_fakes.container_name,
+ )
+ self.assertEqual(datalist, data)
diff --git a/openstackclient/tests/unit/object/v1/test_container_all.py b/openstackclient/tests/unit/object/v1/test_container_all.py
new file mode 100644
index 00000000..58c90e36
--- /dev/null
+++ b/openstackclient/tests/unit/object/v1/test_container_all.py
@@ -0,0 +1,345 @@
+# 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.
+#
+
+import copy
+
+from requests_mock.contrib import fixture
+
+from openstackclient.object.v1 import container as container_cmds
+from openstackclient.tests.unit.object.v1 import fakes as object_fakes
+
+
+class TestContainerAll(object_fakes.TestObjectv1):
+
+ def setUp(self):
+ super(TestContainerAll, self).setUp()
+
+ self.requests_mock = self.useFixture(fixture.Fixture())
+
+
+class TestContainerCreate(TestContainerAll):
+
+ columns = (
+ 'account',
+ 'container',
+ 'x-trans-id',
+ )
+
+ def setUp(self):
+ super(TestContainerCreate, self).setUp()
+
+ # Get the command object to test
+ self.cmd = container_cmds.CreateContainer(self.app, None)
+
+ def test_object_create_container_single(self):
+ self.requests_mock.register_uri(
+ 'PUT',
+ object_fakes.ENDPOINT + '/ernie',
+ headers={'x-trans-id': '314159'},
+ status_code=200,
+ )
+
+ arglist = [
+ 'ernie',
+ ]
+ verifylist = [(
+ 'containers', ['ernie'],
+ )]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+ datalist = [(
+ object_fakes.ACCOUNT_ID,
+ 'ernie',
+ '314159',
+ )]
+ self.assertEqual(datalist, list(data))
+
+ def test_object_create_container_more(self):
+ self.requests_mock.register_uri(
+ 'PUT',
+ object_fakes.ENDPOINT + '/ernie',
+ headers={'x-trans-id': '314159'},
+ status_code=200,
+ )
+ self.requests_mock.register_uri(
+ 'PUT',
+ object_fakes.ENDPOINT + '/bert',
+ headers={'x-trans-id': '42'},
+ status_code=200,
+ )
+
+ arglist = [
+ 'ernie',
+ 'bert',
+ ]
+ verifylist = [(
+ 'containers', ['ernie', 'bert'],
+ )]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+ datalist = [
+ (
+ object_fakes.ACCOUNT_ID,
+ 'ernie',
+ '314159',
+ ),
+ (
+ object_fakes.ACCOUNT_ID,
+ 'bert',
+ '42',
+ ),
+ ]
+ self.assertEqual(datalist, list(data))
+
+
+class TestContainerDelete(TestContainerAll):
+
+ def setUp(self):
+ super(TestContainerDelete, self).setUp()
+
+ # Get the command object to test
+ self.cmd = container_cmds.DeleteContainer(self.app, None)
+
+ def test_object_delete_container_single(self):
+ self.requests_mock.register_uri(
+ 'DELETE',
+ object_fakes.ENDPOINT + '/ernie',
+ status_code=200,
+ )
+
+ arglist = [
+ 'ernie',
+ ]
+ verifylist = [(
+ 'containers', ['ernie'],
+ )]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # Command.take_action() returns None
+ ret = self.cmd.take_action(parsed_args)
+ self.assertIsNone(ret)
+
+ def test_object_delete_container_more(self):
+ self.requests_mock.register_uri(
+ 'DELETE',
+ object_fakes.ENDPOINT + '/ernie',
+ status_code=200,
+ )
+ self.requests_mock.register_uri(
+ 'DELETE',
+ object_fakes.ENDPOINT + '/bert',
+ status_code=200,
+ )
+
+ arglist = [
+ 'ernie',
+ 'bert',
+ ]
+ verifylist = [(
+ 'containers', ['ernie', 'bert'],
+ )]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # Command.take_action() returns None
+ ret = self.cmd.take_action(parsed_args)
+ self.assertIsNone(ret)
+
+
+class TestContainerList(TestContainerAll):
+
+ columns = ('Name',)
+
+ def setUp(self):
+ super(TestContainerList, self).setUp()
+
+ # Get the command object to test
+ self.cmd = container_cmds.ListContainer(self.app, None)
+
+ def test_object_list_containers_no_options(self):
+ return_body = [
+ copy.deepcopy(object_fakes.CONTAINER),
+ copy.deepcopy(object_fakes.CONTAINER_3),
+ copy.deepcopy(object_fakes.CONTAINER_2),
+ ]
+ self.requests_mock.register_uri(
+ 'GET',
+ object_fakes.ENDPOINT + '?format=json',
+ json=return_body,
+ status_code=200,
+ )
+
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # Lister.take_action() returns two tuples
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+ datalist = [
+ (object_fakes.container_name, ),
+ (object_fakes.container_name_3, ),
+ (object_fakes.container_name_2, ),
+ ]
+ self.assertEqual(datalist, list(data))
+
+ def test_object_list_containers_prefix(self):
+ return_body = [
+ copy.deepcopy(object_fakes.CONTAINER),
+ copy.deepcopy(object_fakes.CONTAINER_3),
+ ]
+ self.requests_mock.register_uri(
+ 'GET',
+ object_fakes.ENDPOINT + '?format=json&prefix=bit',
+ json=return_body,
+ status_code=200,
+ )
+
+ arglist = [
+ '--prefix', 'bit',
+ ]
+ verifylist = [
+ ('prefix', 'bit'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # Lister.take_action() returns two tuples
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+ datalist = [
+ (object_fakes.container_name, ),
+ (object_fakes.container_name_3, ),
+ ]
+ self.assertEqual(datalist, list(data))
+
+
+class TestContainerSave(TestContainerAll):
+
+ def setUp(self):
+ super(TestContainerSave, self).setUp()
+
+ # Get the command object to test
+ self.cmd = container_cmds.SaveContainer(self.app, None)
+
+# TODO(dtroyer): need to mock out object_lib.save_object() to test this
+# def test_object_save_container(self):
+# return_body = [
+# copy.deepcopy(object_fakes.OBJECT),
+# copy.deepcopy(object_fakes.OBJECT_2),
+# ]
+# # Initial container list request
+# self.requests_mock.register_uri(
+# 'GET',
+# object_fakes.ENDPOINT + '/oscar?format=json',
+# json=return_body,
+# status_code=200,
+# )
+# # Individual object save requests
+# self.requests_mock.register_uri(
+# 'GET',
+# object_fakes.ENDPOINT + '/oscar/' + object_fakes.object_name_1,
+# json=object_fakes.OBJECT,
+# status_code=200,
+# )
+# self.requests_mock.register_uri(
+# 'GET',
+# object_fakes.ENDPOINT + '/oscar/' + object_fakes.object_name_2,
+# json=object_fakes.OBJECT_2,
+# status_code=200,
+# )
+#
+# arglist = [
+# 'oscar',
+# ]
+# verifylist = [(
+# 'container', 'oscar',
+# )]
+# parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+#
+# # Command.take_action() returns None
+# ret = self.cmd.take_action(parsed_args)
+# self.assertIsNone(ret)
+
+
+class TestContainerShow(TestContainerAll):
+
+ def setUp(self):
+ super(TestContainerShow, self).setUp()
+
+ # Get the command object to test
+ self.cmd = container_cmds.ShowContainer(self.app, None)
+
+ def test_object_show_container(self):
+ headers = {
+ 'x-container-object-count': '42',
+ 'x-container-bytes-used': '123',
+ 'x-container-read': 'qaz',
+ 'x-container-write': 'wsx',
+ 'x-container-sync-to': 'edc',
+ 'x-container-sync-key': 'rfv',
+ }
+ self.requests_mock.register_uri(
+ 'HEAD',
+ object_fakes.ENDPOINT + '/ernie',
+ headers=headers,
+ status_code=200,
+ )
+
+ arglist = [
+ 'ernie',
+ ]
+ verifylist = [(
+ 'container', 'ernie',
+ )]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ collist = (
+ 'account',
+ 'bytes_used',
+ 'container',
+ 'object_count',
+ 'read_acl',
+ 'sync_key',
+ 'sync_to',
+ 'write_acl',
+ )
+ self.assertEqual(collist, columns)
+ datalist = [
+ object_fakes.ACCOUNT_ID,
+ '123',
+ 'ernie',
+ '42',
+ 'qaz',
+ 'rfv',
+ 'edc',
+ 'wsx',
+ ]
+ self.assertEqual(datalist, list(data))
diff --git a/openstackclient/tests/unit/object/v1/test_object.py b/openstackclient/tests/unit/object/v1/test_object.py
new file mode 100644
index 00000000..c0ac204d
--- /dev/null
+++ b/openstackclient/tests/unit/object/v1/test_object.py
@@ -0,0 +1,382 @@
+# Copyright 2013 OpenStack Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+import copy
+import mock
+
+from openstackclient.api import object_store_v1 as object_store
+from openstackclient.object.v1 import object as obj
+from openstackclient.tests.unit.object.v1 import fakes as object_fakes
+
+
+AUTH_TOKEN = "foobar"
+AUTH_URL = "http://0.0.0.0"
+
+
+class TestObject(object_fakes.TestObjectv1):
+
+ def setUp(self):
+ super(TestObject, self).setUp()
+ self.app.client_manager.object_store = object_store.APIv1(
+ session=mock.Mock(),
+ service_type="object-store",
+ )
+ self.api = self.app.client_manager.object_store
+
+
+@mock.patch(
+ 'openstackclient.api.object_store_v1.APIv1.object_list'
+)
+class TestObjectList(TestObject):
+
+ columns = ('Name',)
+ datalist = (
+ (
+ object_fakes.object_name_2,
+ ),
+ )
+
+ def setUp(self):
+ super(TestObjectList, self).setUp()
+
+ # Get the command object to test
+ self.cmd = obj.ListObject(self.app, None)
+
+ def test_object_list_objects_no_options(self, o_mock):
+ o_mock.return_value = [
+ copy.deepcopy(object_fakes.OBJECT),
+ copy.deepcopy(object_fakes.OBJECT_2),
+ ]
+
+ arglist = [
+ object_fakes.container_name,
+ ]
+ verifylist = [
+ ('container', object_fakes.container_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ o_mock.assert_called_with(
+ container=object_fakes.container_name,
+ )
+
+ self.assertEqual(self.columns, columns)
+ datalist = (
+ (object_fakes.object_name_1, ),
+ (object_fakes.object_name_2, ),
+ )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_object_list_objects_prefix(self, o_mock):
+ o_mock.return_value = [
+ copy.deepcopy(object_fakes.OBJECT_2),
+ ]
+
+ arglist = [
+ '--prefix', 'floppy',
+ object_fakes.container_name_2,
+ ]
+ verifylist = [
+ ('prefix', 'floppy'),
+ ('container', object_fakes.container_name_2),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'prefix': 'floppy',
+ }
+ o_mock.assert_called_with(
+ container=object_fakes.container_name_2,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_object_list_objects_delimiter(self, o_mock):
+ o_mock.return_value = [
+ copy.deepcopy(object_fakes.OBJECT_2),
+ ]
+
+ arglist = [
+ '--delimiter', '=',
+ object_fakes.container_name_2,
+ ]
+ verifylist = [
+ ('delimiter', '='),
+ ('container', object_fakes.container_name_2),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'delimiter': '=',
+ }
+ o_mock.assert_called_with(
+ container=object_fakes.container_name_2,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_object_list_objects_marker(self, o_mock):
+ o_mock.return_value = [
+ copy.deepcopy(object_fakes.OBJECT_2),
+ ]
+
+ arglist = [
+ '--marker', object_fakes.object_name_2,
+ object_fakes.container_name_2,
+ ]
+ verifylist = [
+ ('marker', object_fakes.object_name_2),
+ ('container', object_fakes.container_name_2),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'marker': object_fakes.object_name_2,
+ }
+ o_mock.assert_called_with(
+ container=object_fakes.container_name_2,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_object_list_objects_end_marker(self, o_mock):
+ o_mock.return_value = [
+ copy.deepcopy(object_fakes.OBJECT_2),
+ ]
+
+ arglist = [
+ '--end-marker', object_fakes.object_name_2,
+ object_fakes.container_name_2,
+ ]
+ verifylist = [
+ ('end_marker', object_fakes.object_name_2),
+ ('container', object_fakes.container_name_2),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'end_marker': object_fakes.object_name_2,
+ }
+ o_mock.assert_called_with(
+ container=object_fakes.container_name_2,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_object_list_objects_limit(self, o_mock):
+ o_mock.return_value = [
+ copy.deepcopy(object_fakes.OBJECT_2),
+ ]
+
+ arglist = [
+ '--limit', '2',
+ object_fakes.container_name_2,
+ ]
+ verifylist = [
+ ('limit', 2),
+ ('container', object_fakes.container_name_2),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'limit': 2,
+ }
+ o_mock.assert_called_with(
+ container=object_fakes.container_name_2,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_object_list_objects_long(self, o_mock):
+ o_mock.return_value = [
+ copy.deepcopy(object_fakes.OBJECT),
+ copy.deepcopy(object_fakes.OBJECT_2),
+ ]
+
+ arglist = [
+ '--long',
+ object_fakes.container_name,
+ ]
+ verifylist = [
+ ('long', True),
+ ('container', object_fakes.container_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ }
+ o_mock.assert_called_with(
+ container=object_fakes.container_name,
+ **kwargs
+ )
+
+ collist = ('Name', 'Bytes', 'Hash', 'Content Type', 'Last Modified')
+ self.assertEqual(collist, columns)
+ datalist = (
+ (
+ object_fakes.object_name_1,
+ object_fakes.object_bytes_1,
+ object_fakes.object_hash_1,
+ object_fakes.object_content_type_1,
+ object_fakes.object_modified_1,
+ ),
+ (
+ object_fakes.object_name_2,
+ object_fakes.object_bytes_2,
+ object_fakes.object_hash_2,
+ object_fakes.object_content_type_2,
+ object_fakes.object_modified_2,
+ ),
+ )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_object_list_objects_all(self, o_mock):
+ o_mock.return_value = [
+ copy.deepcopy(object_fakes.OBJECT),
+ copy.deepcopy(object_fakes.OBJECT_2),
+ ]
+
+ arglist = [
+ '--all',
+ object_fakes.container_name,
+ ]
+ verifylist = [
+ ('all', True),
+ ('container', object_fakes.container_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'full_listing': True,
+ }
+ o_mock.assert_called_with(
+ container=object_fakes.container_name,
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ datalist = (
+ (object_fakes.object_name_1, ),
+ (object_fakes.object_name_2, ),
+ )
+ self.assertEqual(datalist, tuple(data))
+
+
+@mock.patch(
+ 'openstackclient.api.object_store_v1.APIv1.object_show'
+)
+class TestObjectShow(TestObject):
+
+ def setUp(self):
+ super(TestObjectShow, self).setUp()
+
+ # Get the command object to test
+ self.cmd = obj.ShowObject(self.app, None)
+
+ def test_object_show(self, c_mock):
+ c_mock.return_value = copy.deepcopy(object_fakes.OBJECT)
+
+ arglist = [
+ object_fakes.container_name,
+ object_fakes.object_name_1,
+ ]
+ verifylist = [
+ ('container', object_fakes.container_name),
+ ('object', object_fakes.object_name_1),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ }
+ # lib.container.show_container(api, url, container)
+ c_mock.assert_called_with(
+ container=object_fakes.container_name,
+ object=object_fakes.object_name_1,
+ **kwargs
+ )
+
+ collist = ('bytes', 'content_type', 'hash', 'last_modified', 'name')
+ self.assertEqual(collist, columns)
+ datalist = (
+ object_fakes.object_bytes_1,
+ object_fakes.object_content_type_1,
+ object_fakes.object_hash_1,
+ object_fakes.object_modified_1,
+ object_fakes.object_name_1,
+ )
+ self.assertEqual(datalist, data)
diff --git a/openstackclient/tests/unit/object/v1/test_object_all.py b/openstackclient/tests/unit/object/v1/test_object_all.py
new file mode 100644
index 00000000..a0948b1b
--- /dev/null
+++ b/openstackclient/tests/unit/object/v1/test_object_all.py
@@ -0,0 +1,182 @@
+# 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.
+#
+
+import copy
+
+from requests_mock.contrib import fixture
+
+from openstackclient.object.v1 import object as object_cmds
+from openstackclient.tests.unit.object.v1 import fakes as object_fakes
+
+
+class TestObjectAll(object_fakes.TestObjectv1):
+
+ def setUp(self):
+ super(TestObjectAll, self).setUp()
+
+ self.requests_mock = self.useFixture(fixture.Fixture())
+
+
+class TestObjectCreate(TestObjectAll):
+
+ def setUp(self):
+ super(TestObjectCreate, self).setUp()
+
+ # Get the command object to test
+ self.cmd = object_cmds.CreateObject(self.app, None)
+
+
+class TestObjectList(TestObjectAll):
+
+ columns = ('Name',)
+
+ def setUp(self):
+ super(TestObjectList, self).setUp()
+
+ # Get the command object to test
+ self.cmd = object_cmds.ListObject(self.app, None)
+
+ def test_object_list_objects_no_options(self):
+ return_body = [
+ copy.deepcopy(object_fakes.OBJECT),
+ copy.deepcopy(object_fakes.OBJECT_2),
+ ]
+ self.requests_mock.register_uri(
+ 'GET',
+ object_fakes.ENDPOINT +
+ '/' +
+ object_fakes.container_name +
+ '?format=json',
+ json=return_body,
+ status_code=200,
+ )
+
+ arglist = [
+ object_fakes.container_name,
+ ]
+ verifylist = [
+ ('container', object_fakes.container_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # Lister.take_action() returns two tuples
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+ datalist = [
+ (object_fakes.object_name_1, ),
+ (object_fakes.object_name_2, ),
+ ]
+ self.assertEqual(datalist, list(data))
+
+ def test_object_list_objects_prefix(self):
+ return_body = [
+ copy.deepcopy(object_fakes.OBJECT_2),
+ ]
+ self.requests_mock.register_uri(
+ 'GET',
+ object_fakes.ENDPOINT +
+ '/' +
+ object_fakes.container_name_2 +
+ '?prefix=floppy&format=json',
+ json=return_body,
+ status_code=200,
+ )
+
+ arglist = [
+ '--prefix', 'floppy',
+ object_fakes.container_name_2,
+ ]
+ verifylist = [
+ ('prefix', 'floppy'),
+ ('container', object_fakes.container_name_2),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+ datalist = (
+ (object_fakes.object_name_2, ),
+ )
+ self.assertEqual(datalist, tuple(data))
+
+
+class TestObjectShow(TestObjectAll):
+
+ def setUp(self):
+ super(TestObjectShow, self).setUp()
+
+ # Get the command object to test
+ self.cmd = object_cmds.ShowObject(self.app, None)
+
+ def test_object_show(self):
+ headers = {
+ 'content-type': 'text/plain',
+ 'content-length': '20',
+ 'last-modified': 'yesterday',
+ 'etag': '4c4e39a763d58392724bccf76a58783a',
+ 'x-container-meta-owner': object_fakes.ACCOUNT_ID,
+ 'x-object-manifest': 'manifest',
+ }
+ self.requests_mock.register_uri(
+ 'HEAD',
+ '/'.join([
+ object_fakes.ENDPOINT,
+ object_fakes.container_name,
+ object_fakes.object_name_1,
+ ]),
+ headers=headers,
+ status_code=200,
+ )
+
+ arglist = [
+ object_fakes.container_name,
+ object_fakes.object_name_1,
+ ]
+ verifylist = [
+ ('container', object_fakes.container_name),
+ ('object', object_fakes.object_name_1),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ collist = (
+ 'account',
+ 'container',
+ 'content-length',
+ 'content-type',
+ 'etag',
+ 'last-modified',
+ 'object',
+ 'x-object-manifest',
+ )
+ self.assertEqual(collist, columns)
+ datalist = (
+ object_fakes.ACCOUNT_ID,
+ object_fakes.container_name,
+ '20',
+ 'text/plain',
+ '4c4e39a763d58392724bccf76a58783a',
+ 'yesterday',
+ object_fakes.object_name_1,
+ 'manifest',
+ )
+ self.assertEqual(datalist, data)
diff --git a/openstackclient/tests/unit/test_shell.py b/openstackclient/tests/unit/test_shell.py
new file mode 100644
index 00000000..87cd7f51
--- /dev/null
+++ b/openstackclient/tests/unit/test_shell.py
@@ -0,0 +1,442 @@
+# Copyright 2012-2013 OpenStack Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+import mock
+import os
+import sys
+
+from osc_lib.tests import utils as osc_lib_test_utils
+from oslo_utils import importutils
+import wrapt
+
+from openstackclient import shell
+
+
+DEFAULT_AUTH_URL = "http://127.0.0.1:5000/v2.0/"
+DEFAULT_PROJECT_ID = "xxxx-yyyy-zzzz"
+DEFAULT_PROJECT_NAME = "project"
+DEFAULT_DOMAIN_ID = "aaaa-bbbb-cccc"
+DEFAULT_DOMAIN_NAME = "default"
+DEFAULT_USER_DOMAIN_ID = "aaaa-bbbb-cccc"
+DEFAULT_USER_DOMAIN_NAME = "domain"
+DEFAULT_PROJECT_DOMAIN_ID = "aaaa-bbbb-cccc"
+DEFAULT_PROJECT_DOMAIN_NAME = "domain"
+DEFAULT_USERNAME = "username"
+DEFAULT_PASSWORD = "password"
+
+DEFAULT_CLOUD = "altocumulus"
+DEFAULT_REGION_NAME = "ZZ9_Plural_Z_Alpha"
+DEFAULT_TOKEN = "token"
+DEFAULT_SERVICE_URL = "http://127.0.0.1:8771/v3.0/"
+DEFAULT_AUTH_PLUGIN = "v2password"
+DEFAULT_INTERFACE = "internal"
+
+DEFAULT_COMPUTE_API_VERSION = ""
+DEFAULT_IDENTITY_API_VERSION = ""
+DEFAULT_IMAGE_API_VERSION = ""
+DEFAULT_VOLUME_API_VERSION = ""
+DEFAULT_NETWORK_API_VERSION = ""
+
+LIB_COMPUTE_API_VERSION = ""
+LIB_IDENTITY_API_VERSION = ""
+LIB_IMAGE_API_VERSION = ""
+LIB_VOLUME_API_VERSION = ""
+LIB_NETWORK_API_VERSION = ""
+
+CLOUD_1 = {
+ 'clouds': {
+ 'scc': {
+ 'auth': {
+ 'auth_url': DEFAULT_AUTH_URL,
+ 'project_name': DEFAULT_PROJECT_NAME,
+ 'username': 'zaphod',
+ },
+ 'region_name': 'occ-cloud',
+ 'donut': 'glazed',
+ 'interface': 'public',
+ }
+ }
+}
+
+CLOUD_2 = {
+ 'clouds': {
+ 'megacloud': {
+ 'cloud': 'megadodo',
+ 'auth': {
+ 'project_name': 'heart-o-gold',
+ 'username': 'zaphod',
+ },
+ 'region_name': 'occ-cloud,krikkit,occ-env',
+ 'log_file': '/tmp/test_log_file',
+ 'log_level': 'debug',
+ 'cert': 'mycert',
+ 'key': 'mickey',
+ }
+ }
+}
+
+PUBLIC_1 = {
+ 'public-clouds': {
+ 'megadodo': {
+ 'auth': {
+ 'auth_url': DEFAULT_AUTH_URL,
+ 'project_name': DEFAULT_PROJECT_NAME,
+ },
+ 'region_name': 'occ-public',
+ 'donut': 'cake',
+ }
+ }
+}
+
+
+# The option table values is a tuple of (<value>, <test-opt>, <test-env>)
+# where <value> is the test value to use, <test-opt> is True if this option
+# should be tested as a CLI option and <test-env> is True of this option
+# should be tested as an environment variable.
+
+# Global options that should be parsed before shell.initialize_app() is called
+global_options = {
+ '--os-cloud': (DEFAULT_CLOUD, True, True),
+ '--os-region-name': (DEFAULT_REGION_NAME, True, True),
+ '--os-default-domain': (DEFAULT_DOMAIN_NAME, True, True),
+ '--os-cacert': ('/dev/null', True, True),
+ '--timing': (True, True, False),
+ '--os-profile': ('SECRET_KEY', True, False),
+ '--os-interface': (DEFAULT_INTERFACE, True, True)
+}
+
+
+# Wrap the osc_lib make_shell() function to set the shell class since
+# osc-lib's TestShell class doesn't allow us to specify it yet.
+# TODO(dtroyer): remove this once the shell_class_patch patch is released
+# in osc-lib
+def make_shell_wrapper(func, inst, args, kwargs):
+ if 'shell_class' not in kwargs:
+ kwargs['shell_class'] = shell.OpenStackShell
+ return func(*args, **kwargs)
+
+
+wrapt.wrap_function_wrapper(
+ osc_lib_test_utils,
+ 'make_shell',
+ make_shell_wrapper,
+)
+
+
+class TestShell(osc_lib_test_utils.TestShell):
+
+ # Full name of the OpenStackShell class to test (cliff.app.App subclass)
+ shell_class_name = "openstackclient.shell.OpenStackShell"
+
+ # TODO(dtroyer): remove this once the shell_class_patch patch is released
+ # in osc-lib
+ app_patch = shell_class_name
+
+ def setUp(self):
+ super(TestShell, self).setUp()
+ # TODO(dtroyer): remove this once the shell_class_patch patch is
+ # released in osc-lib
+ self.shell_class = importutils.import_class(self.shell_class_name)
+
+ def _assert_token_endpoint_auth(self, cmd_options, default_args):
+ with mock.patch(
+ self.shell_class_name + ".initialize_app",
+ self.app,
+ ):
+ _shell = osc_lib_test_utils.make_shell(
+ shell_class=self.shell_class,
+ )
+ _cmd = cmd_options + " list role"
+ osc_lib_test_utils.fake_execute(_shell, _cmd)
+ print("_shell: %s" % _shell)
+
+ self.app.assert_called_with(["list", "role"])
+ self.assertEqual(
+ default_args.get("token", ''),
+ _shell.options.token,
+ "token",
+ )
+ self.assertEqual(
+ default_args.get("url", ''),
+ _shell.options.url,
+ "url",
+ )
+
+ def _assert_token_auth(self, cmd_options, default_args):
+ with mock.patch(
+ self.app_patch + ".initialize_app",
+ self.app,
+ ):
+ _shell = osc_lib_test_utils.make_shell(
+ shell_class=self.shell_class,
+ )
+ _cmd = cmd_options + " list role"
+ osc_lib_test_utils.fake_execute(_shell, _cmd)
+ print("_shell: %s" % _shell)
+
+ self.app.assert_called_with(["list", "role"])
+ self.assertEqual(
+ default_args.get("token", ''),
+ _shell.options.token,
+ "token"
+ )
+ self.assertEqual(
+ default_args.get("auth_url", ''),
+ _shell.options.auth_url,
+ "auth_url"
+ )
+
+ def _assert_cli(self, cmd_options, default_args):
+ with mock.patch(
+ self.shell_class_name + ".initialize_app",
+ self.app,
+ ):
+ _shell = osc_lib_test_utils.make_shell(
+ shell_class=self.shell_class,
+ )
+ _cmd = cmd_options + " list server"
+ osc_lib_test_utils.fake_execute(_shell, _cmd)
+
+ self.app.assert_called_with(["list", "server"])
+ self.assertEqual(default_args["compute_api_version"],
+ _shell.options.os_compute_api_version)
+ self.assertEqual(default_args["identity_api_version"],
+ _shell.options.os_identity_api_version)
+ self.assertEqual(default_args["image_api_version"],
+ _shell.options.os_image_api_version)
+ self.assertEqual(default_args["volume_api_version"],
+ _shell.options.os_volume_api_version)
+ self.assertEqual(default_args["network_api_version"],
+ _shell.options.os_network_api_version)
+
+
+class TestShellOptions(TestShell):
+
+ def setUp(self):
+ super(TestShellOptions, self).setUp()
+ self.useFixture(osc_lib_test_utils.EnvFixture())
+
+ def _test_options_init_app(self, test_opts):
+ for opt in test_opts.keys():
+ if not test_opts[opt][1]:
+ continue
+ key = osc_lib_test_utils.opt2attr(opt)
+ if isinstance(test_opts[opt][0], str):
+ cmd = opt + " " + test_opts[opt][0]
+ else:
+ cmd = opt
+ kwargs = {
+ key: test_opts[opt][0],
+ }
+ self._assert_initialize_app_arg(cmd, kwargs)
+
+ def _test_options_get_one_cloud(self, test_opts):
+ for opt in test_opts.keys():
+ if not test_opts[opt][1]:
+ continue
+ key = osc_lib_test_utils.opt2attr(opt)
+ if isinstance(test_opts[opt][0], str):
+ cmd = opt + " " + test_opts[opt][0]
+ else:
+ cmd = opt
+ kwargs = {
+ key: test_opts[opt][0],
+ }
+ self._assert_cloud_config_arg(cmd, kwargs)
+
+ def _test_env_init_app(self, test_opts):
+ for opt in test_opts.keys():
+ if not test_opts[opt][2]:
+ continue
+ key = osc_lib_test_utils.opt2attr(opt)
+ kwargs = {
+ key: test_opts[opt][0],
+ }
+ env = {
+ osc_lib_test_utils.opt2env(opt): test_opts[opt][0],
+ }
+ os.environ = env.copy()
+ self._assert_initialize_app_arg("", kwargs)
+
+ def _test_env_get_one_cloud(self, test_opts):
+ for opt in test_opts.keys():
+ if not test_opts[opt][2]:
+ continue
+ key = osc_lib_test_utils.opt2attr(opt)
+ kwargs = {
+ key: test_opts[opt][0],
+ }
+ env = {
+ osc_lib_test_utils.opt2env(opt): test_opts[opt][0],
+ }
+ os.environ = env.copy()
+ self._assert_cloud_config_arg("", kwargs)
+
+
+class TestShellTokenAuthEnv(TestShell):
+
+ def setUp(self):
+ super(TestShellTokenAuthEnv, self).setUp()
+ env = {
+ "OS_TOKEN": DEFAULT_TOKEN,
+ "OS_AUTH_URL": DEFAULT_AUTH_URL,
+ }
+ self.useFixture(osc_lib_test_utils.EnvFixture(env.copy()))
+
+ def test_env(self):
+ flag = ""
+ kwargs = {
+ "token": DEFAULT_TOKEN,
+ "auth_url": DEFAULT_AUTH_URL,
+ }
+ self._assert_token_auth(flag, kwargs)
+
+ def test_only_token(self):
+ flag = "--os-token xyzpdq"
+ kwargs = {
+ "token": "xyzpdq",
+ "auth_url": DEFAULT_AUTH_URL,
+ }
+ self._assert_token_auth(flag, kwargs)
+
+ def test_only_auth_url(self):
+ flag = "--os-auth-url http://cloud.local:555"
+ kwargs = {
+ "token": DEFAULT_TOKEN,
+ "auth_url": "http://cloud.local:555",
+ }
+ self._assert_token_auth(flag, kwargs)
+
+ def test_empty_auth(self):
+ os.environ = {}
+ flag = ""
+ kwargs = {
+ "token": '',
+ "auth_url": '',
+ }
+ self._assert_token_auth(flag, kwargs)
+
+
+class TestShellTokenEndpointAuthEnv(TestShell):
+
+ def setUp(self):
+ super(TestShellTokenEndpointAuthEnv, self).setUp()
+ env = {
+ "OS_TOKEN": DEFAULT_TOKEN,
+ "OS_URL": DEFAULT_SERVICE_URL,
+ }
+ self.useFixture(osc_lib_test_utils.EnvFixture(env.copy()))
+
+ def test_env(self):
+ flag = ""
+ kwargs = {
+ "token": DEFAULT_TOKEN,
+ "url": DEFAULT_SERVICE_URL,
+ }
+ self._assert_token_endpoint_auth(flag, kwargs)
+
+ def test_only_token(self):
+ flag = "--os-token xyzpdq"
+ kwargs = {
+ "token": "xyzpdq",
+ "url": DEFAULT_SERVICE_URL,
+ }
+ self._assert_token_auth(flag, kwargs)
+
+ def test_only_url(self):
+ flag = "--os-url http://cloud.local:555"
+ kwargs = {
+ "token": DEFAULT_TOKEN,
+ "url": "http://cloud.local:555",
+ }
+ self._assert_token_auth(flag, kwargs)
+
+ def test_empty_auth(self):
+ os.environ = {}
+ flag = ""
+ kwargs = {
+ "token": '',
+ "url": '',
+ }
+ self._assert_token_auth(flag, kwargs)
+
+
+class TestShellCli(TestShell):
+
+ def setUp(self):
+ super(TestShellCli, self).setUp()
+ env = {
+ "OS_COMPUTE_API_VERSION": DEFAULT_COMPUTE_API_VERSION,
+ "OS_IDENTITY_API_VERSION": DEFAULT_IDENTITY_API_VERSION,
+ "OS_IMAGE_API_VERSION": DEFAULT_IMAGE_API_VERSION,
+ "OS_VOLUME_API_VERSION": DEFAULT_VOLUME_API_VERSION,
+ "OS_NETWORK_API_VERSION": DEFAULT_NETWORK_API_VERSION,
+ }
+ self.useFixture(osc_lib_test_utils.EnvFixture(env.copy()))
+
+ def test_default_env(self):
+ flag = ""
+ kwargs = {
+ "compute_api_version": DEFAULT_COMPUTE_API_VERSION,
+ "identity_api_version": DEFAULT_IDENTITY_API_VERSION,
+ "image_api_version": DEFAULT_IMAGE_API_VERSION,
+ "volume_api_version": DEFAULT_VOLUME_API_VERSION,
+ "network_api_version": DEFAULT_NETWORK_API_VERSION,
+ }
+ self._assert_cli(flag, kwargs)
+
+ def test_empty_env(self):
+ os.environ = {}
+ flag = ""
+ kwargs = {
+ "compute_api_version": LIB_COMPUTE_API_VERSION,
+ "identity_api_version": LIB_IDENTITY_API_VERSION,
+ "image_api_version": LIB_IMAGE_API_VERSION,
+ "volume_api_version": LIB_VOLUME_API_VERSION,
+ "network_api_version": LIB_NETWORK_API_VERSION
+ }
+ self._assert_cli(flag, kwargs)
+
+
+class TestShellArgV(TestShell):
+ """Test the deferred help flag"""
+
+ def setUp(self):
+ super(TestShellArgV, self).setUp()
+
+ def test_shell_argv(self):
+ """Test argv decoding
+
+ Python 2 does nothing with argv while Python 3 decodes it into
+ Unicode before we ever see it. We manually decode when running
+ under Python 2 so verify that we get the right argv types.
+
+ Use the argv supplied by the test runner so we get actual Python
+ runtime behaviour; we only need to check the type of argv[0]
+ which will alwyas be present.
+ """
+
+ with mock.patch(
+ self.shell_class_name + ".run",
+ self.app,
+ ):
+ # Ensure type gets through unmolested through shell.main()
+ argv = sys.argv
+ shell.main(sys.argv)
+ self.assertEqual(type(argv[0]), type(self.app.call_args[0][0][0]))
+
+ # When shell.main() gets sys.argv itself it should be decoded
+ shell.main()
+ self.assertEqual(type(u'x'), type(self.app.call_args[0][0][0]))
diff --git a/openstackclient/tests/unit/utils.py b/openstackclient/tests/unit/utils.py
new file mode 100644
index 00000000..3c5c8683
--- /dev/null
+++ b/openstackclient/tests/unit/utils.py
@@ -0,0 +1,75 @@
+# Copyright 2012-2013 OpenStack Foundation
+# Copyright 2013 Nebula Inc.
+#
+# 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.
+#
+
+import fixtures
+import os
+import testtools
+
+from openstackclient.tests.unit import fakes
+
+
+class ParserException(Exception):
+ pass
+
+
+class TestCase(testtools.TestCase):
+
+ def setUp(self):
+ testtools.TestCase.setUp(self)
+
+ if (os.environ.get("OS_STDOUT_CAPTURE") == "True" or
+ os.environ.get("OS_STDOUT_CAPTURE") == "1"):
+ stdout = self.useFixture(fixtures.StringStream("stdout")).stream
+ self.useFixture(fixtures.MonkeyPatch("sys.stdout", stdout))
+
+ if (os.environ.get("OS_STDERR_CAPTURE") == "True" or
+ os.environ.get("OS_STDERR_CAPTURE") == "1"):
+ stderr = self.useFixture(fixtures.StringStream("stderr")).stream
+ self.useFixture(fixtures.MonkeyPatch("sys.stderr", stderr))
+
+ def assertNotCalled(self, m, msg=None):
+ """Assert a function was not called"""
+
+ if m.called:
+ if not msg:
+ msg = 'method %s should not have been called' % m
+ self.fail(msg)
+
+
+class TestCommand(TestCase):
+ """Test cliff command classes"""
+
+ def setUp(self):
+ super(TestCommand, self).setUp()
+ # Build up a fake app
+ self.fake_stdout = fakes.FakeStdout()
+ self.fake_log = fakes.FakeLog()
+ self.app = fakes.FakeApp(self.fake_stdout, self.fake_log)
+ self.app.client_manager = fakes.FakeClientManager()
+ self.app.options = fakes.FakeOptions()
+
+ def check_parser(self, cmd, args, verify_args):
+ cmd_parser = cmd.get_parser('check_parser')
+ try:
+ parsed_args = cmd_parser.parse_args(args)
+ except SystemExit:
+ raise ParserException("Argument parse failed")
+ for av in verify_args:
+ attr, value = av
+ if attr:
+ self.assertIn(attr, parsed_args)
+ self.assertEqual(value, getattr(parsed_args, attr))
+ return parsed_args
diff --git a/openstackclient/tests/unit/volume/__init__.py b/openstackclient/tests/unit/volume/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/unit/volume/__init__.py
diff --git a/openstackclient/tests/unit/volume/test_find_resource.py b/openstackclient/tests/unit/volume/test_find_resource.py
new file mode 100644
index 00000000..d2509315
--- /dev/null
+++ b/openstackclient/tests/unit/volume/test_find_resource.py
@@ -0,0 +1,83 @@
+# Copyright 2013 Nebula Inc.
+#
+# 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.
+#
+
+import mock
+
+from cinderclient.v1 import volume_snapshots
+from cinderclient.v1 import volumes
+from osc_lib import exceptions
+from osc_lib import utils
+
+from openstackclient.tests.unit import utils as test_utils
+from openstackclient.volume import client # noqa
+
+
+# Monkey patch for v1 cinderclient
+# NOTE(dtroyer): Do here because openstackclient.volume.client
+# doesn't do it until the client object is created now.
+volumes.Volume.NAME_ATTR = 'display_name'
+volume_snapshots.Snapshot.NAME_ATTR = 'display_name'
+
+
+ID = '1after909'
+NAME = 'PhilSpector'
+
+
+class TestFindResourceVolumes(test_utils.TestCase):
+
+ def setUp(self):
+ super(TestFindResourceVolumes, self).setUp()
+ api = mock.Mock()
+ api.client = mock.Mock()
+ api.client.get = mock.Mock()
+ resp = mock.Mock()
+ body = {"volumes": [{"id": ID, 'display_name': NAME}]}
+ api.client.get.side_effect = [Exception("Not found"),
+ Exception("Not found"),
+ (resp, body)]
+ self.manager = volumes.VolumeManager(api)
+
+ def test_find(self):
+ result = utils.find_resource(self.manager, NAME)
+ self.assertEqual(ID, result.id)
+ self.assertEqual(NAME, result.display_name)
+
+ def test_not_find(self):
+ self.assertRaises(exceptions.CommandError, utils.find_resource,
+ self.manager, 'GeorgeMartin')
+
+
+class TestFindResourceVolumeSnapshots(test_utils.TestCase):
+
+ def setUp(self):
+ super(TestFindResourceVolumeSnapshots, self).setUp()
+ api = mock.Mock()
+ api.client = mock.Mock()
+ api.client.get = mock.Mock()
+ resp = mock.Mock()
+ body = {"snapshots": [{"id": ID, 'display_name': NAME}]}
+ api.client.get.side_effect = [Exception("Not found"),
+ Exception("Not found"),
+ (resp, body)]
+ self.manager = volume_snapshots.SnapshotManager(api)
+
+ def test_find(self):
+ result = utils.find_resource(self.manager, NAME)
+ self.assertEqual(ID, result.id)
+ self.assertEqual(NAME, result.display_name)
+
+ def test_not_find(self):
+ self.assertRaises(exceptions.CommandError, utils.find_resource,
+ self.manager, 'GeorgeMartin')
diff --git a/openstackclient/tests/unit/volume/v1/__init__.py b/openstackclient/tests/unit/volume/v1/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/unit/volume/v1/__init__.py
diff --git a/openstackclient/tests/unit/volume/v1/fakes.py b/openstackclient/tests/unit/volume/v1/fakes.py
new file mode 100644
index 00000000..c6fee7d1
--- /dev/null
+++ b/openstackclient/tests/unit/volume/v1/fakes.py
@@ -0,0 +1,280 @@
+# Copyright 2013 Nebula Inc.
+#
+# 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.
+#
+
+import mock
+
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit.identity.v2_0 import fakes as identity_fakes
+from openstackclient.tests.unit import utils
+
+
+volume_id = 'vvvvvvvv-vvvv-vvvv-vvvvvvvv'
+volume_name = 'nigel'
+volume_description = 'Nigel Tufnel'
+volume_status = 'available'
+volume_size = 120
+volume_type = 'to-eleven'
+volume_zone = 'stonehenge'
+volume_metadata = {
+ 'Alpha': 'a',
+ 'Beta': 'b',
+ 'Gamma': 'g',
+}
+volume_metadata_str = "Alpha='a', Beta='b', Gamma='g'"
+
+VOLUME = {
+ 'id': volume_id,
+ 'display_name': volume_name,
+ 'display_description': volume_description,
+ 'size': volume_size,
+ 'status': volume_status,
+ 'attach_status': 'detached',
+ 'availability_zone': volume_zone,
+ 'volume_type': volume_type,
+ 'metadata': volume_metadata,
+}
+
+extension_name = 'SchedulerHints'
+extension_namespace = 'http://docs.openstack.org/'\
+ 'block-service/ext/scheduler-hints/api/v2'
+extension_description = 'Pass arbitrary key/value'\
+ 'pairs to the scheduler.'
+extension_updated = '2014-02-07T12:00:0-00:00'
+extension_alias = 'OS-SCH-HNT'
+extension_links = '[{"href":'\
+ '"https://github.com/openstack/block-api", "type":'\
+ ' "text/html", "rel": "describedby"}]'
+
+EXTENSION = {
+ 'name': extension_name,
+ 'namespace': extension_namespace,
+ 'description': extension_description,
+ 'updated': extension_updated,
+ 'alias': extension_alias,
+ 'links': extension_links,
+}
+
+# NOTE(dtroyer): duplicating here the minimum image info needed to test
+# volume create --image until circular references can be
+# avoided by refactoring the test fakes.
+
+image_id = 'im1'
+image_name = 'graven'
+
+
+IMAGE = {
+ 'id': image_id,
+ 'name': image_name,
+}
+
+type_id = "5520dc9e-6f9b-4378-a719-729911c0f407"
+type_name = "fake-lvmdriver-1"
+
+TYPE = {
+ 'id': type_id,
+ 'name': type_name
+}
+
+qos_id = '6f2be1de-997b-4230-b76c-a3633b59e8fb'
+qos_consumer = 'front-end'
+qos_default_consumer = 'both'
+qos_name = "fake-qos-specs"
+qos_specs = {
+ 'foo': 'bar',
+ 'iops': '9001'
+}
+qos_association = {
+ 'association_type': 'volume_type',
+ 'name': type_name,
+ 'id': type_id
+}
+
+QOS = {
+ 'id': qos_id,
+ 'consumer': qos_consumer,
+ 'name': qos_name
+}
+
+QOS_DEFAULT_CONSUMER = {
+ 'id': qos_id,
+ 'consumer': qos_default_consumer,
+ 'name': qos_name
+}
+
+QOS_WITH_SPECS = {
+ 'id': qos_id,
+ 'consumer': qos_consumer,
+ 'name': qos_name,
+ 'specs': qos_specs
+}
+
+QOS_WITH_ASSOCIATIONS = {
+ 'id': qos_id,
+ 'consumer': qos_consumer,
+ 'name': qos_name,
+ 'specs': qos_specs,
+ 'associations': [qos_association]
+}
+
+
+class FakeTransfer(object):
+ """Fake one or more Transfer."""
+
+ @staticmethod
+ def create_one_transfer(attrs=None):
+ """Create a fake transfer.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes of Transfer Request
+ :return:
+ A FakeResource object with volume_id, name, id.
+ """
+ # Set default attribute
+ transfer_info = {
+ 'volume_id': 'ce26708d-a7f8-4b4b-9861-4a80256615a7',
+ 'name': 'fake_transfer_name',
+ 'id': '731a7f53-aa92-4fbd-9de3-6f7d729c926b'
+ }
+
+ # Overwrite default attributes if there are some attributes set
+ attrs = attrs or {}
+
+ transfer_info.update(attrs)
+
+ transfer = fakes.FakeResource(
+ None,
+ transfer_info,
+ loaded=True)
+
+ return transfer
+
+
+class FakeService(object):
+ """Fake one or more Services."""
+
+ @staticmethod
+ def create_one_service(attrs=None):
+ """Create a fake service.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes of service
+ :return:
+ A FakeResource object with host, status, etc.
+ """
+ # Set default attribute
+ service_info = {
+ 'host': 'host_test',
+ 'binary': 'cinder_test',
+ 'status': 'enabled',
+ 'disabled_reason': 'LongHoliday-GoldenWeek',
+ 'zone': 'fake_zone',
+ 'updated_at': 'fake_date',
+ 'state': 'fake_state',
+ }
+
+ # Overwrite default attributes if there are some attributes set
+ attrs = attrs or {}
+
+ service_info.update(attrs)
+
+ service = fakes.FakeResource(
+ None,
+ service_info,
+ loaded=True)
+
+ return service
+
+ @staticmethod
+ def create_services(attrs=None, count=2):
+ """Create multiple fake services.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes of service
+ :param Integer count:
+ The number of services to be faked
+ :return:
+ A list of FakeResource objects
+ """
+ services = []
+ for n in range(0, count):
+ services.append(FakeService.create_one_service(attrs))
+
+ return services
+
+ @staticmethod
+ def get_services(services=None, count=2):
+ """Get an iterable MagicMock object with a list of faked services.
+
+ If services list is provided, then initialize the Mock object with the
+ list. Otherwise create one.
+
+ :param List services:
+ A list of FakeResource objects faking services
+ :param Integer count:
+ The number of services to be faked
+ :return
+ An iterable Mock object with side_effect set to a list of faked
+ services
+ """
+ if services is None:
+ services = FakeService.create_services(count)
+
+ return mock.MagicMock(side_effect=services)
+
+
+class FakeImagev1Client(object):
+
+ def __init__(self, **kwargs):
+ self.images = mock.Mock()
+
+
+class FakeVolumev1Client(object):
+
+ def __init__(self, **kwargs):
+ self.volumes = mock.Mock()
+ self.volumes.resource_class = fakes.FakeResource(None, {})
+ self.services = mock.Mock()
+ self.services.resource_class = fakes.FakeResource(None, {})
+ self.extensions = mock.Mock()
+ self.extensions.resource_class = fakes.FakeResource(None, {})
+ self.qos_specs = mock.Mock()
+ self.qos_specs.resource_class = fakes.FakeResource(None, {})
+ self.volume_types = mock.Mock()
+ self.volume_types.resource_class = fakes.FakeResource(None, {})
+ self.transfers = mock.Mock()
+ self.transfers.resource_class = fakes.FakeResource(None, {})
+ self.auth_token = kwargs['token']
+ self.management_url = kwargs['endpoint']
+
+
+class TestVolumev1(utils.TestCommand):
+
+ def setUp(self):
+ super(TestVolumev1, self).setUp()
+
+ self.app.client_manager.volume = FakeVolumev1Client(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN,
+ )
+
+ self.app.client_manager.identity = identity_fakes.FakeIdentityv2Client(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN,
+ )
+
+ self.app.client_manager.image = FakeImagev1Client(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN,
+ )
diff --git a/openstackclient/tests/unit/volume/v1/test_qos_specs.py b/openstackclient/tests/unit/volume/v1/test_qos_specs.py
new file mode 100644
index 00000000..7b87ccb3
--- /dev/null
+++ b/openstackclient/tests/unit/volume/v1/test_qos_specs.py
@@ -0,0 +1,472 @@
+# Copyright 2015 iWeb Technologies Inc.
+#
+# 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.
+#
+
+import copy
+
+from osc_lib import utils
+
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit.volume.v1 import fakes as volume_fakes
+from openstackclient.volume.v1 import qos_specs
+
+
+class TestQos(volume_fakes.TestVolumev1):
+
+ def setUp(self):
+ super(TestQos, self).setUp()
+
+ self.qos_mock = self.app.client_manager.volume.qos_specs
+ self.qos_mock.reset_mock()
+
+ self.types_mock = self.app.client_manager.volume.volume_types
+ self.types_mock.reset_mock()
+
+
+class TestQosAssociate(TestQos):
+
+ def setUp(self):
+ super(TestQosAssociate, self).setUp()
+
+ # Get the command object to test
+ self.cmd = qos_specs.AssociateQos(self.app, None)
+
+ def test_qos_associate(self):
+ self.qos_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(volume_fakes.QOS),
+ loaded=True
+ )
+ self.types_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(volume_fakes.TYPE),
+ loaded=True
+ )
+ arglist = [
+ volume_fakes.qos_id,
+ volume_fakes.type_id
+ ]
+ verifylist = [
+ ('qos_spec', volume_fakes.qos_id),
+ ('volume_type', volume_fakes.type_id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.qos_mock.associate.assert_called_with(
+ volume_fakes.qos_id,
+ volume_fakes.type_id
+ )
+ self.assertIsNone(result)
+
+
+class TestQosCreate(TestQos):
+
+ columns = (
+ 'consumer',
+ 'id',
+ 'name',
+ )
+ datalist = (
+ volume_fakes.qos_consumer,
+ volume_fakes.qos_id,
+ volume_fakes.qos_name
+ )
+
+ def setUp(self):
+ super(TestQosCreate, self).setUp()
+
+ # Get the command object to test
+ self.cmd = qos_specs.CreateQos(self.app, None)
+
+ def test_qos_create_without_properties(self):
+ self.qos_mock.create.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(volume_fakes.QOS_DEFAULT_CONSUMER),
+ loaded=True
+ )
+
+ arglist = [
+ volume_fakes.qos_name,
+ ]
+ verifylist = [
+ ('name', volume_fakes.qos_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.qos_mock.create.assert_called_with(
+ volume_fakes.qos_name,
+ {'consumer': volume_fakes.qos_default_consumer}
+ )
+
+ self.assertEqual(self.columns, columns)
+ datalist = (
+ volume_fakes.qos_default_consumer,
+ volume_fakes.qos_id,
+ volume_fakes.qos_name
+ )
+ self.assertEqual(datalist, data)
+
+ def test_qos_create_with_consumer(self):
+ self.qos_mock.create.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(volume_fakes.QOS),
+ loaded=True
+ )
+
+ arglist = [
+ volume_fakes.qos_name,
+ '--consumer', volume_fakes.qos_consumer
+ ]
+ verifylist = [
+ ('name', volume_fakes.qos_name),
+ ('consumer', volume_fakes.qos_consumer)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.qos_mock.create.assert_called_with(
+ volume_fakes.qos_name,
+ {'consumer': volume_fakes.qos_consumer}
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_qos_create_with_properties(self):
+ self.qos_mock.create.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(volume_fakes.QOS_WITH_SPECS),
+ loaded=True
+ )
+
+ arglist = [
+ volume_fakes.qos_name,
+ '--consumer', volume_fakes.qos_consumer,
+ '--property', 'foo=bar',
+ '--property', 'iops=9001'
+ ]
+ verifylist = [
+ ('name', volume_fakes.qos_name),
+ ('consumer', volume_fakes.qos_consumer),
+ ('property', volume_fakes.qos_specs)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ specs = volume_fakes.qos_specs.copy()
+ specs.update({'consumer': volume_fakes.qos_consumer})
+ self.qos_mock.create.assert_called_with(
+ volume_fakes.qos_name,
+ specs
+ )
+
+ columns = self.columns + (
+ 'specs',
+ )
+ self.assertEqual(columns, columns)
+ datalist = self.datalist + (
+ volume_fakes.qos_specs,
+ )
+ self.assertEqual(datalist, data)
+
+
+class TestQosDelete(TestQos):
+
+ def setUp(self):
+ super(TestQosDelete, self).setUp()
+
+ self.qos_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(volume_fakes.QOS),
+ loaded=True,
+ )
+
+ # Get the command object to test
+ self.cmd = qos_specs.DeleteQos(self.app, None)
+
+ def test_qos_delete_with_id(self):
+ arglist = [
+ volume_fakes.qos_id
+ ]
+ verifylist = [
+ ('qos_specs', [volume_fakes.qos_id])
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.qos_mock.delete.assert_called_with(volume_fakes.qos_id, False)
+ self.assertIsNone(result)
+
+ def test_qos_delete_with_name(self):
+ arglist = [
+ volume_fakes.qos_name
+ ]
+ verifylist = [
+ ('qos_specs', [volume_fakes.qos_name])
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.qos_mock.delete.assert_called_with(volume_fakes.qos_id, False)
+ self.assertIsNone(result)
+
+ def test_qos_delete_with_force(self):
+ arglist = [
+ '--force',
+ volume_fakes.qos_id
+ ]
+ verifylist = [
+ ('force', True),
+ ('qos_specs', [volume_fakes.qos_id])
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.qos_mock.delete.assert_called_with(volume_fakes.qos_id, True)
+ self.assertIsNone(result)
+
+
+class TestQosDisassociate(TestQos):
+
+ def setUp(self):
+ super(TestQosDisassociate, self).setUp()
+
+ # Get the command object to test
+ self.cmd = qos_specs.DisassociateQos(self.app, None)
+
+ def test_qos_disassociate_with_volume_type(self):
+ self.qos_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(volume_fakes.QOS),
+ loaded=True
+ )
+ self.types_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(volume_fakes.TYPE),
+ loaded=True
+ )
+ arglist = [
+ volume_fakes.qos_id,
+ '--volume-type', volume_fakes.type_id
+ ]
+ verifylist = [
+ ('qos_spec', volume_fakes.qos_id),
+ ('volume_type', volume_fakes.type_id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.qos_mock.disassociate.assert_called_with(
+ volume_fakes.qos_id,
+ volume_fakes.type_id
+ )
+ self.assertIsNone(result)
+
+ def test_qos_disassociate_with_all_volume_types(self):
+ self.qos_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(volume_fakes.QOS),
+ loaded=True
+ )
+
+ arglist = [
+ volume_fakes.qos_id,
+ '--all'
+ ]
+ verifylist = [
+ ('qos_spec', volume_fakes.qos_id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.qos_mock.disassociate_all.assert_called_with(volume_fakes.qos_id)
+ self.assertIsNone(result)
+
+
+class TestQosList(TestQos):
+
+ def setUp(self):
+ super(TestQosList, self).setUp()
+
+ self.qos_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(volume_fakes.QOS_WITH_ASSOCIATIONS),
+ loaded=True,
+ )
+ self.qos_mock.list.return_value = [self.qos_mock.get.return_value]
+ self.qos_mock.get_associations.return_value = [fakes.FakeResource(
+ None,
+ copy.deepcopy(volume_fakes.qos_association),
+ loaded=True,
+ )]
+
+ # Get the command object to test
+ self.cmd = qos_specs.ListQos(self.app, None)
+
+ def test_qos_list(self):
+ arglist = []
+ verifylist = []
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.qos_mock.list.assert_called_with()
+
+ collist = (
+ 'ID',
+ 'Name',
+ 'Consumer',
+ 'Associations',
+ 'Specs',
+ )
+ self.assertEqual(collist, columns)
+ datalist = ((
+ volume_fakes.qos_id,
+ volume_fakes.qos_name,
+ volume_fakes.qos_consumer,
+ volume_fakes.type_name,
+ utils.format_dict(volume_fakes.qos_specs),
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+
+class TestQosSet(TestQos):
+
+ def setUp(self):
+ super(TestQosSet, self).setUp()
+
+ # Get the command object to test
+ self.cmd = qos_specs.SetQos(self.app, None)
+
+ def test_qos_set_with_properties_with_id(self):
+ self.qos_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(volume_fakes.QOS_WITH_SPECS),
+ loaded=True
+ )
+ arglist = [
+ volume_fakes.qos_id,
+ '--property', 'foo=bar',
+ '--property', 'iops=9001'
+ ]
+ verifylist = [
+ ('qos_spec', volume_fakes.qos_id),
+ ('property', volume_fakes.qos_specs)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.qos_mock.set_keys.assert_called_with(
+ volume_fakes.qos_id,
+ volume_fakes.qos_specs
+ )
+ self.assertIsNone(result)
+
+
+class TestQosShow(TestQos):
+
+ def setUp(self):
+ super(TestQosShow, self).setUp()
+
+ self.qos_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(volume_fakes.QOS_WITH_ASSOCIATIONS),
+ loaded=True,
+ )
+ self.qos_mock.get_associations.return_value = [fakes.FakeResource(
+ None,
+ copy.deepcopy(volume_fakes.qos_association),
+ loaded=True,
+ )]
+
+ # Get the command object to test
+ self.cmd = qos_specs.ShowQos(self.app, None)
+
+ def test_qos_show(self):
+ arglist = [
+ volume_fakes.qos_id
+ ]
+ verifylist = [
+ ('qos_spec', volume_fakes.qos_id)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.qos_mock.get.assert_called_with(
+ volume_fakes.qos_id
+ )
+
+ collist = (
+ 'associations',
+ 'consumer',
+ 'id',
+ 'name',
+ 'specs'
+ )
+ self.assertEqual(collist, columns)
+ datalist = (
+ volume_fakes.type_name,
+ volume_fakes.qos_consumer,
+ volume_fakes.qos_id,
+ volume_fakes.qos_name,
+ utils.format_dict(volume_fakes.qos_specs),
+ )
+ self.assertEqual(datalist, tuple(data))
+
+
+class TestQosUnset(TestQos):
+
+ def setUp(self):
+ super(TestQosUnset, self).setUp()
+
+ # Get the command object to test
+ self.cmd = qos_specs.UnsetQos(self.app, None)
+
+ def test_qos_unset_with_properties(self):
+ self.qos_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(volume_fakes.QOS),
+ loaded=True
+ )
+ arglist = [
+ volume_fakes.qos_id,
+ '--property', 'iops',
+ '--property', 'foo'
+ ]
+
+ verifylist = [
+ ('qos_spec', volume_fakes.qos_id),
+ ('property', ['iops', 'foo'])
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.qos_mock.unset_keys.assert_called_with(
+ volume_fakes.qos_id,
+ ['iops', 'foo']
+ )
+ self.assertIsNone(result)
diff --git a/openstackclient/tests/unit/volume/v1/test_service.py b/openstackclient/tests/unit/volume/v1/test_service.py
new file mode 100644
index 00000000..82d21bfc
--- /dev/null
+++ b/openstackclient/tests/unit/volume/v1/test_service.py
@@ -0,0 +1,286 @@
+#
+# 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 osc_lib import exceptions
+
+from openstackclient.tests.unit.volume.v1 import fakes as service_fakes
+from openstackclient.volume.v1 import service
+
+
+class TestService(service_fakes.TestVolumev1):
+
+ def setUp(self):
+ super(TestService, self).setUp()
+
+ # Get a shortcut to the ServiceManager Mock
+ self.service_mock = self.app.client_manager.volume.services
+ self.service_mock.reset_mock()
+
+
+class TestServiceList(TestService):
+
+ # The service to be listed
+ services = service_fakes.FakeService.create_one_service()
+
+ def setUp(self):
+ super(TestServiceList, self).setUp()
+
+ self.service_mock.list.return_value = [self.services]
+
+ # Get the command object to test
+ self.cmd = service.ListService(self.app, None)
+
+ def test_service_list(self):
+ arglist = [
+ '--host', self.services.host,
+ '--service', self.services.binary,
+ ]
+ verifylist = [
+ ('host', self.services.host),
+ ('service', self.services.binary),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ expected_columns = [
+ 'Binary',
+ 'Host',
+ 'Zone',
+ 'Status',
+ 'State',
+ 'Updated At',
+ ]
+
+ # confirming if all expected columns are present in the result.
+ self.assertEqual(expected_columns, columns)
+
+ datalist = ((
+ self.services.binary,
+ self.services.host,
+ self.services.zone,
+ self.services.status,
+ self.services.state,
+ self.services.updated_at,
+ ), )
+
+ # confirming if all expected values are present in the result.
+ self.assertEqual(datalist, tuple(data))
+
+ # checking if proper call was made to list services
+ self.service_mock.list.assert_called_with(
+ self.services.host,
+ self.services.binary,
+ )
+
+ # checking if prohibited columns are present in output
+ self.assertNotIn("Disabled Reason", columns)
+ self.assertNotIn(self.services.disabled_reason,
+ tuple(data))
+
+ def test_service_list_with_long_option(self):
+ arglist = [
+ '--host', self.services.host,
+ '--service', self.services.binary,
+ '--long'
+ ]
+ verifylist = [
+ ('host', self.services.host),
+ ('service', self.services.binary),
+ ('long', True)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ expected_columns = [
+ 'Binary',
+ 'Host',
+ 'Zone',
+ 'Status',
+ 'State',
+ 'Updated At',
+ 'Disabled Reason'
+ ]
+
+ # confirming if all expected columns are present in the result.
+ self.assertEqual(expected_columns, columns)
+
+ datalist = ((
+ self.services.binary,
+ self.services.host,
+ self.services.zone,
+ self.services.status,
+ self.services.state,
+ self.services.updated_at,
+ self.services.disabled_reason,
+ ), )
+
+ # confirming if all expected values are present in the result.
+ self.assertEqual(datalist, tuple(data))
+
+ self.service_mock.list.assert_called_with(
+ self.services.host,
+ self.services.binary,
+ )
+
+
+class TestServiceSet(TestService):
+
+ service = service_fakes.FakeService.create_one_service()
+
+ def setUp(self):
+ super(TestServiceSet, self).setUp()
+
+ self.service_mock.enable.return_value = self.service
+ self.service_mock.disable.return_value = self.service
+ self.service_mock.disable_log_reason.return_value = self.service
+
+ self.cmd = service.SetService(self.app, None)
+
+ def test_service_set_nothing(self):
+ arglist = [
+ self.service.host,
+ self.service.binary,
+ ]
+ verifylist = [
+ ('host', self.service.host),
+ ('service', self.service.binary),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ self.service_mock.enable.assert_not_called()
+ self.service_mock.disable.assert_not_called()
+ self.service_mock.disable_log_reason.assert_not_called()
+ self.assertIsNone(result)
+
+ def test_service_set_enable(self):
+ arglist = [
+ '--enable',
+ self.service.host,
+ self.service.binary,
+ ]
+ verifylist = [
+ ('enable', True),
+ ('host', self.service.host),
+ ('service', self.service.binary),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.service_mock.enable.assert_called_with(
+ self.service.host,
+ self.service.binary
+ )
+ self.service_mock.disable.assert_not_called()
+ self.service_mock.disable_log_reason.assert_not_called()
+ self.assertIsNone(result)
+
+ def test_service_set_disable(self):
+ arglist = [
+ '--disable',
+ self.service.host,
+ self.service.binary,
+ ]
+ verifylist = [
+ ('disable', True),
+ ('host', self.service.host),
+ ('service', self.service.binary),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.service_mock.disable.assert_called_with(
+ self.service.host,
+ self.service.binary
+ )
+ self.service_mock.enable.assert_not_called()
+ self.service_mock.disable_log_reason.assert_not_called()
+ self.assertIsNone(result)
+
+ def test_service_set_disable_with_reason(self):
+ reason = 'earthquake'
+ arglist = [
+ '--disable',
+ '--disable-reason', reason,
+ self.service.host,
+ self.service.binary,
+ ]
+ verifylist = [
+ ('disable', True),
+ ('disable_reason', reason),
+ ('host', self.service.host),
+ ('service', self.service.binary),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.service_mock.disable_log_reason.assert_called_with(
+ self.service.host,
+ self.service.binary,
+ reason
+ )
+ self.assertIsNone(result)
+
+ def test_service_set_only_with_disable_reason(self):
+ reason = 'earthquake'
+ arglist = [
+ '--disable-reason', reason,
+ self.service.host,
+ self.service.binary,
+ ]
+ verifylist = [
+ ('disable_reason', reason),
+ ('host', self.service.host),
+ ('service', self.service.binary),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail("CommandError should be raised.")
+ except exceptions.CommandError as e:
+ self.assertEqual("Cannot specify option --disable-reason without "
+ "--disable specified.", str(e))
+
+ def test_service_set_enable_with_disable_reason(self):
+ reason = 'earthquake'
+ arglist = [
+ '--enable',
+ '--disable-reason', reason,
+ self.service.host,
+ self.service.binary,
+ ]
+ verifylist = [
+ ('enable', True),
+ ('disable_reason', reason),
+ ('host', self.service.host),
+ ('service', self.service.binary),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail("CommandError should be raised.")
+ except exceptions.CommandError as e:
+ self.assertEqual("Cannot specify option --disable-reason without "
+ "--disable specified.", str(e))
diff --git a/openstackclient/tests/unit/volume/v1/test_transfer_request.py b/openstackclient/tests/unit/volume/v1/test_transfer_request.py
new file mode 100644
index 00000000..f7980c34
--- /dev/null
+++ b/openstackclient/tests/unit/volume/v1/test_transfer_request.py
@@ -0,0 +1,114 @@
+#
+# 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 openstackclient.tests.unit.volume.v1 import fakes as transfer_fakes
+from openstackclient.volume.v1 import volume_transfer_request
+
+
+class TestTransfer(transfer_fakes.TestVolumev1):
+
+ def setUp(self):
+ super(TestTransfer, self).setUp()
+
+ # Get a shortcut to the TransferManager Mock
+ self.transfer_mock = self.app.client_manager.volume.transfers
+ self.transfer_mock.reset_mock()
+
+
+class TestTransferList(TestTransfer):
+
+ # The Transfers to be listed
+ volume_transfers = transfer_fakes.FakeTransfer.create_one_transfer()
+
+ def setUp(self):
+ super(TestTransferList, self).setUp()
+
+ self.transfer_mock.list.return_value = [self.volume_transfers]
+
+ # Get the command object to test
+ self.cmd = volume_transfer_request.ListTransferRequests(self.app, None)
+
+ def test_transfer_list_without_argument(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ expected_columns = [
+ 'ID',
+ 'Volume',
+ 'Name',
+ ]
+
+ # confirming if all expected columns are present in the result.
+ self.assertEqual(expected_columns, columns)
+
+ datalist = ((
+ self.volume_transfers.id,
+ self.volume_transfers.volume_id,
+ self.volume_transfers.name,
+ ), )
+
+ # confirming if all expected values are present in the result.
+ self.assertEqual(datalist, tuple(data))
+
+ # checking if proper call was made to list volume_transfers
+ self.transfer_mock.list.assert_called_with(
+ detailed=True,
+ search_opts={'all_tenants': 0}
+ )
+
+ def test_transfer_list_with_argument(self):
+ arglist = [
+ "--all-projects"
+ ]
+ verifylist = [
+ ("all_projects", True)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ expected_columns = [
+ 'ID',
+ 'Volume',
+ 'Name',
+ ]
+
+ # confirming if all expected columns are present in the result.
+ self.assertEqual(expected_columns, columns)
+
+ datalist = ((
+ self.volume_transfers.id,
+ self.volume_transfers.volume_id,
+ self.volume_transfers.name,
+ ), )
+
+ # confirming if all expected values are present in the result.
+ self.assertEqual(datalist, tuple(data))
+
+ # checking if proper call was made to list volume_transfers
+ self.transfer_mock.list.assert_called_with(
+ detailed=True,
+ search_opts={'all_tenants': 1}
+ )
diff --git a/openstackclient/tests/unit/volume/v1/test_volume.py b/openstackclient/tests/unit/volume/v1/test_volume.py
new file mode 100644
index 00000000..f90566fd
--- /dev/null
+++ b/openstackclient/tests/unit/volume/v1/test_volume.py
@@ -0,0 +1,716 @@
+# Copyright 2013 Nebula Inc.
+#
+# 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.
+#
+
+import copy
+import mock
+
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit.identity.v2_0 import fakes as identity_fakes
+from openstackclient.tests.unit.volume.v1 import fakes as volume_fakes
+from openstackclient.volume.v1 import volume
+
+
+class TestVolume(volume_fakes.TestVolumev1):
+
+ def setUp(self):
+ super(TestVolume, self).setUp()
+
+ # Get a shortcut to the VolumeManager Mock
+ self.volumes_mock = self.app.client_manager.volume.volumes
+ self.volumes_mock.reset_mock()
+
+ # Get a shortcut to the TenantManager Mock
+ self.projects_mock = self.app.client_manager.identity.tenants
+ self.projects_mock.reset_mock()
+
+ # Get a shortcut to the UserManager Mock
+ self.users_mock = self.app.client_manager.identity.users
+ self.users_mock.reset_mock()
+
+ # Get a shortcut to the ImageManager Mock
+ self.images_mock = self.app.client_manager.image.images
+ self.images_mock.reset_mock()
+
+
+# TODO(dtroyer): The volume create tests are incomplete, only the minimal
+# options and the options that require additional processing
+# are implemented at this time.
+
+class TestVolumeCreate(TestVolume):
+
+ project = identity_fakes.FakeProject.create_one_project()
+ user = identity_fakes.FakeUser.create_one_user()
+
+ columns = (
+ 'attach_status',
+ 'availability_zone',
+ 'display_description',
+ 'display_name',
+ 'id',
+ 'properties',
+ 'size',
+ 'status',
+ 'type',
+ )
+ datalist = (
+ 'detached',
+ volume_fakes.volume_zone,
+ volume_fakes.volume_description,
+ volume_fakes.volume_name,
+ volume_fakes.volume_id,
+ volume_fakes.volume_metadata_str,
+ volume_fakes.volume_size,
+ volume_fakes.volume_status,
+ volume_fakes.volume_type,
+ )
+
+ def setUp(self):
+ super(TestVolumeCreate, self).setUp()
+
+ self.volumes_mock.create.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(volume_fakes.VOLUME),
+ loaded=True,
+ )
+
+ # Get the command object to test
+ self.cmd = volume.CreateVolume(self.app, None)
+
+ def test_volume_create_min_options(self):
+ arglist = [
+ '--size', str(volume_fakes.volume_size),
+ volume_fakes.volume_name,
+ ]
+ verifylist = [
+ ('size', volume_fakes.volume_size),
+ ('name', volume_fakes.volume_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # VolumeManager.create(size, snapshot_id=, source_volid=,
+ # display_name=, display_description=,
+ # volume_type=, user_id=,
+ # project_id=, availability_zone=,
+ # metadata=, imageRef=)
+ self.volumes_mock.create.assert_called_with(
+ volume_fakes.volume_size,
+ None,
+ None,
+ volume_fakes.volume_name,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_volume_create_options(self):
+ arglist = [
+ '--size', str(volume_fakes.volume_size),
+ '--description', volume_fakes.volume_description,
+ '--type', volume_fakes.volume_type,
+ '--availability-zone', volume_fakes.volume_zone,
+ volume_fakes.volume_name,
+ ]
+ verifylist = [
+ ('size', volume_fakes.volume_size),
+ ('description', volume_fakes.volume_description),
+ ('type', volume_fakes.volume_type),
+ ('availability_zone', volume_fakes.volume_zone),
+ ('name', volume_fakes.volume_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # VolumeManager.create(size, snapshot_id=, source_volid=,
+ # display_name=, display_description=,
+ # volume_type=, user_id=,
+ # project_id=, availability_zone=,
+ # metadata=, imageRef=)
+ self.volumes_mock.create.assert_called_with(
+ volume_fakes.volume_size,
+ None,
+ None,
+ volume_fakes.volume_name,
+ volume_fakes.volume_description,
+ volume_fakes.volume_type,
+ None,
+ None,
+ volume_fakes.volume_zone,
+ None,
+ None,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_volume_create_user_project_id(self):
+ # Return a project
+ self.projects_mock.get.return_value = self.project
+ # Return a user
+ self.users_mock.get.return_value = self.user
+
+ arglist = [
+ '--size', str(volume_fakes.volume_size),
+ '--project', self.project.id,
+ '--user', self.user.id,
+ volume_fakes.volume_name,
+ ]
+ verifylist = [
+ ('size', volume_fakes.volume_size),
+ ('project', self.project.id),
+ ('user', self.user.id),
+ ('name', volume_fakes.volume_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # VolumeManager.create(size, snapshot_id=, source_volid=,
+ # display_name=, display_description=,
+ # volume_type=, user_id=,
+ # project_id=, availability_zone=,
+ # metadata=, imageRef=)
+ self.volumes_mock.create.assert_called_with(
+ volume_fakes.volume_size,
+ None,
+ None,
+ volume_fakes.volume_name,
+ None,
+ None,
+ self.user.id,
+ self.project.id,
+ None,
+ None,
+ None,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_volume_create_user_project_name(self):
+ # Return a project
+ self.projects_mock.get.return_value = self.project
+ # Return a user
+ self.users_mock.get.return_value = self.user
+
+ arglist = [
+ '--size', str(volume_fakes.volume_size),
+ '--project', self.project.name,
+ '--user', self.user.name,
+ volume_fakes.volume_name,
+ ]
+ verifylist = [
+ ('size', volume_fakes.volume_size),
+ ('project', self.project.name),
+ ('user', self.user.name),
+ ('name', volume_fakes.volume_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # VolumeManager.create(size, snapshot_id=, source_volid=,
+ # display_name=, display_description=,
+ # volume_type=, user_id=,
+ # project_id=, availability_zone=,
+ # metadata=, imageRef=)
+ self.volumes_mock.create.assert_called_with(
+ volume_fakes.volume_size,
+ None,
+ None,
+ volume_fakes.volume_name,
+ None,
+ None,
+ self.user.id,
+ self.project.id,
+ None,
+ None,
+ None,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_volume_create_properties(self):
+ arglist = [
+ '--property', 'Alpha=a',
+ '--property', 'Beta=b',
+ '--size', str(volume_fakes.volume_size),
+ volume_fakes.volume_name,
+ ]
+ verifylist = [
+ ('property', {'Alpha': 'a', 'Beta': 'b'}),
+ ('size', volume_fakes.volume_size),
+ ('name', volume_fakes.volume_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # VolumeManager.create(size, snapshot_id=, source_volid=,
+ # display_name=, display_description=,
+ # volume_type=, user_id=,
+ # project_id=, availability_zone=,
+ # metadata=, imageRef=)
+ self.volumes_mock.create.assert_called_with(
+ volume_fakes.volume_size,
+ None,
+ None,
+ volume_fakes.volume_name,
+ None,
+ None,
+ None,
+ None,
+ None,
+ {'Alpha': 'a', 'Beta': 'b'},
+ None,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_volume_create_image_id(self):
+ self.images_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(volume_fakes.IMAGE),
+ loaded=True,
+ )
+
+ arglist = [
+ '--image', volume_fakes.image_id,
+ '--size', str(volume_fakes.volume_size),
+ volume_fakes.volume_name,
+ ]
+ verifylist = [
+ ('image', volume_fakes.image_id),
+ ('size', volume_fakes.volume_size),
+ ('name', volume_fakes.volume_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # VolumeManager.create(size, snapshot_id=, source_volid=,
+ # display_name=, display_description=,
+ # volume_type=, user_id=,
+ # project_id=, availability_zone=,
+ # metadata=, imageRef=)
+ self.volumes_mock.create.assert_called_with(
+ volume_fakes.volume_size,
+ None,
+ None,
+ volume_fakes.volume_name,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ volume_fakes.image_id,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_volume_create_image_name(self):
+ self.images_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(volume_fakes.IMAGE),
+ loaded=True,
+ )
+
+ arglist = [
+ '--image', volume_fakes.image_name,
+ '--size', str(volume_fakes.volume_size),
+ volume_fakes.volume_name,
+ ]
+ verifylist = [
+ ('image', volume_fakes.image_name),
+ ('size', volume_fakes.volume_size),
+ ('name', volume_fakes.volume_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # VolumeManager.create(size, snapshot_id=, source_volid=,
+ # display_name=, display_description=,
+ # volume_type=, user_id=,
+ # project_id=, availability_zone=,
+ # metadata=, imageRef=)
+ self.volumes_mock.create.assert_called_with(
+ volume_fakes.volume_size,
+ None,
+ None,
+ volume_fakes.volume_name,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ volume_fakes.image_id,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+
+class TestVolumeList(TestVolume):
+
+ columns = (
+ 'ID',
+ 'Display Name',
+ 'Status',
+ 'Size',
+ 'Attached to',
+ )
+ datalist = (
+ (
+ volume_fakes.volume_id,
+ volume_fakes.volume_name,
+ volume_fakes.volume_status,
+ volume_fakes.volume_size,
+ '',
+ ),
+ )
+
+ def setUp(self):
+ super(TestVolumeList, self).setUp()
+
+ self.volumes_mock.list.return_value = [
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(volume_fakes.VOLUME),
+ loaded=True,
+ ),
+ ]
+
+ # Get the command object to test
+ self.cmd = volume.ListVolume(self.app, None)
+
+ def test_volume_list_no_options(self):
+ arglist = []
+ verifylist = [
+ ('long', False),
+ ('all_projects', False),
+ ('name', None),
+ ('status', None),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_volume_list_name(self):
+ arglist = [
+ '--name', volume_fakes.volume_name,
+ ]
+ verifylist = [
+ ('long', False),
+ ('all_projects', False),
+ ('name', volume_fakes.volume_name),
+ ('status', None),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.assertEqual(self.columns, tuple(columns))
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_volume_list_status(self):
+ arglist = [
+ '--status', volume_fakes.volume_status,
+ ]
+ verifylist = [
+ ('long', False),
+ ('all_projects', False),
+ ('name', None),
+ ('status', volume_fakes.volume_status),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.assertEqual(self.columns, tuple(columns))
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_volume_list_all_projects(self):
+ arglist = [
+ '--all-projects',
+ ]
+ verifylist = [
+ ('long', False),
+ ('all_projects', True),
+ ('name', None),
+ ('status', None),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.assertEqual(self.columns, tuple(columns))
+ self.assertEqual(self.datalist, tuple(data))
+
+ def test_volume_list_long(self):
+ arglist = [
+ '--long',
+ ]
+ verifylist = [
+ ('long', True),
+ ('all_projects', False),
+ ('name', None),
+ ('status', None),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ collist = (
+ 'ID',
+ 'Display Name',
+ 'Status',
+ 'Size',
+ 'Type',
+ 'Bootable',
+ 'Attached to',
+ 'Properties',
+ )
+ self.assertEqual(collist, columns)
+
+ datalist = ((
+ volume_fakes.volume_id,
+ volume_fakes.volume_name,
+ volume_fakes.volume_status,
+ volume_fakes.volume_size,
+ volume_fakes.volume_type,
+ '',
+ '',
+ "Alpha='a', Beta='b', Gamma='g'",
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+
+class TestVolumeSet(TestVolume):
+
+ def setUp(self):
+ super(TestVolumeSet, self).setUp()
+
+ self.volumes_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(volume_fakes.VOLUME),
+ loaded=True,
+ )
+
+ self.volumes_mock.update.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(volume_fakes.VOLUME),
+ loaded=True,
+ )
+ # Get the command object to test
+ self.cmd = volume.SetVolume(self.app, None)
+
+ def test_volume_set_no_options(self):
+ arglist = [
+ volume_fakes.volume_name,
+ ]
+ verifylist = [
+ ('name', None),
+ ('description', None),
+ ('size', None),
+ ('property', None),
+ ('volume', volume_fakes.volume_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.assertIsNone(result)
+
+ def test_volume_set_name(self):
+ arglist = [
+ '--name', 'qwerty',
+ volume_fakes.volume_name,
+ ]
+ verifylist = [
+ ('name', 'qwerty'),
+ ('description', None),
+ ('size', None),
+ ('property', None),
+ ('volume', volume_fakes.volume_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'display_name': 'qwerty',
+ }
+ self.volumes_mock.update.assert_called_with(
+ volume_fakes.volume_id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_volume_set_description(self):
+ arglist = [
+ '--description', 'new desc',
+ volume_fakes.volume_name,
+ ]
+ verifylist = [
+ ('name', None),
+ ('description', 'new desc'),
+ ('size', None),
+ ('property', None),
+ ('volume', volume_fakes.volume_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'display_description': 'new desc',
+ }
+ self.volumes_mock.update.assert_called_with(
+ volume_fakes.volume_id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_volume_set_size(self):
+ arglist = [
+ '--size', '130',
+ volume_fakes.volume_name,
+ ]
+ verifylist = [
+ ('name', None),
+ ('description', None),
+ ('size', 130),
+ ('property', None),
+ ('volume', volume_fakes.volume_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ size = 130
+ self.volumes_mock.extend.assert_called_with(
+ volume_fakes.volume_id,
+ size
+ )
+ self.assertIsNone(result)
+
+ @mock.patch.object(volume.LOG, 'error')
+ def test_volume_set_size_smaller(self, mock_log_error):
+ arglist = [
+ '--size', '100',
+ volume_fakes.volume_name,
+ ]
+ verifylist = [
+ ('name', None),
+ ('description', None),
+ ('size', 100),
+ ('property', None),
+ ('volume', volume_fakes.volume_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ mock_log_error.assert_called_with("New size must be greater "
+ "than %s GB",
+ volume_fakes.volume_size)
+ self.assertIsNone(result)
+
+ @mock.patch.object(volume.LOG, 'error')
+ def test_volume_set_size_not_available(self, mock_log_error):
+ self.volumes_mock.get.return_value.status = 'error'
+ arglist = [
+ '--size', '130',
+ volume_fakes.volume_name,
+ ]
+ verifylist = [
+ ('name', None),
+ ('description', None),
+ ('size', 130),
+ ('property', None),
+ ('volume', volume_fakes.volume_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ mock_log_error.assert_called_with("Volume is in %s state, it must be "
+ "available before size can be "
+ "extended", 'error')
+ self.assertIsNone(result)
+
+ def test_volume_set_property(self):
+ arglist = [
+ '--property', 'myprop=myvalue',
+ volume_fakes.volume_name,
+ ]
+ verifylist = [
+ ('name', None),
+ ('description', None),
+ ('size', None),
+ ('property', {'myprop': 'myvalue'}),
+ ('volume', volume_fakes.volume_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ metadata = {
+ 'myprop': 'myvalue'
+ }
+ self.volumes_mock.set_metadata.assert_called_with(
+ volume_fakes.volume_id,
+ metadata
+ )
+ self.assertIsNone(result)
diff --git a/openstackclient/tests/unit/volume/v2/__init__.py b/openstackclient/tests/unit/volume/v2/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/unit/volume/v2/__init__.py
diff --git a/openstackclient/tests/unit/volume/v2/fakes.py b/openstackclient/tests/unit/volume/v2/fakes.py
new file mode 100644
index 00000000..a958c468
--- /dev/null
+++ b/openstackclient/tests/unit/volume/v2/fakes.py
@@ -0,0 +1,696 @@
+#
+# 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.
+#
+
+import copy
+import mock
+import random
+import uuid
+
+from osc_lib import utils as common_utils
+
+from openstackclient.tests.unit import fakes
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+from openstackclient.tests.unit.image.v2 import fakes as image_fakes
+from openstackclient.tests.unit import utils
+
+
+class FakeTransfer(object):
+ """Fake one or more Transfer."""
+
+ @staticmethod
+ def create_one_transfer(attrs=None):
+ """Create a fake transfer.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes of Transfer Request
+ :return:
+ A FakeResource object with volume_id, name, id.
+ """
+ # Set default attribute
+ transfer_info = {
+ 'volume_id': 'ce26708d-a7f8-4b4b-9861-4a80256615a7',
+ 'name': 'fake_transfer_name',
+ 'id': '731a7f53-aa92-4fbd-9de3-6f7d729c926b'
+ }
+
+ # Overwrite default attributes if there are some attributes set
+ attrs = attrs or {}
+
+ transfer_info.update(attrs)
+
+ transfer = fakes.FakeResource(
+ None,
+ transfer_info,
+ loaded=True)
+
+ return transfer
+
+
+class FakeTypeAccess(object):
+ """Fake one or more volume type access."""
+
+ @staticmethod
+ def create_one_type_access(attrs=None):
+ """Create a fake volume type access for project.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with Volume_type_ID and Project_ID.
+ """
+ if attrs is None:
+ attrs = {}
+
+ # Set default attributes.
+ type_access_attrs = {
+ 'volume_type_id': 'volume-type-id-' + uuid.uuid4().hex,
+ 'project_id': 'project-id-' + uuid.uuid4().hex,
+ }
+
+ # Overwrite default attributes.
+ type_access_attrs.update(attrs)
+
+ type_access = fakes.FakeResource(
+ None,
+ type_access_attrs,
+ loaded=True)
+
+ return type_access
+
+
+class FakeService(object):
+ """Fake one or more Services."""
+
+ @staticmethod
+ def create_one_service(attrs=None):
+ """Create a fake service.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes of service
+ :return:
+ A FakeResource object with host, status, etc.
+ """
+ # Set default attribute
+ service_info = {
+ 'host': 'host_test',
+ 'binary': 'cinder_test',
+ 'status': 'enabled',
+ 'disabled_reason': 'LongHoliday-GoldenWeek',
+ 'zone': 'fake_zone',
+ 'updated_at': 'fake_date',
+ 'state': 'fake_state',
+ }
+
+ # Overwrite default attributes if there are some attributes set
+ attrs = attrs or {}
+
+ service_info.update(attrs)
+
+ service = fakes.FakeResource(
+ None,
+ service_info,
+ loaded=True)
+
+ return service
+
+ @staticmethod
+ def create_services(attrs=None, count=2):
+ """Create multiple fake services.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes of service
+ :param Integer count:
+ The number of services to be faked
+ :return:
+ A list of FakeResource objects
+ """
+ services = []
+ for n in range(0, count):
+ services.append(FakeService.create_one_service(attrs))
+
+ return services
+
+
+class FakeVolumeClient(object):
+
+ def __init__(self, **kwargs):
+ self.volumes = mock.Mock()
+ self.volumes.resource_class = fakes.FakeResource(None, {})
+ self.extensions = mock.Mock()
+ self.extensions.resource_class = fakes.FakeResource(None, {})
+ self.volume_snapshots = mock.Mock()
+ self.volume_snapshots.resource_class = fakes.FakeResource(None, {})
+ self.backups = mock.Mock()
+ self.backups.resource_class = fakes.FakeResource(None, {})
+ self.volume_types = mock.Mock()
+ self.volume_types.resource_class = fakes.FakeResource(None, {})
+ self.volume_type_access = mock.Mock()
+ self.volume_type_access.resource_class = fakes.FakeResource(None, {})
+ self.restores = mock.Mock()
+ self.restores.resource_class = fakes.FakeResource(None, {})
+ self.qos_specs = mock.Mock()
+ self.qos_specs.resource_class = fakes.FakeResource(None, {})
+ self.availability_zones = mock.Mock()
+ self.availability_zones.resource_class = fakes.FakeResource(None, {})
+ self.transfers = mock.Mock()
+ self.transfers.resource_class = fakes.FakeResource(None, {})
+ self.services = mock.Mock()
+ self.services.resource_class = fakes.FakeResource(None, {})
+ self.auth_token = kwargs['token']
+ self.management_url = kwargs['endpoint']
+
+
+class TestVolume(utils.TestCommand):
+
+ def setUp(self):
+ super(TestVolume, self).setUp()
+
+ self.app.client_manager.volume = FakeVolumeClient(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN
+ )
+ self.app.client_manager.identity = identity_fakes.FakeIdentityv3Client(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN
+ )
+ self.app.client_manager.image = image_fakes.FakeImagev2Client(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN
+ )
+
+
+class FakeVolume(object):
+ """Fake one or more volumes.
+
+ TODO(xiexs): Currently, only volume API v2 is supported by this class.
+ """
+
+ @staticmethod
+ def create_one_volume(attrs=None):
+ """Create a fake volume.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes of volume
+ :return:
+ A FakeResource object with id, name, status, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attribute
+ volume_info = {
+ 'id': 'volume-id' + uuid.uuid4().hex,
+ 'name': 'volume-name' + uuid.uuid4().hex,
+ 'description': 'description' + uuid.uuid4().hex,
+ 'status': random.choice(['available', 'in_use']),
+ 'size': random.randint(1, 20),
+ 'volume_type':
+ random.choice(['fake_lvmdriver-1', 'fake_lvmdriver-2']),
+ 'bootable':
+ random.randint(0, 1),
+ 'metadata': {
+ 'key' + uuid.uuid4().hex: 'val' + uuid.uuid4().hex,
+ 'key' + uuid.uuid4().hex: 'val' + uuid.uuid4().hex,
+ 'key' + uuid.uuid4().hex: 'val' + uuid.uuid4().hex},
+ 'snapshot_id': random.randint(1, 5),
+ 'availability_zone': 'zone' + uuid.uuid4().hex,
+ 'attachments': [{
+ 'device': '/dev/' + uuid.uuid4().hex,
+ 'server_id': uuid.uuid4().hex,
+ }, ],
+ }
+
+ # Overwrite default attributes if there are some attributes set
+ volume_info.update(attrs)
+
+ volume = fakes.FakeResource(
+ None,
+ volume_info,
+ loaded=True)
+ return volume
+
+ @staticmethod
+ def create_volumes(attrs=None, count=2):
+ """Create multiple fake volumes.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes of volume
+ :param Integer count:
+ The number of volumes to be faked
+ :return:
+ A list of FakeResource objects
+ """
+ volumes = []
+ for n in range(0, count):
+ volumes.append(FakeVolume.create_one_volume(attrs))
+
+ return volumes
+
+ @staticmethod
+ def get_volumes(volumes=None, count=2):
+ """Get an iterable MagicMock object with a list of faked volumes.
+
+ If volumes list is provided, then initialize the Mock object with the
+ list. Otherwise create one.
+
+ :param List volumes:
+ A list of FakeResource objects faking volumes
+ :param Integer count:
+ The number of volumes to be faked
+ :return
+ An iterable Mock object with side_effect set to a list of faked
+ volumes
+ """
+ if volumes is None:
+ volumes = FakeVolume.create_volumes(count)
+
+ return mock.MagicMock(side_effect=volumes)
+
+ @staticmethod
+ def get_volume_columns(volume=None):
+ """Get the volume columns from a faked volume object.
+
+ :param volume:
+ A FakeResource objects faking volume
+ :return
+ A tuple which may include the following keys:
+ ('id', 'name', 'description', 'status', 'size', 'volume_type',
+ 'metadata', 'snapshot', 'availability_zone', 'attachments')
+ """
+ if volume is not None:
+ return tuple(k for k in sorted(volume.keys()))
+ return tuple([])
+
+ @staticmethod
+ def get_volume_data(volume=None):
+ """Get the volume data from a faked volume object.
+
+ :param volume:
+ A FakeResource objects faking volume
+ :return
+ A tuple which may include the following values:
+ ('ce26708d', 'fake_volume', 'fake description', 'available',
+ 20, 'fake_lvmdriver-1', "Alpha='a', Beta='b', Gamma='g'",
+ 1, 'nova', [{'device': '/dev/ice', 'server_id': '1233'}])
+ """
+ data_list = []
+ if volume is not None:
+ for x in sorted(volume.keys()):
+ if x == 'tags':
+ # The 'tags' should be format_list
+ data_list.append(
+ common_utils.format_list(volume.info.get(x)))
+ else:
+ data_list.append(volume.info.get(x))
+ return tuple(data_list)
+
+
+class FakeAvailabilityZone(object):
+ """Fake one or more volume availability zones (AZs)."""
+
+ @staticmethod
+ def create_one_availability_zone(attrs=None):
+ """Create a fake AZ.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object with zoneName, zoneState, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ availability_zone = {
+ 'zoneName': uuid.uuid4().hex,
+ 'zoneState': {'available': True},
+ }
+
+ # Overwrite default attributes.
+ availability_zone.update(attrs)
+
+ availability_zone = fakes.FakeResource(
+ info=copy.deepcopy(availability_zone),
+ loaded=True)
+ return availability_zone
+
+ @staticmethod
+ def create_availability_zones(attrs=None, count=2):
+ """Create multiple fake AZs.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of AZs to fake
+ :return:
+ A list of FakeResource objects faking the AZs
+ """
+ availability_zones = []
+ for i in range(0, count):
+ availability_zone = \
+ FakeAvailabilityZone.create_one_availability_zone(attrs)
+ availability_zones.append(availability_zone)
+
+ return availability_zones
+
+
+class FakeBackup(object):
+ """Fake one or more backup."""
+
+ @staticmethod
+ def create_one_backup(attrs=None):
+ """Create a fake backup.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object with id, name, volume_id, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ backup_info = {
+ "id": 'backup-id-' + uuid.uuid4().hex,
+ "name": 'backup-name-' + uuid.uuid4().hex,
+ "volume_id": 'volume-id-' + uuid.uuid4().hex,
+ "snapshot_id": 'snapshot-id' + uuid.uuid4().hex,
+ "description": 'description-' + uuid.uuid4().hex,
+ "object_count": None,
+ "container": 'container-' + uuid.uuid4().hex,
+ "size": random.randint(1, 20),
+ "status": "error",
+ "availability_zone": 'zone' + uuid.uuid4().hex,
+ }
+
+ # Overwrite default attributes.
+ backup_info.update(attrs)
+
+ backup = fakes.FakeResource(
+ info=copy.deepcopy(backup_info),
+ loaded=True)
+ return backup
+
+ @staticmethod
+ def create_backups(attrs=None, count=2):
+ """Create multiple fake backups.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of backups to fake
+ :return:
+ A list of FakeResource objects faking the backups
+ """
+ backups = []
+ for i in range(0, count):
+ backup = FakeBackup.create_one_backup(attrs)
+ backups.append(backup)
+
+ return backups
+
+ @staticmethod
+ def get_backups(backups=None, count=2):
+ """Get an iterable MagicMock object with a list of faked backups.
+
+ If backups list is provided, then initialize the Mock object with the
+ list. Otherwise create one.
+
+ :param List volumes:
+ A list of FakeResource objects faking backups
+ :param Integer count:
+ The number of backups to be faked
+ :return
+ An iterable Mock object with side_effect set to a list of faked
+ backups
+ """
+ if backups is None:
+ backups = FakeBackup.create_backups(count)
+
+ return mock.MagicMock(side_effect=backups)
+
+
+class FakeExtension(object):
+ """Fake one or more extension."""
+
+ @staticmethod
+ def create_one_extension(attrs=None):
+ """Create a fake extension.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object with name, namespace, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ extension_info = {
+ 'name': 'name-' + uuid.uuid4().hex,
+ 'namespace': ('http://docs.openstack.org/'
+ 'block-service/ext/scheduler-hints/api/v2'),
+ 'description': 'description-' + uuid.uuid4().hex,
+ 'updated': '2013-04-18T00:00:00+00:00',
+ 'alias': 'OS-SCH-HNT',
+ 'links': ('[{"href":'
+ '"https://github.com/openstack/block-api", "type":'
+ ' "text/html", "rel": "describedby"}]'),
+ }
+
+ # Overwrite default attributes.
+ extension_info.update(attrs)
+
+ extension = fakes.FakeResource(
+ info=copy.deepcopy(extension_info),
+ loaded=True)
+ return extension
+
+
+class FakeQos(object):
+ """Fake one or more Qos specification."""
+
+ @staticmethod
+ def create_one_qos(attrs=None):
+ """Create a fake Qos specification.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object with id, name, consumer, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ qos_info = {
+ "id": 'qos-id-' + uuid.uuid4().hex,
+ "name": 'qos-name-' + uuid.uuid4().hex,
+ "consumer": 'front-end',
+ "specs": {"foo": "bar", "iops": "9001"},
+ }
+
+ # Overwrite default attributes.
+ qos_info.update(attrs)
+
+ qos = fakes.FakeResource(
+ info=copy.deepcopy(qos_info),
+ loaded=True)
+ return qos
+
+ @staticmethod
+ def create_one_qos_association(attrs=None):
+ """Create a fake Qos specification association.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object with id, name, association_type, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ qos_association_info = {
+ "id": 'type-id-' + uuid.uuid4().hex,
+ "name": 'type-name-' + uuid.uuid4().hex,
+ "association_type": 'volume_type',
+ }
+
+ # Overwrite default attributes.
+ qos_association_info.update(attrs)
+
+ qos_association = fakes.FakeResource(
+ info=copy.deepcopy(qos_association_info),
+ loaded=True)
+ return qos_association
+
+ @staticmethod
+ def create_qoses(attrs=None, count=2):
+ """Create multiple fake Qos specifications.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of Qos specifications to fake
+ :return:
+ A list of FakeResource objects faking the Qos specifications
+ """
+ qoses = []
+ for i in range(0, count):
+ qos = FakeQos.create_one_qos(attrs)
+ qoses.append(qos)
+
+ return qoses
+
+ @staticmethod
+ def get_qoses(qoses=None, count=2):
+ """Get an iterable MagicMock object with a list of faked qoses.
+
+ If qoses list is provided, then initialize the Mock object with the
+ list. Otherwise create one.
+
+ :param List volumes:
+ A list of FakeResource objects faking qoses
+ :param Integer count:
+ The number of qoses to be faked
+ :return
+ An iterable Mock object with side_effect set to a list of faked
+ qoses
+ """
+ if qoses is None:
+ qoses = FakeQos.create_qoses(count)
+
+ return mock.MagicMock(side_effect=qoses)
+
+
+class FakeSnapshot(object):
+ """Fake one or more snapshot."""
+
+ @staticmethod
+ def create_one_snapshot(attrs=None):
+ """Create a fake snapshot.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object with id, name, description, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ snapshot_info = {
+ "id": 'snapshot-id-' + uuid.uuid4().hex,
+ "name": 'snapshot-name-' + uuid.uuid4().hex,
+ "description": 'snapshot-description-' + uuid.uuid4().hex,
+ "size": 10,
+ "status": "available",
+ "metadata": {"foo": "bar"},
+ "created_at": "2015-06-03T18:49:19.000000",
+ "volume_id": 'vloume-id-' + uuid.uuid4().hex,
+ }
+
+ # Overwrite default attributes.
+ snapshot_info.update(attrs)
+
+ snapshot = fakes.FakeResource(
+ info=copy.deepcopy(snapshot_info),
+ loaded=True)
+ return snapshot
+
+ @staticmethod
+ def create_snapshots(attrs=None, count=2):
+ """Create multiple fake snapshots.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of snapshots to fake
+ :return:
+ A list of FakeResource objects faking the snapshots
+ """
+ snapshots = []
+ for i in range(0, count):
+ snapshot = FakeSnapshot.create_one_snapshot(attrs)
+ snapshots.append(snapshot)
+
+ return snapshots
+
+ @staticmethod
+ def get_snapshots(snapshots=None, count=2):
+ """Get an iterable MagicMock object with a list of faked snapshots.
+
+ If snapshots list is provided, then initialize the Mock object with the
+ list. Otherwise create one.
+
+ :param List volumes:
+ A list of FakeResource objects faking snapshots
+ :param Integer count:
+ The number of snapshots to be faked
+ :return
+ An iterable Mock object with side_effect set to a list of faked
+ snapshots
+ """
+ if snapshots is None:
+ snapshots = FakeSnapshot.create_snapshots(count)
+
+ return mock.MagicMock(side_effect=snapshots)
+
+
+class FakeType(object):
+ """Fake one or more type."""
+
+ @staticmethod
+ def create_one_type(attrs=None, methods=None):
+ """Create a fake type.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param Dictionary methods:
+ A dictionary with all methods
+ :return:
+ A FakeResource object with id, name, description, etc.
+ """
+ attrs = attrs or {}
+ methods = methods or {}
+
+ # Set default attributes.
+ type_info = {
+ "id": 'type-id-' + uuid.uuid4().hex,
+ "name": 'type-name-' + uuid.uuid4().hex,
+ "description": 'type-description-' + uuid.uuid4().hex,
+ "extra_specs": {"foo": "bar"},
+ "is_public": True,
+ }
+
+ # Overwrite default attributes.
+ type_info.update(attrs)
+
+ volume_type = fakes.FakeResource(
+ info=copy.deepcopy(type_info),
+ methods=methods,
+ loaded=True)
+ return volume_type
+
+ @staticmethod
+ def create_types(attrs=None, count=2):
+ """Create multiple fake types.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of types to fake
+ :return:
+ A list of FakeResource objects faking the types
+ """
+ volume_types = []
+ for i in range(0, count):
+ volume_type = FakeType.create_one_type(attrs)
+ volume_types.append(volume_type)
+
+ return volume_types
diff --git a/openstackclient/tests/unit/volume/v2/test_backup.py b/openstackclient/tests/unit/volume/v2/test_backup.py
new file mode 100644
index 00000000..45633870
--- /dev/null
+++ b/openstackclient/tests/unit/volume/v2/test_backup.py
@@ -0,0 +1,388 @@
+#
+# 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.
+#
+
+import mock
+from mock import call
+
+from osc_lib import exceptions
+from osc_lib import utils
+
+from openstackclient.tests.unit.volume.v2 import fakes as volume_fakes
+from openstackclient.volume.v2 import backup
+
+
+class TestBackup(volume_fakes.TestVolume):
+
+ def setUp(self):
+ super(TestBackup, self).setUp()
+
+ self.backups_mock = self.app.client_manager.volume.backups
+ self.backups_mock.reset_mock()
+ self.volumes_mock = self.app.client_manager.volume.volumes
+ self.volumes_mock.reset_mock()
+ self.snapshots_mock = self.app.client_manager.volume.volume_snapshots
+ self.snapshots_mock.reset_mock()
+ self.restores_mock = self.app.client_manager.volume.restores
+ self.restores_mock.reset_mock()
+
+
+class TestBackupCreate(TestBackup):
+
+ volume = volume_fakes.FakeVolume.create_one_volume()
+ snapshot = volume_fakes.FakeSnapshot.create_one_snapshot()
+ new_backup = volume_fakes.FakeBackup.create_one_backup(
+ attrs={'volume_id': volume.id, 'snapshot_id': snapshot.id})
+
+ columns = (
+ 'availability_zone',
+ 'container',
+ 'description',
+ 'id',
+ 'name',
+ 'object_count',
+ 'size',
+ 'snapshot_id',
+ 'status',
+ 'volume_id',
+ )
+ data = (
+ new_backup.availability_zone,
+ new_backup.container,
+ new_backup.description,
+ new_backup.id,
+ new_backup.name,
+ new_backup.object_count,
+ new_backup.size,
+ new_backup.snapshot_id,
+ new_backup.status,
+ new_backup.volume_id,
+ )
+
+ def setUp(self):
+ super(TestBackupCreate, self).setUp()
+
+ self.volumes_mock.get.return_value = self.volume
+ self.snapshots_mock.get.return_value = self.snapshot
+ self.backups_mock.create.return_value = self.new_backup
+
+ # Get the command object to test
+ self.cmd = backup.CreateVolumeBackup(self.app, None)
+
+ def test_backup_create(self):
+ arglist = [
+ "--name", self.new_backup.name,
+ "--description", self.new_backup.description,
+ "--container", self.new_backup.container,
+ "--force",
+ "--incremental",
+ "--snapshot", self.new_backup.snapshot_id,
+ self.new_backup.volume_id,
+ ]
+ verifylist = [
+ ("name", self.new_backup.name),
+ ("description", self.new_backup.description),
+ ("container", self.new_backup.container),
+ ("force", True),
+ ("incremental", True),
+ ("snapshot", self.new_backup.snapshot_id),
+ ("volume", self.new_backup.volume_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.backups_mock.create.assert_called_with(
+ self.new_backup.volume_id,
+ container=self.new_backup.container,
+ name=self.new_backup.name,
+ description=self.new_backup.description,
+ force=True,
+ incremental=True,
+ snapshot_id=self.new_backup.snapshot_id,
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_backup_create_without_name(self):
+ arglist = [
+ "--description", self.new_backup.description,
+ "--container", self.new_backup.container,
+ self.new_backup.volume_id,
+ ]
+ verifylist = [
+ ("description", self.new_backup.description),
+ ("container", self.new_backup.container),
+ ("volume", self.new_backup.volume_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.backups_mock.create.assert_called_with(
+ self.new_backup.volume_id,
+ container=self.new_backup.container,
+ name=None,
+ description=self.new_backup.description,
+ force=False,
+ incremental=False,
+ snapshot_id=None,
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestBackupDelete(TestBackup):
+
+ backups = volume_fakes.FakeBackup.create_backups(count=2)
+
+ def setUp(self):
+ super(TestBackupDelete, self).setUp()
+
+ self.backups_mock.get = (
+ volume_fakes.FakeBackup.get_backups(self.backups))
+ self.backups_mock.delete.return_value = None
+
+ # Get the command object to mock
+ self.cmd = backup.DeleteVolumeBackup(self.app, None)
+
+ def test_backup_delete(self):
+ arglist = [
+ self.backups[0].id
+ ]
+ verifylist = [
+ ("backups", [self.backups[0].id])
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.backups_mock.delete.assert_called_with(
+ self.backups[0].id, False)
+ self.assertIsNone(result)
+
+ def test_backup_delete_with_force(self):
+ arglist = [
+ '--force',
+ self.backups[0].id,
+ ]
+ verifylist = [
+ ('force', True),
+ ("backups", [self.backups[0].id])
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.backups_mock.delete.assert_called_with(self.backups[0].id, True)
+ self.assertIsNone(result)
+
+ def test_delete_multiple_backups(self):
+ arglist = []
+ for b in self.backups:
+ arglist.append(b.id)
+ verifylist = [
+ ('backups', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for b in self.backups:
+ calls.append(call(b.id, False))
+ self.backups_mock.delete.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_delete_multiple_backups_with_exception(self):
+ arglist = [
+ self.backups[0].id,
+ 'unexist_backup',
+ ]
+ verifylist = [
+ ('backups', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [self.backups[0], exceptions.CommandError]
+ with mock.patch.object(utils, 'find_resource',
+ side_effect=find_mock_result) as find_mock:
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 backups failed to delete.',
+ str(e))
+
+ find_mock.assert_any_call(self.backups_mock, self.backups[0].id)
+ find_mock.assert_any_call(self.backups_mock, 'unexist_backup')
+
+ self.assertEqual(2, find_mock.call_count)
+ self.backups_mock.delete.assert_called_once_with(
+ self.backups[0].id, False
+ )
+
+
+class TestBackupList(TestBackup):
+
+ volume = volume_fakes.FakeVolume.create_one_volume()
+ backups = volume_fakes.FakeBackup.create_backups(
+ attrs={'volume_id': volume.name}, count=3)
+
+ columns = [
+ 'ID',
+ 'Name',
+ 'Description',
+ 'Status',
+ 'Size',
+ ]
+ columns_long = columns + [
+ 'Availability Zone',
+ 'Volume',
+ 'Container',
+ ]
+
+ data = []
+ for b in backups:
+ data.append((
+ b.id,
+ b.name,
+ b.description,
+ b.status,
+ b.size,
+ ))
+ data_long = []
+ for b in backups:
+ data_long.append((
+ b.id,
+ b.name,
+ b.description,
+ b.status,
+ b.size,
+ b.availability_zone,
+ b.volume_id,
+ b.container,
+ ))
+
+ def setUp(self):
+ super(TestBackupList, self).setUp()
+
+ self.volumes_mock.list.return_value = [self.volume]
+ self.backups_mock.list.return_value = self.backups
+ # Get the command to test
+ self.cmd = backup.ListVolumeBackup(self.app, None)
+
+ def test_backup_list_without_options(self):
+ arglist = []
+ verifylist = [("long", False)]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_backup_list_with_options(self):
+ arglist = ["--long"]
+ verifylist = [("long", True)]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns_long, columns)
+ self.assertEqual(self.data_long, list(data))
+
+
+class TestBackupRestore(TestBackup):
+
+ volume = volume_fakes.FakeVolume.create_one_volume()
+ backup = volume_fakes.FakeBackup.create_one_backup(
+ attrs={'volume_id': volume.id})
+
+ def setUp(self):
+ super(TestBackupRestore, self).setUp()
+
+ self.backups_mock.get.return_value = self.backup
+ self.volumes_mock.get.return_value = self.volume
+ self.restores_mock.restore.return_value = None
+ # Get the command object to mock
+ self.cmd = backup.RestoreVolumeBackup(self.app, None)
+
+ def test_backup_restore(self):
+ arglist = [
+ self.backup.id,
+ self.backup.volume_id
+ ]
+ verifylist = [
+ ("backup", self.backup.id),
+ ("volume", self.backup.volume_id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.restores_mock.restore.assert_called_with(self.backup.id,
+ self.backup.volume_id)
+ self.assertIsNone(result)
+
+
+class TestBackupShow(TestBackup):
+
+ backup = volume_fakes.FakeBackup.create_one_backup()
+
+ columns = (
+ 'availability_zone',
+ 'container',
+ 'description',
+ 'id',
+ 'name',
+ 'object_count',
+ 'size',
+ 'snapshot_id',
+ 'status',
+ 'volume_id',
+ )
+ data = (
+ backup.availability_zone,
+ backup.container,
+ backup.description,
+ backup.id,
+ backup.name,
+ backup.object_count,
+ backup.size,
+ backup.snapshot_id,
+ backup.status,
+ backup.volume_id,
+ )
+
+ def setUp(self):
+ super(TestBackupShow, self).setUp()
+
+ self.backups_mock.get.return_value = self.backup
+ # Get the command object to test
+ self.cmd = backup.ShowVolumeBackup(self.app, None)
+
+ def test_backup_show(self):
+ arglist = [
+ self.backup.id
+ ]
+ verifylist = [
+ ("backup", self.backup.id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.backups_mock.get.assert_called_with(self.backup.id)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
diff --git a/openstackclient/tests/unit/volume/v2/test_qos_specs.py b/openstackclient/tests/unit/volume/v2/test_qos_specs.py
new file mode 100644
index 00000000..7597e852
--- /dev/null
+++ b/openstackclient/tests/unit/volume/v2/test_qos_specs.py
@@ -0,0 +1,453 @@
+# Copyright 2015 iWeb Technologies Inc.
+#
+# 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.
+#
+
+import mock
+from mock import call
+
+from osc_lib import exceptions
+from osc_lib import utils
+
+from openstackclient.tests.unit.volume.v2 import fakes as volume_fakes
+from openstackclient.volume.v2 import qos_specs
+
+
+class TestQos(volume_fakes.TestVolume):
+
+ def setUp(self):
+ super(TestQos, self).setUp()
+
+ self.qos_mock = self.app.client_manager.volume.qos_specs
+ self.qos_mock.reset_mock()
+
+ self.types_mock = self.app.client_manager.volume.volume_types
+ self.types_mock.reset_mock()
+
+
+class TestQosAssociate(TestQos):
+
+ volume_type = volume_fakes.FakeType.create_one_type()
+ qos_spec = volume_fakes.FakeQos.create_one_qos()
+
+ def setUp(self):
+ super(TestQosAssociate, self).setUp()
+
+ self.qos_mock.get.return_value = self.qos_spec
+ self.types_mock.get.return_value = self.volume_type
+ # Get the command object to test
+ self.cmd = qos_specs.AssociateQos(self.app, None)
+
+ def test_qos_associate(self):
+ arglist = [
+ self.qos_spec.id,
+ self.volume_type.id
+ ]
+ verifylist = [
+ ('qos_spec', self.qos_spec.id),
+ ('volume_type', self.volume_type.id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.qos_mock.associate.assert_called_with(
+ self.qos_spec.id,
+ self.volume_type.id
+ )
+ self.assertIsNone(result)
+
+
+class TestQosCreate(TestQos):
+
+ new_qos_spec = volume_fakes.FakeQos.create_one_qos()
+ columns = (
+ 'consumer',
+ 'id',
+ 'name',
+ 'specs'
+ )
+ data = (
+ new_qos_spec.consumer,
+ new_qos_spec.id,
+ new_qos_spec.name,
+ new_qos_spec.specs
+ )
+
+ def setUp(self):
+ super(TestQosCreate, self).setUp()
+
+ self.qos_mock.create.return_value = self.new_qos_spec
+ # Get the command object to test
+ self.cmd = qos_specs.CreateQos(self.app, None)
+
+ def test_qos_create_without_properties(self):
+ arglist = [
+ self.new_qos_spec.name,
+ ]
+ verifylist = [
+ ('name', self.new_qos_spec.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.qos_mock.create.assert_called_with(
+ self.new_qos_spec.name,
+ {'consumer': 'both'}
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_qos_create_with_consumer(self):
+ arglist = [
+ '--consumer', self.new_qos_spec.consumer,
+ self.new_qos_spec.name,
+ ]
+ verifylist = [
+ ('consumer', self.new_qos_spec.consumer),
+ ('name', self.new_qos_spec.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.qos_mock.create.assert_called_with(
+ self.new_qos_spec.name,
+ {'consumer': self.new_qos_spec.consumer}
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_qos_create_with_properties(self):
+ arglist = [
+ '--consumer', self.new_qos_spec.consumer,
+ '--property', 'foo=bar',
+ '--property', 'iops=9001',
+ self.new_qos_spec.name,
+ ]
+ verifylist = [
+ ('consumer', self.new_qos_spec.consumer),
+ ('property', self.new_qos_spec.specs),
+ ('name', self.new_qos_spec.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.new_qos_spec.specs.update(
+ {'consumer': self.new_qos_spec.consumer})
+ self.qos_mock.create.assert_called_with(
+ self.new_qos_spec.name,
+ self.new_qos_spec.specs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestQosDelete(TestQos):
+
+ qos_specs = volume_fakes.FakeQos.create_qoses(count=2)
+
+ def setUp(self):
+ super(TestQosDelete, self).setUp()
+
+ self.qos_mock.get = (
+ volume_fakes.FakeQos.get_qoses(self.qos_specs))
+ # Get the command object to test
+ self.cmd = qos_specs.DeleteQos(self.app, None)
+
+ def test_qos_delete(self):
+ arglist = [
+ self.qos_specs[0].id
+ ]
+ verifylist = [
+ ('qos_specs', [self.qos_specs[0].id])
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.qos_mock.delete.assert_called_with(
+ self.qos_specs[0].id, False)
+ self.assertIsNone(result)
+
+ def test_qos_delete_with_force(self):
+ arglist = [
+ '--force',
+ self.qos_specs[0].id
+ ]
+ verifylist = [
+ ('force', True),
+ ('qos_specs', [self.qos_specs[0].id])
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.qos_mock.delete.assert_called_with(
+ self.qos_specs[0].id, True)
+ self.assertIsNone(result)
+
+ def test_delete_multiple_qoses(self):
+ arglist = []
+ for q in self.qos_specs:
+ arglist.append(q.id)
+ verifylist = [
+ ('qos_specs', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for q in self.qos_specs:
+ calls.append(call(q.id, False))
+ self.qos_mock.delete.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_delete_multiple_qoses_with_exception(self):
+ arglist = [
+ self.qos_specs[0].id,
+ 'unexist_qos',
+ ]
+ verifylist = [
+ ('qos_specs', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [self.qos_specs[0], exceptions.CommandError]
+ with mock.patch.object(utils, 'find_resource',
+ side_effect=find_mock_result) as find_mock:
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual(
+ '1 of 2 QoS specifications failed to delete.', str(e))
+
+ find_mock.assert_any_call(self.qos_mock, self.qos_specs[0].id)
+ find_mock.assert_any_call(self.qos_mock, 'unexist_qos')
+
+ self.assertEqual(2, find_mock.call_count)
+ self.qos_mock.delete.assert_called_once_with(
+ self.qos_specs[0].id, False
+ )
+
+
+class TestQosDisassociate(TestQos):
+
+ volume_type = volume_fakes.FakeType.create_one_type()
+ qos_spec = volume_fakes.FakeQos.create_one_qos()
+
+ def setUp(self):
+ super(TestQosDisassociate, self).setUp()
+
+ self.qos_mock.get.return_value = self.qos_spec
+ self.types_mock.get.return_value = self.volume_type
+ # Get the command object to test
+ self.cmd = qos_specs.DisassociateQos(self.app, None)
+
+ def test_qos_disassociate_with_volume_type(self):
+ arglist = [
+ '--volume-type', self.volume_type.id,
+ self.qos_spec.id,
+ ]
+ verifylist = [
+ ('volume_type', self.volume_type.id),
+ ('qos_spec', self.qos_spec.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.qos_mock.disassociate.assert_called_with(
+ self.qos_spec.id,
+ self.volume_type.id
+ )
+ self.assertIsNone(result)
+
+ def test_qos_disassociate_with_all_volume_types(self):
+ arglist = [
+ '--all',
+ self.qos_spec.id,
+ ]
+ verifylist = [
+ ('qos_spec', self.qos_spec.id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.qos_mock.disassociate_all.assert_called_with(self.qos_spec.id)
+ self.assertIsNone(result)
+
+
+class TestQosList(TestQos):
+
+ qos_specs = volume_fakes.FakeQos.create_qoses(count=2)
+ qos_association = volume_fakes.FakeQos.create_one_qos_association()
+
+ columns = (
+ 'ID',
+ 'Name',
+ 'Consumer',
+ 'Associations',
+ 'Specs',
+ )
+ data = []
+ for q in qos_specs:
+ data.append((
+ q.id,
+ q.name,
+ q.consumer,
+ qos_association.name,
+ utils.format_dict(q.specs),
+ ))
+
+ def setUp(self):
+ super(TestQosList, self).setUp()
+
+ self.qos_mock.list.return_value = self.qos_specs
+ self.qos_mock.get_associations.return_value = [self.qos_association]
+
+ # Get the command object to test
+ self.cmd = qos_specs.ListQos(self.app, None)
+
+ def test_qos_list(self):
+ arglist = []
+ verifylist = []
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.qos_mock.list.assert_called_with()
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+
+class TestQosSet(TestQos):
+
+ qos_spec = volume_fakes.FakeQos.create_one_qos()
+
+ def setUp(self):
+ super(TestQosSet, self).setUp()
+
+ self.qos_mock.get.return_value = self.qos_spec
+ # Get the command object to test
+ self.cmd = qos_specs.SetQos(self.app, None)
+
+ def test_qos_set_with_properties_with_id(self):
+ arglist = [
+ '--property', 'foo=bar',
+ '--property', 'iops=9001',
+ self.qos_spec.id,
+ ]
+ verifylist = [
+ ('property', self.qos_spec.specs),
+ ('qos_spec', self.qos_spec.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.qos_mock.set_keys.assert_called_with(
+ self.qos_spec.id,
+ self.qos_spec.specs
+ )
+ self.assertIsNone(result)
+
+
+class TestQosShow(TestQos):
+
+ qos_spec = volume_fakes.FakeQos.create_one_qos()
+ qos_association = volume_fakes.FakeQos.create_one_qos_association()
+
+ columns = (
+ 'associations',
+ 'consumer',
+ 'id',
+ 'name',
+ 'specs'
+ )
+ data = (
+ qos_association.name,
+ qos_spec.consumer,
+ qos_spec.id,
+ qos_spec.name,
+ utils.format_dict(qos_spec.specs),
+ )
+
+ def setUp(self):
+ super(TestQosShow, self).setUp()
+
+ self.qos_mock.get.return_value = self.qos_spec
+ self.qos_mock.get_associations.return_value = [self.qos_association]
+
+ # Get the command object to test
+ self.cmd = qos_specs.ShowQos(self.app, None)
+
+ def test_qos_show(self):
+ arglist = [
+ self.qos_spec.id
+ ]
+ verifylist = [
+ ('qos_spec', self.qos_spec.id)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.qos_mock.get.assert_called_with(
+ self.qos_spec.id
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, tuple(data))
+
+
+class TestQosUnset(TestQos):
+
+ qos_spec = volume_fakes.FakeQos.create_one_qos()
+
+ def setUp(self):
+ super(TestQosUnset, self).setUp()
+
+ self.qos_mock.get.return_value = self.qos_spec
+ # Get the command object to test
+ self.cmd = qos_specs.UnsetQos(self.app, None)
+
+ def test_qos_unset_with_properties(self):
+ arglist = [
+ '--property', 'iops',
+ '--property', 'foo',
+ self.qos_spec.id,
+ ]
+ verifylist = [
+ ('property', ['iops', 'foo']),
+ ('qos_spec', self.qos_spec.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.qos_mock.unset_keys.assert_called_with(
+ self.qos_spec.id,
+ ['iops', 'foo']
+ )
+ self.assertIsNone(result)
diff --git a/openstackclient/tests/unit/volume/v2/test_service.py b/openstackclient/tests/unit/volume/v2/test_service.py
new file mode 100644
index 00000000..3e9b2df9
--- /dev/null
+++ b/openstackclient/tests/unit/volume/v2/test_service.py
@@ -0,0 +1,286 @@
+#
+# 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 osc_lib import exceptions
+
+from openstackclient.tests.unit.volume.v2 import fakes as service_fakes
+from openstackclient.volume.v2 import service
+
+
+class TestService(service_fakes.TestVolume):
+
+ def setUp(self):
+ super(TestService, self).setUp()
+
+ # Get a shortcut to the ServiceManager Mock
+ self.service_mock = self.app.client_manager.volume.services
+ self.service_mock.reset_mock()
+
+
+class TestServiceList(TestService):
+
+ # The service to be listed
+ services = service_fakes.FakeService.create_one_service()
+
+ def setUp(self):
+ super(TestServiceList, self).setUp()
+
+ self.service_mock.list.return_value = [self.services]
+
+ # Get the command object to test
+ self.cmd = service.ListService(self.app, None)
+
+ def test_service_list(self):
+ arglist = [
+ '--host', self.services.host,
+ '--service', self.services.binary,
+ ]
+ verifylist = [
+ ('host', self.services.host),
+ ('service', self.services.binary),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ expected_columns = [
+ 'Binary',
+ 'Host',
+ 'Zone',
+ 'Status',
+ 'State',
+ 'Updated At',
+ ]
+
+ # confirming if all expected columns are present in the result.
+ self.assertEqual(expected_columns, columns)
+
+ datalist = ((
+ self.services.binary,
+ self.services.host,
+ self.services.zone,
+ self.services.status,
+ self.services.state,
+ self.services.updated_at,
+ ), )
+
+ # confirming if all expected values are present in the result.
+ self.assertEqual(datalist, tuple(data))
+
+ # checking if proper call was made to list services
+ self.service_mock.list.assert_called_with(
+ self.services.host,
+ self.services.binary,
+ )
+
+ # checking if prohibited columns are present in output
+ self.assertNotIn("Disabled Reason", columns)
+ self.assertNotIn(self.services.disabled_reason,
+ tuple(data))
+
+ def test_service_list_with_long_option(self):
+ arglist = [
+ '--host', self.services.host,
+ '--service', self.services.binary,
+ '--long'
+ ]
+ verifylist = [
+ ('host', self.services.host),
+ ('service', self.services.binary),
+ ('long', True)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ expected_columns = [
+ 'Binary',
+ 'Host',
+ 'Zone',
+ 'Status',
+ 'State',
+ 'Updated At',
+ 'Disabled Reason'
+ ]
+
+ # confirming if all expected columns are present in the result.
+ self.assertEqual(expected_columns, columns)
+
+ datalist = ((
+ self.services.binary,
+ self.services.host,
+ self.services.zone,
+ self.services.status,
+ self.services.state,
+ self.services.updated_at,
+ self.services.disabled_reason,
+ ), )
+
+ # confirming if all expected values are present in the result.
+ self.assertEqual(datalist, tuple(data))
+
+ self.service_mock.list.assert_called_with(
+ self.services.host,
+ self.services.binary,
+ )
+
+
+class TestServiceSet(TestService):
+
+ service = service_fakes.FakeService.create_one_service()
+
+ def setUp(self):
+ super(TestServiceSet, self).setUp()
+
+ self.service_mock.enable.return_value = self.service
+ self.service_mock.disable.return_value = self.service
+ self.service_mock.disable_log_reason.return_value = self.service
+
+ self.cmd = service.SetService(self.app, None)
+
+ def test_service_set_nothing(self):
+ arglist = [
+ self.service.host,
+ self.service.binary,
+ ]
+ verifylist = [
+ ('host', self.service.host),
+ ('service', self.service.binary),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ self.service_mock.enable.assert_not_called()
+ self.service_mock.disable.assert_not_called()
+ self.service_mock.disable_log_reason.assert_not_called()
+ self.assertIsNone(result)
+
+ def test_service_set_enable(self):
+ arglist = [
+ '--enable',
+ self.service.host,
+ self.service.binary,
+ ]
+ verifylist = [
+ ('enable', True),
+ ('host', self.service.host),
+ ('service', self.service.binary),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.service_mock.enable.assert_called_with(
+ self.service.host,
+ self.service.binary
+ )
+ self.service_mock.disable.assert_not_called()
+ self.service_mock.disable_log_reason.assert_not_called()
+ self.assertIsNone(result)
+
+ def test_service_set_disable(self):
+ arglist = [
+ '--disable',
+ self.service.host,
+ self.service.binary,
+ ]
+ verifylist = [
+ ('disable', True),
+ ('host', self.service.host),
+ ('service', self.service.binary),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.service_mock.disable.assert_called_with(
+ self.service.host,
+ self.service.binary
+ )
+ self.service_mock.enable.assert_not_called()
+ self.service_mock.disable_log_reason.assert_not_called()
+ self.assertIsNone(result)
+
+ def test_service_set_disable_with_reason(self):
+ reason = 'earthquake'
+ arglist = [
+ '--disable',
+ '--disable-reason', reason,
+ self.service.host,
+ self.service.binary,
+ ]
+ verifylist = [
+ ('disable', True),
+ ('disable_reason', reason),
+ ('host', self.service.host),
+ ('service', self.service.binary),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.service_mock.disable_log_reason.assert_called_with(
+ self.service.host,
+ self.service.binary,
+ reason
+ )
+ self.assertIsNone(result)
+
+ def test_service_set_only_with_disable_reason(self):
+ reason = 'earthquake'
+ arglist = [
+ '--disable-reason', reason,
+ self.service.host,
+ self.service.binary,
+ ]
+ verifylist = [
+ ('disable_reason', reason),
+ ('host', self.service.host),
+ ('service', self.service.binary),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail("CommandError should be raised.")
+ except exceptions.CommandError as e:
+ self.assertEqual("Cannot specify option --disable-reason without "
+ "--disable specified.", str(e))
+
+ def test_service_set_enable_with_disable_reason(self):
+ reason = 'earthquake'
+ arglist = [
+ '--enable',
+ '--disable-reason', reason,
+ self.service.host,
+ self.service.binary,
+ ]
+ verifylist = [
+ ('enable', True),
+ ('disable_reason', reason),
+ ('host', self.service.host),
+ ('service', self.service.binary),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail("CommandError should be raised.")
+ except exceptions.CommandError as e:
+ self.assertEqual("Cannot specify option --disable-reason without "
+ "--disable specified.", str(e))
diff --git a/openstackclient/tests/unit/volume/v2/test_snapshot.py b/openstackclient/tests/unit/volume/v2/test_snapshot.py
new file mode 100644
index 00000000..333d8d72
--- /dev/null
+++ b/openstackclient/tests/unit/volume/v2/test_snapshot.py
@@ -0,0 +1,458 @@
+#
+# 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.
+#
+
+import argparse
+import mock
+from mock import call
+
+from osc_lib import exceptions
+from osc_lib import utils
+
+from openstackclient.tests.unit.volume.v2 import fakes as volume_fakes
+from openstackclient.volume.v2 import snapshot
+
+
+class TestSnapshot(volume_fakes.TestVolume):
+
+ def setUp(self):
+ super(TestSnapshot, self).setUp()
+
+ self.snapshots_mock = self.app.client_manager.volume.volume_snapshots
+ self.snapshots_mock.reset_mock()
+ self.volumes_mock = self.app.client_manager.volume.volumes
+ self.volumes_mock.reset_mock()
+
+
+class TestSnapshotCreate(TestSnapshot):
+
+ columns = (
+ 'created_at',
+ 'description',
+ 'id',
+ 'name',
+ 'properties',
+ 'size',
+ 'status',
+ 'volume_id',
+ )
+
+ def setUp(self):
+ super(TestSnapshotCreate, self).setUp()
+
+ self.volume = volume_fakes.FakeVolume.create_one_volume()
+ self.new_snapshot = volume_fakes.FakeSnapshot.create_one_snapshot(
+ attrs={'volume_id': self.volume.id})
+
+ self.data = (
+ self.new_snapshot.created_at,
+ self.new_snapshot.description,
+ self.new_snapshot.id,
+ self.new_snapshot.name,
+ utils.format_dict(self.new_snapshot.metadata),
+ self.new_snapshot.size,
+ self.new_snapshot.status,
+ self.new_snapshot.volume_id,
+ )
+
+ self.volumes_mock.get.return_value = self.volume
+ self.snapshots_mock.create.return_value = self.new_snapshot
+ # Get the command object to test
+ self.cmd = snapshot.CreateSnapshot(self.app, None)
+
+ def test_snapshot_create(self):
+ arglist = [
+ "--name", self.new_snapshot.name,
+ "--description", self.new_snapshot.description,
+ "--force",
+ '--property', 'Alpha=a',
+ '--property', 'Beta=b',
+ self.new_snapshot.volume_id,
+ ]
+ verifylist = [
+ ("name", self.new_snapshot.name),
+ ("description", self.new_snapshot.description),
+ ("force", True),
+ ('property', {'Alpha': 'a', 'Beta': 'b'}),
+ ("volume", self.new_snapshot.volume_id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.snapshots_mock.create.assert_called_with(
+ self.new_snapshot.volume_id,
+ force=True,
+ name=self.new_snapshot.name,
+ description=self.new_snapshot.description,
+ metadata={'Alpha': 'a', 'Beta': 'b'},
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_snapshot_create_without_name(self):
+ arglist = [
+ self.new_snapshot.volume_id,
+ "--description", self.new_snapshot.description,
+ "--force"
+ ]
+ verifylist = [
+ ("volume", self.new_snapshot.volume_id),
+ ("description", self.new_snapshot.description),
+ ("force", True)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.snapshots_mock.create.assert_called_with(
+ self.new_snapshot.volume_id,
+ force=True,
+ name=None,
+ description=self.new_snapshot.description,
+ metadata=None,
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestSnapshotDelete(TestSnapshot):
+
+ snapshots = volume_fakes.FakeSnapshot.create_snapshots(count=2)
+
+ def setUp(self):
+ super(TestSnapshotDelete, self).setUp()
+
+ self.snapshots_mock.get = (
+ volume_fakes.FakeSnapshot.get_snapshots(self.snapshots))
+ self.snapshots_mock.delete.return_value = None
+
+ # Get the command object to mock
+ self.cmd = snapshot.DeleteSnapshot(self.app, None)
+
+ def test_snapshot_delete(self):
+ arglist = [
+ self.snapshots[0].id
+ ]
+ verifylist = [
+ ("snapshots", [self.snapshots[0].id])
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.snapshots_mock.delete.assert_called_with(
+ self.snapshots[0].id)
+ self.assertIsNone(result)
+
+ def test_delete_multiple_snapshots(self):
+ arglist = []
+ for s in self.snapshots:
+ arglist.append(s.id)
+ verifylist = [
+ ('snapshots', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for s in self.snapshots:
+ calls.append(call(s.id))
+ self.snapshots_mock.delete.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_delete_multiple_snapshots_with_exception(self):
+ arglist = [
+ self.snapshots[0].id,
+ 'unexist_snapshot',
+ ]
+ verifylist = [
+ ('snapshots', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [self.snapshots[0], exceptions.CommandError]
+ with mock.patch.object(utils, 'find_resource',
+ side_effect=find_mock_result) as find_mock:
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 snapshots failed to delete.',
+ str(e))
+
+ find_mock.assert_any_call(
+ self.snapshots_mock, self.snapshots[0].id)
+ find_mock.assert_any_call(self.snapshots_mock, 'unexist_snapshot')
+
+ self.assertEqual(2, find_mock.call_count)
+ self.snapshots_mock.delete.assert_called_once_with(
+ self.snapshots[0].id
+ )
+
+
+class TestSnapshotList(TestSnapshot):
+
+ volume = volume_fakes.FakeVolume.create_one_volume()
+ snapshots = volume_fakes.FakeSnapshot.create_snapshots(
+ attrs={'volume_id': volume.name}, count=3)
+
+ columns = [
+ "ID",
+ "Name",
+ "Description",
+ "Status",
+ "Size"
+ ]
+ columns_long = columns + [
+ "Created At",
+ "Volume",
+ "Properties"
+ ]
+
+ data = []
+ for s in snapshots:
+ data.append((
+ s.id,
+ s.name,
+ s.description,
+ s.status,
+ s.size,
+ ))
+ data_long = []
+ for s in snapshots:
+ data_long.append((
+ s.id,
+ s.name,
+ s.description,
+ s.status,
+ s.size,
+ s.created_at,
+ s.volume_id,
+ utils.format_dict(s.metadata),
+ ))
+
+ def setUp(self):
+ super(TestSnapshotList, self).setUp()
+
+ self.volumes_mock.list.return_value = [self.volume]
+ self.snapshots_mock.list.return_value = self.snapshots
+ # Get the command to test
+ self.cmd = snapshot.ListSnapshot(self.app, None)
+
+ def test_snapshot_list_without_options(self):
+ arglist = []
+ verifylist = [
+ ('all_projects', False),
+ ("long", False)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.snapshots_mock.list.assert_called_once_with(
+ limit=None, marker=None, search_opts={'all_tenants': False})
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_snapshot_list_with_options(self):
+ arglist = [
+ "--long",
+ "--limit", "2",
+ "--marker", self.snapshots[0].id,
+ ]
+ verifylist = [
+ ("long", True),
+ ("limit", 2),
+ ("marker", self.snapshots[0].id),
+ ('all_projects', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.snapshots_mock.list.assert_called_once_with(
+ limit=2,
+ marker=self.snapshots[0].id,
+ search_opts={'all_tenants': False}
+ )
+ self.assertEqual(self.columns_long, columns)
+ self.assertEqual(self.data_long, list(data))
+
+ def test_snapshot_list_all_projects(self):
+ arglist = [
+ '--all-projects',
+ ]
+ verifylist = [
+ ('long', False),
+ ('all_projects', True)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.snapshots_mock.list.assert_called_once_with(
+ limit=None, marker=None, search_opts={'all_tenants': True})
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_snapshot_list_negative_limit(self):
+ arglist = [
+ "--limit", "-2",
+ ]
+ verifylist = [
+ ("limit", -2),
+ ]
+ self.assertRaises(argparse.ArgumentTypeError, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+
+class TestSnapshotSet(TestSnapshot):
+
+ snapshot = volume_fakes.FakeSnapshot.create_one_snapshot()
+
+ def setUp(self):
+ super(TestSnapshotSet, self).setUp()
+
+ self.snapshots_mock.get.return_value = self.snapshot
+ self.snapshots_mock.set_metadata.return_value = None
+ self.snapshots_mock.update.return_value = None
+ # Get the command object to mock
+ self.cmd = snapshot.SetSnapshot(self.app, None)
+
+ def test_snapshot_set(self):
+ arglist = [
+ "--name", "new_snapshot",
+ "--property", "x=y",
+ "--property", "foo=foo",
+ self.snapshot.id,
+ ]
+ new_property = {"x": "y", "foo": "foo"}
+ verifylist = [
+ ("name", "new_snapshot"),
+ ("property", new_property),
+ ("snapshot", self.snapshot.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ kwargs = {
+ "name": "new_snapshot",
+ }
+ self.snapshots_mock.update.assert_called_with(
+ self.snapshot.id, **kwargs)
+ self.snapshots_mock.set_metadata.assert_called_with(
+ self.snapshot.id, new_property
+ )
+ self.assertIsNone(result)
+
+ def test_snapshot_set_state_to_error(self):
+ arglist = [
+ "--state", "error",
+ self.snapshot.id
+ ]
+ verifylist = [
+ ("state", "error"),
+ ("snapshot", self.snapshot.id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.snapshots_mock.reset_state.assert_called_with(
+ self.snapshot.id, "error")
+ self.assertIsNone(result)
+
+
+class TestSnapshotShow(TestSnapshot):
+
+ columns = (
+ 'created_at',
+ 'description',
+ 'id',
+ 'name',
+ 'properties',
+ 'size',
+ 'status',
+ 'volume_id',
+ )
+
+ def setUp(self):
+ super(TestSnapshotShow, self).setUp()
+
+ self.snapshot = volume_fakes.FakeSnapshot.create_one_snapshot()
+
+ self.data = (
+ self.snapshot.created_at,
+ self.snapshot.description,
+ self.snapshot.id,
+ self.snapshot.name,
+ utils.format_dict(self.snapshot.metadata),
+ self.snapshot.size,
+ self.snapshot.status,
+ self.snapshot.volume_id,
+ )
+
+ self.snapshots_mock.get.return_value = self.snapshot
+ # Get the command object to test
+ self.cmd = snapshot.ShowSnapshot(self.app, None)
+
+ def test_snapshot_show(self):
+ arglist = [
+ self.snapshot.id
+ ]
+ verifylist = [
+ ("snapshot", self.snapshot.id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.snapshots_mock.get.assert_called_with(self.snapshot.id)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestSnapshotUnset(TestSnapshot):
+
+ snapshot = volume_fakes.FakeSnapshot.create_one_snapshot()
+
+ def setUp(self):
+ super(TestSnapshotUnset, self).setUp()
+
+ self.snapshots_mock.get.return_value = self.snapshot
+ self.snapshots_mock.delete_metadata.return_value = None
+ # Get the command object to mock
+ self.cmd = snapshot.UnsetSnapshot(self.app, None)
+
+ def test_snapshot_unset(self):
+ arglist = [
+ "--property", "foo",
+ self.snapshot.id,
+ ]
+ verifylist = [
+ ("property", ["foo"]),
+ ("snapshot", self.snapshot.id),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.snapshots_mock.delete_metadata.assert_called_with(
+ self.snapshot.id, ["foo"]
+ )
+ self.assertIsNone(result)
diff --git a/openstackclient/tests/unit/volume/v2/test_transfer_request.py b/openstackclient/tests/unit/volume/v2/test_transfer_request.py
new file mode 100644
index 00000000..32108c02
--- /dev/null
+++ b/openstackclient/tests/unit/volume/v2/test_transfer_request.py
@@ -0,0 +1,114 @@
+#
+# 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 openstackclient.tests.unit.volume.v2 import fakes as transfer_fakes
+from openstackclient.volume.v2 import volume_transfer_request
+
+
+class TestTransfer(transfer_fakes.TestVolume):
+
+ def setUp(self):
+ super(TestTransfer, self).setUp()
+
+ # Get a shortcut to the TransferManager Mock
+ self.transfer_mock = self.app.client_manager.volume.transfers
+ self.transfer_mock.reset_mock()
+
+
+class TestTransferList(TestTransfer):
+
+ # The Transfers to be listed
+ volume_transfers = transfer_fakes.FakeTransfer.create_one_transfer()
+
+ def setUp(self):
+ super(TestTransferList, self).setUp()
+
+ self.transfer_mock.list.return_value = [self.volume_transfers]
+
+ # Get the command object to test
+ self.cmd = volume_transfer_request.ListTransferRequests(self.app, None)
+
+ def test_transfer_list_without_argument(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ expected_columns = [
+ 'ID',
+ 'Volume',
+ 'Name',
+ ]
+
+ # confirming if all expected columns are present in the result.
+ self.assertEqual(expected_columns, columns)
+
+ datalist = ((
+ self.volume_transfers.id,
+ self.volume_transfers.volume_id,
+ self.volume_transfers.name,
+ ), )
+
+ # confirming if all expected values are present in the result.
+ self.assertEqual(datalist, tuple(data))
+
+ # checking if proper call was made to list volume_transfers
+ self.transfer_mock.list.assert_called_with(
+ detailed=True,
+ search_opts={'all_tenants': 0}
+ )
+
+ def test_transfer_list_with_argument(self):
+ arglist = [
+ "--all-projects"
+ ]
+ verifylist = [
+ ("all_projects", True)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ expected_columns = [
+ 'ID',
+ 'Volume',
+ 'Name',
+ ]
+
+ # confirming if all expected columns are present in the result.
+ self.assertEqual(expected_columns, columns)
+
+ datalist = ((
+ self.volume_transfers.id,
+ self.volume_transfers.volume_id,
+ self.volume_transfers.name,
+ ), )
+
+ # confirming if all expected values are present in the result.
+ self.assertEqual(datalist, tuple(data))
+
+ # checking if proper call was made to list volume_transfers
+ self.transfer_mock.list.assert_called_with(
+ detailed=True,
+ search_opts={'all_tenants': 1}
+ )
diff --git a/openstackclient/tests/unit/volume/v2/test_type.py b/openstackclient/tests/unit/volume/v2/test_type.py
new file mode 100644
index 00000000..84f87e3b
--- /dev/null
+++ b/openstackclient/tests/unit/volume/v2/test_type.py
@@ -0,0 +1,575 @@
+#
+# 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.
+#
+
+import mock
+
+from osc_lib import exceptions
+from osc_lib import utils
+
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+from openstackclient.tests.unit import utils as tests_utils
+from openstackclient.tests.unit.volume.v2 import fakes as volume_fakes
+from openstackclient.volume.v2 import volume_type
+
+
+class TestType(volume_fakes.TestVolume):
+
+ def setUp(self):
+ super(TestType, self).setUp()
+
+ self.types_mock = self.app.client_manager.volume.volume_types
+ self.types_mock.reset_mock()
+
+ self.types_access_mock = (
+ self.app.client_manager.volume.volume_type_access)
+ self.types_access_mock.reset_mock()
+
+ self.projects_mock = self.app.client_manager.identity.projects
+ self.projects_mock.reset_mock()
+
+
+class TestTypeCreate(TestType):
+
+ project = identity_fakes.FakeProject.create_one_project()
+ columns = (
+ 'description',
+ 'id',
+ 'is_public',
+ 'name',
+ )
+
+ def setUp(self):
+ super(TestTypeCreate, self).setUp()
+
+ self.new_volume_type = volume_fakes.FakeType.create_one_type()
+ self.data = (
+ self.new_volume_type.description,
+ self.new_volume_type.id,
+ True,
+ self.new_volume_type.name,
+ )
+
+ self.types_mock.create.return_value = self.new_volume_type
+ self.projects_mock.get.return_value = self.project
+ # Get the command object to test
+ self.cmd = volume_type.CreateVolumeType(self.app, None)
+
+ def test_type_create_public(self):
+ arglist = [
+ "--description", self.new_volume_type.description,
+ "--public",
+ self.new_volume_type.name,
+ ]
+ verifylist = [
+ ("description", self.new_volume_type.description),
+ ("public", True),
+ ("private", False),
+ ("name", self.new_volume_type.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.types_mock.create.assert_called_with(
+ self.new_volume_type.name,
+ description=self.new_volume_type.description,
+ is_public=True,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_type_create_private(self):
+ arglist = [
+ "--description", self.new_volume_type.description,
+ "--private",
+ "--project", self.project.id,
+ self.new_volume_type.name,
+ ]
+ verifylist = [
+ ("description", self.new_volume_type.description),
+ ("public", False),
+ ("private", True),
+ ("project", self.project.id),
+ ("name", self.new_volume_type.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.types_mock.create.assert_called_with(
+ self.new_volume_type.name,
+ description=self.new_volume_type.description,
+ is_public=False,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_public_type_create_with_project(self):
+ arglist = [
+ '--project', self.project.id,
+ self.new_volume_type.name,
+ ]
+ verifylist = [
+ ('project', self.project.id),
+ ('name', self.new_volume_type.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
+
+
+class TestTypeDelete(TestType):
+
+ volume_type = volume_fakes.FakeType.create_one_type()
+
+ def setUp(self):
+ super(TestTypeDelete, self).setUp()
+
+ self.types_mock.get.return_value = self.volume_type
+ self.types_mock.delete.return_value = None
+
+ # Get the command object to mock
+ self.cmd = volume_type.DeleteVolumeType(self.app, None)
+
+ def test_type_delete(self):
+ arglist = [
+ self.volume_type.id
+ ]
+ verifylist = [
+ ("volume_types", [self.volume_type.id])
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.types_mock.delete.assert_called_with(self.volume_type)
+ self.assertIsNone(result)
+
+
+class TestTypeList(TestType):
+
+ volume_types = volume_fakes.FakeType.create_types()
+
+ columns = [
+ "ID",
+ "Name"
+ ]
+ columns_long = columns + [
+ "Description",
+ "Properties"
+ ]
+
+ data = []
+ for t in volume_types:
+ data.append((
+ t.id,
+ t.name,
+ ))
+ data_long = []
+ for t in volume_types:
+ data_long.append((
+ t.id,
+ t.name,
+ t.description,
+ utils.format_dict(t.extra_specs),
+ ))
+
+ def setUp(self):
+ super(TestTypeList, self).setUp()
+
+ self.types_mock.list.return_value = self.volume_types
+ # get the command to test
+ self.cmd = volume_type.ListVolumeType(self.app, None)
+
+ def test_type_list_without_options(self):
+ arglist = []
+ verifylist = [
+ ("long", False),
+ ("private", False),
+ ("public", False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.types_mock.list.assert_called_once_with(is_public=None)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_type_list_with_options(self):
+ arglist = [
+ "--long",
+ "--public",
+ ]
+ verifylist = [
+ ("long", True),
+ ("private", False),
+ ("public", True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.types_mock.list.assert_called_once_with(is_public=True)
+ self.assertEqual(self.columns_long, columns)
+ self.assertEqual(self.data_long, list(data))
+
+ def test_type_list_with_private_option(self):
+ arglist = [
+ "--private",
+ ]
+ verifylist = [
+ ("long", False),
+ ("private", True),
+ ("public", False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.types_mock.list.assert_called_once_with(is_public=False)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+
+class TestTypeSet(TestType):
+
+ project = identity_fakes.FakeProject.create_one_project()
+ volume_type = volume_fakes.FakeType.create_one_type(
+ methods={'set_keys': None})
+
+ def setUp(self):
+ super(TestTypeSet, self).setUp()
+
+ self.types_mock.get.return_value = self.volume_type
+
+ # Return a project
+ self.projects_mock.get.return_value = self.project
+ # Get the command object to test
+ self.cmd = volume_type.SetVolumeType(self.app, None)
+
+ def test_type_set_name(self):
+ new_name = 'new_name'
+ arglist = [
+ '--name', new_name,
+ self.volume_type.id,
+ ]
+ verifylist = [
+ ('name', new_name),
+ ('description', None),
+ ('property', None),
+ ('volume_type', self.volume_type.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': new_name,
+ }
+ self.types_mock.update.assert_called_with(
+ self.volume_type.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_type_set_description(self):
+ new_desc = 'new_desc'
+ arglist = [
+ '--description', new_desc,
+ self.volume_type.id,
+ ]
+ verifylist = [
+ ('name', None),
+ ('description', new_desc),
+ ('property', None),
+ ('volume_type', self.volume_type.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'description': new_desc,
+ }
+ self.types_mock.update.assert_called_with(
+ self.volume_type.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_type_set_property(self):
+ arglist = [
+ '--property', 'myprop=myvalue',
+ self.volume_type.id,
+ ]
+ verifylist = [
+ ('name', None),
+ ('description', None),
+ ('property', {'myprop': 'myvalue'}),
+ ('volume_type', self.volume_type.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.volume_type.set_keys.assert_called_once_with(
+ {'myprop': 'myvalue'})
+ self.assertIsNone(result)
+
+ def test_type_set_not_called_without_project_argument(self):
+ arglist = [
+ '--project', '',
+ self.volume_type.id,
+ ]
+ verifylist = [
+ ('project', ''),
+ ('volume_type', self.volume_type.id),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.assertIsNone(result)
+
+ self.assertFalse(self.types_access_mock.add_project_access.called)
+
+ def test_type_set_failed_with_missing_volume_type_argument(self):
+ arglist = [
+ '--project', 'identity_fakes.project_id',
+ ]
+ verifylist = [
+ ('project', 'identity_fakes.project_id'),
+ ]
+
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser,
+ self.cmd,
+ arglist,
+ verifylist)
+
+ def test_type_set_project_access(self):
+ arglist = [
+ '--project', self.project.id,
+ self.volume_type.id,
+ ]
+ verifylist = [
+ ('project', self.project.id),
+ ('volume_type', self.volume_type.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.assertIsNone(result)
+
+ self.types_access_mock.add_project_access.assert_called_with(
+ self.volume_type.id,
+ self.project.id,
+ )
+
+
+class TestTypeShow(TestType):
+
+ columns = (
+ 'access_project_ids',
+ 'description',
+ 'id',
+ 'is_public',
+ 'name',
+ 'properties',
+ )
+
+ def setUp(self):
+ super(TestTypeShow, self).setUp()
+
+ self.volume_type = volume_fakes.FakeType.create_one_type()
+ self.data = (
+ None,
+ self.volume_type.description,
+ self.volume_type.id,
+ True,
+ self.volume_type.name,
+ utils.format_dict(self.volume_type.extra_specs)
+ )
+
+ self.types_mock.get.return_value = self.volume_type
+
+ # Get the command object to test
+ self.cmd = volume_type.ShowVolumeType(self.app, None)
+
+ def test_type_show(self):
+ arglist = [
+ self.volume_type.id
+ ]
+ verifylist = [
+ ("volume_type", self.volume_type.id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.types_mock.get.assert_called_with(self.volume_type.id)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+ def test_type_show_with_access(self):
+ arglist = [
+ self.volume_type.id
+ ]
+ verifylist = [
+ ("volume_type", self.volume_type.id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ private_type = volume_fakes.FakeType.create_one_type(
+ attrs={'is_public': False})
+ type_access_list = volume_fakes.FakeTypeAccess.create_one_type_access()
+ with mock.patch.object(self.types_mock, 'get',
+ return_value=private_type):
+ with mock.patch.object(self.types_access_mock, 'list',
+ return_value=[type_access_list]):
+ columns, data = self.cmd.take_action(parsed_args)
+ self.types_mock.get.assert_called_once_with(
+ self.volume_type.id)
+ self.types_access_mock.list.assert_called_once_with(
+ private_type.id)
+
+ self.assertEqual(self.columns, columns)
+ private_type_data = (
+ utils.format_list([type_access_list.project_id]),
+ private_type.description,
+ private_type.id,
+ private_type.is_public,
+ private_type.name,
+ utils.format_dict(private_type.extra_specs)
+ )
+ self.assertEqual(private_type_data, data)
+
+ def test_type_show_with_list_access_exec(self):
+ arglist = [
+ self.volume_type.id
+ ]
+ verifylist = [
+ ("volume_type", self.volume_type.id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ private_type = volume_fakes.FakeType.create_one_type(
+ attrs={'is_public': False})
+ with mock.patch.object(self.types_mock, 'get',
+ return_value=private_type):
+ with mock.patch.object(self.types_access_mock, 'list',
+ side_effect=Exception()):
+ columns, data = self.cmd.take_action(parsed_args)
+ self.types_mock.get.assert_called_once_with(
+ self.volume_type.id)
+ self.types_access_mock.list.assert_called_once_with(
+ private_type.id)
+
+ self.assertEqual(self.columns, columns)
+ private_type_data = (
+ None,
+ private_type.description,
+ private_type.id,
+ private_type.is_public,
+ private_type.name,
+ utils.format_dict(private_type.extra_specs)
+ )
+ self.assertEqual(private_type_data, data)
+
+
+class TestTypeUnset(TestType):
+
+ project = identity_fakes.FakeProject.create_one_project()
+ volume_type = volume_fakes.FakeType.create_one_type(
+ methods={'unset_keys': None})
+
+ def setUp(self):
+ super(TestTypeUnset, self).setUp()
+
+ self.types_mock.get.return_value = self.volume_type
+
+ # Return a project
+ self.projects_mock.get.return_value = self.project
+
+ # Get the command object to test
+ self.cmd = volume_type.UnsetVolumeType(self.app, None)
+
+ def test_type_unset(self):
+ arglist = [
+ '--property', 'property',
+ '--property', 'multi_property',
+ self.volume_type.id,
+ ]
+ verifylist = [
+ ('property', ['property', 'multi_property']),
+ ('volume_type', self.volume_type.id),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.volume_type.unset_keys.assert_called_once_with(
+ ['property', 'multi_property'])
+ self.assertIsNone(result)
+
+ def test_type_unset_project_access(self):
+ arglist = [
+ '--project', self.project.id,
+ self.volume_type.id,
+ ]
+ verifylist = [
+ ('project', self.project.id),
+ ('volume_type', self.volume_type.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.assertIsNone(result)
+
+ self.types_access_mock.remove_project_access.assert_called_with(
+ self.volume_type.id,
+ self.project.id,
+ )
+
+ def test_type_unset_not_called_without_project_argument(self):
+ arglist = [
+ '--project', '',
+ self.volume_type.id,
+ ]
+ verifylist = [
+ ('project', ''),
+ ('volume_type', self.volume_type.id),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.assertIsNone(result)
+
+ self.assertFalse(self.types_access_mock.remove_project_access.called)
+
+ def test_type_unset_failed_with_missing_volume_type_argument(self):
+ arglist = [
+ '--project', 'identity_fakes.project_id',
+ ]
+ verifylist = [
+ ('project', 'identity_fakes.project_id'),
+ ]
+
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser,
+ self.cmd,
+ arglist,
+ verifylist)
diff --git a/openstackclient/tests/unit/volume/v2/test_volume.py b/openstackclient/tests/unit/volume/v2/test_volume.py
new file mode 100644
index 00000000..66f8f74d
--- /dev/null
+++ b/openstackclient/tests/unit/volume/v2/test_volume.py
@@ -0,0 +1,966 @@
+#
+# 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.
+#
+
+import mock
+from mock import call
+
+from osc_lib import exceptions
+from osc_lib import utils
+
+from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
+from openstackclient.tests.unit.image.v2 import fakes as image_fakes
+from openstackclient.tests.unit.volume.v2 import fakes as volume_fakes
+from openstackclient.volume.v2 import volume
+
+
+class TestVolume(volume_fakes.TestVolume):
+
+ def setUp(self):
+ super(TestVolume, self).setUp()
+
+ self.volumes_mock = self.app.client_manager.volume.volumes
+ self.volumes_mock.reset_mock()
+
+ self.projects_mock = self.app.client_manager.identity.projects
+ self.projects_mock.reset_mock()
+
+ self.users_mock = self.app.client_manager.identity.users
+ self.users_mock.reset_mock()
+
+ self.images_mock = self.app.client_manager.image.images
+ self.images_mock.reset_mock()
+
+ self.snapshots_mock = self.app.client_manager.volume.volume_snapshots
+ self.snapshots_mock.reset_mock()
+
+ def setup_volumes_mock(self, count):
+ volumes = volume_fakes.FakeVolume.create_volumes(count=count)
+
+ self.volumes_mock.get = volume_fakes.FakeVolume.get_volumes(
+ volumes,
+ 0)
+ return volumes
+
+
+class TestVolumeCreate(TestVolume):
+
+ project = identity_fakes.FakeProject.create_one_project()
+ user = identity_fakes.FakeUser.create_one_user()
+
+ columns = (
+ 'attachments',
+ 'availability_zone',
+ 'bootable',
+ 'description',
+ 'id',
+ 'name',
+ 'properties',
+ 'size',
+ 'snapshot_id',
+ 'status',
+ 'type',
+ )
+
+ def setUp(self):
+ super(TestVolumeCreate, self).setUp()
+
+ self.new_volume = volume_fakes.FakeVolume.create_one_volume()
+ self.volumes_mock.create.return_value = self.new_volume
+
+ self.datalist = (
+ self.new_volume.attachments,
+ self.new_volume.availability_zone,
+ self.new_volume.bootable,
+ self.new_volume.description,
+ self.new_volume.id,
+ self.new_volume.name,
+ utils.format_dict(self.new_volume.metadata),
+ self.new_volume.size,
+ self.new_volume.snapshot_id,
+ self.new_volume.status,
+ self.new_volume.volume_type,
+ )
+
+ # Get the command object to test
+ self.cmd = volume.CreateVolume(self.app, None)
+
+ def test_volume_create_min_options(self):
+ arglist = [
+ '--size', str(self.new_volume.size),
+ self.new_volume.name,
+ ]
+ verifylist = [
+ ('size', self.new_volume.size),
+ ('name', self.new_volume.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.volumes_mock.create.assert_called_with(
+ size=self.new_volume.size,
+ snapshot_id=None,
+ name=self.new_volume.name,
+ description=None,
+ volume_type=None,
+ user_id=None,
+ project_id=None,
+ availability_zone=None,
+ metadata=None,
+ imageRef=None,
+ source_volid=None
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_volume_create_options(self):
+ arglist = [
+ '--size', str(self.new_volume.size),
+ '--description', self.new_volume.description,
+ '--type', self.new_volume.volume_type,
+ '--availability-zone', self.new_volume.availability_zone,
+ self.new_volume.name,
+ ]
+ verifylist = [
+ ('size', self.new_volume.size),
+ ('description', self.new_volume.description),
+ ('type', self.new_volume.volume_type),
+ ('availability_zone', self.new_volume.availability_zone),
+ ('name', self.new_volume.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.volumes_mock.create.assert_called_with(
+ size=self.new_volume.size,
+ snapshot_id=None,
+ name=self.new_volume.name,
+ description=self.new_volume.description,
+ volume_type=self.new_volume.volume_type,
+ user_id=None,
+ project_id=None,
+ availability_zone=self.new_volume.availability_zone,
+ metadata=None,
+ imageRef=None,
+ source_volid=None
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_volume_create_user_project_id(self):
+ # Return a project
+ self.projects_mock.get.return_value = self.project
+ # Return a user
+ self.users_mock.get.return_value = self.user
+
+ arglist = [
+ '--size', str(self.new_volume.size),
+ '--project', self.project.id,
+ '--user', self.user.id,
+ self.new_volume.name,
+ ]
+ verifylist = [
+ ('size', self.new_volume.size),
+ ('project', self.project.id),
+ ('user', self.user.id),
+ ('name', self.new_volume.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.volumes_mock.create.assert_called_with(
+ size=self.new_volume.size,
+ snapshot_id=None,
+ name=self.new_volume.name,
+ description=None,
+ volume_type=None,
+ user_id=self.user.id,
+ project_id=self.project.id,
+ availability_zone=None,
+ metadata=None,
+ imageRef=None,
+ source_volid=None
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_volume_create_user_project_name(self):
+ # Return a project
+ self.projects_mock.get.return_value = self.project
+ # Return a user
+ self.users_mock.get.return_value = self.user
+
+ arglist = [
+ '--size', str(self.new_volume.size),
+ '--project', self.project.name,
+ '--user', self.user.name,
+ self.new_volume.name,
+ ]
+ verifylist = [
+ ('size', self.new_volume.size),
+ ('project', self.project.name),
+ ('user', self.user.name),
+ ('name', self.new_volume.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.volumes_mock.create.assert_called_with(
+ size=self.new_volume.size,
+ snapshot_id=None,
+ name=self.new_volume.name,
+ description=None,
+ volume_type=None,
+ user_id=self.user.id,
+ project_id=self.project.id,
+ availability_zone=None,
+ metadata=None,
+ imageRef=None,
+ source_volid=None
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_volume_create_properties(self):
+ arglist = [
+ '--property', 'Alpha=a',
+ '--property', 'Beta=b',
+ '--size', str(self.new_volume.size),
+ self.new_volume.name,
+ ]
+ verifylist = [
+ ('property', {'Alpha': 'a', 'Beta': 'b'}),
+ ('size', self.new_volume.size),
+ ('name', self.new_volume.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.volumes_mock.create.assert_called_with(
+ size=self.new_volume.size,
+ snapshot_id=None,
+ name=self.new_volume.name,
+ description=None,
+ volume_type=None,
+ user_id=None,
+ project_id=None,
+ availability_zone=None,
+ metadata={'Alpha': 'a', 'Beta': 'b'},
+ imageRef=None,
+ source_volid=None
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_volume_create_image_id(self):
+ image = image_fakes.FakeImage.create_one_image()
+ self.images_mock.get.return_value = image
+
+ arglist = [
+ '--image', image.id,
+ '--size', str(self.new_volume.size),
+ self.new_volume.name,
+ ]
+ verifylist = [
+ ('image', image.id),
+ ('size', self.new_volume.size),
+ ('name', self.new_volume.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.volumes_mock.create.assert_called_with(
+ size=self.new_volume.size,
+ snapshot_id=None,
+ name=self.new_volume.name,
+ description=None,
+ volume_type=None,
+ user_id=None,
+ project_id=None,
+ availability_zone=None,
+ metadata=None,
+ imageRef=image.id,
+ source_volid=None,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_volume_create_image_name(self):
+ image = image_fakes.FakeImage.create_one_image()
+ self.images_mock.get.return_value = image
+
+ arglist = [
+ '--image', image.name,
+ '--size', str(self.new_volume.size),
+ self.new_volume.name,
+ ]
+ verifylist = [
+ ('image', image.name),
+ ('size', self.new_volume.size),
+ ('name', self.new_volume.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.volumes_mock.create.assert_called_with(
+ size=self.new_volume.size,
+ snapshot_id=None,
+ name=self.new_volume.name,
+ description=None,
+ volume_type=None,
+ user_id=None,
+ project_id=None,
+ availability_zone=None,
+ metadata=None,
+ imageRef=image.id,
+ source_volid=None
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_volume_create_with_snapshot(self):
+ snapshot = volume_fakes.FakeSnapshot.create_one_snapshot()
+ self.new_volume.snapshot_id = snapshot.id
+ arglist = [
+ '--size', str(self.new_volume.size),
+ '--snapshot', self.new_volume.snapshot_id,
+ self.new_volume.name,
+ ]
+ verifylist = [
+ ('size', self.new_volume.size),
+ ('snapshot', self.new_volume.snapshot_id),
+ ('name', self.new_volume.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.snapshots_mock.get.return_value = snapshot
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.volumes_mock.create.assert_called_once_with(
+ size=self.new_volume.size,
+ snapshot_id=snapshot.id,
+ name=self.new_volume.name,
+ description=None,
+ volume_type=None,
+ user_id=None,
+ project_id=None,
+ availability_zone=None,
+ metadata=None,
+ imageRef=None,
+ source_volid=None
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+
+class TestVolumeDelete(TestVolume):
+
+ def setUp(self):
+ super(TestVolumeDelete, self).setUp()
+
+ self.volumes_mock.delete.return_value = None
+
+ # Get the command object to mock
+ self.cmd = volume.DeleteVolume(self.app, None)
+
+ def test_volume_delete_one_volume(self):
+ volumes = self.setup_volumes_mock(count=1)
+
+ arglist = [
+ volumes[0].id
+ ]
+ verifylist = [
+ ("force", False),
+ ("purge", False),
+ ("volumes", [volumes[0].id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.volumes_mock.delete.assert_called_once_with(
+ volumes[0].id, cascade=False)
+ self.assertIsNone(result)
+
+ def test_volume_delete_multi_volumes(self):
+ volumes = self.setup_volumes_mock(count=3)
+
+ arglist = [v.id for v in volumes]
+ verifylist = [
+ ('force', False),
+ ('purge', False),
+ ('volumes', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ calls = [call(v.id, cascade=False) for v in volumes]
+ self.volumes_mock.delete.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_volume_delete_multi_volumes_with_exception(self):
+ volumes = self.setup_volumes_mock(count=2)
+
+ arglist = [
+ volumes[0].id,
+ 'unexist_volume',
+ ]
+ verifylist = [
+ ('force', False),
+ ('purge', False),
+ ('volumes', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [volumes[0], exceptions.CommandError]
+ with mock.patch.object(utils, 'find_resource',
+ side_effect=find_mock_result) as find_mock:
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 volumes failed to delete.',
+ str(e))
+
+ find_mock.assert_any_call(self.volumes_mock, volumes[0].id)
+ find_mock.assert_any_call(self.volumes_mock, 'unexist_volume')
+
+ self.assertEqual(2, find_mock.call_count)
+ self.volumes_mock.delete.assert_called_once_with(
+ volumes[0].id, cascade=False)
+
+ def test_volume_delete_with_purge(self):
+ volumes = self.setup_volumes_mock(count=1)
+
+ arglist = [
+ '--purge',
+ volumes[0].id,
+ ]
+ verifylist = [
+ ('force', False),
+ ('purge', True),
+ ('volumes', [volumes[0].id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.volumes_mock.delete.assert_called_once_with(
+ volumes[0].id, cascade=True)
+ self.assertIsNone(result)
+
+ def test_volume_delete_with_force(self):
+ volumes = self.setup_volumes_mock(count=1)
+
+ arglist = [
+ '--force',
+ volumes[0].id,
+ ]
+ verifylist = [
+ ('force', True),
+ ('purge', False),
+ ('volumes', [volumes[0].id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.volumes_mock.force_delete.assert_called_once_with(volumes[0].id)
+ self.assertIsNone(result)
+
+
+class TestVolumeList(TestVolume):
+
+ project = identity_fakes.FakeProject.create_one_project()
+ user = identity_fakes.FakeUser.create_one_user()
+
+ columns = [
+ 'ID',
+ 'Display Name',
+ 'Status',
+ 'Size',
+ 'Attached to',
+ ]
+
+ def setUp(self):
+ super(TestVolumeList, self).setUp()
+
+ self.mock_volume = volume_fakes.FakeVolume.create_one_volume()
+ self.volumes_mock.list.return_value = [self.mock_volume]
+
+ self.users_mock.get.return_value = self.user
+
+ self.projects_mock.get.return_value = self.project
+
+ # Get the command object to test
+ self.cmd = volume.ListVolume(self.app, None)
+
+ def test_volume_list_no_options(self):
+ arglist = []
+ verifylist = [
+ ('long', False),
+ ('all_projects', False),
+ ('name', None),
+ ('status', None),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+
+ server = self.mock_volume.attachments[0]['server_id']
+ device = self.mock_volume.attachments[0]['device']
+ msg = 'Attached to %s on %s ' % (server, device)
+ datalist = ((
+ self.mock_volume.id,
+ self.mock_volume.name,
+ self.mock_volume.status,
+ self.mock_volume.size,
+ msg,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_volume_list_project(self):
+ arglist = [
+ '--project', self.project.name,
+ ]
+ verifylist = [
+ ('project', self.project.name),
+ ('long', False),
+ ('all_projects', False),
+ ('status', None),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+
+ server = self.mock_volume.attachments[0]['server_id']
+ device = self.mock_volume.attachments[0]['device']
+ msg = 'Attached to %s on %s ' % (server, device)
+ datalist = ((
+ self.mock_volume.id,
+ self.mock_volume.name,
+ self.mock_volume.status,
+ self.mock_volume.size,
+ msg,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_volume_list_project_domain(self):
+ arglist = [
+ '--project', self.project.name,
+ '--project-domain', self.project.domain_id,
+ ]
+ verifylist = [
+ ('project', self.project.name),
+ ('project_domain', self.project.domain_id),
+ ('long', False),
+ ('all_projects', False),
+ ('status', None),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+
+ server = self.mock_volume.attachments[0]['server_id']
+ device = self.mock_volume.attachments[0]['device']
+ msg = 'Attached to %s on %s ' % (server, device)
+ datalist = ((
+ self.mock_volume.id,
+ self.mock_volume.name,
+ self.mock_volume.status,
+ self.mock_volume.size,
+ msg,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_volume_list_user(self):
+ arglist = [
+ '--user', self.user.name,
+ ]
+ verifylist = [
+ ('user', self.user.name),
+ ('long', False),
+ ('all_projects', False),
+ ('status', None),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+ server = self.mock_volume.attachments[0]['server_id']
+ device = self.mock_volume.attachments[0]['device']
+ msg = 'Attached to %s on %s ' % (server, device)
+ datalist = ((
+ self.mock_volume.id,
+ self.mock_volume.name,
+ self.mock_volume.status,
+ self.mock_volume.size,
+ msg,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_volume_list_user_domain(self):
+ arglist = [
+ '--user', self.user.name,
+ '--user-domain', self.user.domain_id,
+ ]
+ verifylist = [
+ ('user', self.user.name),
+ ('user_domain', self.user.domain_id),
+ ('long', False),
+ ('all_projects', False),
+ ('status', None),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+
+ server = self.mock_volume.attachments[0]['server_id']
+ device = self.mock_volume.attachments[0]['device']
+ msg = 'Attached to %s on %s ' % (server, device)
+ datalist = ((
+ self.mock_volume.id,
+ self.mock_volume.name,
+ self.mock_volume.status,
+ self.mock_volume.size,
+ msg,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_volume_list_name(self):
+ arglist = [
+ '--name', self.mock_volume.name,
+ ]
+ verifylist = [
+ ('long', False),
+ ('all_projects', False),
+ ('name', self.mock_volume.name),
+ ('status', None),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+
+ server = self.mock_volume.attachments[0]['server_id']
+ device = self.mock_volume.attachments[0]['device']
+ msg = 'Attached to %s on %s ' % (server, device)
+ datalist = ((
+ self.mock_volume.id,
+ self.mock_volume.name,
+ self.mock_volume.status,
+ self.mock_volume.size,
+ msg,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_volume_list_status(self):
+ arglist = [
+ '--status', self.mock_volume.status,
+ ]
+ verifylist = [
+ ('long', False),
+ ('all_projects', False),
+ ('name', None),
+ ('status', self.mock_volume.status),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+
+ server = self.mock_volume.attachments[0]['server_id']
+ device = self.mock_volume.attachments[0]['device']
+ msg = 'Attached to %s on %s ' % (server, device)
+ datalist = ((
+ self.mock_volume.id,
+ self.mock_volume.name,
+ self.mock_volume.status,
+ self.mock_volume.size,
+ msg,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_volume_list_all_projects(self):
+ arglist = [
+ '--all-projects',
+ ]
+ verifylist = [
+ ('long', False),
+ ('all_projects', True),
+ ('name', None),
+ ('status', None),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.columns, columns)
+
+ server = self.mock_volume.attachments[0]['server_id']
+ device = self.mock_volume.attachments[0]['device']
+ msg = 'Attached to %s on %s ' % (server, device)
+ datalist = ((
+ self.mock_volume.id,
+ self.mock_volume.name,
+ self.mock_volume.status,
+ self.mock_volume.size,
+ msg,
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+ def test_volume_list_long(self):
+ arglist = [
+ '--long',
+ ]
+ verifylist = [
+ ('long', True),
+ ('all_projects', False),
+ ('name', None),
+ ('status', None),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ collist = [
+ 'ID',
+ 'Display Name',
+ 'Status',
+ 'Size',
+ 'Type',
+ 'Bootable',
+ 'Attached to',
+ 'Properties',
+ ]
+ self.assertEqual(collist, columns)
+
+ server = self.mock_volume.attachments[0]['server_id']
+ device = self.mock_volume.attachments[0]['device']
+ msg = 'Attached to %s on %s ' % (server, device)
+ datalist = ((
+ self.mock_volume.id,
+ self.mock_volume.name,
+ self.mock_volume.status,
+ self.mock_volume.size,
+ self.mock_volume.volume_type,
+ self.mock_volume.bootable,
+ msg,
+ utils.format_dict(self.mock_volume.metadata),
+ ), )
+ self.assertEqual(datalist, tuple(data))
+
+
+class TestVolumeSet(TestVolume):
+
+ def setUp(self):
+ super(TestVolumeSet, self).setUp()
+
+ self.new_volume = volume_fakes.FakeVolume.create_one_volume()
+ self.volumes_mock.get.return_value = self.new_volume
+
+ # Get the command object to test
+ self.cmd = volume.SetVolume(self.app, None)
+
+ def test_volume_set_image_property(self):
+ arglist = [
+ '--image-property', 'Alpha=a',
+ '--image-property', 'Beta=b',
+ self.new_volume.id,
+ ]
+ verifylist = [
+ ('image_property', {'Alpha': 'a', 'Beta': 'b'}),
+ ('volume', self.new_volume.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns nothing
+ self.cmd.take_action(parsed_args)
+ self.volumes_mock.set_image_metadata.assert_called_with(
+ self.new_volume.id, parsed_args.image_property)
+
+ def test_volume_set_state(self):
+ arglist = [
+ '--state', 'error',
+ self.new_volume.id
+ ]
+ verifylist = [
+ ('state', 'error'),
+ ('volume', self.new_volume.id)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.volumes_mock.reset_state.assert_called_with(
+ self.new_volume.id, 'error')
+ self.assertIsNone(result)
+
+ def test_volume_set_state_failed(self):
+ self.volumes_mock.reset_state.side_effect = exceptions.CommandError()
+ arglist = [
+ '--state', 'error',
+ self.new_volume.id
+ ]
+ verifylist = [
+ ('state', 'error'),
+ ('volume', self.new_volume.id)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('One or more of the set operations failed',
+ str(e))
+ self.volumes_mock.reset_state.assert_called_with(
+ self.new_volume.id, 'error')
+
+
+class TestVolumeShow(TestVolume):
+
+ def setUp(self):
+ super(TestVolumeShow, self).setUp()
+
+ self._volume = volume_fakes.FakeVolume.create_one_volume()
+ self.volumes_mock.get.return_value = self._volume
+ # Get the command object to test
+ self.cmd = volume.ShowVolume(self.app, None)
+
+ def test_volume_show(self):
+ arglist = [
+ self._volume.id
+ ]
+ verifylist = [
+ ("volume", self._volume.id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ self.volumes_mock.get.assert_called_with(self._volume.id)
+
+ self.assertEqual(
+ volume_fakes.FakeVolume.get_volume_columns(self._volume),
+ columns)
+
+ self.assertEqual(
+ volume_fakes.FakeVolume.get_volume_data(self._volume),
+ data)
+
+
+class TestVolumeUnset(TestVolume):
+
+ def setUp(self):
+ super(TestVolumeUnset, self).setUp()
+
+ self.new_volume = volume_fakes.FakeVolume.create_one_volume()
+ self.volumes_mock.get.return_value = self.new_volume
+
+ # Get the command object to set property
+ self.cmd_set = volume.SetVolume(self.app, None)
+
+ # Get the command object to unset property
+ self.cmd_unset = volume.UnsetVolume(self.app, None)
+
+ def test_volume_unset_image_property(self):
+
+ # Arguments for setting image properties
+ arglist = [
+ '--image-property', 'Alpha=a',
+ '--image-property', 'Beta=b',
+ self.new_volume.id,
+ ]
+ verifylist = [
+ ('image_property', {'Alpha': 'a', 'Beta': 'b'}),
+ ('volume', self.new_volume.id),
+ ]
+ parsed_args = self.check_parser(self.cmd_set, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns nothing
+ self.cmd_set.take_action(parsed_args)
+
+ # Arguments for unsetting image properties
+ arglist_unset = [
+ '--image-property', 'Alpha',
+ self.new_volume.id,
+ ]
+ verifylist_unset = [
+ ('image_property', ['Alpha']),
+ ('volume', self.new_volume.id),
+ ]
+ parsed_args_unset = self.check_parser(self.cmd_unset,
+ arglist_unset,
+ verifylist_unset)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns nothing
+ self.cmd_unset.take_action(parsed_args_unset)
+
+ self.volumes_mock.delete_image_metadata.assert_called_with(
+ self.new_volume.id, parsed_args_unset.image_property)