class TestCompletion(unittest.TestCase): def setUp(self): self.mgr = CommandManager() self.cmd = TestCmd('test-cmd') self.mgr.add('test-cmd', self.cmd) def test_bad_cmd(self): with self.assertRaises(CommandInvalid): CommandParser('foo -h') with self.assertRaises(CommandInvalid): CommandParser('bar ') with self.assertRaises(CommandNotFound): CommandParser('') with self.assertRaises(CommandNotFound): CommandParser('ex') def test_cmd(self): parser = CommandParser('test-cmd') self.assertEqual(parser.cmd, self.mgr.get('test-cmd')) self.assertEqual(parser.cmd_name, 'test-cmd') def test_option_parsing(self): parser = CommandParser('test-cmd -h') self.assertEqual(len(list(parser.used_options)), 1) expected = ['--bar', '--foo', '-l'] parsed = [a.option_strings[0] for a in parser.available_options] self.assertEqual(parsed, expected) parser = CommandParser('test-cmd --foo -h') self.assertEqual(len(list(parser.used_options)), 2) expected = ['--bar', '-l'] parsed = [a.option_strings[0] for a in parser.available_options] self.assertEqual(parsed, expected)
def __call__(self, env_file=None, force=False): env = json.load(env_file, object_pairs_hook=OrderedDict) self._provision_defaults = {} for key, defaults in env.get('defaults', {}).items(): self._provision_defaults[key] = self._normalize_keys(defaults) self.mgr = CommandManager() if env.get('namespace'): self.mgr.load_namespace(env.get('namespace')) logger.debug('Namespace %s loaded' % env['namespace']) wanted_env = env['provision'] wanted_env = self._normalize_env(wanted_env) wanted_env = self._setup_defaults_values(wanted_env) wanted_env = self._validate_env(wanted_env) current_env = self._get_current_env(wanted_env.keys()) current_env = self._normalize_env(current_env) current_env = self._setup_defaults_values(current_env) current_env = self._validate_env(current_env) diff_env = self._diff_envs(current_env, wanted_env) if self._confirm_diff(diff_env, force=force): self._apply_diff(diff_env)
class TestParser(unittest.TestCase): def setUp(self): self.mgr = CommandManager() self.cmd = TestCmd('test-cmd') self.cmd2 = TestCmd2('test-cmd2') self.mgr.add('test-cmd', self.cmd) self.mgr.add('test-cmd2', self.cmd2) def test_bad_cmd(self): with self.assertRaises(CommandInvalid): CommandParser(Document('foo -h')) with self.assertRaises(CommandInvalid): CommandParser(Document('bar ')) with self.assertRaises(CommandNotFound): CommandParser(Document()) with self.assertRaises(CommandNotFound): CommandParser(Document('ex')) def test_cmd(self): parser = CommandParser(Document('test-cmd')) self.assertEqual(parser.cmd, self.mgr.get('test-cmd')) self.assertEqual(parser.cmd_name, 'test-cmd') def test_option_parsing(self): parser = CommandParser(Document('test-cmd -h')) self.assertEqual(len(list(parser.used_options)), 0) expected = ['-l', '--foo', '--bar'] parsed = [ o.short_name or o.long_name for o in parser.available_options ] self.assertEqual(parsed, expected) parser = CommandParser(Document('test-cmd --bar -h')) self.assertEqual(len(list(parser.used_options)), 1) expected = ['-l', '--foo', '--bar'] parsed = [ o.short_name or o.long_name for o in parser.available_options ] self.assertEqual(parsed, expected) def test_arg_parsing(self): parser = CommandParser( Document('test-cmd --foo bar arg1_value -l arg2_value ')) self.assertEqual(list(parser.used_args), [self.cmd.args['arg1'], self.cmd.args['arg2']]) parser = CommandParser(Document('test-cmd arg1_value -l')) self.assertEqual(list(parser.used_args), [self.cmd.args['arg1']]) self.assertEqual(list(parser.available_args), [self.cmd.args['arg2']]) parser = CommandParser(Document('test-cmd2 arg1_value -l')) self.assertEqual(list(parser.available_args), [self.cmd2.args['arg2']]) parser = CommandParser(Document('test-cmd2 arg1_value -l arg2_value')) self.assertEqual(list(parser.available_args), [self.cmd2.args['arg2']]) parser = CommandParser( Document('test-cmd2 arg1_value -l arg2_value arg2_value2')) self.assertEqual(list(parser.available_args), [self.cmd2.args['arg2']])
class TestParser(unittest.TestCase): def setUp(self): self.mgr = CommandManager() self.cmd = TestCmd('test-cmd') self.cmd2 = TestCmd2('test-cmd2') self.mgr.add('test-cmd', self.cmd) self.mgr.add('test-cmd2', self.cmd2) def test_bad_cmd(self): with self.assertRaises(CommandInvalid): CommandParser(Document('foo -h')) with self.assertRaises(CommandInvalid): CommandParser(Document('bar ')) with self.assertRaises(CommandNotFound): CommandParser(Document()) with self.assertRaises(CommandNotFound): CommandParser(Document('ex')) def test_cmd(self): parser = CommandParser(Document('test-cmd')) self.assertEqual(parser.cmd, self.mgr.get('test-cmd')) self.assertEqual(parser.cmd_name, 'test-cmd') def test_option_parsing(self): parser = CommandParser(Document('test-cmd -h')) self.assertEqual(len(list(parser.used_options)), 0) expected = ['-l', '--foo', '--bar'] parsed = [o.short_name or o.long_name for o in parser.available_options] self.assertEqual(parsed, expected) parser = CommandParser(Document('test-cmd --bar -h')) self.assertEqual(len(list(parser.used_options)), 1) expected = ['-l', '--foo', '--bar'] parsed = [o.short_name or o.long_name for o in parser.available_options] self.assertEqual(parsed, expected) def test_arg_parsing(self): parser = CommandParser(Document('test-cmd --foo bar arg1_value -l arg2_value ')) self.assertEqual(list(parser.used_args), [self.cmd.args['arg1'], self.cmd.args['arg2']]) parser = CommandParser(Document('test-cmd arg1_value -l')) self.assertEqual(list(parser.used_args), [self.cmd.args['arg1']]) self.assertEqual(list(parser.available_args), [self.cmd.args['arg2']]) parser = CommandParser(Document('test-cmd2 arg1_value -l')) self.assertEqual(list(parser.available_args), [self.cmd2.args['arg2']]) parser = CommandParser(Document('test-cmd2 arg1_value -l arg2_value')) self.assertEqual(list(parser.available_args), [self.cmd2.args['arg2']]) parser = CommandParser(Document('test-cmd2 arg1_value -l arg2_value arg2_value2')) self.assertEqual(list(parser.available_args), [self.cmd2.args['arg2']])
class TestParser(unittest.TestCase): def setUp(self): self.mgr = CommandManager() self.cmd = TestCmd('test-cmd') self.mgr.add('test-cmd', self.cmd) def test_bad_cmd(self): with self.assertRaises(CommandInvalid): CommandParser('foo -h') with self.assertRaises(CommandInvalid): CommandParser('bar ') with self.assertRaises(CommandNotFound): CommandParser('') with self.assertRaises(CommandNotFound): CommandParser('ex') def test_cmd(self): parser = CommandParser('test-cmd') self.assertEqual(parser.cmd, self.mgr.get('test-cmd')) self.assertEqual(parser.cmd_name, 'test-cmd') def test_option_parsing(self): parser = CommandParser('test-cmd -h') self.assertEqual(len(list(parser.used_options)), 0) expected = ['--bar', '--foo', '-l'] parsed = [ o.short_name or o.long_name for o in parser.available_options ] self.assertEqual(parsed, expected) parser = CommandParser('test-cmd --bar -h') self.assertEqual(len(list(parser.used_options)), 1) expected = ['--bar', '--foo', '-l'] parsed = [ o.short_name or o.long_name for o in parser.available_options ] self.assertEqual(parsed, expected)
def __call__(self, gremlin_server=None, checks=None, tests=None, clean=False, loop=False, loop_interval=None, json=False, zk_server=False): if clean: CommandManager().load_namespace('contrail_api_cli.clean') utils.JSON_OUTPUT = json utils.ZK_SERVER = zk_server self.gremlin_server = gremlin_server if tests: self.run_tests(tests) else: if loop is True: self.run_loop(checks, clean, loop_interval) else: self.run(checks, clean)
def setUp(self): self.mgr = CommandManager() self.cmd = TestCmd('test-cmd') self.mgr.add('test-cmd', self.cmd)
class Provision(Command): description = 'Provision contrail environment' env_file = Arg(help='JSON file of environment to provision', type=argparse.FileType('r')) force = Option('-f', help="Don't ask for confirmation", default=False, action="store_true") @property def __doc__(self): # Hack to include rst doc with sections # not included by sphinx but can be view # with the man command. return sys.modules[__name__].__doc__ def _get_current_env(self, keys): """Build the current environment of the given resources (keys). For each resource we run "get-resource" or "list-resource" and populate the env. """ env = OrderedDict() for key in keys: if self._is_property(key): cmd = self._get_command(key, Actions.GET) else: cmd = self._get_command(key, Actions.LIST) try: env[key] = json.loads( self._call_command(cmd, defaults=self._provision_defaults.get( key, {}))) except CommandError as e: raise CommandError('Failed to get current values for %s: %s' % (key, e)) return env def _is_property(self, string): try: self.mgr.get('set-%s' % string) return True except CommandNotFound: return False def _get_add_command(self, key): if self._is_property(key): action = Actions.SET else: action = Actions.ADD return self._get_command(key, action) def _get_command(self, key, action): try: return self.mgr.get('%s-%s' % (action, key)) except CommandNotFound: raise CommandError("No command to %s %s" % (action, key)) def _get_command_args(self, cmd): argspec = inspect.getargspec(cmd.__call__) if len(argspec.args) > 1: return [arg for arg in argspec.args[1:]] return [] def _call_command(self, cmd, defaults={}): """Call a command. If the command needs arguments they have to be passed as a dict in the defaults kwarg. """ kwargs = {} for arg in self._get_command_args(cmd): kwargs[arg] = defaults.get(arg) logger.debug('Calling %s with %s' % (cmd, kwargs)) return cmd(**kwargs) def _normalize_env(self, env): """Normalize an input environement. Replace '-' by '_' in provisionning arg names. Make sure calls definitions are in lists. """ for key, value in env.items(): if type(value) == OrderedDict: value = dict(value.items()) if type(value) == dict: env[key] = [value] elif type(value) != list: raise CommandError( 'Unsupported provisioning data type in %s: %s' % (key, value)) for idx, call in enumerate(env[key]): env[key][idx] = self._normalize_keys(call) return env def _setup_defaults_values(self, env): for key, values in env.items(): for idx, kwargs in enumerate(values): defaults = copy.deepcopy(self._provision_defaults.get(key, {})) defaults.update(kwargs) env[key][idx] = defaults return env def _normalize_keys(self, values): new_values = {} for key, value in values.items(): new_values[key.replace('-', '_')] = value return new_values def _validate_env(self, env): """Given an env, validate that all arguments are consistent. """ for key, values in env.items(): for idx, call in enumerate(values): env[key][idx] = self._validate_call(key, call) return env def _validate_call(self, key, values): """Validate call parameters. The wanted env is globally structured as follow: { "provision": { "resource": [ { "arg": "value", "arg2": 34 } ], ... } } We try to get the provisioning method for "resource", which is "add-resource" or "set-resource". Then, given the arguments we validate them using the command parser and set default values where needed. """ cmd = self._get_add_command(key) # default args values from argparse parser for action in cmd.parser._actions: if action.dest == 'help': continue if isinstance(action, argparse._StoreConstAction): values[action.dest] = values.get(action.dest, action.default) else: arg_strings = values.get(action.dest, []) if type(arg_strings) != list: arg_strings = [arg_strings] try: values[action.dest] = cmd.parser._get_values( action, arg_strings) if not values[action.dest] and action.default: values[action.dest] = action.default except argparse.ArgumentError as e: raise CommandError('Error in %s: %s' % (key, text_type(e))) # remove unknown args from call for arg, value in copy.deepcopy(values.items()): if arg not in self._get_command_args(cmd): logger.debug('Unknown arg %s for %s. Ignored' % (arg, cmd.__call__)) del values[arg] return values def _diff_envs(self, current, wanted): """Make a diff of the current env and the wanted env. Compare only common resources between the envs. This allows to partially provision the env. If the wanted env has a bgp-router list we try to converge the current env bgp-router list. Removing bgp-routers not in the wanted list, adding bgp-routers not in the current list. """ diff_env = { Actions.SET: OrderedDict(), Actions.ADD: OrderedDict(), Actions.DEL: OrderedDict(), } for key, values in wanted.items(): add_values = [v for v in values if v not in current.get(key, [])] if add_values: if self._is_property(key): diff_env[Actions.SET][key] = add_values else: diff_env[Actions.ADD][key] = add_values for key, values in current.items(): if key not in wanted: continue if self._is_property(key): continue del_values = [v for v in values if v not in wanted[key]] if del_values: diff_env[Actions.DEL][key] = del_values return diff_env def _confirm_diff(self, diff, force=False): """Show actions to be made and ask for confirmation unless force is True. """ if not any( [True if diff[action] else False for action in Actions.APPLY]): printo('Nothing to do') return False for action in Actions.APPLY: if not diff[action]: continue printo("\n%s the resources :\n" % action.capitalize()) for key, values in diff[action].items(): printo('%s : %s\n' % (key, json.dumps(values, indent=2))) if force or continue_prompt(): return True else: return False def _apply_diff(self, diff): """Takes the generated diff and call methods to converge to the wanted env. First delete unwanted resources, then set wanted properties, finally add wanted resources. """ for action in Actions.APPLY: for key, values in diff.get(action, {}).items(): cmd = self._get_command(key, action) for kwargs in values: try: self._call_command(cmd, defaults=kwargs) except CommandError as e: raise CommandError('Call to %s %s failed: %s' % (action, key, e)) def __call__(self, env_file=None, force=False): env = json.load(env_file, object_pairs_hook=OrderedDict) self._provision_defaults = {} for key, defaults in env.get('defaults', {}).items(): self._provision_defaults[key] = self._normalize_keys(defaults) self.mgr = CommandManager() if env.get('namespace'): self.mgr.load_namespace(env.get('namespace')) logger.debug('Namespace %s loaded' % env['namespace']) wanted_env = env['provision'] wanted_env = self._normalize_env(wanted_env) wanted_env = self._setup_defaults_values(wanted_env) wanted_env = self._validate_env(wanted_env) current_env = self._get_current_env(wanted_env.keys()) current_env = self._normalize_env(current_env) current_env = self._setup_defaults_values(current_env) current_env = self._validate_env(current_env) diff_env = self._diff_envs(current_env, wanted_env) if self._confirm_diff(diff_env, force=force): self._apply_diff(diff_env)
import functools import json from cStringIO import StringIO import sys from six import text_type import time import logging from gremlin_python.process.graph_traversal import id, label, union, values from contrail_api_cli.resource import Resource from contrail_api_cli.exceptions import CommandError from contrail_api_cli.utils import printo from contrail_api_cli.manager import CommandManager cmd_mgr = CommandManager(load_default=False) cmd_mgr.load_namespace('contrail_api_cli.clean') JSON_OUTPUT = False ZK_SERVER = 'localhost:2181' def log(string): if JSON_OUTPUT: return printo(string) def to_resources(fun): @functools.wraps(fun) def wrapper(*args): t = fun(*args)
def setUp(self): CLITest.setUp(self) self.mgr = CommandManager() self.mgr.load_namespace('contrail_api_cli.shell_command') self.mgr.add('cmd', Cmd('cmd')) self.mgr.add('arg-test', ArgTest('arg-test'))
class TestCommand(CLITest): def setUp(self): CLITest.setUp(self) self.mgr = CommandManager() self.mgr.load_namespace('contrail_api_cli.shell_command') self.mgr.add('cmd', Cmd('cmd')) self.mgr.add('arg-test', ArgTest('arg-test')) def test_cd(self): self.mgr.get('cd')('foo') self.assertEqual(Context().shell.current_path, Path('/foo')) self.mgr.get('cd')('bar') self.assertEqual(Context().shell.current_path, Path('/foo/bar')) self.mgr.get('cd')('..') self.assertEqual(Context().shell.current_path, Path('/foo')) self.mgr.get('cd')('') self.assertEqual(Context().shell.current_path, Path('/foo')) self.mgr.get('cd')('/') self.assertEqual(Context().shell.current_path, Path('/')) @mock.patch('contrail_api_cli.resource.Context.session') def test_root_collection(self, mock_session): Context().shell.current_path = Path('/') mock_session.get_json.return_value = { 'href': self.BASE, 'links': [{ 'link': { 'href': self.BASE + '/instance-ips', 'path': Path('/instance-ips'), 'name': 'instance-ip', 'rel': 'collection' } }, { 'link': { 'href': self.BASE + '/instance-ip', 'path': Path('/instance-ip'), 'name': 'instance-ip', 'rel': 'resource-base' } }] } result = self.mgr.get('ls')() self.assertEqual('instance-ip', result) mock_session.get_json.side_effect = [{ 'href': self.BASE, 'links': [{ 'link': { 'href': self.BASE + '/foos', 'path': Path('/foos'), 'name': 'foo', 'rel': 'collection' } }, { 'link': { 'href': self.BASE + '/bars', 'path': Path('/bars'), 'name': 'bar', 'rel': 'collection' } }] }, { 'foos': [{ 'href': self.BASE + '/foo/ec1afeaa-8930-43b0-a60a-939f23a50724', 'uuid': 'ec1afeaa-8930-43b0-a60a-939f23a50724' }, { 'href': self.BASE + '/foo/c2588045-d6fb-4f37-9f46-9451f653fb6a', 'uuid': 'c2588045-d6fb-4f37-9f46-9451f653fb6a' }] }, { 'bars': [{ 'href': self.BASE + '/bar/ffe8de43-a141-4336-8d70-bf970813bbf7', 'uuid': 'ffe8de43-a141-4336-8d70-bf970813bbf7' }] }] Context().shell.current_path = Path('/') expected_result = """foo/ec1afeaa-8930-43b0-a60a-939f23a50724 foo/c2588045-d6fb-4f37-9f46-9451f653fb6a bar/ffe8de43-a141-4336-8d70-bf970813bbf7""" result = self.mgr.get('ls')(paths=['*']) self.assertEqual(result, expected_result) @mock.patch('contrail_api_cli.resource.Context.session') def test_resource_collection(self, mock_session): mock_session.get_json.return_value = { 'foos': [{ 'href': self.BASE + '/foo/ec1afeaa-8930-43b0-a60a-939f23a50724', 'uuid': 'ec1afeaa-8930-43b0-a60a-939f23a50724' }, { 'href': self.BASE + '/foo/c2588045-d6fb-4f37-9f46-9451f653fb6a', 'uuid': 'c2588045-d6fb-4f37-9f46-9451f653fb6a' }] } Context().shell.current_path = Path('/foo') result = self.mgr.get('ls')() self.assertEqual( '\n'.join([ 'ec1afeaa-8930-43b0-a60a-939f23a50724', 'c2588045-d6fb-4f37-9f46-9451f653fb6a' ]), result) Context().shell.current_path = Path('/') result = self.mgr.get('ls')(paths=['foo']) self.assertEqual( '\n'.join([ 'foo/ec1afeaa-8930-43b0-a60a-939f23a50724', 'foo/c2588045-d6fb-4f37-9f46-9451f653fb6a' ]), result) @mock.patch('contrail_api_cli.resource.Context.session') def test_resource_ls(self, mock_session): mock_session.get_json.return_value = { 'foo': { 'href': self.BASE + '/foo/ec1afeaa-8930-43b0-a60a-939f23a50724', 'uuid': 'ec1afeaa-8930-43b0-a60a-939f23a50724', } } Context().shell.current_path = Path('/foo') expected_result = 'ec1afeaa-8930-43b0-a60a-939f23a50724' result = self.mgr.get('ls')( paths=['ec1afeaa-8930-43b0-a60a-939f23a50724']) self.assertEqual(result, expected_result) @mock.patch('contrail_api_cli.resource.Context.session') def test_resource_long_ls(self, mock_session): mock_session.id_to_fqname.return_value = { 'type': 'foo', 'fq_name': FQName('default-project:foo:ec1afeaa-8930-43b0-a60a-939f23a50724') } mock_session.get_json.return_value = { 'foo': { 'href': self.BASE + '/foo/ec1afeaa-8930-43b0-a60a-939f23a50724', 'uuid': 'ec1afeaa-8930-43b0-a60a-939f23a50724', 'fq_name': [ 'default-project', 'foo', 'ec1afeaa-8930-43b0-a60a-939f23a50724' ], 'prop': { 'foo': False, 'bar': [1, 2, 3] } } } Context().shell.current_path = Path('/') result = self.mgr.get('ls')( paths=['foo/ec1afeaa-8930-43b0-a60a-939f23a50724'], int=True) expected_result = "foo/ec1afeaa-8930-43b0-a60a-939f23a50724 default-project:foo:ec1afeaa-8930-43b0-a60a-939f23a50724" self.assertEqual(result, expected_result) Context().shell.current_path = Path('/foo') result = self.mgr.get('ls')( paths=['ec1afeaa-8930-43b0-a60a-939f23a50724'], int=True, fields=['prop']) expected_results = [ "ec1afeaa-8930-43b0-a60a-939f23a50724 foo=False|bar=1,2,3", "ec1afeaa-8930-43b0-a60a-939f23a50724 bar=1,2,3|foo=False" ] self.assertTrue(any([result == r for r in expected_results])) @mock.patch('contrail_api_cli.resource.Context.session') def test_resource_parent_uuid_ls(self, mock_session): mock_session.configure_mock(base_url=self.BASE) self.mgr.get('ls')(paths=['foo']) mock_session.get_json.assert_called_with(self.BASE + '/foos') self.mgr.get('ls')(paths=['foo'], parent_uuid='1ad831be-3b21-4870-aadf-8efc2b0a480d') mock_session.get_json.assert_called_with( self.BASE + '/foos', parent_id='1ad831be-3b21-4870-aadf-8efc2b0a480d') @mock.patch('contrail_api_cli.commands.cat.highlight_json') @mock.patch('contrail_api_cli.resource.Context.session') def test_resource_cat(self, mock_session, mock_highlight_json): # bind original method to mock_session mock_session.id_to_fqname = client.ContrailAPISession.id_to_fqname.__get__( mock_session) mock_session.make_url = client.ContrailAPISession.make_url.__get__( mock_session) # called by id_to_fqname def post(url, json=None): if json['uuid'] == "ec1afeaa-8930-43b0-a60a-939f23a50724": return { "type": "foo", "fq_name": ["foo", "ec1afeaa-8930-43b0-a60a-939f23a50724"] } if json['uuid'] == "15315402-8a21-4116-aeaa-b6a77dceb191": return { "type": "bar", "fq_name": ["bar", "15315402-8a21-4116-aeaa-b6a77dceb191"] } mock_session.post_json.side_effect = post mock_highlight_json.side_effect = lambda d: d mock_session.get_json.return_value = { 'foo': { 'href': self.BASE + '/foo/ec1afeaa-8930-43b0-a60a-939f23a50724', 'uuid': 'ec1afeaa-8930-43b0-a60a-939f23a50724', 'attr': None, 'fq_name': ['foo', 'ec1afeaa-8930-43b0-a60a-939f23a50724'], 'bar_refs': [{ 'href': self.BASE + '/bar/15315402-8a21-4116-aeaa-b6a77dceb191', 'uuid': '15315402-8a21-4116-aeaa-b6a77dceb191', 'to': ['bar', '15315402-8a21-4116-aeaa-b6a77dceb191'] }] } } Context().shell.current_path = Path('/foo') expected_resource = Resource( 'foo', uuid='ec1afeaa-8930-43b0-a60a-939f23a50724', href=self.BASE + '/foo/ec1afeaa-8930-43b0-a60a-939f23a50724', attr=None, fq_name='foo:ec1afeaa-8930-43b0-a60a-939f23a50724') expected_resource['bar_refs'] = [ Resource('bar', uuid='15315402-8a21-4116-aeaa-b6a77dceb191', href=self.BASE + '/bar/15315402-8a21-4116-aeaa-b6a77dceb191', to=['bar', '15315402-8a21-4116-aeaa-b6a77dceb191']) ] result = self.mgr.get('cat')( paths=['ec1afeaa-8930-43b0-a60a-939f23a50724']) self.assertEqual(expected_resource.json(), result) @mock.patch('contrail_api_cli.resource.Context.session') def test_notfound_fqname_ls(self, mock_session): fq_name = 'default-domain:foo' Context().shell.current_path = Path('/foo') mock_session.fqname_to_id.side_effect = client.HttpError( http_status=404) with self.assertRaises(ResourceNotFound) as e: self.mgr.get('ls')(paths=[fq_name]) self.assertEqual("%s doesn't exists" % fq_name, str(e)) self.assertFalse(mock_session.get_json.called) @mock.patch('contrail_api_cli.resource.Context.session') def test_count(self, mock_session): mock_session.get_json.return_value = {'foos': {'count': 3}} Context().shell.current_path = Path('/foo') result = self.mgr.get('du')() self.assertEqual(result, '3') Context().shell.current_path = Path('/') result = self.mgr.get('du')(paths=['foo']) self.assertEqual(result, '3') Context().shell.current_path = Path('/foo/%s' % uuid.uuid4()) with self.assertRaises(CommandError): self.mgr.get('du')() @mock.patch('contrail_api_cli.resource.Context.session') @mock.patch('contrail_api_cli.commands.rm.continue_prompt') def test_rm(self, mock_continue_prompt, mock_session): mock_session.configure_mock(base_url=self.BASE) Context().shell.current_path = Path('/') t = ['foo/6b6a7f47-807e-4c39-8ac6-3adcf2f5498f'] mock_session.delete.return_value = True self.mgr.get('rm')(paths=t, force=True) mock_session.delete.assert_has_calls([ mock.call(self.BASE + '/foo/6b6a7f47-807e-4c39-8ac6-3adcf2f5498f') ]) self.assertFalse(mock_continue_prompt.called) @mock.patch('contrail_api_cli.resource.Context.session') def test_rm_multiple_resources(self, mock_session): mock_session.configure_mock(base_url=self.BASE) Context().shell.current_path = Path('/foo') ts = [ '6b6a7f47-807e-4c39-8ac6-3adcf2f5498f', '22916187-5b6f-40f1-b7b6-fc6fe9f23bce' ] mock_session.delete.return_value = True self.mgr.get('rm')(paths=ts, force=True) mock_session.delete.assert_has_calls([ mock.call(self.BASE + '/foo/22916187-5b6f-40f1-b7b6-fc6fe9f23bce'), mock.call(self.BASE + '/foo/6b6a7f47-807e-4c39-8ac6-3adcf2f5498f') ]) @mock.patch('contrail_api_cli.resource.Context.session') def test_rm_wildcard_resources(self, mock_session): mock_session.configure_mock(base_url=self.BASE) Context().shell.current_path = Path('/foo') mock_session.get_json.return_value = { 'foos': [{ 'href': self.BASE + '/foo/ec1afeaa-8930-43b0-a60a-939f23a50724', 'uuid': 'ec1afeaa-8930-43b0-a60a-939f23a50724', 'fq_name': ['default', 'foo', '1'] }, { 'href': self.BASE + '/foo/c2588045-d6fb-4f37-9f46-9451f653fb6a', 'uuid': 'c2588045-d6fb-4f37-9f46-9451f653fb6a', 'fq_name': ['default', 'foo', '1'] }] } mock_session.delete.return_value = True t = ['ec1afeaa-8930*', 'c2588045-d6fb-4f37-9f46-9451f653fb6a'] self.mgr.get('rm')(paths=t, force=True) mock_session.delete.assert_has_calls([ mock.call(self.BASE + '/foo/c2588045-d6fb-4f37-9f46-9451f653fb6a'), mock.call(self.BASE + '/foo/ec1afeaa-8930-43b0-a60a-939f23a50724') ]) t = ['*', 'c2588045-d6fb-4f37-9f46-9451f653fb6a'] self.mgr.get('rm')(paths=t, force=True) mock_session.delete.assert_has_calls([ mock.call(self.BASE + '/foo/c2588045-d6fb-4f37-9f46-9451f653fb6a'), mock.call(self.BASE + '/foo/ec1afeaa-8930-43b0-a60a-939f23a50724') ]) t = ['default:*', 'c2588045-d6fb-4f37-9f46-9451f653fb6a'] self.mgr.get('rm')(paths=t, force=True) mock_session.delete.assert_has_calls([ mock.call(self.BASE + '/foo/c2588045-d6fb-4f37-9f46-9451f653fb6a'), mock.call(self.BASE + '/foo/ec1afeaa-8930-43b0-a60a-939f23a50724') ]) @mock.patch('contrail_api_cli.resource.Context.session') @mock.patch('contrail_api_cli.commands.rm.continue_prompt') def test_rm_noconfirm(self, mock_continue_prompt, mock_session): Context().shell.current_path = Path('/') mock_continue_prompt.return_value = False t = ['foo/6b6a7f47-807e-4c39-8ac6-3adcf2f5498f'] self.mgr.get('rm')(paths=t) self.assertFalse(mock_session.delete.called) @mock.patch('contrail_api_cli.resource.Context.session') @mock.patch('contrail_api_cli.commands.rm.continue_prompt') def test_rm_recursive(self, mock_continue_prompt, mock_session): Context().shell.current_path = Path('/') Collection('bar') Collection('foobar') t = ['foo/6b6a7f47-807e-4c39-8ac6-3adcf2f5498f'] mock_continue_prompt.return_value = True mock_session.configure_mock(base_url=self.BASE) mock_session.get_json.side_effect = [{ 'foo': { 'href': self.BASE + '/foo/6b6a7f47-807e-4c39-8ac6-3adcf2f5498f', 'uuid': '6b6a7f47-807e-4c39-8ac6-3adcf2f5498f', 'bar_back_refs': [{ 'href': self.BASE + '/bar/22916187-5b6f-40f1-b7b6-fc6fe9f23bce', 'uuid': '22916187-5b6f-40f1-b7b6-fc6fe9f23bce', 'to': ['bar', '22916187-5b6f-40f1-b7b6-fc6fe9f23bce'] }, { 'href': self.BASE + '/bar/776bdf88-6283-4c4b-9392-93a857807307', 'uuid': '776bdf88-6283-4c4b-9392-93a857807307', 'to': ['bar', '776bdf88-6283-4c4b-9392-93a857807307'] }] } }, { 'bar': { 'href': self.BASE + '/bar/22916187-5b6f-40f1-b7b6-fc6fe9f23bce', 'uuid': '22916187-5b6f-40f1-b7b6-fc6fe9f23bce', 'foobar_back_refs': [{ 'href': self.BASE + '/foobar/1050223f-a230-4ed6-96f1-c332700c5e01', 'to': ['foobar', '1050223f-a230-4ed6-96f1-c332700c5e01'], 'uuid': '1050223f-a230-4ed6-96f1-c332700c5e01' }] } }, { 'foobar': { 'href': self.BASE + '/foobar/1050223f-a230-4ed6-96f1-c332700c5e01', 'uuid': '1050223f-a230-4ed6-96f1-c332700c5e01' } }, { 'bar': { 'href': self.BASE + '/bar/776bdf88-6283-4c4b-9392-93a857807307', 'uuid': '776bdf88-6283-4c4b-9392-93a857807307' } }] mock_session.delete.return_value = True self.mgr.get('rm')(paths=t, recursive=True) expected_calls = [ mock.call.delete(self.BASE + '/bar/776bdf88-6283-4c4b-9392-93a857807307'), mock.call.delete(self.BASE + '/foobar/1050223f-a230-4ed6-96f1-c332700c5e01'), mock.call.delete(self.BASE + '/bar/22916187-5b6f-40f1-b7b6-fc6fe9f23bce'), mock.call.delete(self.BASE + '/foo/6b6a7f47-807e-4c39-8ac6-3adcf2f5498f') ] mock_session.delete.assert_has_calls(expected_calls) @mock.patch('contrail_api_cli.resource.Context.session') @mock.patch('contrail_api_cli.commands.shell.prompt') def test_pipes(self, mock_prompt, mock_session): old_stdout = sys.stdout out = io.BytesIO() sys.stdout = out mock_prompt.side_effect = ["cmd | grep piped", "cmd", "exit"] self.mgr.get('shell')() sys.stdout = old_stdout result = out.getvalue() self.assertEqual(result, b'piped\nnot piped\n') @mock.patch('contrail_api_cli.resource.Context.session') @mock.patch('contrail_api_cli.commands.shell.prompt') def test_shell_args(self, mock_prompt, mock_session): old_stdout = sys.stdout out = io.BytesIO() sys.stdout = out mock_prompt.side_effect = ["arg-test \"foo bar\"", "exit"] self.mgr.get('shell')() sys.stdout = old_stdout result = out.getvalue() self.assertEqual(result, b'foo bar\n') @mock.patch('contrail_api_cli.resource.Context.session') def test_ln(self, mock_session): Context().schema = create_schema_from_version('2.21') r1 = Resource('virtual-network', uuid='9174e7d3-865b-4faf-ab0f-c083e43fee6d') r2 = Resource('route-table', uuid='9174e7d3-865b-4faf-ab0f-c083e43fee6d') r3 = Resource('project', uuid='9174e7d3-865b-4faf-ab0f-c083e43fee6d') r5 = Resource('logical-router', uuid='9174e7d3-865b-4faf-ab0f-c083e43fee6d') self.mgr.get('ln')(resources=[r1.path, r2.path]) self.mgr.get('ln')(resources=[r1.path, r2.path], remove=True) self.mgr.get('ln')(resources=[r1.path, r5.path]) self.mgr.get('ln')(resources=[r1.path, r5.path], remove=True) with self.assertRaises(CommandError): self.mgr.get('ln')(resources=[r1.path, r3.path]) with self.assertRaises(CommandError): self.mgr.get('ln')(resources=[ 'foo/9174e7d3-865b-4faf-ab0f-c083e43fee6d', r1.path ]) Context().schema = DummySchema() def test_schema(self): self.mgr.get('schema')(schema_version='2.21') self.mgr.get('schema')(schema_version='2.21', resource_name='virtual-network') self.mgr.get('schema')(schema_version='2.21', resource_name='route-target') with self.assertRaises(CommandError): self.mgr.get('schema')(schema_version='2.21', resource_name='foo') with self.assertRaises(CommandError): self.mgr.get('schema')(schema_version='4.0', resource_name='route-target') self.mgr.get('schema')(schema_version='4.0', list_version=True)
def cmd(name): return CommandManager().get(name)
class TestCommand(CLITest): def setUp(self): CLITest.setUp(self) self.mgr = CommandManager() self.mgr.load_namespace('contrail_api_cli.shell_command') self.mgr.add('cmd', Cmd('cmd')) self.mgr.add('arg-test', ArgTest('arg-test')) def test_cd(self): self.mgr.get('cd')('foo') self.assertEqual(Context().shell.current_path, Path('/foo')) self.mgr.get('cd')('bar') self.assertEqual(Context().shell.current_path, Path('/foo/bar')) self.mgr.get('cd')('..') self.assertEqual(Context().shell.current_path, Path('/foo')) self.mgr.get('cd')('') self.assertEqual(Context().shell.current_path, Path('/foo')) self.mgr.get('cd')('/') self.assertEqual(Context().shell.current_path, Path('/')) @mock.patch('contrail_api_cli.resource.Context.session') def test_root_collection(self, mock_session): Context().shell.current_path = Path('/') mock_session.get_json.return_value = { 'href': self.BASE, 'links': [ {'link': {'href': self.BASE + '/instance-ips', 'path': Path('/instance-ips'), 'name': 'instance-ip', 'rel': 'collection'}}, {'link': {'href': self.BASE + '/instance-ip', 'path': Path('/instance-ip'), 'name': 'instance-ip', 'rel': 'resource-base'}} ] } result = self.mgr.get('ls')() self.assertEqual('instance-ip', result) mock_session.get_json.side_effect = [ { 'href': self.BASE, 'links': [ {'link': {'href': self.BASE + '/foos', 'path': Path('/foos'), 'name': 'foo', 'rel': 'collection'}}, {'link': {'href': self.BASE + '/bars', 'path': Path('/bars'), 'name': 'bar', 'rel': 'collection'}} ] }, { 'foos': [ {'href': self.BASE + '/foo/ec1afeaa-8930-43b0-a60a-939f23a50724', 'uuid': 'ec1afeaa-8930-43b0-a60a-939f23a50724'}, {'href': self.BASE + '/foo/c2588045-d6fb-4f37-9f46-9451f653fb6a', 'uuid': 'c2588045-d6fb-4f37-9f46-9451f653fb6a'} ] }, { 'bars': [ {'href': self.BASE + '/bar/ffe8de43-a141-4336-8d70-bf970813bbf7', 'uuid': 'ffe8de43-a141-4336-8d70-bf970813bbf7'} ] } ] Context().shell.current_path = Path('/') expected_result = """foo/ec1afeaa-8930-43b0-a60a-939f23a50724 foo/c2588045-d6fb-4f37-9f46-9451f653fb6a bar/ffe8de43-a141-4336-8d70-bf970813bbf7""" result = self.mgr.get('ls')(paths=['*']) self.assertEqual(result, expected_result) @mock.patch('contrail_api_cli.resource.Context.session') def test_resource_collection(self, mock_session): mock_session.get_json.return_value = { 'foos': [ {'href': self.BASE + '/foo/ec1afeaa-8930-43b0-a60a-939f23a50724', 'uuid': 'ec1afeaa-8930-43b0-a60a-939f23a50724'}, {'href': self.BASE + '/foo/c2588045-d6fb-4f37-9f46-9451f653fb6a', 'uuid': 'c2588045-d6fb-4f37-9f46-9451f653fb6a'} ] } Context().shell.current_path = Path('/foo') result = self.mgr.get('ls')() self.assertEqual('\n'.join(['ec1afeaa-8930-43b0-a60a-939f23a50724', 'c2588045-d6fb-4f37-9f46-9451f653fb6a']), result) Context().shell.current_path = Path('/') result = self.mgr.get('ls')(paths=['foo']) self.assertEqual('\n'.join(['foo/ec1afeaa-8930-43b0-a60a-939f23a50724', 'foo/c2588045-d6fb-4f37-9f46-9451f653fb6a']), result) @mock.patch('contrail_api_cli.resource.Context.session') def test_resource_ls(self, mock_session): mock_session.get_json.return_value = { 'foo': { 'href': self.BASE + '/foo/ec1afeaa-8930-43b0-a60a-939f23a50724', 'uuid': 'ec1afeaa-8930-43b0-a60a-939f23a50724', } } Context().shell.current_path = Path('/foo') expected_result = 'ec1afeaa-8930-43b0-a60a-939f23a50724' result = self.mgr.get('ls')(paths=['ec1afeaa-8930-43b0-a60a-939f23a50724']) self.assertEqual(result, expected_result) @mock.patch('contrail_api_cli.resource.Context.session') def test_resource_long_ls(self, mock_session): mock_session.id_to_fqname.return_value = { 'type': 'foo', 'fq_name': FQName('default-project:foo:ec1afeaa-8930-43b0-a60a-939f23a50724') } mock_session.get_json.return_value = { 'foo': { 'href': self.BASE + '/foo/ec1afeaa-8930-43b0-a60a-939f23a50724', 'uuid': 'ec1afeaa-8930-43b0-a60a-939f23a50724', 'fq_name': ['default-project', 'foo', 'ec1afeaa-8930-43b0-a60a-939f23a50724'], 'prop': { 'foo': False, 'bar': [1, 2, 3] } } } Context().shell.current_path = Path('/') result = self.mgr.get('ls')(paths=['foo/ec1afeaa-8930-43b0-a60a-939f23a50724'], long=True) expected_result = "foo/ec1afeaa-8930-43b0-a60a-939f23a50724 default-project:foo:ec1afeaa-8930-43b0-a60a-939f23a50724" self.assertEqual(result, expected_result) Context().shell.current_path = Path('/foo') result = self.mgr.get('ls')(paths=['ec1afeaa-8930-43b0-a60a-939f23a50724'], long=True, fields=['prop']) expected_results = ["ec1afeaa-8930-43b0-a60a-939f23a50724 foo=False|bar=1,2,3", "ec1afeaa-8930-43b0-a60a-939f23a50724 bar=1,2,3|foo=False"] self.assertTrue(any([result == r for r in expected_results])) @mock.patch('contrail_api_cli.resource.Context.session') def test_resource_parent_uuid_ls(self, mock_session): mock_session.configure_mock(base_url=self.BASE) self.mgr.get('ls')(paths=['foo']) mock_session.get_json.assert_called_with(self.BASE + '/foos') self.mgr.get('ls')(paths=['foo'], parent_uuid='1ad831be-3b21-4870-aadf-8efc2b0a480d') mock_session.get_json.assert_called_with(self.BASE + '/foos', parent_id='1ad831be-3b21-4870-aadf-8efc2b0a480d') @mock.patch('contrail_api_cli.commands.cat.highlight_json') @mock.patch('contrail_api_cli.resource.Context.session') def test_resource_cat(self, mock_session, mock_highlight_json): # bind original method to mock_session mock_session.id_to_fqname = client.ContrailAPISession.id_to_fqname.__get__(mock_session) mock_session.make_url = client.ContrailAPISession.make_url.__get__(mock_session) # called by id_to_fqname def post(url, json=None): if json['uuid'] == "ec1afeaa-8930-43b0-a60a-939f23a50724": return { "type": "foo", "fq_name": [ "foo", "ec1afeaa-8930-43b0-a60a-939f23a50724" ] } if json['uuid'] == "15315402-8a21-4116-aeaa-b6a77dceb191": return { "type": "bar", "fq_name": [ "bar", "15315402-8a21-4116-aeaa-b6a77dceb191" ] } mock_session.post_json.side_effect = post mock_highlight_json.side_effect = lambda d: d mock_session.get_json.return_value = { 'foo': { 'href': self.BASE + '/foo/ec1afeaa-8930-43b0-a60a-939f23a50724', 'uuid': 'ec1afeaa-8930-43b0-a60a-939f23a50724', 'attr': None, 'fq_name': [ 'foo', 'ec1afeaa-8930-43b0-a60a-939f23a50724' ], 'bar_refs': [ { 'href': self.BASE + '/bar/15315402-8a21-4116-aeaa-b6a77dceb191', 'uuid': '15315402-8a21-4116-aeaa-b6a77dceb191', 'to': [ 'bar', '15315402-8a21-4116-aeaa-b6a77dceb191' ] } ] } } Context().shell.current_path = Path('/foo') expected_resource = Resource('foo', uuid='ec1afeaa-8930-43b0-a60a-939f23a50724', href=self.BASE + '/foo/ec1afeaa-8930-43b0-a60a-939f23a50724', attr=None, fq_name='foo:ec1afeaa-8930-43b0-a60a-939f23a50724') expected_resource['bar_refs'] = [ Resource('bar', uuid='15315402-8a21-4116-aeaa-b6a77dceb191', href=self.BASE + '/bar/15315402-8a21-4116-aeaa-b6a77dceb191', to=['bar', '15315402-8a21-4116-aeaa-b6a77dceb191']) ] result = self.mgr.get('cat')(paths=['ec1afeaa-8930-43b0-a60a-939f23a50724']) self.assertEqual(expected_resource.json(), result) @mock.patch('contrail_api_cli.resource.Context.session') def test_notfound_fqname_ls(self, mock_session): fq_name = 'default-domain:foo' Context().shell.current_path = Path('/foo') mock_session.fqname_to_id.side_effect = client.HttpError(http_status=404) with self.assertRaises(ResourceNotFound) as e: self.mgr.get('ls')(paths=[fq_name]) self.assertEqual("%s doesn't exists" % fq_name, str(e)) self.assertFalse(mock_session.get_json.called) @mock.patch('contrail_api_cli.resource.Context.session') def test_count(self, mock_session): mock_session.get_json.return_value = { 'foos': { 'count': 3 } } Context().shell.current_path = Path('/foo') result = self.mgr.get('du')() self.assertEqual(result, '3') Context().shell.current_path = Path('/') result = self.mgr.get('du')(paths=['foo']) self.assertEqual(result, '3') Context().shell.current_path = Path('/foo/%s' % uuid.uuid4()) with self.assertRaises(CommandError): self.mgr.get('du')() @mock.patch('contrail_api_cli.resource.Context.session') @mock.patch('contrail_api_cli.commands.rm.continue_prompt') def test_rm(self, mock_continue_prompt, mock_session): mock_session.configure_mock(base_url=self.BASE) Context().shell.current_path = Path('/') t = ['foo/6b6a7f47-807e-4c39-8ac6-3adcf2f5498f'] mock_session.delete.return_value = True self.mgr.get('rm')(paths=t, force=True) mock_session.delete.assert_has_calls([ mock.call(self.BASE + '/foo/6b6a7f47-807e-4c39-8ac6-3adcf2f5498f') ]) self.assertFalse(mock_continue_prompt.called) @mock.patch('contrail_api_cli.resource.Context.session') def test_rm_multiple_resources(self, mock_session): mock_session.configure_mock(base_url=self.BASE) Context().shell.current_path = Path('/foo') ts = ['6b6a7f47-807e-4c39-8ac6-3adcf2f5498f', '22916187-5b6f-40f1-b7b6-fc6fe9f23bce'] mock_session.delete.return_value = True self.mgr.get('rm')(paths=ts, force=True) mock_session.delete.assert_has_calls([ mock.call(self.BASE + '/foo/22916187-5b6f-40f1-b7b6-fc6fe9f23bce'), mock.call(self.BASE + '/foo/6b6a7f47-807e-4c39-8ac6-3adcf2f5498f') ]) @mock.patch('contrail_api_cli.resource.Context.session') def test_rm_wildcard_resources(self, mock_session): mock_session.configure_mock(base_url=self.BASE) Context().shell.current_path = Path('/foo') mock_session.get_json.return_value = { 'foos': [ {'href': self.BASE + '/foo/ec1afeaa-8930-43b0-a60a-939f23a50724', 'uuid': 'ec1afeaa-8930-43b0-a60a-939f23a50724', 'fq_name': ['default', 'foo', '1']}, {'href': self.BASE + '/foo/c2588045-d6fb-4f37-9f46-9451f653fb6a', 'uuid': 'c2588045-d6fb-4f37-9f46-9451f653fb6a', 'fq_name': ['default', 'foo', '1']} ] } mock_session.delete.return_value = True t = ['ec1afeaa-8930*', 'c2588045-d6fb-4f37-9f46-9451f653fb6a'] self.mgr.get('rm')(paths=t, force=True) mock_session.delete.assert_has_calls([ mock.call(self.BASE + '/foo/c2588045-d6fb-4f37-9f46-9451f653fb6a'), mock.call(self.BASE + '/foo/ec1afeaa-8930-43b0-a60a-939f23a50724') ]) t = ['*', 'c2588045-d6fb-4f37-9f46-9451f653fb6a'] self.mgr.get('rm')(paths=t, force=True) mock_session.delete.assert_has_calls([ mock.call(self.BASE + '/foo/c2588045-d6fb-4f37-9f46-9451f653fb6a'), mock.call(self.BASE + '/foo/ec1afeaa-8930-43b0-a60a-939f23a50724') ]) t = ['default:*', 'c2588045-d6fb-4f37-9f46-9451f653fb6a'] self.mgr.get('rm')(paths=t, force=True) mock_session.delete.assert_has_calls([ mock.call(self.BASE + '/foo/c2588045-d6fb-4f37-9f46-9451f653fb6a'), mock.call(self.BASE + '/foo/ec1afeaa-8930-43b0-a60a-939f23a50724') ]) @mock.patch('contrail_api_cli.resource.Context.session') @mock.patch('contrail_api_cli.commands.rm.continue_prompt') def test_rm_noconfirm(self, mock_continue_prompt, mock_session): Context().shell.current_path = Path('/') mock_continue_prompt.return_value = False t = ['foo/6b6a7f47-807e-4c39-8ac6-3adcf2f5498f'] self.mgr.get('rm')(paths=t) self.assertFalse(mock_session.delete.called) @mock.patch('contrail_api_cli.resource.Context.session') @mock.patch('contrail_api_cli.commands.rm.continue_prompt') def test_rm_recursive(self, mock_continue_prompt, mock_session): Context().shell.current_path = Path('/') Collection('bar') Collection('foobar') t = ['foo/6b6a7f47-807e-4c39-8ac6-3adcf2f5498f'] mock_continue_prompt.return_value = True mock_session.configure_mock(base_url=self.BASE) mock_session.get_json.side_effect = [ { 'foo': { 'href': self.BASE + '/foo/6b6a7f47-807e-4c39-8ac6-3adcf2f5498f', 'uuid': '6b6a7f47-807e-4c39-8ac6-3adcf2f5498f', 'bar_back_refs': [ { 'href': self.BASE + '/bar/22916187-5b6f-40f1-b7b6-fc6fe9f23bce', 'uuid': '22916187-5b6f-40f1-b7b6-fc6fe9f23bce', 'to': [ 'bar', '22916187-5b6f-40f1-b7b6-fc6fe9f23bce' ] }, { 'href': self.BASE + '/bar/776bdf88-6283-4c4b-9392-93a857807307', 'uuid': '776bdf88-6283-4c4b-9392-93a857807307', 'to': [ 'bar', '776bdf88-6283-4c4b-9392-93a857807307' ] } ] } }, { 'bar': { 'href': self.BASE + '/bar/22916187-5b6f-40f1-b7b6-fc6fe9f23bce', 'uuid': '22916187-5b6f-40f1-b7b6-fc6fe9f23bce', 'foobar_back_refs': [ { 'href': self.BASE + '/foobar/1050223f-a230-4ed6-96f1-c332700c5e01', 'to': [ 'foobar', '1050223f-a230-4ed6-96f1-c332700c5e01' ], 'uuid': '1050223f-a230-4ed6-96f1-c332700c5e01' } ] } }, { 'foobar': { 'href': self.BASE + '/foobar/1050223f-a230-4ed6-96f1-c332700c5e01', 'uuid': '1050223f-a230-4ed6-96f1-c332700c5e01' } }, { 'bar': { 'href': self.BASE + '/bar/776bdf88-6283-4c4b-9392-93a857807307', 'uuid': '776bdf88-6283-4c4b-9392-93a857807307' } } ] mock_session.delete.return_value = True self.mgr.get('rm')(paths=t, recursive=True) expected_calls = [ mock.call.delete(self.BASE + '/bar/776bdf88-6283-4c4b-9392-93a857807307'), mock.call.delete(self.BASE + '/foobar/1050223f-a230-4ed6-96f1-c332700c5e01'), mock.call.delete(self.BASE + '/bar/22916187-5b6f-40f1-b7b6-fc6fe9f23bce'), mock.call.delete(self.BASE + '/foo/6b6a7f47-807e-4c39-8ac6-3adcf2f5498f') ] mock_session.delete.assert_has_calls(expected_calls) @mock.patch('contrail_api_cli.resource.Context.session') @mock.patch('contrail_api_cli.commands.shell.prompt') def test_pipes(self, mock_prompt, mock_session): old_stdout = sys.stdout out = io.BytesIO() sys.stdout = out mock_prompt.side_effect = [ "cmd | grep piped", "cmd", "exit" ] self.mgr.get('shell')() sys.stdout = old_stdout result = out.getvalue() self.assertEqual(result, b'piped\nnot piped\n') @mock.patch('contrail_api_cli.resource.Context.session') @mock.patch('contrail_api_cli.commands.shell.prompt') def test_shell_args(self, mock_prompt, mock_session): old_stdout = sys.stdout out = io.BytesIO() sys.stdout = out mock_prompt.side_effect = [ "arg-test \"foo bar\"", "exit" ] self.mgr.get('shell')() sys.stdout = old_stdout result = out.getvalue() self.assertEqual(result, b'foo bar\n') @mock.patch('contrail_api_cli.resource.Context.session') def test_ln(self, mock_session): Context().schema = create_schema_from_version('2.21') r1 = Resource('virtual-network', uuid='9174e7d3-865b-4faf-ab0f-c083e43fee6d') r2 = Resource('route-table', uuid='9174e7d3-865b-4faf-ab0f-c083e43fee6d') r3 = Resource('project', uuid='9174e7d3-865b-4faf-ab0f-c083e43fee6d') r5 = Resource('logical-router', uuid='9174e7d3-865b-4faf-ab0f-c083e43fee6d') self.mgr.get('ln')(resources=[r1.path, r2.path]) self.mgr.get('ln')(resources=[r1.path, r2.path], remove=True) self.mgr.get('ln')(resources=[r1.path, r5.path]) self.mgr.get('ln')(resources=[r1.path, r5.path], remove=True) with self.assertRaises(CommandError): self.mgr.get('ln')(resources=[r1.path, r3.path]) with self.assertRaises(CommandError): self.mgr.get('ln')(resources=['foo/9174e7d3-865b-4faf-ab0f-c083e43fee6d', r1.path]) Context().schema = DummySchema() def test_schema(self): self.mgr.get('schema')(schema_version='2.21') self.mgr.get('schema')(schema_version='2.21', resource_name='virtual-network') self.mgr.get('schema')(schema_version='2.21', resource_name='route-target') with self.assertRaises(CommandError): self.mgr.get('schema')(schema_version='2.21', resource_name='foo') with self.assertRaises(CommandError): self.mgr.get('schema')(schema_version='4.0', resource_name='route-target') self.mgr.get('schema')(schema_version='4.0', list_version=True)