summaryrefslogtreecommitdiff
path: root/openstackclient/tests/unit
diff options
context:
space:
mode:
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)