Merge lp:~javier.collado/utah/battery_measurements_config into lp:utah
- battery_measurements_config
- Merge into dev
Status: | Merged |
---|---|
Approved by: | Max Brustkern |
Approved revision: | 833 |
Merged at revision: | 822 |
Proposed branch: | lp:~javier.collado/utah/battery_measurements_config |
Merge into: | lp:utah |
Diff against target: |
477 lines (+147/-66) 5 files modified
utah/client/common.py (+59/-32) utah/client/runner.py (+33/-12) utah/client/testcase.py (+29/-13) utah/client/tests/test_testcase.py (+1/-0) utah/client/testsuite.py (+25/-9) |
To merge this branch: | bzr merge lp:~javier.collado/utah/battery_measurements_config |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Max Brustkern (community) | Approve | ||
Joe Talbott (community) | Approve | ||
Javier Collado (community) | Needs Resubmitting | ||
Review via email:
|
Commit message
Description of the change
This branch adds a new boolean field `battery_
to the master runlist. When this field is set to `true` battery measurements
are taken if battery information is available. When this field is `false`,
which is the default value, no information will be gathered at all.
The initial design was to make it possible to specify `battery_
also in the test case control file. However, I think the additional complexity
needed to handle this wasn't really paying off. Anyway, if you think otherwise,
please let me know.
I'd like to add some documentation strings to the code that has been added
and/or updated, but if could let review the code as it is right now, it would
be great. Thanks.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andy Doan (doanac) wrote : | # |
- 832. By Javier Collado
-
Removed vim side effect
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Javier Collado (javier.collado) wrote : | # |
@Andy
Indeed, I am. Thanks for pointing that out.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Max Brustkern (nuclearbob) wrote : | # |
Now that line 93 exists, is line 90 still needed?
The rest of it looks good to me, but I haven't tested it yet.
- 833. By Javier Collado
-
Removed unused code
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Javier Collado (javier.collado) wrote : | # |
@Max
Fixed, I believe that was never really needed since it was set by the subclass
as an instance variable as it happens after these changes.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Max Brustkern (nuclearbob) wrote : | # |
Cool. I'll try to get my laptop fired up today to test it, but if you've already tested it, it's probably good to go in.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Joe Talbott (joetalbott) wrote : | # |
Looks good to me.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Max Brustkern (nuclearbob) wrote : | # |
This looks good to me.
Preview Diff
1 | === modified file 'utah/client/common.py' |
2 | --- utah/client/common.py 2013-02-06 14:16:20 +0000 |
3 | +++ utah/client/common.py 2013-02-15 08:57:19 +0000 |
4 | @@ -83,7 +83,8 @@ |
5 | |
6 | # Inspired by: |
7 | # http://stackoverflow.com/a/3326559 |
8 | -def run_cmd(command, cwd=None, timeout=0, cmd_type=CMD_TC_TEST, run_as=None): |
9 | +def run_cmd(command, cwd=None, timeout=0, cmd_type=CMD_TC_TEST, run_as=None, |
10 | + battery_measurements=False): |
11 | |
12 | if run_as is not None: |
13 | # add -n so sudo will not prompt for a password on the tty |
14 | @@ -103,7 +104,9 @@ |
15 | def alarm_handler(_signum, _frame): |
16 | raise TimeoutAlarm |
17 | |
18 | - start_battery = battery.get_data() |
19 | + if battery_measurements: |
20 | + start_battery = battery.get_data() |
21 | + |
22 | start_time = datetime.datetime.now() |
23 | p = subprocess.Popen("{} {}".format(cmd_prefix, command), |
24 | shell=True, cwd=cwd, |
25 | @@ -144,19 +147,23 @@ |
26 | ) |
27 | |
28 | time_delta = datetime.datetime.now() - start_time |
29 | - end_battery = battery.get_data() |
30 | - |
31 | - return make_result(command=command, |
32 | - retcode=p.returncode, |
33 | - stdout=stdout, |
34 | - stderr=stderr, |
35 | - start_time=start_time.strftime(DATE_FORMAT), |
36 | - time_delta=str(time_delta), |
37 | - cmd_type=cmd_type, |
38 | - user=run_as, |
39 | - start_battery=start_battery, |
40 | - end_battery=end_battery, |
41 | - ) |
42 | + |
43 | + kwargs = {'command': command, |
44 | + 'retcode': p.returncode, |
45 | + 'stdout': stdout, |
46 | + 'stderr': stderr, |
47 | + 'start_time': start_time.strftime(DATE_FORMAT), |
48 | + 'time_delta': str(time_delta), |
49 | + 'cmd_type': cmd_type, |
50 | + 'user': run_as, |
51 | + } |
52 | + |
53 | + if battery_measurements: |
54 | + end_battery = battery.get_data() |
55 | + kwargs['start_battery'] = start_battery |
56 | + kwargs['end_battery'] = end_battery |
57 | + |
58 | + return make_result(**kwargs) |
59 | |
60 | |
61 | def normalize_encoding(value, encoding='utf-8'): |
62 | @@ -237,12 +244,24 @@ |
63 | return data |
64 | |
65 | |
66 | +# Validator that sets values to defaults as explained in: |
67 | +# https://github.com/Julian/jsonschema/issues/4 |
68 | +class DefaultValidator(jsonschema.Validator): |
69 | + def validate_properties(self, properties, instance, schema): |
70 | + (super(DefaultValidator, self) |
71 | + .validate_properties(properties, instance, schema)) |
72 | + instance.update((k, v['default']) |
73 | + for k, v in properties.iteritems() |
74 | + if k not in instance and 'default' in v) |
75 | + |
76 | + |
77 | def parse_control_file(filename, schema): |
78 | """ |
79 | Parse a control file and check against the schema |
80 | """ |
81 | control_data = parse_yaml_file(filename) |
82 | - jsonschema.validate(control_data, schema) |
83 | + validator = DefaultValidator() |
84 | + validator.validate(control_data, schema) |
85 | return control_data |
86 | |
87 | |
88 | @@ -453,19 +472,29 @@ |
89 | """ |
90 | Base class for Version Ccontrol System support. |
91 | """ |
92 | - repo = "" |
93 | + |
94 | + def __init__(self, repo, destination='', battery_measurements=False): |
95 | + self.repo = repo |
96 | + self.destination = destination |
97 | + self.battery_measurements = battery_measurements |
98 | |
99 | def get(self, directory=REPO_DEFAULT_DIR): |
100 | """ |
101 | Method to retrieve a copy of the repository |
102 | """ |
103 | - return run_cmd(self.get_command, cwd=directory, cmd_type=CMD_TS_FETCH) |
104 | + return run_cmd(self.get_command, |
105 | + cwd=directory, |
106 | + cmd_type=CMD_TS_FETCH, |
107 | + battery_measurements=self.battery_measurements) |
108 | |
109 | def revision(self, directory=REPO_DEFAULT_DIR): |
110 | """ |
111 | Return the revision identifier. |
112 | """ |
113 | - return run_cmd(self.rev_command, cwd=directory, cmd_type=CMD_TS_FETCH) |
114 | + return run_cmd(self.rev_command, |
115 | + cwd=directory, |
116 | + cmd_type=CMD_TS_FETCH, |
117 | + battery_measurements=self.battery_measurements) |
118 | |
119 | def get_revision(self, directory=REPO_DEFAULT_DIR): |
120 | """ |
121 | @@ -487,23 +516,23 @@ |
122 | bazaar handler. |
123 | """ |
124 | |
125 | - def __init__(self, repo, branch=True, options="", destination=""): |
126 | - self.repo = repo |
127 | + def __init__(self, repo, branch=True, options="", destination="", |
128 | + **kwargs): |
129 | + super(BzrHandler, self).__init__(repo, destination, **kwargs) |
130 | self.options = options |
131 | - self.destination = destination |
132 | |
133 | if branch: |
134 | self.get_command = "bzr branch {} {} {}".format( |
135 | options, |
136 | self.repo, |
137 | - destination, |
138 | + self.destination, |
139 | ) |
140 | |
141 | self.rev_command = "bzr revno" |
142 | else: |
143 | self.get_command = "bzr export {} {} {}".format( |
144 | options, |
145 | - destination, |
146 | + self.destination, |
147 | self.repo, |
148 | ) |
149 | |
150 | @@ -515,15 +544,14 @@ |
151 | git handler. |
152 | """ |
153 | |
154 | - def __init__(self, repo, options="", destination=""): |
155 | - self.repo = repo |
156 | + def __init__(self, repo, options="", destination="", **kwargs): |
157 | + super(GitHandler, self).__init__(repo, destination, **kwargs) |
158 | self.options = options |
159 | - self.destination = destination |
160 | |
161 | self.get_command = "git clone {} {} {}".format( |
162 | options, |
163 | self.repo, |
164 | - destination, |
165 | + self.destination, |
166 | ) |
167 | |
168 | self.rev_command = "git rev-parse HEAD" |
169 | @@ -532,13 +560,12 @@ |
170 | class DevHandler(VCSHandler): |
171 | """ Copy from a local directory for development. """ |
172 | |
173 | - def __init__(self, repo, destination="."): |
174 | - self.repo = repo |
175 | - self.destination = destination |
176 | + def __init__(self, repo, destination=".", **kwargs): |
177 | + super(DevHandler, self).__init__(repo, destination, **kwargs) |
178 | |
179 | self.get_command = "cp -r {} {}".format( |
180 | self.repo, |
181 | - destination, |
182 | + self.destination, |
183 | ) |
184 | |
185 | self.rev_command = "echo 'DEVELOPMENT'" |
186 | |
187 | === modified file 'utah/client/runner.py' |
188 | --- utah/client/runner.py 2013-02-13 19:36:40 +0000 |
189 | +++ utah/client/runner.py 2013-02-15 08:57:19 +0000 |
190 | @@ -13,7 +13,10 @@ |
191 | # You should have received a copy of the GNU General Public License along |
192 | # with this program. If not, see <http://www.gnu.org/licenses/>. |
193 | |
194 | -from utah.client.common import DEFAULT_TSLIST |
195 | +from utah.client.common import ( |
196 | + DEFAULT_TSLIST, |
197 | + DefaultValidator, |
198 | +) |
199 | from utah.client.result import Result |
200 | from utah.client.testsuite import TestSuite |
201 | from utah.client.state_agent import StateAgentYAML |
202 | @@ -130,6 +133,10 @@ |
203 | "type": [MASTER_RUNLIST_SCHEMA_ORIG], |
204 | "required": True, |
205 | }, |
206 | + 'battery_measurements': { |
207 | + 'type': 'boolean', |
208 | + 'default': False, |
209 | + } |
210 | } |
211 | } |
212 | |
213 | @@ -256,7 +263,8 @@ |
214 | """ |
215 | Run the test suites we've parsed. |
216 | """ |
217 | - self.result.start_battery = battery.get_data() |
218 | + if self.battery_measurements: |
219 | + self.result.start_battery = battery.get_data() |
220 | |
221 | # Return value to indicate whether processing of a Runner should |
222 | # continue. This is to avoid a shutdown race on reboot cases. |
223 | @@ -279,7 +287,8 @@ |
224 | self.status = "DONE" |
225 | self.save_state() |
226 | |
227 | - self.result.end_battery = battery.get_data() |
228 | + if self.battery_measurements: |
229 | + self.result.end_battery = battery.get_data() |
230 | return self.process_results() |
231 | |
232 | def add_suite(self, suite): |
233 | @@ -378,8 +387,9 @@ |
234 | raise exceptions.MissingFile(runlist) |
235 | |
236 | data = parse_yaml_file(local_filename) |
237 | + validator = DefaultValidator() |
238 | try: |
239 | - jsonschema.validate(data, self.MASTER_RUNLIST_SCHEMA) |
240 | + validator.validate(data, self.MASTER_RUNLIST_SCHEMA) |
241 | except jsonschema.ValidationError as exception: |
242 | raise exceptions.ValidationError( |
243 | 'Master runlist failed to validate: {!r}\n' |
244 | @@ -398,6 +408,8 @@ |
245 | if 'publish' in data: |
246 | self.result.publish = data['publish'] |
247 | |
248 | + self.battery_measurements = data['battery_measurements'] |
249 | + |
250 | seen = [] |
251 | |
252 | orig_dir = os.getcwd() |
253 | @@ -421,15 +433,20 @@ |
254 | fetch_location = suite['fetch_location'] |
255 | |
256 | name = suite['name'] |
257 | + kwargs = {'repo': fetch_location, |
258 | + 'destination': name, |
259 | + 'battery_measurements': self.battery_measurements, |
260 | + } |
261 | if fetch_method == 'bzr': |
262 | - vcs_handler = BzrHandler(repo=fetch_location, destination=name) |
263 | + vcs_class = BzrHandler |
264 | elif fetch_method == 'bzr-export': |
265 | - vcs_handler = BzrHandler(branch=False, |
266 | - repo=fetch_location, destination=name) |
267 | + vcs_class = BzrHandler |
268 | + kwargs['branch'] = False |
269 | elif fetch_method == 'dev': |
270 | - vcs_handler = DevHandler(repo=fetch_location, destination=name) |
271 | + vcs_class = DevHandler |
272 | else: |
273 | - vcs_handler = GitHandler(repo=fetch_location, destination=name) |
274 | + vcs_class = GitHandler |
275 | + vcs_handler = vcs_class(**kwargs) |
276 | |
277 | includes = suite.get('include_tests') |
278 | excludes = suite.get('exclude_tests') |
279 | @@ -483,10 +500,14 @@ |
280 | self.fetched_suites.append(name) |
281 | |
282 | # Create a TestSuite |
283 | - s = TestSuite(name=name, runlist_file=suite_runlist, |
284 | - includes=includes, excludes=excludes, |
285 | - result=self.result, path=self.testsuitedir, |
286 | + s = TestSuite(name=name, |
287 | + runlist_file=suite_runlist, |
288 | + includes=includes, |
289 | + excludes=excludes, |
290 | + result=self.result, |
291 | + path=self.testsuitedir, |
292 | timeout=self.timeout, |
293 | + battery_measurements=self.battery_measurements, |
294 | _save_state_callback=self.save_state, |
295 | _reboot_callback=self.reboot) |
296 | self.add_suite(s) |
297 | |
298 | === modified file 'utah/client/testcase.py' |
299 | --- utah/client/testcase.py 2012-12-08 02:10:12 +0000 |
300 | +++ utah/client/testcase.py 2013-02-15 08:57:19 +0000 |
301 | @@ -94,6 +94,7 @@ |
302 | } |
303 | |
304 | def __init__(self, name, path, result, command=None, timeout=None, |
305 | + battery_measurements=False, |
306 | _control_data=None, _save_state_callback=None, |
307 | _reboot_callback=None): |
308 | """ |
309 | @@ -108,6 +109,7 @@ |
310 | self.results = [] |
311 | self.result = result |
312 | self.timeout = timeout |
313 | + self.battery_measurements = battery_measurements |
314 | self.command = command |
315 | self.reboot_callback = _reboot_callback |
316 | self.run_as = None |
317 | @@ -170,8 +172,12 @@ |
318 | """ |
319 | if self.status == 'NOTRUN': |
320 | self.set_status('BUILD') |
321 | - result.add_result(run_cmd(self.build_cmd, cwd=self.working_dir, |
322 | - cmd_type=CMD_TC_BUILD)) |
323 | + cmd_result = run_cmd( |
324 | + self.build_cmd, |
325 | + cwd=self.working_dir, |
326 | + cmd_type=CMD_TC_BUILD, |
327 | + battery_measurements=self.battery_measurements) |
328 | + result.add_result(cmd_result) |
329 | |
330 | def setup(self, result): |
331 | """ |
332 | @@ -179,8 +185,12 @@ |
333 | """ |
334 | if self.status == 'BUILD' and result.status == 'PASS': |
335 | self.set_status('SETUP') |
336 | - result.add_result(run_cmd(self.tc_setup, cwd=self.working_dir, |
337 | - cmd_type=CMD_TC_SETUP)) |
338 | + cmd_result = run_cmd( |
339 | + self.tc_setup, |
340 | + cwd=self.working_dir, |
341 | + cmd_type=CMD_TC_SETUP, |
342 | + battery_measurements=self.battery_measurements) |
343 | + result.add_result(cmd_result) |
344 | |
345 | def cleanup(self, result): |
346 | """ |
347 | @@ -188,8 +198,12 @@ |
348 | """ |
349 | if self.status == 'RUN': |
350 | self.set_status('CLEANUP') |
351 | - result.add_result(run_cmd(self.tc_cleanup, cwd=self.working_dir, |
352 | - cmd_type=CMD_TC_CLEANUP)) |
353 | + cmd_result = run_cmd( |
354 | + self.tc_cleanup, |
355 | + cwd=self.working_dir, |
356 | + cmd_type=CMD_TC_CLEANUP, |
357 | + battery_measurements=self.battery_measurements) |
358 | + result.add_result(cmd_result) |
359 | |
360 | def run(self): |
361 | """ |
362 | @@ -244,13 +258,15 @@ |
363 | 'action': self.action, |
364 | 'expected_results': self.expected_results, |
365 | } |
366 | - result.add_result(run_cmd(self.command, |
367 | - timeout=timeout, |
368 | - cwd=self.working_dir, |
369 | - cmd_type=CMD_TC_TEST, |
370 | - run_as=self.run_as, |
371 | - ), |
372 | - extra_info=extra_info) |
373 | + cmd_result = run_cmd( |
374 | + self.command, |
375 | + timeout=timeout, |
376 | + cwd=self.working_dir, |
377 | + cmd_type=CMD_TC_TEST, |
378 | + run_as=self.run_as, |
379 | + battery_measurements=self.battery_measurements, |
380 | + ) |
381 | + result.add_result(cmd_result, extra_info=extra_info) |
382 | |
383 | # only if we haven't failed or errored so far do |
384 | # we set the summary for the testcase. |
385 | |
386 | === modified file 'utah/client/tests/test_testcase.py' |
387 | --- utah/client/tests/test_testcase.py 2012-12-11 09:47:51 +0000 |
388 | +++ utah/client/tests/test_testcase.py 2013-02-15 08:57:19 +0000 |
389 | @@ -118,6 +118,7 @@ |
390 | 'dependencies': 'n/a', |
391 | 'action': 'n/a', |
392 | 'expected_results': 'n/a', |
393 | + 'battery_measurements': False, |
394 | } |
395 | |
396 | result = ResultYAML() |
397 | |
398 | === modified file 'utah/client/testsuite.py' |
399 | --- utah/client/testsuite.py 2012-12-08 02:10:12 +0000 |
400 | +++ utah/client/testsuite.py 2013-02-15 08:57:19 +0000 |
401 | @@ -82,7 +82,7 @@ |
402 | |
403 | def __init__(self, name, path, result, runlist_file=DEFAULT_TSLIST, |
404 | control_file=DEFAULT_TSCONTROL, includes=None, excludes=None, |
405 | - timeout=None, |
406 | + timeout=None, battery_measurements=False, |
407 | _control_data=None, _runlist_data=None, |
408 | _save_state_callback=None, _reboot_callback=None): |
409 | |
410 | @@ -92,6 +92,7 @@ |
411 | self.failures = 0 |
412 | self.errors = 0 |
413 | self.timeout = timeout |
414 | + self.battery_measurements = battery_measurements |
415 | |
416 | # work from within the testsuite's directory. |
417 | # eg. /var/lib/utah/examples |
418 | @@ -164,9 +165,12 @@ |
419 | |
420 | command = test.get('command') |
421 | |
422 | - tc = TestCase(name=name, path=test_path, |
423 | - command=command, timeout=self.timeout, |
424 | + tc = TestCase(name=name, |
425 | + path=test_path, |
426 | + command=command, |
427 | + timeout=self.timeout, |
428 | result=self.result, |
429 | + battery_measurements=self.battery_measurements, |
430 | _save_state_callback=self.save_state_callback, |
431 | _reboot_callback=self.reboot_callback) |
432 | if 'overrides' in test: |
433 | @@ -193,8 +197,12 @@ |
434 | """ |
435 | if self.status == 'NOTRUN': |
436 | self.set_status('BUILD') |
437 | - result.add_result(run_cmd(self.build_cmd, cwd=self.name, |
438 | - cmd_type=CMD_TS_BUILD)) |
439 | + cmd_result = run_cmd( |
440 | + self.build_cmd, |
441 | + cwd=self.name, |
442 | + cmd_type=CMD_TS_BUILD, |
443 | + battery_measurements=self.battery_measurements) |
444 | + result.add_result(cmd_result) |
445 | |
446 | def setup(self, result): |
447 | """ |
448 | @@ -202,8 +210,12 @@ |
449 | """ |
450 | if self.status == 'BUILD' and result.status == 'PASS': |
451 | self.set_status('SETUP') |
452 | - result.add_result(run_cmd(self.ts_setup, cwd=self.name, |
453 | - cmd_type=CMD_TS_SETUP)) |
454 | + cmd_result = run_cmd( |
455 | + self.ts_setup, |
456 | + cwd=self.name, |
457 | + cmd_type=CMD_TS_SETUP, |
458 | + battery_measurements=self.battery_measurements) |
459 | + result.add_result(cmd_result) |
460 | |
461 | def cleanup(self, result): |
462 | """ |
463 | @@ -211,8 +223,12 @@ |
464 | """ |
465 | if self.status == 'INPROGRESS': |
466 | self.set_status('CLEANUP') |
467 | - result.add_result(run_cmd(self.ts_cleanup, cwd=self.name, |
468 | - cmd_type=CMD_TS_CLEANUP)) |
469 | + cmd_result = run_cmd( |
470 | + self.ts_cleanup, |
471 | + cwd=self.name, |
472 | + cmd_type=CMD_TS_CLEANUP, |
473 | + battery_measurements=self.battery_measurements) |
474 | + result.add_result(cmd_result) |
475 | |
476 | def run(self): |
477 | """ |
102 + kkkk"""
I you must be a VIM user :)