Fully test CommandTree
authorStavros Sachtouris <saxtouri@admin.grnet.gr>
Mon, 15 Jul 2013 14:16:54 +0000 (17:16 +0300)
committerStavros Sachtouris <saxtouri@admin.grnet.gr>
Mon, 15 Jul 2013 14:16:54 +0000 (17:16 +0300)
Refs: #4058

kamaki/cli/__init__.py
kamaki/cli/command_shell.py
kamaki/cli/command_tree/__init__.py
kamaki/cli/command_tree/test.py
kamaki/clients/compute/__init__.py

index c056814..a151b9a 100644 (file)
@@ -346,9 +346,9 @@ def _groups_help(arguments):
         if pkg:
             cmds = getattr(pkg, '_commands')
             try:
-                for cmd in cmds:
-                    if cmd.name in acceptable_groups:
-                        descriptions[cmd.name] = cmd.help
+                for cmd_tree in cmds:
+                    if cmd_tree.name in acceptable_groups:
+                        descriptions[cmd_tree.name] = cmd_tree.description
             except TypeError:
                 if _debug:
                     kloger.warning(
index a1a7265..3788124 100644 (file)
@@ -150,7 +150,7 @@ class Shell(Cmd):
             pass
 
     def _roll_command(self, cmd_path=None):
-        for subname in self.cmd_tree.get_subnames(cmd_path):
+        for subname in self.cmd_tree.subnames(cmd_path):
             self._unregister_method('do_%s' % subname)
             self._unregister_method('complete_%s' % subname)
             self._unregister_method('help_%s' % subname)
@@ -288,7 +288,7 @@ class Shell(Cmd):
                     cmd_args[','.join(arg.parsed_name)] = arg.help
                 print_dict(cmd_args, indent=2)
                 stdout.write('%s %s' % (self.prompt, line))
-            return subcmd.get_subnames()
+            return subcmd.subnames()
         self._register_method(complete_method, 'complete_%s' % cmd.name)
 
     @property
@@ -311,7 +311,7 @@ class Shell(Cmd):
             intro = self.cmd_tree.name
 
         acceptable = parser.arguments['config'].get_groups()
-        total = self.cmd_tree.get_group_names()
+        total = self.cmd_tree.groups.keys()
         self.cmd_tree.exclude(set(total).difference(acceptable))
 
         for subcmd in self.cmd_tree.get_subcommands(path):
index 758b91c..24215ab 100644 (file)
@@ -101,25 +101,19 @@ class Command(object):
         return cmd, args[index:]
 
     def pretty_print(self, recursive=False):
-        print('Path: %s (Name: %s) is_cmd: %s\n\thelp: %s' % (
-            self.path,
-            self.name,
-            self.is_command,
-            self.help))
+        print('%s\t\t(Name: %s is_cmd: %s help: %s)' % (
+            self.path, self.name, self.is_command, self.help))
         for cmd in self.subcommands.values():
             cmd.pretty_print(recursive)
 
 
 class CommandTree(object):
 
-    groups = {}
-    _all_commands = {}
-    name = None
-    description = None
-
     def __init__(self, name, description=''):
         self.name = name
         self.description = description
+        self.groups = dict()
+        self._all_commands = dict()
 
     def exclude(self, groups_to_exclude=[]):
         for group in groups_to_exclude:
@@ -143,17 +137,17 @@ class CommandTree(object):
                 self._all_commands[path] = new_cmd
                 cmd.add_subcmd(new_cmd)
                 cmd = new_cmd
-        if cmd_class:
-            cmd.cmd_class = cmd_class
-        if description is not None:
-            cmd.help = description
+        cmd.cmd_class = cmd_class or None
+        cmd.help = description or None
 
     def find_best_match(self, terms):
         """Find a command that best matches a given list of terms
 
-        :param terms: (list of str) match them against paths in cmd_tree
+        :param terms: (list of str) match against paths in cmd_tree, e.g.
+            ['aa', 'bb', 'cc'] matches aa_bb_cc
 
-        :returns: (Command, list) the matching command, the remaining terms
+        :returns: (Command, list) the matching command, the remaining terms or
+            None
         """
         path = []
         for term in terms:
@@ -170,7 +164,10 @@ class CommandTree(object):
         tdesc = new_tree.description
         self.groups.update(new_tree.groups)
         self._all_commands.update(new_tree._all_commands)
-        self.set_description(tname, tdesc)
+        try:
+            self._all_commands[tname].help = tdesc
+        except KeyError:
+            self.add_command(tname, tdesc)
 
     def has_command(self, path):
         return path in self._all_commands
@@ -178,53 +175,14 @@ class CommandTree(object):
     def get_command(self, path):
         return self._all_commands[path]
 
-    def get_groups(self):
-        return self.groups.values()
-
-    def get_group_names(self):
-        return self.groups.keys()
-
-    def set_description(self, path, description):
-        self._all_commands[path].help = description
-
-    def get_description(self, path):
-        return self._all_commands[path].help
-
-    def get_subnames(self, path=None):
+    def subnames(self, path=None):
         if path in (None, ''):
-            return self.get_group_names()
+            return self.groups.keys()
         return self._all_commands[path].subcommands.keys()
 
     def get_subcommands(self, path=None):
         return self._all_commands[path].subcommands.values() if (
-            path) else self.get_groups()
-
-    def get_parent(self, path):
-        if '_' not in path:
-            return None
-        terms = path.split('_')
-        parent_path = '_'.join(terms[:-1])
-        return self._all_commands[parent_path]
-
-    def get_closest_ancestor_command(self, path):
-        path, sep, name = path.rpartition('_')
-        while len(path) > 0:
-            cmd = self._all_commands[path]
-            if cmd.is_command:
-                return cmd
-            path, sep, name = path.rpartition('_')
-        return None
-
-        if '_' not in path:
-            return None
-        terms = path.split()[:-1]
-        while len(terms) > 0:
-            tmp_path = '_'.join(terms)
-            cmd = self._all_commands[tmp_path]
-            if cmd.is_command:
-                return cmd
-            terms = terms[:-1]
-        raise KeyError('No ancestor commands')
+            path) else self.groups.values()
 
     def pretty_print(self, group=None):
         if group is None:
index f64ae90..5964bd7 100644 (file)
@@ -165,18 +165,30 @@ class Command(TestCase):
 
 class CommandTree(TestCase):
 
+    def _add_commands(self, ctree):
+        for cmd in self.commands:
+            ctree.add_command(cmd.path, cmd.help, cmd.cmd_class)
+
+    def _commands_are_equal(self, c1, c2):
+        self.assertEqual(c1.path, c2.path)
+        self.assertEqual(c1.name, c2.name)
+        self.assertEqual(c1.cmd_class, c2.cmd_class)
+        self.assertEqual(c1.help, c2.help)
+
     def setUp(self):
         cmd = command_tree.Command('cmd', subcommands=dict(
             cmd0a=command_tree.Command('cmd_cmd0a', subcommands=dict(
                 cmd1a=command_tree.Command(
                     'cmd_cmd0a_cmd1a', subcommands=dict(
-                        cmd2=command_tree.Command('cmd_cmd0a_cmd1a_cmd2'),
-                    )
+                        cmd2=command_tree.Command(
+                            'cmd_cmd0a_cmd1a_cmd2', cmd_class=Command)
+                        ),
                 ),
                 cmd1b=command_tree.Command(
                     'cmd_cmd0a_cmd1b', subcommands=dict(
-                        cmd2=command_tree.Command('cmd_cmd0a_cmd1b_cmd2'),
-                    )
+                        cmd2=command_tree.Command(
+                            'cmd_cmd0a_cmd1b_cmd2', cmd_class=Command)
+                        ),
                 )
             )),
             cmd0b=command_tree.Command('cmd_cmd0b'),
@@ -184,8 +196,9 @@ class CommandTree(TestCase):
                 cmd1a=command_tree.Command('cmd_cmd0c_cmd1a'),
                 cmd1b=command_tree.Command(
                     'cmd_cmd0c_cmd1b', subcommands=dict(
-                        cmd2=command_tree.Command('cmd_cmd0c_cmd1b_cmd2'),
-                    )
+                        cmd2=command_tree.Command(
+                            'cmd_cmd0c_cmd1b_cmd2', cmd_class=Command)
+                        ),
                 )
             ))
         ))
@@ -201,6 +214,7 @@ class CommandTree(TestCase):
             cmd.subcommands['cmd0c'].subcommands['cmd1a'],
             cmd.subcommands['cmd0c'].subcommands['cmd1b'],
             cmd.subcommands['cmd0c'].subcommands['cmd1b'].subcommands['cmd2'],
+            command_tree.Command('othercmd')
         ]
 
     def tearDown(self):
@@ -209,8 +223,155 @@ class CommandTree(TestCase):
         del self.commands
 
     def test___init__(self):
-        ctree = command_tree.CommandTree('sampleTree', 'a sample Tree')
-        ctree.pretty_print()
+        name, description = 'sampleTree', 'a sample Tree'
+        ctree = command_tree.CommandTree(name)
+        for attr, exp in (
+                ('groups', {}), ('_all_commands', {}),
+                ('name', name), ('description', '')):
+            self.assertEqual(getattr(ctree, attr), exp)
+        ctree = command_tree.CommandTree(name, description)
+        for attr, exp in (
+                ('groups', {}), ('_all_commands', {}),
+                ('name', name), ('description', description)):
+            self.assertEqual(getattr(ctree, attr), exp)
+
+    def test_exclude(self):
+        ctree = command_tree.CommandTree('excludeTree', 'test exclude group')
+        exp = dict()
+        for cmd in self.commands[0:6]:
+            ctree.groups[cmd.name] = cmd
+            exp[cmd.name] = cmd
+        self.assertEqual(exp, ctree.groups)
+        ctree.exclude(exp.keys()[1::2])
+        for key in exp.keys()[1::2]:
+            exp.pop(key)
+        self.assertEqual(exp, ctree.groups)
+
+    def test_add_command(self):
+        ctree = command_tree.CommandTree('addCommand', 'test add_command')
+        self._add_commands(ctree)
+        for cmd in self.commands:
+            self.assertTrue(cmd, ctree._all_commands)
+            if cmd.path.count('_'):
+                self.assertFalse(cmd.name in ctree.groups)
+            else:
+                self.assertTrue(cmd.name in ctree.groups)
+                self._commands_are_equal(cmd, ctree.groups[cmd.name])
+
+    def test_find_best_match(self):
+        ctree = command_tree.CommandTree('bestMatch', 'test find_best_match')
+        for cmd in self.commands:
+            terms = cmd.path.split('_')
+            best_match, rest = ctree.find_best_match(terms)
+            if len(terms) > 1:
+                self.assertEqual(best_match.path, '_'.join(terms[:-1]))
+            else:
+                self.assertEqual(best_match, None)
+            self.assertEqual(rest, terms[-1:])
+            ctree.add_command(cmd.path, cmd.help, cmd.cmd_class)
+            best_match, rest = ctree.find_best_match(terms)
+            self._commands_are_equal(best_match, cmd)
+            self.assertEqual(rest, [])
+
+    def test_add_tree(self):
+        ctree = command_tree.CommandTree('tree', 'the main tree')
+        ctree1 = command_tree.CommandTree('tree1', 'the first tree')
+        ctree2 = command_tree.CommandTree('tree2', 'the second tree')
+
+        cmds = list(self.commands)
+        del self.commands
+        cmds1, cmds2 = cmds[:6], cmds[6:]
+        self.commands = cmds1
+        self._add_commands(ctree1)
+        self.commands = cmds2
+        self._add_commands(ctree2)
+        self.commands = cmds
+
+        def check_all(
+                p1=False, p2=False, p3=False, p4=False, p5=False, p6=False):
+            for cmd in cmds[:6]:
+                self.assertEquals(cmd.path in ctree._all_commands, p1)
+                self.assertEquals(cmd.path in ctree1._all_commands, p2)
+                if cmd.path != 'cmd':
+                    self.assertEquals(cmd.path in ctree2._all_commands, p3)
+            for cmd in cmds[6:]:
+                self.assertEquals(cmd.path in ctree._all_commands, p4)
+                if cmd.path != 'cmd':
+                    self.assertEquals(cmd.path in ctree1._all_commands, p5)
+                self.assertEquals(cmd.path in ctree2._all_commands, p6)
+
+        check_all(False, True, False, False, False, True)
+        ctree.add_tree(ctree1)
+        check_all(True, True, False, False, False, True)
+        ctree.add_tree(ctree2)
+        check_all(True, True, False, True, False, True)
+        ctree2.add_tree(ctree1)
+        check_all(True, True, True, True, False, True)
+
+    def test_has_command(self):
+        ctree = command_tree.CommandTree('treeHasCommand', 'test has_command')
+        for cmd in self.commands:
+            self.assertFalse(ctree.has_command(cmd.path))
+        self._add_commands(ctree)
+        for cmd in self.commands:
+            self.assertTrue(ctree.has_command(cmd.path))
+        self.assertFalse(ctree.has_command('NON_EXISTING_COMMAND'))
+
+    def test_get_command(self):
+        ctree = command_tree.CommandTree('treeGetCommand', 'test get_command')
+        for cmd in self.commands:
+            self.assertRaises(KeyError, ctree.get_command, cmd.path)
+        self._add_commands(ctree)
+        for cmd in self.commands:
+            self._commands_are_equal(ctree.get_command(cmd.path), cmd)
+        self.assertRaises(KeyError, ctree.get_command, 'NON_EXISTNG_COMMAND')
+
+    def test_subnames(self):
+        ctree = command_tree.CommandTree('treeSubnames', 'test subnames')
+        self.assertEqual(ctree.subnames(), [])
+        self.assertRaises(KeyError, ctree.subnames, 'cmd')
+        self._add_commands(ctree)
+        for l1, l2 in (
+                (ctree.subnames(), ['cmd', 'othercmd']),
+                (ctree.subnames('cmd'), ['cmd0a', 'cmd0b', 'cmd0c']),
+                (ctree.subnames('cmd_cmd0a'), ['cmd1a', 'cmd1b']),
+                (ctree.subnames('cmd_cmd0a_cmd1a'), ['cmd2', ]),
+                (ctree.subnames('cmd_cmd0a_cmd1b'), ['cmd2', ]),
+                (ctree.subnames('cmd_cmd0a_cmd1a_cmd2'), []),
+                (ctree.subnames('cmd_cmd0a_cmd1b_cmd2'), []),
+                (ctree.subnames('cmd_cmd0b'), []),
+                (ctree.subnames('cmd_cmd0c'), ['cmd1a', 'cmd1b']),
+                (ctree.subnames('cmd_cmd0c_cmd1a'), []),
+                (ctree.subnames('cmd_cmd0c_cmd1b'), ['cmd2', ]),
+                (ctree.subnames('cmd_cmd0c_cmd1b_cmd2'), []),
+                (ctree.subnames('othercmd'), [])):
+            l1.sort(), l2.sort(), self.assertEqual(l1, l2)
+        self.assertRaises(KeyError, ctree.subnames, 'NON_EXISTNG_CMD')
+
+    def test_get_subcommands(self):
+        ctree = command_tree.CommandTree('treeSub', 'test get_subcommands')
+        self.assertEqual(ctree.get_subcommands(), [])
+        self.assertRaises(KeyError, ctree.get_subcommands, 'cmd')
+        self._add_commands(ctree)
+        for s1, l2 in (
+            ('', ['cmd', 'othercmd']),
+            ('cmd', ['cmd0a', 'cmd0b', 'cmd0c']),
+            ('cmd_cmd0a', ['cmd1a', 'cmd1b']),
+            ('cmd_cmd0a_cmd1a', ['cmd2', ]),
+            ('cmd_cmd0a_cmd1b', ['cmd2', ]),
+            ('cmd_cmd0a_cmd1a_cmd2', []),
+            ('cmd_cmd0a_cmd1b_cmd2', []),
+            ('cmd_cmd0b', []),
+            ('cmd_cmd0c', ['cmd1a', 'cmd1b']),
+            ('cmd_cmd0c_cmd1a', []),
+            ('cmd_cmd0c_cmd1b', ['cmd2', ]),
+            ('cmd_cmd0c_cmd1b_cmd2', []),
+            ('othercmd', [])
+        ):
+            l1 = [cmd.path for cmd in ctree.get_subcommands(s1)]
+            l2 = ['_'.join([s1, i]) for i in l2] if s1 else l2
+            l1.sort(), l2.sort(), self.assertEqual(l1, l2)
+        self.assertRaises(KeyError, ctree.get_subcommands, 'NON_EXISTNG_CMD')
 
 
 if __name__ == '__main__':
index edb0979..1e0583f 100644 (file)
@@ -320,9 +320,7 @@ class ComputeClient(ComputeRestClient):
 
         :param pool: (str) pool of ips to allocate from
 
-        :returns: (dict) {
-                fixed_ip: ..., id: ..., instance_id: ..., ip: ..., pool: ...
-            }
+        :returns: (dict) {fixed_ip: . id: . instance_id: . ip: . pool: .}
         """
         json_data = dict(pool=pool) if pool else dict()
         r = self.floating_ips_post(tenant_id, json_data)