From e89a10eb247341fc99d4abcdbb292e68a36f221e Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 7 Nov 2016 13:23:18 -0600 Subject: [PATCH] Add unit tests for region-* shell commands Change-Id: Id7a5418233f17baaa4e0d72ea1b3d26b4dc46783 --- cratonclient/shell/v1/regions_shell.py | 41 ++-- .../tests/integration/test_regions_shell.py | 5 +- .../tests/unit/shell/v1/test_regions_shell.py | 202 ++++++++++++++++++ 3 files changed, 230 insertions(+), 18 deletions(-) create mode 100644 cratonclient/tests/unit/shell/v1/test_regions_shell.py diff --git a/cratonclient/shell/v1/regions_shell.py b/cratonclient/shell/v1/regions_shell.py index e23492a..f3dac2f 100644 --- a/cratonclient/shell/v1/regions_shell.py +++ b/cratonclient/shell/v1/regions_shell.py @@ -10,9 +10,11 @@ # See the License for the specific language governing permissions and # limitations under the License. """Hosts resource and resource shell wrapper.""" +from __future__ import print_function from cratonclient.common import cliutils -from cratonclient.v1.regions import REGION_FIELDS as r_fields +from cratonclient import exceptions as exc +from cratonclient.v1 import regions @cliutils.arg('-n', '--name', @@ -24,10 +26,10 @@ from cratonclient.v1.regions import REGION_FIELDS as r_fields def do_region_create(cc, args): """Register a new region with the Craton service.""" fields = {k: v for (k, v) in vars(args).items() - if k in r_fields and not (v is None)} + if k in regions.REGION_FIELDS and not (v is None)} region = cc.regions.create(**fields) - data = {f: getattr(region, f, '') for f in r_fields} + data = {f: getattr(region, f, '') for f in regions.REGION_FIELDS} cliutils.print_dict(data, wrap=72) @@ -38,7 +40,7 @@ def do_region_create(cc, args): def do_region_show(cc, args): """Show detailed information about a region.""" region = cc.regions.get(args.id) - data = {f: getattr(region, f, '') for f in r_fields} + data = {f: getattr(region, f, '') for f in regions.REGION_FIELDS} cliutils.print_dict(data, wrap=72) @@ -49,19 +51,20 @@ def do_region_show(cc, args): @cliutils.arg('-n', '--name', metavar='', help='Name of the region.') -@cliutils.arg('-p', '--project', - dest='project_id', - metavar='', - type=int, - help='ID of the project that the region belongs to.') @cliutils.arg('--note', help='Note about the region.') def do_region_update(cc, args): """Update a region that is registered with the Craton service.""" fields = {k: v for (k, v) in vars(args).items() - if k in r_fields and not (v is None)} - region = cc.regions.update(**fields) - data = {f: getattr(region, f, '') for f in r_fields} + if k in regions.REGION_FIELDS and not (v is None)} + item_id = fields.pop('id') + if not fields: + raise exc.CommandError( + 'Nothing to update... Please specify one or more of --name, or ' + '--note' + ) + region = cc.regions.update(item_id, **fields) + data = {f: getattr(region, f, '') for f in regions.REGION_FIELDS} cliutils.print_dict(data, wrap=72) @@ -71,6 +74,14 @@ def do_region_update(cc, args): help='ID of the region.') def do_region_delete(cc, args): """Delete a region that is registered with the Craton service.""" - response = cc.regions.delete(args.id) - print("Region {0} was {1}successfully deleted.". - format(args.id, '' if response else 'un')) + try: + response = cc.regions.delete(args.id) + except exc.ClientException as client_exc: + raise exc.CommandError( + 'Failed to delete region {} due to "{}:{}"'.format( + args.id, client_exc.__class__, str(client_exc), + ) + ) + else: + print("Region {0} was {1} deleted.". + format(args.id, 'successfully' if response else 'not')) diff --git a/cratonclient/tests/integration/test_regions_shell.py b/cratonclient/tests/integration/test_regions_shell.py index 95ebc01..489e063 100644 --- a/cratonclient/tests/integration/test_regions_shell.py +++ b/cratonclient/tests/integration/test_regions_shell.py @@ -137,7 +137,7 @@ class TestRegionsShell(base.ShellTestCase): valid_input = Namespace(id=1, name='mock_region') regions_shell.do_region_update(client, valid_input) - mock_update.assert_called_once_with(**vars(valid_input)) + mock_update.assert_called_once_with(1, name='mock_region') @mock.patch('cratonclient.v1.regions.RegionManager.update') def test_do_region_update_ignores_unknown_fields(self, mock_update): @@ -150,5 +150,4 @@ class TestRegionsShell(base.ShellTestCase): name='mock_region', invalid=True) regions_shell.do_region_update(client, invalid_input) - vars(invalid_input).pop('invalid') - mock_update.assert_called_once_with(**vars(invalid_input)) + mock_update.assert_called_once_with(1, name='mock_region') diff --git a/cratonclient/tests/unit/shell/v1/test_regions_shell.py b/cratonclient/tests/unit/shell/v1/test_regions_shell.py new file mode 100644 index 0000000..38349d7 --- /dev/null +++ b/cratonclient/tests/unit/shell/v1/test_regions_shell.py @@ -0,0 +1,202 @@ +# -*- coding: utf-8 -*- + +# 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. +"""Tests for the shell functions for the regions resource.""" +import mock + +from cratonclient import exceptions +from cratonclient.shell.v1 import regions_shell +from cratonclient.tests.unit.shell import base +from cratonclient.v1 import regions + + +class TestDoRegionShow(base.TestShellCommandUsingPrintDict): + """Unit tests for the region-show command.""" + + def test_prints_region_data(self): + """Verify we print the data for the region.""" + args = self.args_for(id=1234) + + regions_shell.do_region_show(self.craton_client, args) + + self.craton_client.regions.get.assert_called_once_with(1234) + self.print_dict.assert_called_once_with( + {field: mock.ANY for field in regions.REGION_FIELDS}, + wrap=72, + ) + + +class TestDoRegionCreate(base.TestShellCommandUsingPrintDict): + """Unit tests for the region-create command.""" + + def args_for(self, **kwargs): + """Generate arguments for region-create.""" + kwargs.setdefault('name', 'New region') + kwargs.setdefault('note', None) + return super(TestDoRegionCreate, self).args_for(**kwargs) + + def test_accepts_only_required_arguments(self): + """Verify operation with only --name provided.""" + args = self.args_for() + + regions_shell.do_region_create(self.craton_client, args) + + self.craton_client.regions.create.assert_called_once_with( + name='New region', + ) + self.print_dict.assert_called_once_with( + {field: mock.ANY for field in regions.REGION_FIELDS}, + wrap=72, + ) + + def test_accepts_optional_arguments(self): + """Verify operation with --note passed as well.""" + args = self.args_for(note='This is a note') + + regions_shell.do_region_create(self.craton_client, args) + + self.craton_client.regions.create.assert_called_once_with( + name='New region', + note='This is a note', + ) + self.print_dict.assert_called_once_with( + {field: mock.ANY for field in regions.REGION_FIELDS}, + wrap=72, + ) + + +class TestDoRegionUpdate(base.TestShellCommandUsingPrintDict): + """Unit tests for region-update command.""" + + def args_for(self, **kwargs): + """Generate arguments for region-update.""" + kwargs.setdefault('id', 12345) + kwargs.setdefault('name', None) + kwargs.setdefault('note', None) + return super(TestDoRegionUpdate, self).args_for(**kwargs) + + def test_nothing_to_update_raises_error(self): + """Verify specifying nothing raises a CommandError.""" + args = self.args_for() + + self.assertRaisesCommandErrorWith( + regions_shell.do_region_update, + args, + ) + self.assertFalse(self.craton_client.regions.update.called) + self.assertFalse(self.print_dict.called) + + def test_name_is_updated(self): + """Verify the name attribute update is sent.""" + args = self.args_for(name='A New Name') + + regions_shell.do_region_update(self.craton_client, args) + + self.craton_client.regions.update.assert_called_once_with( + 12345, + name='A New Name', + ) + self.print_dict.assert_called_once_with( + {field: mock.ANY for field in regions.REGION_FIELDS}, + wrap=72, + ) + + def test_note_is_updated(self): + """Verify the note attribute is updated.""" + args = self.args_for(note='A New Note') + + regions_shell.do_region_update(self.craton_client, args) + + self.craton_client.regions.update.assert_called_once_with( + 12345, + note='A New Note', + ) + self.print_dict.assert_called_once_with( + {field: mock.ANY for field in regions.REGION_FIELDS}, + wrap=72, + ) + + def test_everything_is_updated(self): + """Verify the note and name are updated.""" + args = self.args_for( + note='A New Note', + name='A New Name', + ) + + regions_shell.do_region_update(self.craton_client, args) + + self.craton_client.regions.update.assert_called_once_with( + 12345, + note='A New Note', + name='A New Name', + ) + self.print_dict.assert_called_once_with( + {field: mock.ANY for field in regions.REGION_FIELDS}, + wrap=72, + ) + + +class TestDoRegionDelete(base.TestShellCommand): + """Unit tests for the region-delete command.""" + + def setUp(self): + """Mock the print function.""" + super(TestDoRegionDelete, self).setUp() + self.print_mock = mock.patch( + 'cratonclient.shell.v1.regions_shell.print' + ) + self.print_func = self.print_mock.start() + + def tearDown(self): + """Clean up our print function mock.""" + super(TestDoRegionDelete, self).tearDown() + self.print_mock.stop() + + def args_for(self, **kwargs): + """Generate args for the region-delete command.""" + kwargs.setdefault('id', 123456) + return super(TestDoRegionDelete, self).args_for(**kwargs) + + def test_successful(self): + """Verify successful deletion.""" + self.craton_client.regions.delete.return_value = True + args = self.args_for() + + regions_shell.do_region_delete(self.craton_client, args) + + self.craton_client.regions.delete.assert_called_once_with(123456) + self.print_func.assert_called_once_with( + 'Region 123456 was successfully deleted.' + ) + + def test_failed(self): + """Verify failed deletion.""" + self.craton_client.regions.delete.return_value = False + args = self.args_for() + + regions_shell.do_region_delete(self.craton_client, args) + + self.craton_client.regions.delete.assert_called_once_with(123456) + self.print_func.assert_called_once_with( + 'Region 123456 was not deleted.' + ) + + def test_failed_with_exception(self): + """Verify we raise a CommandError on client exceptions.""" + self.craton_client.regions.delete.side_effect = exceptions.NotFound + args = self.args_for() + + self.assertRaisesCommandErrorWith(regions_shell.do_region_delete, args) + + self.craton_client.regions.delete.assert_called_once_with(123456) + self.assertFalse(self.print_func.called)