Ian Cordasco 683f342506 Make column ordering consistent and predictable
This changes how we sort columns in listings and how we display the
column headings. The default columns are now stored as lists so that
they are the same from run to run. This simplifies some of the logic in
the shell modules as well. Instead of keeping static mappings of
attributes to column headings, we now use some simple python logic, to
title case the columns.

This commit covers:

- cell-* commands
- cloud-* commands
- host-* commands
- project-* commands
- region-* commands

Finally, we noticed that the cloud-list and region-list commands were
behaving differently from the rest of the -list commands. This
unifies the interface to add the --detail flag.

Closes-bug: #1659103
Closes-bug: #1659427
Closes-bug: #1668221
Change-Id: If5906780e501c7b9ba93ecf54a7bcf6db5ddfa1c
2017-03-03 10:25:53 -06:00

273 lines
9.5 KiB
Python

# -*- 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 clouds resource."""
import mock
from cratonclient import exceptions
from cratonclient.shell.v1 import clouds_shell
from cratonclient.tests.unit.shell import base
class TestDoCloudShow(base.TestShellCommandUsingPrintDict):
"""Unit tests for the cloud-show command."""
def test_prints_cloud_data(self):
"""Verify we print the data for the cloud."""
args = self.args_for(id=1234)
clouds_shell.do_cloud_show(self.craton_client, args)
self.craton_client.clouds.get.assert_called_once_with(1234)
self.formatter.configure.assert_called_once_with(wrap=72)
self.assertEqual(1, self.formatter.handle.call_count)
class TestDoCloudCreate(base.TestShellCommandUsingPrintDict):
"""Unit tests for the cloud-create command."""
def args_for(self, **kwargs):
"""Generate arguments for cloud-create."""
kwargs.setdefault('name', 'New cloud')
kwargs.setdefault('note', None)
return super(TestDoCloudCreate, self).args_for(**kwargs)
def test_accepts_only_required_arguments(self):
"""Verify operation with only --name provided."""
args = self.args_for()
clouds_shell.do_cloud_create(self.craton_client, args)
self.craton_client.clouds.create.assert_called_once_with(
name='New cloud',
)
self.formatter.configure.assert_called_once_with(wrap=72)
self.assertEqual(1, self.formatter.handle.call_count)
def test_accepts_optional_arguments(self):
"""Verify operation with --note passed as well."""
args = self.args_for(note='This is a note')
clouds_shell.do_cloud_create(self.craton_client, args)
self.craton_client.clouds.create.assert_called_once_with(
name='New cloud',
note='This is a note',
)
self.formatter.configure.assert_called_once_with(wrap=72)
self.assertEqual(1, self.formatter.handle.call_count)
class TestDoCloudUpdate(base.TestShellCommandUsingPrintDict):
"""Unit tests for cloud-update command."""
def args_for(self, **kwargs):
"""Generate arguments for cloud-update."""
kwargs.setdefault('id', 12345)
kwargs.setdefault('name', None)
kwargs.setdefault('note', None)
return super(TestDoCloudUpdate, self).args_for(**kwargs)
def test_nothing_to_update_raises_error(self):
"""Verify specifying nothing raises a CommandError."""
args = self.args_for()
self.assertRaisesCommandErrorWith(
clouds_shell.do_cloud_update,
args,
)
self.assertFalse(self.craton_client.clouds.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')
clouds_shell.do_cloud_update(self.craton_client, args)
self.craton_client.clouds.update.assert_called_once_with(
12345,
name='A New Name',
)
self.formatter.configure.assert_called_once_with(wrap=72)
self.assertEqual(1, self.formatter.handle.call_count)
def test_note_is_updated(self):
"""Verify the note attribute is updated."""
args = self.args_for(note='A New Note')
clouds_shell.do_cloud_update(self.craton_client, args)
self.craton_client.clouds.update.assert_called_once_with(
12345,
note='A New Note',
)
self.formatter.configure.assert_called_once_with(wrap=72)
self.assertEqual(1, self.formatter.handle.call_count)
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',
)
clouds_shell.do_cloud_update(self.craton_client, args)
self.craton_client.clouds.update.assert_called_once_with(
12345,
note='A New Note',
name='A New Name',
)
self.formatter.configure.assert_called_once_with(wrap=72)
self.assertEqual(1, self.formatter.handle.call_count)
class TestDoCloudDelete(base.TestShellCommand):
"""Unit tests for the cloud-delete command."""
def setUp(self):
"""Mock the print function."""
super(TestDoCloudDelete, self).setUp()
self.print_mock = mock.patch(
'cratonclient.shell.v1.clouds_shell.print'
)
self.print_func = self.print_mock.start()
def tearDown(self):
"""Clean up our print function mock."""
super(TestDoCloudDelete, self).tearDown()
self.print_mock.stop()
def args_for(self, **kwargs):
"""Generate args for the cloud-delete command."""
kwargs.setdefault('id', 123456)
return super(TestDoCloudDelete, self).args_for(**kwargs)
def test_successful(self):
"""Verify successful deletion."""
self.craton_client.clouds.delete.return_value = True
args = self.args_for()
clouds_shell.do_cloud_delete(self.craton_client, args)
self.craton_client.clouds.delete.assert_called_once_with(123456)
self.print_func.assert_called_once_with(
'Cloud 123456 was successfully deleted.'
)
def test_failed(self):
"""Verify failed deletion."""
self.craton_client.clouds.delete.return_value = False
args = self.args_for()
clouds_shell.do_cloud_delete(self.craton_client, args)
self.craton_client.clouds.delete.assert_called_once_with(123456)
self.print_func.assert_called_once_with(
'Cloud 123456 was not deleted.'
)
def test_failed_with_exception(self):
"""Verify we raise a CommandError on client exceptions."""
self.craton_client.clouds.delete.side_effect = exceptions.NotFound
args = self.args_for()
self.assertRaisesCommandErrorWith(clouds_shell.do_cloud_delete, args)
self.craton_client.clouds.delete.assert_called_once_with(123456)
self.assertFalse(self.print_func.called)
class TestDoCloudList(base.TestShellCommandUsingPrintList):
"""Test cloud-list command."""
def args_for(self, **kwargs):
"""Generate the default argument list for cloud-list."""
kwargs.setdefault('detail', False)
kwargs.setdefault('limit', None)
kwargs.setdefault('fields', clouds_shell.DEFAULT_CLOUD_FIELDS)
kwargs.setdefault('marker', None)
kwargs.setdefault('all', False)
return super(TestDoCloudList, self).args_for(**kwargs)
def test_with_defaults(self):
"""Test cloud-list with default values."""
args = self.args_for()
clouds_shell.do_cloud_list(self.craton_client, args)
self.assertFieldsEqualTo(clouds_shell.DEFAULT_CLOUD_FIELDS)
def test_negative_limit(self):
"""Ensure we raise an exception for negative limits."""
args = self.args_for(limit=-1)
self.assertRaisesCommandErrorWith(clouds_shell.do_cloud_list, args)
def test_positive_limit(self):
"""Verify that we pass positive limits to the call to list."""
args = self.args_for(limit=5)
clouds_shell.do_cloud_list(self.craton_client, args)
self.craton_client.clouds.list.assert_called_once_with(
limit=5,
marker=None,
autopaginate=False,
)
self.assertFieldsEqualTo(clouds_shell.DEFAULT_CLOUD_FIELDS)
def test_fields(self):
"""Verify that we print out specific fields."""
args = self.args_for(fields=['id', 'name', 'note'])
clouds_shell.do_cloud_list(self.craton_client, args)
self.assertFieldsEqualTo(['id', 'name', 'note'])
def test_invalid_fields(self):
"""Verify that we error out with invalid fields."""
args = self.args_for(fields=['uuid', 'not-name', 'nate'])
self.assertRaisesCommandErrorWith(clouds_shell.do_cloud_list, args)
self.assertNothingWasCalled()
def test_autopagination(self):
"""Verify autopagination is controlled by --all."""
args = self.args_for(all=True)
clouds_shell.do_cloud_list(self.craton_client, args)
self.craton_client.clouds.list.assert_called_once_with(
limit=100,
marker=None,
autopaginate=True,
)
def test_autopagination_overrides_limit(self):
"""Verify --all overrides --limit."""
args = self.args_for(all=True, limit=35)
clouds_shell.do_cloud_list(self.craton_client, args)
self.craton_client.clouds.list.assert_called_once_with(
limit=100,
marker=None,
autopaginate=True,
)
def test_marker_pass_through(self):
"""Verify we pass our marker through to the client."""
args = self.args_for(marker=31)
clouds_shell.do_cloud_list(self.craton_client, args)
self.craton_client.clouds.list.assert_called_once_with(
marker=31,
autopaginate=False,
)