Add unit tests for host commands
As part of getting away from using calls to the shell in the tests, we will need code coverage of the commands library which will no longer be used when the shell is no longer called. This change is the first of serveral to provide unnit test coverage for commands/host. As a result of writing these tests, I needed to tweak a few things, some to make mocking possible, and fix some minor issues: - move delete confirmation prompt to its own method so it can be mocked. - remove extra space from failed Host check message - fix return code to 0 in Host setup, when the host is already setup. - in shell, move inventory check to a method so it can be mocked. Change-Id: I63cb1afd5313959a6fdda11e9c2b03317c60197a
This commit is contained in:
parent
5d8343a3b9
commit
8e960e4a2b
|
@ -40,12 +40,14 @@
|
|||
check:
|
||||
jobs:
|
||||
- openstack-tox-pep8
|
||||
- openstack-tox-py27
|
||||
- kollacli-tox-mypy
|
||||
- kollacli-tox-functional
|
||||
- kollacli-tox-functional-py35
|
||||
gate:
|
||||
jobs:
|
||||
- openstack-tox-pep8
|
||||
- openstack-tox-py27
|
||||
- kollacli-tox-mypy
|
||||
- kollacli-tox-functional
|
||||
- kollacli-tox-functional-py35
|
||||
|
|
|
@ -90,15 +90,10 @@ class HostDestroy(Command):
|
|||
if parsed_args.removeimages:
|
||||
remove_images = True
|
||||
|
||||
if include_data:
|
||||
question = ('This will delete all containers and data'
|
||||
', are you sure? (y/n)')
|
||||
answer = raw_input(question)
|
||||
while answer != 'y' and answer != 'n':
|
||||
answer = raw_input(question)
|
||||
if answer is 'n':
|
||||
LOG.info('Aborting destroy')
|
||||
return
|
||||
if include_data and not self._is_ok_to_delete_data():
|
||||
LOG.info('Aborting destroy')
|
||||
return
|
||||
|
||||
verbose_level = self.app.options.verbose_level
|
||||
|
||||
job = CLIENT.host_destroy(hostnames, destroy_type,
|
||||
|
@ -123,6 +118,14 @@ class HostDestroy(Command):
|
|||
except Exception as e:
|
||||
raise Exception(traceback.format_exc())
|
||||
|
||||
def _is_ok_to_delete_data(self):
|
||||
question = ('This will delete all containers and data'
|
||||
', are you sure? (y/n)')
|
||||
answer = raw_input(question)
|
||||
while answer != 'y' and answer != 'n':
|
||||
answer = raw_input(question)
|
||||
return True if answer == 'y' else False
|
||||
|
||||
|
||||
class HostRemove(Command):
|
||||
"""Remove host from openstack-kolla."""
|
||||
|
@ -231,7 +234,7 @@ class HostCheck(Command):
|
|||
status = u._('success')
|
||||
msg = ''
|
||||
if not info['success']:
|
||||
status = u._('failed- ')
|
||||
status = u._('failed-')
|
||||
msg = info['msg']
|
||||
all_ok = False
|
||||
LOG.info(u._('Host {host}: {sts} {msg}')
|
||||
|
@ -280,7 +283,7 @@ class HostSetup(Command):
|
|||
LOG.info(
|
||||
u._LI('Skipping setup of host ({host}) as '
|
||||
'ssh check is ok.').format(host=hostname))
|
||||
return True
|
||||
return 0
|
||||
|
||||
if parsed_args.insecure:
|
||||
password = parsed_args.insecure.strip()
|
||||
|
|
|
@ -41,7 +41,7 @@ class KollaCli(App):
|
|||
|
||||
inventory_path = os.path.join(get_kolla_cli_etc(),
|
||||
INVENTORY_PATH)
|
||||
if os.path.isfile(inventory_path) is False:
|
||||
if not self._is_inventory_present(inventory_path):
|
||||
err_string = u._(
|
||||
'Required file ({inventory}) does not exist.\n'
|
||||
'Please re-install the kollacli to '
|
||||
|
@ -57,6 +57,9 @@ class KollaCli(App):
|
|||
|
||||
self.dump_stack_trace = False
|
||||
|
||||
def _is_inventory_present(self, inventory_path):
|
||||
return os.path.isfile(inventory_path)
|
||||
|
||||
|
||||
def main(argv=sys.argv[1:]):
|
||||
shell = KollaCli()
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
# Copyright (c) 2018 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 testtools
|
||||
|
||||
from kolla_cli.api.host import Host
|
||||
from kolla_cli.common.ansible.job import AnsibleJob
|
||||
from kolla_cli import shell
|
||||
|
||||
|
||||
class KollaCliUnitTest(testtools.TestCase):
|
||||
|
||||
def run_cli_command(self, command_string):
|
||||
# return 0 if command succeeded, non-0 if failed
|
||||
args = command_string.split()
|
||||
return shell.main(args)
|
||||
|
||||
def get_fake_job(self):
|
||||
return AnsibleJob(None, None, None, None)
|
||||
|
||||
def get_fake_host(self, hostname='foo'):
|
||||
return Host(hostname)
|
|
@ -0,0 +1,225 @@
|
|||
# Copyright (c) 2018 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 kolla_cli.tests.unit.common import KollaCliUnitTest
|
||||
|
||||
|
||||
class TestUnit(KollaCliUnitTest):
|
||||
@mock.patch('kolla_cli.api.client.ClientApi.host_add')
|
||||
@mock.patch('kolla_cli.shell.KollaCli._is_inventory_present',
|
||||
return_value=True)
|
||||
def test_host_add(self, _, mock_add):
|
||||
hostname = 'foo'
|
||||
ret = self.run_cli_command('host add %s' % hostname)
|
||||
self.assertEqual(ret, 0)
|
||||
mock_add.assert_called_once_with([hostname])
|
||||
|
||||
@mock.patch('kolla_cli.api.client.ClientApi.host_remove')
|
||||
@mock.patch('kolla_cli.shell.KollaCli._is_inventory_present',
|
||||
return_value=True)
|
||||
def test_host_remove(self, _, mock_remove):
|
||||
hostname = 'foo'
|
||||
ret = self.run_cli_command('host remove %s' % hostname)
|
||||
self.assertEqual(ret, 0)
|
||||
mock_remove.assert_called_once_with([hostname])
|
||||
|
||||
@mock.patch('kolla_cli.api.client.ClientApi.host_get_all')
|
||||
@mock.patch('kolla_cli.api.client.ClientApi.host_get')
|
||||
@mock.patch('kolla_cli.shell.KollaCli._is_inventory_present',
|
||||
return_value=True)
|
||||
def test_host_list(self, _, mock_get, mock_get_all):
|
||||
# get all hosts
|
||||
mock_get_all.return_value = []
|
||||
ret = self.run_cli_command('host list')
|
||||
self.assertEqual(ret, 0)
|
||||
mock_get_all.assert_called_once_with()
|
||||
|
||||
# get a specific host
|
||||
hostname = 'foo'
|
||||
mock_get.return_value = []
|
||||
ret = self.run_cli_command('host list %s' % hostname)
|
||||
self.assertEqual(ret, 0)
|
||||
mock_get.assert_called_once_with([hostname])
|
||||
|
||||
@mock.patch('kolla_cli.commands.host.HostDestroy._is_ok_to_delete_data',
|
||||
return_value='y')
|
||||
@mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status')
|
||||
@mock.patch('kolla_cli.api.client.ClientApi.host_get_all')
|
||||
@mock.patch('kolla_cli.api.client.ClientApi.host_destroy')
|
||||
@mock.patch('kolla_cli.shell.KollaCli._is_inventory_present',
|
||||
return_value=True)
|
||||
def test_host_destroy(self, _, mock_destroy, mock_get_all,
|
||||
mock_get_status, mock_prompt):
|
||||
hostname = 'foo'
|
||||
mock_get_all.return_value = [self.get_fake_host(hostname)]
|
||||
mock_destroy.return_value = self.get_fake_job()
|
||||
mock_get_status.return_value = 0
|
||||
|
||||
# default destroy hostname
|
||||
ret = self.run_cli_command('host destroy %s' % hostname)
|
||||
self.assertEqual(ret, 0)
|
||||
mock_destroy.assert_called_once_with([hostname], 'kill', 1,
|
||||
False, False)
|
||||
# destroy all
|
||||
mock_destroy.reset_mock()
|
||||
ret = self.run_cli_command('host destroy all')
|
||||
self.assertEqual(ret, 0)
|
||||
mock_destroy.assert_called_once_with([hostname], 'kill', 1,
|
||||
False, False)
|
||||
# destroy --stop
|
||||
mock_destroy.reset_mock()
|
||||
ret = self.run_cli_command('host destroy %s --stop' % hostname)
|
||||
self.assertEqual(ret, 0)
|
||||
mock_destroy.assert_called_once_with([hostname], 'stop', 1,
|
||||
False, False)
|
||||
# destroy --includedata
|
||||
mock_destroy.reset_mock()
|
||||
ret = self.run_cli_command('host destroy %s --includedata' % hostname)
|
||||
self.assertEqual(ret, 0)
|
||||
mock_destroy.assert_called_once_with([hostname], 'kill', 1,
|
||||
True, False)
|
||||
|
||||
# destroy --removeimages
|
||||
mock_destroy.reset_mock()
|
||||
ret = self.run_cli_command('host destroy %s --removeimages'
|
||||
% hostname)
|
||||
self.assertEqual(ret, 0)
|
||||
mock_destroy.assert_called_once_with([hostname], 'kill', 1,
|
||||
False, True)
|
||||
|
||||
@mock.patch('kolla_cli.commands.host.LOG.info')
|
||||
@mock.patch('kolla_cli.api.client.ClientApi.host_get_all')
|
||||
@mock.patch('kolla_cli.api.client.ClientApi.host_ssh_check')
|
||||
@mock.patch('kolla_cli.shell.KollaCli._is_inventory_present',
|
||||
return_value=True)
|
||||
def test_host_ssh_check(self, _, mock_ssh_check, mock_get_all, mock_log):
|
||||
hostname = 'foo'
|
||||
check_ok_response = {hostname: {'success': True}}
|
||||
check_bad_response = {hostname: {'success': False, 'msg': 'FAILED'}}
|
||||
mock_get_all.return_value = [self.get_fake_host(hostname)]
|
||||
|
||||
# host check hostname (success)
|
||||
mock_ssh_check.return_value = check_ok_response
|
||||
ret = self.run_cli_command('host check %s' % hostname)
|
||||
self.assertEqual(ret, 0)
|
||||
mock_ssh_check.assert_called_once_with([hostname])
|
||||
mock_log.assert_called_once_with('Host %s: success ' % hostname)
|
||||
|
||||
# host check all (success)
|
||||
mock_ssh_check.reset_mock()
|
||||
mock_log.reset_mock()
|
||||
mock_ssh_check.return_value = check_ok_response
|
||||
ret = self.run_cli_command('host check all')
|
||||
self.assertEqual(ret, 0)
|
||||
mock_ssh_check.assert_called_once_with([hostname])
|
||||
mock_log.assert_called_once_with('Host %s: success ' % hostname)
|
||||
|
||||
# host check hostname (fail)
|
||||
mock_ssh_check.reset_mock()
|
||||
mock_log.reset_mock()
|
||||
mock_ssh_check.return_value = check_bad_response
|
||||
ret = self.run_cli_command('host check %s' % hostname)
|
||||
self.assertEqual(ret, 1)
|
||||
mock_ssh_check.assert_called_once_with([hostname])
|
||||
mock_log.assert_called_once_with('Host %s: failed- FAILED' % hostname)
|
||||
|
||||
@mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status')
|
||||
@mock.patch('kolla_cli.commands.host.ClientApi.host_precheck')
|
||||
@mock.patch('kolla_cli.api.client.ClientApi.host_get_all')
|
||||
@mock.patch('kolla_cli.shell.KollaCli._is_inventory_present',
|
||||
return_value=True)
|
||||
def test_host_precheck(self, _, mock_get_all, mock_precheck,
|
||||
mock_get_status):
|
||||
hostname = 'foo'
|
||||
mock_get_all.return_value = [self.get_fake_host(hostname)]
|
||||
|
||||
# host check hostname --predeploy (success)
|
||||
mock_precheck.return_value = self.get_fake_job()
|
||||
mock_get_status.return_value = 0
|
||||
ret = self.run_cli_command('host check %s --predeploy' % hostname)
|
||||
self.assertEqual(ret, 0)
|
||||
mock_precheck.assert_called_once_with([hostname], 1)
|
||||
|
||||
# host check hostname --predeploy (fail)
|
||||
mock_precheck.reset_mock()
|
||||
mock_get_status.return_value = 1
|
||||
ret = self.run_cli_command('host check %s --predeploy' % hostname)
|
||||
self.assertEqual(ret, 1)
|
||||
mock_precheck.assert_called_once_with([hostname], 1)
|
||||
|
||||
@mock.patch('kolla_cli.commands.host.HostSetup._get_yml_data')
|
||||
@mock.patch('getpass.getpass')
|
||||
@mock.patch('kolla_cli.commands.host.ClientApi.host_ssh_check')
|
||||
@mock.patch('kolla_cli.commands.host.ClientApi.host_setup')
|
||||
@mock.patch('kolla_cli.api.client.ClientApi.host_get_all')
|
||||
@mock.patch('kolla_cli.shell.KollaCli._is_inventory_present',
|
||||
return_value=True)
|
||||
def test_host_setup(self, _, mock_get_all, mock_setup, mock_ssh_check,
|
||||
mock_passwd, mock_yml):
|
||||
password = 'PASSWORD'
|
||||
hostname = 'foo'
|
||||
mock_get_all.return_value = [self.get_fake_host(hostname)]
|
||||
mock_passwd.return_value = password
|
||||
|
||||
# single host setup (host not yet setup)
|
||||
mock_ssh_check.return_value = {hostname: {'success': False}}
|
||||
ret = self.run_cli_command('host setup %s' % hostname)
|
||||
self.assertEqual(ret, 0)
|
||||
mock_ssh_check.assert_called_once_with([hostname])
|
||||
mock_setup.assert_called_once_with({hostname: {'password': password}})
|
||||
|
||||
# single host setup --insecure (host already setup)
|
||||
mock_ssh_check.reset_mock()
|
||||
mock_setup.reset_mock()
|
||||
mock_ssh_check.return_value = {hostname: {'success': True}}
|
||||
ret = self.run_cli_command('host setup %s --insecure %s'
|
||||
% (hostname, password))
|
||||
self.assertEqual(ret, 0)
|
||||
mock_ssh_check.assert_called_once_with([hostname])
|
||||
mock_setup.assert_not_called()
|
||||
|
||||
# multi-host setup
|
||||
mock_ssh_check.reset_mock()
|
||||
mock_setup.reset_mock()
|
||||
fake_path = '/bogus'
|
||||
mock_yml.return_value = {hostname: {'password': password}}
|
||||
ret = self.run_cli_command('host setup --file %s' % fake_path)
|
||||
self.assertEqual(ret, 0)
|
||||
mock_setup.assert_called_once_with({hostname: {'password': password}})
|
||||
mock_yml.assert_called_once_with(fake_path)
|
||||
mock_ssh_check.assert_not_called()
|
||||
|
||||
@mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status')
|
||||
@mock.patch('kolla_cli.api.client.ClientApi.host_get_all')
|
||||
@mock.patch('kolla_cli.api.client.ClientApi.host_stop')
|
||||
@mock.patch('kolla_cli.shell.KollaCli._is_inventory_present',
|
||||
return_value=True)
|
||||
def test_host_stop(self, _, mock_stop, mock_get_all,
|
||||
mock_get_status):
|
||||
hostname = 'foo'
|
||||
mock_get_all.return_value = [self.get_fake_host(hostname)]
|
||||
mock_get_status.return_value = 0
|
||||
mock_stop.return_value = self.get_fake_job()
|
||||
|
||||
# host stop hostname
|
||||
ret = self.run_cli_command('host stop %s' % hostname)
|
||||
self.assertEqual(ret, 0)
|
||||
mock_stop.assert_called_once_with([hostname], 1)
|
||||
|
||||
# host stop all
|
||||
mock_stop.reset_mock()
|
||||
ret = self.run_cli_command('host stop all')
|
||||
self.assertEqual(ret, 0)
|
||||
mock_stop.assert_called_once_with([hostname], 1)
|
5
tox.ini
5
tox.ini
|
@ -1,7 +1,7 @@
|
|||
[tox]
|
||||
minversion = 1.6
|
||||
skipsdist = True
|
||||
envlist = pep8,mypy,functional,functional-py35
|
||||
envlist = pep8,mypy,functional,functional-py35,py27
|
||||
|
||||
[testenv]
|
||||
usedevelop=True
|
||||
|
@ -17,6 +17,9 @@ commands =
|
|||
find . -type f -name "*.py[c|o]" -delete
|
||||
find . -type d -name "__pycache__" -delete
|
||||
|
||||
[testenv:py27]
|
||||
commands = ostestr {posargs}
|
||||
|
||||
[testenv:functional]
|
||||
whitelist_externals =
|
||||
{[testenv]whitelist_externals}
|
||||
|
|
Loading…
Reference in New Issue