nfv/nfv/nfv-tests/nfv_unit_tests/tests/test_nfv_client.py

292 lines
11 KiB
Python
Executable File

#
# Copyright (c) 2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
import copy
import os
from unittest import mock
from nfv_client import shell
from nfv_unit_tests.tests import testcase
class TestNFVClientShell(testcase.NFVTestCase):
def setUp(self):
super(TestNFVClientShell, self).setUp()
def tearDown(self):
super(TestNFVClientShell, self).tearDown()
# -- Failure cases --
# Each failure case will :
# - invoke _print_message (as part of exit)
# - invoke print_usage (to indicate proper arguments)
# - raise a SystemExit exception
@mock.patch('argparse.ArgumentParser._print_message')
@mock.patch('argparse.ArgumentParser.print_usage')
def _test_shell_bad_or_empty_args(self,
mock_usage=None,
mock_message=None,
shell_args=None):
self.assertRaises(SystemExit, shell.process_main, shell_args)
mock_usage.assert_called_once()
mock_message.assert_called_once()
# --- Help Cases ----
# -h will print_help and SystemExit
@mock.patch('argparse.ArgumentParser.print_help')
def _test_shell_help(self, mock_help=None, shell_args=None):
self.assertRaises(SystemExit, shell.process_main, shell_args)
mock_help.assert_called_once()
class TestNFVClientShellRobustness(TestNFVClientShell):
# invalid arguments causes process_main to exit
def test_shell_bad_args(self):
shell_args = ['invalid-arg', ]
self._test_shell_bad_or_empty_args(shell_args=shell_args)
# empty arguments causes process_main to exit
def test_shell_no_args(self):
shell_args = []
self._test_shell_bad_or_empty_args(shell_args=shell_args)
class StrategyMixin(object):
MOCK_ENV = {
'OS_AUTH_URL': 'FAKE_OS_AUTH_URL',
'OS_PROJECT_NAME': 'FAKE_OS_PROJECT_NAME',
'OS_PROJECT_DOMAIN_NAME': 'FAKE_OS_PROJECT_DOMAIN_NAME',
'OS_USERNAME': 'FAKE_OS_USERNAME',
'OS_PASSWORD': 'FAKE_OS_PASSWORD',
'OS_USER_DOMAIN_NAME': 'FAKE_OS_USER_DOMAIN_NAME',
'OS_REGION_NAME': 'FAKE_OS_REGION_NAME',
'OS_INTERFACE': 'FAKE_OS_INTERFACE'
}
MOCK_ENV_OVERRIDES = {
'OS_AUTH_URL': '--os-auth-url=FAKE_OS_AUTH_URL',
'OS_PROJECT_NAME': '--os-project-name=FAKE_OS_PROJECT_NAME',
'OS_PROJECT_DOMAIN_NAME':
'--os-project-domain-name=FAKE_OS_PROJECT_DOMAIN_NAME',
'OS_USERNAME': '--os-username=FAKE_OS_USERNAME',
'OS_PASSWORD': '--os-password=FAKE_OS_PASSWORD',
'OS_USER_DOMAIN_NAME':
'--os-user-domain-name=FAKE_OS_USER_DOMAIN_NAME',
'OS_REGION_NAME': '--os-region-name=FAKE_OS_REGION_NAME',
'OS_INTERFACE': '--os-interface=FAKE_OS_INTERFACE'
}
def set_strategy(self, strategy):
"""Invoked by the child class setupmethod to set the strategy"""
self.strategy = strategy
def required_create_fields(self):
"""Override in the child class if create has required fields"""
return []
def optional_create_fields(self):
"""Override in the child class if create has optional fields"""
return []
# -- Show commands --
# The strategy commands use the same underling sw_update class, but
# but with different modes
# Test the show commands are not invoked when env values missing
@mock.patch('nfv_client.sw_update.show_strategy')
def _test_shell_show_missing_env(self, mock_show=None, shell_args=None):
shell.process_main(shell_args)
mock_show.assert_not_called()
# Test the show commands are invoked when env values detected
@mock.patch('nfv_client.sw_update.show_strategy')
def _test_shell_show(self, mock_show=None, shell_args=None):
with mock.patch.dict(os.environ, self.MOCK_ENV):
shell.process_main(shell_args)
mock_show.assert_called_once()
@mock.patch('nfv_client.sw_update.show_strategy')
def _test_shell_show_incomplete_env(self,
mock_show=None,
shell_args=None,
pop_env=None,
expect_fails=True):
# setup a mostly complete environment
test_env = copy.copy(self.MOCK_ENV)
test_env.pop(pop_env)
with mock.patch.dict(os.environ, test_env):
shell.process_main(shell_args)
if expect_fails:
mock_show.assert_not_called()
else:
mock_show.assert_called_once()
def test_shell_strategy_missing_subcommand(self):
"""Test the strategy fails with a missing subcommand"""
shell_args = [self.strategy, ]
self._test_shell_bad_or_empty_args(shell_args=shell_args)
def test_shell_strategy_invalid_subcommand(self):
"""Test the strategy fails with an invalid subcommand"""
shell_args = [self.strategy, 'foo']
self._test_shell_bad_or_empty_args(shell_args=shell_args)
def test_shell_strategy_help(self):
"""Test the strategy supports the help subcommand"""
shell_args = [self.strategy, '-h', ]
self._test_shell_help(shell_args=shell_args)
def test_shell_strategy_show_incomplete_env(self):
"""Test that if any required env variable is missing, it fails"""
shell_args = [self.strategy, 'show', ]
for pop_env in list(self.MOCK_ENV.keys()):
# OS_PROJECT_DOMAIN_NAME was made optional
if pop_env == "OS_PROJECT_DOMAIN_NAME":
continue
# remove the pop_env variable from the environment
self._test_shell_show_incomplete_env(shell_args=shell_args,
pop_env=pop_env)
def test_shell_strategy_show_env_overrides(self):
"""
Tests that passing certain values to the CLI override the env and
that removing that value from the env will not cause failure
"""
for env_val, override_val in self.MOCK_ENV_OVERRIDES.items():
shell_args = [override_val, self.strategy, 'show', ]
self._test_shell_show_incomplete_env(shell_args=shell_args,
pop_env=env_val,
expect_fails=False)
def test_shell_strategy_show(self):
shell_args = [self.strategy, 'show', ]
self._test_shell_show(shell_args=shell_args)
def test_shell_strategy_show_bad_extra_arg(self):
shell_args = [self.strategy, 'show', '--bad']
self._test_shell_bad_or_empty_args(shell_args=shell_args)
def test_shell_strategy_show_debug(self):
shell_args = ["--debug", self.strategy, 'show']
self._test_shell_show(shell_args=shell_args)
def test_shell_strategy_show_details(self):
shell_args = [self.strategy, 'show', '--details']
self._test_shell_show(shell_args=shell_args)
def test_shell_strategy_show_active(self):
shell_args = [self.strategy, 'show', '--active']
self._test_shell_show(shell_args=shell_args)
def test_shell_strategy_show_active_details(self):
shell_args = [self.strategy, 'show', '--details', '--active']
self._test_shell_show(shell_args=shell_args)
# -- Abort command --
# Test the abort command can be invoked. Requires the env to be set
@mock.patch('nfv_client.sw_update.abort_strategy')
def _test_shell_abort(self, mock_abort=None, shell_args=None):
with mock.patch.dict(os.environ, self.MOCK_ENV):
shell.process_main(shell_args)
mock_abort.assert_called_once()
def test_shell_strategy_abort(self):
shell_args = [self.strategy, 'abort']
self._test_shell_abort(shell_args=shell_args)
# -- Apply command --
# Test the apply command can be invoked. Requires the env to be set
@mock.patch('nfv_client.sw_update.apply_strategy')
def _test_shell_apply(self, mock_apply=None, shell_args=None):
with mock.patch.dict(os.environ, self.MOCK_ENV):
shell.process_main(shell_args)
mock_apply.assert_called_once()
def test_shell_strategy_apply(self):
shell_args = [self.strategy, 'apply']
self._test_shell_apply(shell_args=shell_args)
# -- Delete command --
# Test the delete command can be invoked. Requires the env to be set
@mock.patch('nfv_client.sw_update.delete_strategy')
def _test_shell_delete(self, mock_delete=None, shell_args=None):
with mock.patch.dict(os.environ, self.MOCK_ENV):
shell.process_main(shell_args)
mock_delete.assert_called_once()
def test_shell_strategy_delete(self):
shell_args = [self.strategy, 'delete']
self._test_shell_delete(shell_args=shell_args)
# -- Create command --
# Test the create command can be invoked. Requires the env to be set
@mock.patch('nfv_client.sw_update.create_strategy')
def _test_shell_create(self, mock_create=None, shell_args=None):
with mock.patch.dict(os.environ, self.MOCK_ENV):
shell.process_main(shell_args)
mock_create.assert_called_once()
# -- Create command --
def test_shell_strategy_create(self):
shell_args = [self.strategy, 'create']
# create may have 'required' additional fields
shell_args.extend(self.required_create_fields())
self._test_shell_create(shell_args=shell_args)
def test_shell_strategy_create_optional(self):
shell_args = [self.strategy, 'create']
# create may have 'required' additional fields and optional ones
shell_args.extend(self.required_create_fields())
shell_args.extend(self.optional_create_fields())
self._test_shell_create(shell_args=shell_args)
class TestCLIUpgradeStrategy(TestNFVClientShell,
StrategyMixin):
def setUp(self):
super(TestCLIUpgradeStrategy, self).setUp()
self.set_strategy('upgrade-strategy')
class TestCLIPatchStrategy(TestNFVClientShell,
StrategyMixin):
def setUp(self):
super(TestCLIPatchStrategy, self).setUp()
self.set_strategy('patch-strategy')
class TestCLIFwUpdateStrategy(TestNFVClientShell,
StrategyMixin):
def setUp(self):
super(TestCLIFwUpdateStrategy, self).setUp()
self.set_strategy('fw-update-strategy')
class TestCLIKubeRootCAUpdateStrategy(TestNFVClientShell,
StrategyMixin):
def setUp(self):
super(TestCLIKubeRootCAUpdateStrategy, self).setUp()
self.set_strategy('kube-rootca-update-strategy')
class TestCLIKubeUpgradeStrategy(TestNFVClientShell,
StrategyMixin):
def setUp(self):
super(TestCLIKubeUpgradeStrategy, self).setUp()
self.set_strategy('kube-upgrade-strategy')
def required_create_fields(self):
"""Kube Upgrade requires a to-version for create"""
return ['--to-version=1.2.3']
class TestSystemConfigUpdateStrategy(TestNFVClientShell,
StrategyMixin):
def setUp(self):
super(TestSystemConfigUpdateStrategy, self).setUp()
self.set_strategy('system-config-update-strategy')