Merge lp:~bcsaller/pyjuju/sane_output_test_option into lp:pyjuju
- sane_output_test_option
- Merge into trunk
Status: | Work in progress |
---|---|
Proposed branch: | lp:~bcsaller/pyjuju/sane_output_test_option |
Merge into: | lp:pyjuju |
Diff against target: |
226 lines (+135/-3) 2 files modified
juju/hooks/commands.py (+37/-3) juju/hooks/tests/test_invoker.py (+98/-0) |
To merge this branch: | bzr merge lp:~bcsaller/pyjuju/sane_output_test_option |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Juju Engineering | Pending | ||
Review via email: mp+106067@code.launchpad.net |
Commit message
Description of the change
Adds support for --test to cli utils
This branch bundles two related changes, support for --test on relation-get, unit-get and config-get.
This should be similar to the additions made in the golang version.
Also this changes to always use a formatter for output and the smart output formatter was changed to
YAML dump collection types, normal string values are still printed w/o serialization.
Gustavo Niemeyer (niemeyer) wrote : | # |
Some details here are not clear to me. I'd appreciate having a chat
about this feature with you before this goes in.
https:/
File juju/hooks/cli.py (right):
https:/
juju/hooks/
What was your thinking here? I believe it should dump yaml in all
cases. i.e. "true", not "True".
https:/
File juju/hooks/
https:/
juju/hooks/
json?
Clint Byrum (clint-fewbar) wrote : | # |
I've been thinking about this, and this is a backward incompatible change, I'm afraid.
Up until now, charms w/ boolean configs have been able to count on "True" or "False" and have been written as such.
This will change the case, and that is, unfortunately, not acceptable in the planned "fixes only" release of Juju.
The --test is fantastic, and should be added. But I'm afraid if we do the other bit without bumping to a new "major release" we will have many many broken charms very suddenly.
Kapil Thangavelu (hazmat) wrote : | # |
its backwards incompatible for charms, which we should fix and encourage extant users to update. the existing output is broken in that it depends on no standard except the implicit one by python's str/repr output. The whole 'smart' format stuff was decidedly not.
Gustavo Niemeyer (niemeyer) wrote : | # |
Mail sent to canonical-juju. This bug will be fixed, we have no option. The decision of when to fix it is your hands, Clint.
Kapil Thangavelu (hazmat) wrote : | # |
bug in base formatter.
https:/
File juju/hooks/cli.py (right):
https:/
juju/hooks/
None is not a callable type, this tries a double output if formatter is
None. please default formatter to the correct default output.
Kapil Thangavelu (hazmat) wrote : | # |
it would be nice to rebase this on current trunk where the formatting work has been done in a compatible fashion, and slim this branch down to just the --test option which is still useful
Benjamin Saller (bcsaller) wrote : | # |
Please take a look.
https:/
File juju/hooks/cli.py (right):
https:/
juju/hooks/
On 2012/05/17 02:42:44, niemeyer wrote:
> What was your thinking here? I believe it should dump yaml in all
cases. i.e.
> "true", not "True".
You're correct that non-string types should appear here.
Kapil Thangavelu (hazmat) wrote : | # |
I'm still a little unclear as to the desired behavior outcome and its
testing with this branch, as it currently tested it doesn't seem
particularly useful.
https:/
File juju/hooks/
https:/
juju/hooks/
missing doc string describing purpose/usage.
https:/
juju/hooks/
there's a lot of unesc. method delegation here. just inline the
test_true/
The use of the mixin, also feels like its adding complexity here, around
subclass ordering and proper lineage to customize_parser vs. render
(which have inverse call lineages). Incorporating into the base class
might be cleaner via class flag switch.
https:/
juju/hooks/
Why is this returning None, why is it implemented at all? ditto for the
two other implementations of the same here.
https:/
File juju/hooks/
https:/
juju/hooks/
this is testing something very different then what the cli usage would
commonly be, namely the cli usage would be testing for values unset.
For values set, a null value seems valid, has the go team documented the
behavior of this cli param?
Unmerged revisions
- 556. By Benjamin Saller
-
test option support in cli hooks
Preview Diff
1 | === modified file 'juju/hooks/commands.py' |
2 | --- juju/hooks/commands.py 2012-05-03 16:46:40 +0000 |
3 | +++ juju/hooks/commands.py 2012-07-03 18:49:20 +0000 |
4 | @@ -1,3 +1,4 @@ |
5 | +import json |
6 | import logging |
7 | import os |
8 | import pipes |
9 | @@ -14,7 +15,28 @@ |
10 | BAD_CHARS = re.compile("[\-\./:()<>|?*]|(\\\)") |
11 | |
12 | |
13 | -class RelationGetCli(CommandLineClient): |
14 | +class TestOptionMixin(object): |
15 | + def customize_parser(self): |
16 | + self.parser.add_argument("--test", |
17 | + action="store_true", |
18 | + default=False, |
19 | + help="Exit code indicates if the value " |
20 | + "is present and not empty") |
21 | + |
22 | + def tests_true(self, result): |
23 | + return 0 if bool(result) else 1 |
24 | + |
25 | + def handle_test(self, result): |
26 | + self.exit_code = self.tests_true(result) |
27 | + |
28 | + def render(self, result): |
29 | + if self.options.test is True: |
30 | + self.handle_test(result) |
31 | + else: |
32 | + super(TestOptionMixin, self).render(result) |
33 | + |
34 | + |
35 | +class RelationGetCli(TestOptionMixin, CommandLineClient): |
36 | keyvalue_pairs = False |
37 | |
38 | def customize_parser(self): |
39 | @@ -24,6 +46,7 @@ |
40 | "-r", dest="relation_id", default="", metavar="RELATION ID") |
41 | self.parser.add_argument("settings_name", default="", nargs="?") |
42 | self.parser.add_argument("unit_name", default=remote_unit, nargs="?") |
43 | + super(RelationGetCli, self).customize_parser() |
44 | |
45 | @inlineCallbacks |
46 | def run(self): |
47 | @@ -88,6 +111,9 @@ |
48 | self.options.relation_id, |
49 | self.options.keyvalue_pairs) |
50 | |
51 | + def render(self, result): |
52 | + return None |
53 | + |
54 | |
55 | def relation_set(): |
56 | """Entry point for relation-set.""" |
57 | @@ -179,11 +205,12 @@ |
58 | sys.exit(client()) |
59 | |
60 | |
61 | -class ConfigGetCli(CommandLineClient): |
62 | +class ConfigGetCli(TestOptionMixin, CommandLineClient): |
63 | keyvalue_pairs = False |
64 | |
65 | def customize_parser(self): |
66 | self.parser.add_argument("option_name", default="", nargs="?") |
67 | + super(ConfigGetCli, self).customize_parser() |
68 | |
69 | @inlineCallbacks |
70 | def run(self): |
71 | @@ -213,6 +240,9 @@ |
72 | return self.client.open_port( |
73 | self.options.client_id, *self.options.port_protocol) |
74 | |
75 | + def render(self, result): |
76 | + return None |
77 | + |
78 | |
79 | def open_port(): |
80 | """Entry point for open-port.""" |
81 | @@ -234,6 +264,9 @@ |
82 | return self.client.close_port( |
83 | self.options.client_id, *self.options.port_protocol) |
84 | |
85 | + def render(self, result): |
86 | + return None |
87 | + |
88 | |
89 | def close_port(): |
90 | """Entry point for close-port.""" |
91 | @@ -241,11 +274,12 @@ |
92 | sys.exit(client()) |
93 | |
94 | |
95 | -class UnitGetCli(CommandLineClient): |
96 | +class UnitGetCli(TestOptionMixin, CommandLineClient): |
97 | keyvalue_pairs = False |
98 | |
99 | def customize_parser(self): |
100 | self.parser.add_argument("setting_name") |
101 | + super(UnitGetCli, self).customize_parser() |
102 | |
103 | @inlineCallbacks |
104 | def run(self): |
105 | |
106 | === modified file 'juju/hooks/tests/test_invoker.py' |
107 | --- juju/hooks/tests/test_invoker.py 2012-07-03 07:30:53 +0000 |
108 | +++ juju/hooks/tests/test_invoker.py 2012-07-03 18:49:20 +0000 |
109 | @@ -340,6 +340,49 @@ |
110 | self.assertEqual('VAR_NAME=rabbit\n\n', data) |
111 | |
112 | @defer.inlineCallbacks |
113 | + def test_relation_get_test_option(self): |
114 | + yield self.build_default_relationships() |
115 | + |
116 | + hook_log = self.capture_logging("hook") |
117 | + |
118 | + # Populate and verify some data we will |
119 | + # later extract with the hook |
120 | + values = {"string": "rabbit hole", |
121 | + "emptylist": [], |
122 | + "emptystring": "", |
123 | + "zero": 0, |
124 | + "number": 1} |
125 | + yield self.wordpress_relation.set_data(values) |
126 | + |
127 | + exe = yield self.ua.get_invoker( |
128 | + "db:42", "add", "mysql/0", self.mysql_relation, |
129 | + client_id="client_id") |
130 | + exe.environment["JUJU_REMOTE_UNIT"] = "wordpress/0" |
131 | + |
132 | + @defer.inlineCallbacks |
133 | + def test_exit(variable, expected): |
134 | + # --test can return a bad exit code from the POV of |
135 | + # the invoker, this is fine, its just the way I'm using |
136 | + # it to get at the value thats otherwise fine in the |
137 | + # hook itself |
138 | + try: |
139 | + result = yield exe(self.create_hook("relation-get", |
140 | + "--test %s" % variable)) |
141 | + self.assertEqual(result, expected) |
142 | + except errors.CharmInvocationError: |
143 | + if expected == 1: |
144 | + pass |
145 | + data = hook_log.getvalue() |
146 | + self.assertEqual(data, "") |
147 | + |
148 | + yield test_exit("string", 0) |
149 | + yield test_exit("emptylist", 1) |
150 | + yield test_exit("emptystring", 1) |
151 | + yield test_exit("zero", 1) |
152 | + yield test_exit("number", 0) |
153 | + |
154 | + |
155 | + @defer.inlineCallbacks |
156 | def test_relation_get_format_shell_bad_vars(self): |
157 | """If illegal values are make somehow available warn.""" |
158 | yield self.build_default_relationships() |
159 | @@ -433,6 +476,49 @@ |
160 | self.assertEqual(data["name"], "rabbit") |
161 | self.assertEqual(data["forgotten"], "lyrics") |
162 | |
163 | + @defer.inlineCallbacks |
164 | + def test_config_get_test_option(self): |
165 | + """Validate that config-get returns expected values.""" |
166 | + yield self.build_default_relationships() |
167 | + |
168 | + hook_log = self.capture_logging("hook") |
169 | + |
170 | + # Populate and verify some data we will |
171 | + # later extract with the hook |
172 | + expected = {"string": "rabbit", |
173 | + "empty": "", |
174 | + "emptylist": []} |
175 | + |
176 | + exe = yield self.ua.get_invoker( |
177 | + "db:42", "add", "mysql/0", self.mysql_relation, |
178 | + client_id="client_id") |
179 | + |
180 | + context = yield self.ua.get_context("client_id") |
181 | + config = yield context.get_config() |
182 | + config.update(expected) |
183 | + yield config.write() |
184 | + |
185 | + # invoke relation-get and verify the result |
186 | + @defer.inlineCallbacks |
187 | + def test_exit(variable, expected): |
188 | + # --test can return a bad exit code from the POV of |
189 | + # the invoker, this is fine, its just the way I'm using |
190 | + # it to get at the value thats otherwise fine in the |
191 | + # hook itself |
192 | + try: |
193 | + result = yield exe(self.create_hook("config-get", |
194 | + "--test %s" % variable)) |
195 | + self.assertEqual(result, expected) |
196 | + except errors.CharmInvocationError: |
197 | + if expected == 1: |
198 | + pass |
199 | + data = hook_log.getvalue() |
200 | + self.assertEqual(data, "") |
201 | + |
202 | + yield test_exit("string", 0) |
203 | + yield test_exit("emptylist", 1) |
204 | + yield test_exit("emptystring", 1) |
205 | + |
206 | |
207 | class RelationInvokerTestBase(InvokerTestBase, RelationTestBase): |
208 | |
209 | @@ -684,6 +770,18 @@ |
210 | self.assertEqual("mysql-0.example.com", data.strip()) |
211 | |
212 | @defer.inlineCallbacks |
213 | + def test_unit_get_test_option(self): |
214 | + """Private addresses can be tested for.""" |
215 | + hook_log = self.capture_logging("hook") |
216 | + exe = yield self.ua.get_invoker( |
217 | + "database:42", "add", "mysql/0", self.relation, |
218 | + client_id="client_id") |
219 | + result = yield exe(self.create_hook("unit-get", "--test private-address")) |
220 | + self.assertEqual(result, 0) |
221 | + data = hook_log.getvalue() |
222 | + self.assertEqual("", data.strip()) |
223 | + |
224 | + @defer.inlineCallbacks |
225 | def test_spawn_cli_get_unit_unknown_public_address(self): |
226 | """If for some hysterical raison, the public address hasn't been set. |
227 |
Reviewers: mp+106067_ code.launchpad. net,
Message:
Please take a look.
Description:
Adds support for --test and doesn't output Python reprs
This branch bundles two related changes, support for --test on
relation-get, unit-get and config-get.
This should be similar to the additions made in the golang version.
Also this changes to always use a formatter for output and the smart
output formatter was changed to
YAML dump collection types, normal string values are still printed w/o
serialization.
https:/ /code.launchpad .net/~bcsaller/ juju/sane_ output_ test_option/ +merge/ 106067
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/6216053/
Affected files: commands. py tests/test_ invoker. py
A [revision details]
M juju/hooks/cli.py
M juju/hooks/
M juju/hooks/