summaryrefslogtreecommitdiff
path: root/openstackclient/tests
diff options
context:
space:
mode:
authorDean Troyer <dtroyer@gmail.com>2013-07-03 16:47:40 -0500
committerDean Troyer <dtroyer@gmail.com>2013-08-16 14:35:46 -0500
commit493339d4da6b56f46416fff583ff6cc7748570ec (patch)
tree847fe6214daca6548d41d402d89b92e618173991 /openstackclient/tests
parent93612bbf53500bfeace7460e7cb317ed0073a6d1 (diff)
downloadpython-openstackclient-493339d4da6b56f46416fff583ff6cc7748570ec.tar.gz
Add Identity v2 project tests
* establish the the form of cliff command classes * implement some common fake objects * implement Identity command tests for v2 project * fix stdout/stderr capture Also re-work the project create and set commands for exclusive options (--enable|--disable) to actually behave properly. Yay tests! Change-Id: Icbb313db544c1f8dd3c9af7709971838b5a4d115
Diffstat (limited to 'openstackclient/tests')
-rw-r--r--openstackclient/tests/fakes.py62
-rw-r--r--openstackclient/tests/identity/__init__.py2
-rw-r--r--openstackclient/tests/identity/fakes.py40
-rw-r--r--openstackclient/tests/identity/v2_0/__init__.py14
-rw-r--r--openstackclient/tests/identity/v2_0/test_projects.py355
-rw-r--r--openstackclient/tests/utils.py34
6 files changed, 501 insertions, 6 deletions
diff --git a/openstackclient/tests/fakes.py b/openstackclient/tests/fakes.py
new file mode 100644
index 00000000..d0cd4a9f
--- /dev/null
+++ b/openstackclient/tests/fakes.py
@@ -0,0 +1,62 @@
+# 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 sys
+
+
+class FakeStdout:
+ 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 FakeApp(object):
+ def __init__(self, _stdout):
+ self.stdout = _stdout
+ self.client_manager = None
+ self.stdin = sys.stdin
+ self.stdout = _stdout or sys.stdout
+ self.stderr = sys.stderr
+
+
+class FakeClientManager(object):
+ def __init__(self):
+ pass
+
+
+class FakeResource(object):
+ def __init__(self, manager, info, loaded=False):
+ self.manager = manager
+ self._info = info
+ self._add_details(info)
+ self._loaded = loaded
+
+ def _add_details(self, info):
+ for (k, v) in info.iteritems():
+ setattr(self, k, v)
+
+ 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)
diff --git a/openstackclient/tests/identity/__init__.py b/openstackclient/tests/identity/__init__.py
index ebf59b32..c534c012 100644
--- a/openstackclient/tests/identity/__init__.py
+++ b/openstackclient/tests/identity/__init__.py
@@ -1,4 +1,4 @@
-# Copyright 2013 OpenStack, LLC.
+# 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
diff --git a/openstackclient/tests/identity/fakes.py b/openstackclient/tests/identity/fakes.py
new file mode 100644
index 00000000..b1e385e2
--- /dev/null
+++ b/openstackclient/tests/identity/fakes.py
@@ -0,0 +1,40 @@
+# 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 import fakes
+
+
+class FakeIdentityv2Client(object):
+ def __init__(self, **kwargs):
+ self.tenants = mock.Mock()
+ self.tenants.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.auth_tenant_id = 'fake-tenant'
+ self.auth_user_id = 'fake-user'
+
+
+class FakeIdentityv3Client(object):
+ def __init__(self, **kwargs):
+ self.domains = mock.Mock()
+ self.domains.resource_class = fakes.FakeResource(None, {})
+ self.projects = mock.Mock()
+ self.projects.resource_class = fakes.FakeResource(None, {})
+ self.users = mock.Mock()
+ self.users.resource_class = fakes.FakeResource(None, {})
diff --git a/openstackclient/tests/identity/v2_0/__init__.py b/openstackclient/tests/identity/v2_0/__init__.py
new file mode 100644
index 00000000..c534c012
--- /dev/null
+++ b/openstackclient/tests/identity/v2_0/__init__.py
@@ -0,0 +1,14 @@
+# 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.
+#
diff --git a/openstackclient/tests/identity/v2_0/test_projects.py b/openstackclient/tests/identity/v2_0/test_projects.py
new file mode 100644
index 00000000..c937028f
--- /dev/null
+++ b/openstackclient/tests/identity/v2_0/test_projects.py
@@ -0,0 +1,355 @@
+# 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.v2_0 import project
+from openstackclient.tests import fakes
+from openstackclient.tests.identity import fakes as identity_fakes
+from openstackclient.tests import utils
+
+
+IDENTITY_API_VERSION = "2.0"
+
+user_id = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'
+user_name = 'paul'
+user_description = 'Sir Paul'
+
+project_id = '8-9-64'
+project_name = 'beatles'
+project_description = 'Fab Four'
+
+USER = {
+ 'id': user_id,
+ 'name': user_name,
+ 'tenantId': project_id,
+}
+
+PROJECT = {
+ 'id': project_id,
+ 'name': project_name,
+ 'description': project_description,
+ 'enabled': True,
+}
+
+
+class TestProject(utils.TestCommand):
+
+ def setUp(self):
+ super(TestProject, self).setUp()
+ self.app.client_manager.identity = \
+ identity_fakes.FakeIdentityv2Client()
+
+ # Get a shortcut to the TenantManager Mock
+ self.projects_mock = self.app.client_manager.identity.tenants
+
+
+class TestProjectCreate(TestProject):
+
+ def setUp(self):
+ super(TestProjectCreate, self).setUp()
+
+ self.projects_mock.create.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(PROJECT),
+ loaded=True,
+ )
+
+ # Get the command object to test
+ self.cmd = project.CreateProject(self.app, None)
+
+ def test_project_create_no_options(self):
+ arglist = [project_name]
+ verifylist = [
+ ('project_name', project_name),
+ ('enable', False),
+ ('disable', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # DisplayCommandBase.take_action() returns two tuples
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'description': None,
+ 'enabled': True,
+ }
+ self.projects_mock.create.assert_called_with(project_name, **kwargs)
+
+ collist = ('description', 'enabled', 'id', 'name')
+ self.assertEqual(columns, collist)
+ datalist = (project_description, True, project_id, project_name)
+ self.assertEqual(data, datalist)
+
+ def test_project_create_description(self):
+ arglist = ['--description', 'new desc', project_name]
+ verifylist = [('description', 'new desc')]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # DisplayCommandBase.take_action() returns two tuples
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'description': 'new desc',
+ 'enabled': True,
+ }
+ self.projects_mock.create.assert_called_with(project_name, **kwargs)
+
+ collist = ('description', 'enabled', 'id', 'name')
+ self.assertEqual(columns, collist)
+ datalist = (project_description, True, project_id, project_name)
+ self.assertEqual(data, datalist)
+
+ def test_project_create_enable(self):
+ arglist = ['--enable', project_name]
+ verifylist = [('enable', True), ('disable', False)]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # DisplayCommandBase.take_action() returns two tuples
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'description': None,
+ 'enabled': True,
+ }
+ self.projects_mock.create.assert_called_with(project_name, **kwargs)
+
+ collist = ('description', 'enabled', 'id', 'name')
+ self.assertEqual(columns, collist)
+ datalist = (project_description, True, project_id, project_name)
+ self.assertEqual(data, datalist)
+
+ def test_project_create_disable(self):
+ arglist = ['--disable', project_name]
+ verifylist = [('enable', False), ('disable', True)]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # DisplayCommandBase.take_action() returns two tuples
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'description': None,
+ 'enabled': False,
+ }
+ self.projects_mock.create.assert_called_with(project_name, **kwargs)
+
+ collist = ('description', 'enabled', 'id', 'name')
+ self.assertEqual(columns, collist)
+ datalist = (project_description, True, project_id, project_name)
+ self.assertEqual(data, datalist)
+
+
+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 = fakes.FakeResource(
+ None,
+ copy.deepcopy(PROJECT),
+ loaded=True,
+ )
+ 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 = [user_id]
+ verifylist = [('project', user_id)]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.run(parsed_args)
+ self.assertEqual(result, 0)
+
+ self.projects_mock.delete.assert_called_with(project_id)
+
+
+class TestProjectList(TestProject):
+
+ def setUp(self):
+ super(TestProjectList, self).setUp()
+
+ self.projects_mock.list.return_value = [
+ fakes.FakeResource(
+ None,
+ copy.deepcopy(PROJECT),
+ loaded=True,
+ ),
+ ]
+
+ # 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)
+
+ # DisplayCommandBase.take_action() returns two tuples
+ columns, data = self.cmd.take_action(parsed_args)
+ self.projects_mock.list.assert_called_with()
+
+ collist = ('ID', 'Name')
+ self.assertEqual(columns, collist)
+ datalist = ((project_id, project_name), )
+ self.assertEqual(tuple(data), datalist)
+
+ def test_project_list_long(self):
+ arglist = ['--long']
+ verifylist = [('long', True)]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # DisplayCommandBase.take_action() returns two tuples
+ columns, data = self.cmd.take_action(parsed_args)
+ self.projects_mock.list.assert_called_with()
+
+ collist = ('ID', 'Name', 'Description', 'Enabled')
+ self.assertEqual(columns, collist)
+ datalist = ((project_id, project_name, project_description, True), )
+ self.assertEqual(tuple(data), datalist)
+
+
+class TestProjectSet(TestProject):
+
+ def setUp(self):
+ super(TestProjectSet, self).setUp()
+
+ self.projects_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(PROJECT),
+ loaded=True,
+ )
+
+ # Get the command object to test
+ self.cmd = project.SetProject(self.app, None)
+
+ def test_project_set_no_options(self):
+ arglist = [project_name]
+ verifylist = [
+ ('project', project_name),
+ ('enable', False),
+ ('disable', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.run(parsed_args)
+ self.assertEqual(result, 0)
+
+ # Set expected values
+ kwargs = {
+ 'description': project_description,
+ 'enabled': True,
+ 'tenant_name': project_name,
+ }
+ self.projects_mock.update.assert_called_with(project_id, **kwargs)
+
+ def test_project_set_name(self):
+ arglist = ['--name', 'qwerty', project_name]
+ verifylist = [('name', 'qwerty')]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.run(parsed_args)
+ self.assertEqual(result, 0)
+
+ # Set expected values
+ kwargs = {
+ 'description': project_description,
+ 'enabled': True,
+ 'tenant_name': 'qwerty',
+ }
+ self.projects_mock.update.assert_called_with(project_id, **kwargs)
+
+ def test_project_set_description(self):
+ arglist = ['--description', 'new desc', project_name]
+ verifylist = [('description', 'new desc')]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.run(parsed_args)
+ self.assertEqual(result, 0)
+
+ # Set expected values
+ kwargs = {
+ 'description': 'new desc',
+ 'enabled': True,
+ 'tenant_name': project_name,
+ }
+ self.projects_mock.update.assert_called_with(project_id, **kwargs)
+
+ def test_project_set_enable(self):
+ arglist = ['--enable', project_name]
+ verifylist = [('enable', True), ('disable', False)]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.run(parsed_args)
+ self.assertEqual(result, 0)
+
+ # Set expected values
+ kwargs = {
+ 'description': project_description,
+ 'enabled': True,
+ 'tenant_name': project_name,
+ }
+ self.projects_mock.update.assert_called_with(project_id, **kwargs)
+
+ def test_project_set_disable(self):
+ arglist = ['--disable', project_name]
+ verifylist = [('enable', False), ('disable', True)]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.run(parsed_args)
+ self.assertEqual(result, 0)
+
+ # Set expected values
+ kwargs = {
+ 'description': project_description,
+ 'enabled': False,
+ 'tenant_name': project_name,
+ }
+ self.projects_mock.update.assert_called_with(project_id, **kwargs)
+
+
+class TestProjectShow(TestProject):
+
+ def setUp(self):
+ super(TestProjectShow, self).setUp()
+
+ self.projects_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(PROJECT),
+ loaded=True,
+ )
+
+ # Get the command object to test
+ self.cmd = project.ShowProject(self.app, None)
+
+ def test_project_show(self):
+ arglist = [user_id]
+ verifylist = [('project', user_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.projects_mock.get.assert_called_with(user_id)
+
+ collist = ('description', 'enabled', 'id', 'name')
+ self.assertEqual(columns, collist)
+ datalist = (project_description, True, project_id, project_name)
+ self.assertEqual(data, datalist)
diff --git a/openstackclient/tests/utils.py b/openstackclient/tests/utils.py
index 3e24ff4a..ff7d8a33 100644
--- a/openstackclient/tests/utils.py
+++ b/openstackclient/tests/utils.py
@@ -1,4 +1,5 @@
-# Copyright 2012-2013 OpenStack, LLC.
+# 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
@@ -19,18 +20,20 @@ import fixtures
import sys
import testtools
+from openstackclient.tests import fakes
+
class TestCase(testtools.TestCase):
def setUp(self):
testtools.TestCase.setUp(self)
- if (os.environ.get("OS_STDOUT_NOCAPTURE") == "True" and
- os.environ.get("OS_STDOUT_NOCAPTURE") == "1"):
+ 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_NOCAPTURE") == "True" and
- os.environ.get("OS_STDERR_NOCAPTURE") == "1"):
+ 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))
@@ -57,3 +60,24 @@ class TestCase(testtools.TestCase):
else:
standardMsg = '%r != %r' % (d1, d2)
self.fail(standardMsg)
+
+
+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.app = fakes.FakeApp(self.fake_stdout)
+ self.app.client_manager = fakes.FakeClientManager()
+
+ def check_parser(self, cmd, args, verify_args):
+ cmd_parser = cmd.get_parser('check_parser')
+ parsed_args = cmd_parser.parse_args(args)
+ for av in verify_args:
+ attr, value = av
+ if attr:
+ self.assertIn(attr, parsed_args)
+ self.assertEqual(getattr(parsed_args, attr), value)
+ return parsed_args