OLD | NEW |
1 # Copyright 2015 The Chromium Authors. All rights reserved. | 1 # Copyright 2015 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 import json | 5 import json |
6 import os | 6 import os |
7 | 7 |
8 from recipe_engine import recipe_api | 8 from recipe_engine import recipe_api |
9 from . import perf_test | 9 from . import perf_test |
10 | 10 |
11 BUCKET = 'chrome-perf' | 11 BUCKET = 'chrome-perf' |
12 RESULTS_GS_DIR = 'bisect-results' | 12 RESULTS_GS_DIR = 'bisect-results' |
| 13 PARSER_PATH = 'tracing/bin/parse_metric'.split('/') |
13 | 14 |
14 | 15 |
15 class BisectTesterApi(recipe_api.RecipeApi): | 16 class BisectTesterApi(recipe_api.RecipeApi): |
16 """A module for the bisect tester bot using the chromium recipe.""" | 17 """A module for the bisect tester bot using the chromium recipe.""" |
17 | 18 |
18 def __init__(self, **kwargs): | 19 def __init__(self, **kwargs): |
19 super(BisectTesterApi, self).__init__(**kwargs) | 20 super(BisectTesterApi, self).__init__(**kwargs) |
20 self._device_to_test = None | 21 self._device_to_test = None |
21 | 22 |
22 @property | 23 @property |
23 def device_to_test(self): | 24 def device_to_test(self): |
24 return self._device_to_test | 25 return self._device_to_test |
25 | 26 |
26 @device_to_test.setter | 27 @device_to_test.setter |
27 def device_to_test(self, value): | 28 def device_to_test(self, value): |
28 self._device_to_test = value | 29 self._device_to_test = value |
29 | 30 |
30 def local_test_enabled(self): | |
31 buildername = os.environ.get('BUILDBOT_BUILDERNAME') | |
32 cr_config = self.m.chromium.c | |
33 if buildername and buildername.endswith('_bisect') and cr_config or ( | |
34 self.m.properties.get('local_test')): | |
35 return True # pragma: no cover | |
36 return False | |
37 | |
38 def load_config_from_dict(self, bisect_config): | 31 def load_config_from_dict(self, bisect_config): |
39 """Copies the required configuration keys to a new dict.""" | 32 """Copies the required configuration keys to a new dict.""" |
40 return { | 33 return { |
41 'command': bisect_config['command'], | 34 'command': bisect_config['command'], |
42 'metric': bisect_config.get('metric'), | 35 'metric': bisect_config.get('metric'), |
43 'repeat_count': int(bisect_config.get('repeat_count', 20)), | 36 'repeat_count': int(bisect_config.get('repeat_count', 20)), |
44 # The default is to NOT timeout, hence 0. | 37 # The default is to NOT timeout, hence 0. |
45 'max_time_minutes': float(bisect_config.get('max_time_minutes', 0)), | 38 'max_time_minutes': float(bisect_config.get('max_time_minutes', 0)), |
46 'test_type': bisect_config.get('test_type', 'perf') | 39 'test_type': bisect_config.get('test_type', 'perf') |
47 } | 40 } |
48 | 41 |
49 def run_test(self, test_config, **kwargs): | 42 def run_test(self, test_config, **kwargs): |
50 """Exposes perf tests implementation.""" | 43 """Exposes perf tests implementation.""" |
51 return perf_test.run_perf_test(self, test_config, **kwargs) | 44 return perf_test.run_perf_test(self, test_config, **kwargs) |
52 | |
53 def digest_run_results(self, run_results, retcodes, cfg): | |
54 # TODO(qyearsley): Change this to not use cfg or retcodes and just | |
55 # return values (or error) regardless of test_type. | |
56 if not run_results or not retcodes: # pragma: no cover | |
57 return {'error': 'No values to aggregate.'} | |
58 if cfg.get('test_type') == 'return_code': | |
59 return {'values': retcodes} | |
60 return {'values': run_results['measured_values']} | |
61 | |
62 def upload_results(self, output, results, retcodes, test_parameters): | |
63 """Puts the results as a JSON file in a GS bucket.""" | |
64 job_name = (test_parameters.get('job_name') or | |
65 self.m.properties.get('job_name')) | |
66 gs_filename = '%s/%s.results' % (RESULTS_GS_DIR, job_name) | |
67 contents = {'results': results, 'output': output, 'retcodes': retcodes} | |
68 contents_json = json.dumps(contents) | |
69 local_save_results = self.m.python('saving json to temp file', | |
70 self.resource('put_temp.py'), | |
71 stdout=self.m.raw_io.output(), | |
72 stdin=self.m.raw_io.input( | |
73 contents_json)) | |
74 | |
75 local_file = local_save_results.stdout.splitlines()[0].strip() | |
76 # TODO(robertocn): Look into using self.m.json.input(contents) instead of | |
77 # local_file. | |
78 self.m.gsutil.upload(local_file, BUCKET, gs_filename) | |
79 | |
80 def upload_job_url(self): | |
81 """Puts the URL to the job's status on a GS file.""" | |
82 # If we are running the test locally there is no need for this. | |
83 if self.local_test_enabled(): | |
84 return # pragma: no cover | |
85 gs_filename = RESULTS_GS_DIR + '/' + self.m.properties.get( | |
86 'job_name') | |
87 if 'TESTING_MASTER_HOST' in os.environ: # pragma: no cover | |
88 url = "http://%s:8041/json/builders/%s/builds/%s" % ( | |
89 os.environ['TESTING_MASTER_HOST'], | |
90 self.m.properties['buildername'], | |
91 self.m.properties['buildnumber']) | |
92 else: | |
93 url = "http://build.chromium.org/p/%s/json/builders/%s/builds/%s" % ( | |
94 self.m.properties['mastername'], | |
95 self.m.properties['buildername'], | |
96 self.m.properties['buildnumber']) | |
97 local_save_results = self.m.python('saving url to temp file', | |
98 self.resource('put_temp.py'), | |
99 stdout=self.m.raw_io.output(), | |
100 stdin=self.m.raw_io.input(url)) | |
101 local_file = local_save_results.stdout.splitlines()[0].strip() | |
102 self.m.gsutil.upload( | |
103 local_file, BUCKET, gs_filename, name=str(gs_filename)) | |
OLD | NEW |