1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
"""test subcommand option parsing."""
import argparse
import sys
from Bcfg2.Compat import StringIO
from Bcfg2.Options import Option, get_parser, new_parser, Subcommand, \
Subparser, CommandRegistry
import Bcfg2.Options.Subcommands
from testsuite.Testsrc.Testlib.TestOptions import make_config, OptionTestCase
class MockSubcommand(Subcommand):
"""fake subcommand that just records the options it was called with."""
run_options = None
def run(self, setup):
self.__class__.run_options = setup
class One(MockSubcommand):
"""fake subcommand for testing."""
options = [Option("--test-one")]
class Two(MockSubcommand):
"""fake subcommand for testing."""
options = [Option("--test-two")]
def local_subclass(cls):
"""get a subclass of ``cls`` that adds no functionality.
This can be used to subclass the various test classes above so
that their options don't get modified by option parsing.
"""
return type("Local%s" % cls.__name__, (cls,), {})
class TestSubcommands(OptionTestCase):
"""tests for subcommands and subparsers."""
def setUp(self):
self.registry = CommandRegistry()
self.one = local_subclass(One)
self.two = local_subclass(Two)
self.registry.register_command(self.one)
self.registry.register_command(self.two)
self.result = argparse.Namespace()
Bcfg2.Options.Subcommands.master_setup = self.result
new_parser()
self.parser = get_parser(namespace=self.result,
components=[self])
self.parser.add_options(self.registry.subcommand_options)
def test_register_commands(self):
"""register subcommands."""
registry = CommandRegistry()
registry.register_commands(globals().values(),
parent=MockSubcommand)
self.assertItemsEqual(registry.commands.keys(),
["one", "two", "help"])
self.assertIsInstance(registry.commands['one'], One)
self.assertIsInstance(registry.commands['two'], Two)
@make_config()
def test_get_subcommand(self, config_file):
"""parse simple subcommands."""
self.parser.parse(["-C", config_file, "localone"])
self.assertEqual(self.result.subcommand, "localone")
def test_subcommand_usage(self):
"""sane usage message from subcommands."""
self.assertEqual(
One().usage(),
"one [--test-one TEST_ONE] - fake subcommand for testing.")
# subclasses do not inherit the docstring from the parent, so
# this tests a command subclass without a docstring, even
# though that should never happen due to the pylint tests.
self.assertEqual(self.one().usage().strip(),
"localone [--test-one TEST_ONE]")
def _get_subcommand_output(self, args):
self.parser.parse(args)
old_stdout = sys.stdout
sys.stdout = StringIO()
rv = self.registry.runcommand()
output = [l for l in sys.stdout.getvalue().splitlines()
if not l.startswith("DEBUG: ")]
sys.stdout = old_stdout
return (rv, output)
@make_config()
def test_help(self, config_file):
"""sane help message from subcommand registry."""
rv, output = self._get_subcommand_output(["-C", config_file, "help"])
self.assertIn(rv, [0, None])
# the help message will look like:
#
# localhelp [<command>]
# localone [--test-one TEST_ONE]
# localtwo [--test-two TEST_TWO]
commands = []
command_help = {
"help": self.registry.help.usage(),
"localone": self.one().usage(),
"localtwo": self.two().usage()}
for line in output:
command = line.split()[0]
commands.append(command)
if command not in command_help:
self.fail("Got help for unknown command %s: %s" %
(command, line))
self.assertEqual(line, command_help[command])
self.assertItemsEqual(commands, command_help.keys())
@make_config()
def test_subcommand_help(self, config_file):
"""get help message on a single command."""
rv, output = self._get_subcommand_output(
["-C", config_file, "help", "localone"])
self.assertIn(rv, [0, None])
self.assertEqual(output[0].strip(),
"usage: %s" % self.one().usage().strip())
@make_config()
def test_nonexistent_subcommand_help(self, config_file):
"""get help message on a nonexistent command."""
rv, output = self._get_subcommand_output(
["-C", config_file, "help", "blargle"])
self.assertNotEqual(rv, 0)
self.assertIn("No such command", output[0])
|