Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(513)

Side by Side Diff: build/android/pylib/remote/device/remote_device_test_run.py

Issue 1415533007: [Android] Add sharding for AMP instrumentation tests. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 # Copyright 2014 The Chromium Authors. All rights reserved. 1 # Copyright 2014 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 """Run specific test on specific environment.""" 5 """Run specific test on specific environment."""
6 6
7 import json 7 import json
8 import logging 8 import logging
9 import os 9 import os
10 import random
10 import re 11 import re
11 import shutil 12 import shutil
12 import string 13 import string
13 import tempfile 14 import tempfile
14 import time 15 import time
15 import zipfile 16 import zipfile
16 17
17 from devil.utils import zip_utils 18 from devil.utils import reraiser_thread
18 from pylib.base import base_test_result 19 from pylib.base import base_test_result
19 from pylib.base import test_run 20 from pylib.base import test_run
20 from pylib.remote.device import appurify_constants
21 from pylib.remote.device import appurify_sanitized 21 from pylib.remote.device import appurify_sanitized
22 from pylib.remote.device import remote_device_helper 22 from pylib.remote.device import remote_device_helper
23 23
24 _DEVICE_OFFLINE_RE = re.compile('error: device not found') 24 _DEVICE_OFFLINE_RE = re.compile('error: device not found')
25 _LONG_MSG_RE = re.compile('longMsg=(.*)$') 25 _LONG_MSG_RE = re.compile('longMsg=(.*)$')
26 _SHORT_MSG_RE = re.compile('shortMsg=(.*)$') 26 _SHORT_MSG_RE = re.compile('shortMsg=(.*)$')
27 27
28 class RemoteDeviceTestRun(test_run.TestRun): 28 class RemoteDeviceTestRun(test_run.TestRun):
29 """Run tests on a remote device.""" 29 """Run tests on a remote device."""
30 30
31 _TEST_RUN_KEY = 'test_run' 31 WAIT_TIME = 10
32 _TEST_RUN_ID_KEY = 'test_run_id'
33
34 WAIT_TIME = 5
35 COMPLETE = 'complete' 32 COMPLETE = 'complete'
36 HEARTBEAT_INTERVAL = 300 33 HEARTBEAT_INTERVAL = 300
37 34
35 _TEST_RUN_KEY = 'test_run'
36 _TEST_RUN_IDS_KEY = 'test_run_ids'
37
38 def __init__(self, env, test_instance): 38 def __init__(self, env, test_instance):
39 """Constructor. 39 """Constructor.
40 40
41 Args: 41 Args:
42 env: Environment the tests will run in. 42 env: Environment the tests will run in.
43 test_instance: The test that will be run. 43 test_instance: The test that will be run.
44 """ 44 """
45 super(RemoteDeviceTestRun, self).__init__(env, test_instance) 45 super(RemoteDeviceTestRun, self).__init__(env, test_instance)
46 self._app_id = None
47 self._appurify_configs = {
48 'network': env.network_config,
49 'pcap': env.pcap_config,
50 'profiler': env.profiler_config,
51 'videocapture': env.videocapture_config,
52 }
53 self._device_ids = None
46 self._env = env 54 self._env = env
47 self._test_instance = test_instance 55 self._test_instance = test_instance
48 self._app_id = '' 56 self._test_ids = []
49 self._test_id = '' 57 self._test_run_ids = []
50 self._results = '' 58
51 self._test_run_id = '' 59 def _GetTestFramework(self):
52 self._results_temp_dir = None 60 raise NotImplementedError
61
62 def _SetupTestShards(self, num_shards):
63 raise NotImplementedError
64
65 def _GetAppPath(self):
66 raise NotImplementedError
53 67
54 #override 68 #override
55 def SetUp(self): 69 def SetUp(self):
56 """Set up a test run.""" 70 """Set up a test run."""
57 if self._env.trigger: 71 if self._env.trigger:
58 self._TriggerSetUp() 72 num_shards = 1
73 if self._ShouldShard():
74 num_shards = min(self._env.num_shards, len(self._env.device_ids))
75 # TODO(mikecase): Change to always run with the number of shards passed.
76 # Will need some shards to wait for new devices to become available.
77 if num_shards < self._env.num_shards:
78 logging.warning(
79 'Requested to shard across %s devices, only %s availible.',
80 self._env.num_shards, num_shards)
81 logging.info('Sharding test run across %s device(s).', num_shards)
82
83 self._test_ids = self._SetupTestShards(num_shards)
84
59 elif self._env.collect: 85 elif self._env.collect:
60 assert isinstance(self._env.collect, basestring), ( 86 assert isinstance(self._env.collect, basestring), (
61 'File for storing test_run_id must be a string.') 87 'File for storing test_run_id must be a string.')
62 with open(self._env.collect, 'r') as persisted_data_file: 88 with open(self._env.collect, 'r') as persisted_data_file:
63 persisted_data = json.loads(persisted_data_file.read()) 89 persisted_data = json.loads(persisted_data_file.read())
64 self._env.LoadFrom(persisted_data) 90 self._LoadFrom(persisted_data)
65 self.LoadFrom(persisted_data)
66 91
67 def _TriggerSetUp(self): 92 def _ShouldShard(self):
68 """Set up the triggering of a test run."""
69 raise NotImplementedError 93 raise NotImplementedError
70 94
71 #override 95 def _Trigger(self, device_id, test_id):
96 with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
97 logging.WARNING):
98 test_start_response = appurify_sanitized.api.tests_run(
99 access_token=self._env.token, device_type_id=device_id,
100 app_id=self._app_id, test_id=test_id)
101 remote_device_helper.TestHttpResponse(test_start_response,
102 'Unable to run test.')
103 return test_start_response.json()['response']['test_run_id']
104
72 def RunTests(self): 105 def RunTests(self):
73 """Run the test.""" 106 """Run the test."""
107
74 if self._env.trigger: 108 if self._env.trigger:
75 with appurify_sanitized.SanitizeLogging(self._env.verbose_count, 109 def trigger(device_id, test_id):
76 logging.WARNING): 110 test_run_id = self._Trigger(device_id, test_id)
77 test_start_res = appurify_sanitized.api.tests_run( 111 self._test_run_ids.append(test_run_id)
78 self._env.token, self._env.device_type_id, self._app_id, 112
79 self._test_id) 113 self._app_id = self._UploadAppToDevice(self._GetAppPath())
80 remote_device_helper.TestHttpResponse( 114 self._device_ids = random.sample(
81 test_start_res, 'Unable to run test.') 115 self._env.device_ids, len(self._test_ids))
82 self._test_run_id = test_start_res.json()['response']['test_run_id'] 116
83 logging.info('Test run id: %s', self._test_run_id) 117 workers = reraiser_thread.ReraiserThreadGroup(
118 [reraiser_thread.ReraiserThread(
119 trigger, args=[device_id, test_id],
120 name='trigger test %s' % test_id)
121 for device_id, test_id in zip(self._device_ids, self._test_ids)])
122 workers.StartAll()
123 workers.JoinAll()
84 124
85 if self._env.collect: 125 if self._env.collect:
86 current_status = '' 126 parsed_results = base_test_result.TestRunResults()
87 timeout_counter = 0
88 heartbeat_counter = 0
89 while self._GetTestStatus(self._test_run_id) != self.COMPLETE:
90 if self._results['detailed_status'] != current_status:
91 logging.info('Test status: %s', self._results['detailed_status'])
92 current_status = self._results['detailed_status']
93 timeout_counter = 0
94 heartbeat_counter = 0
95 if heartbeat_counter > self.HEARTBEAT_INTERVAL:
96 logging.info('Test status: %s', self._results['detailed_status'])
97 heartbeat_counter = 0
98 127
99 timeout = self._env.timeouts.get( 128 def collect(test_run_id):
100 current_status, self._env.timeouts['unknown']) 129 with tempfile.NamedTemporaryFile(
101 if timeout_counter > timeout: 130 prefix='results-', suffix='.zip') as download_results_file:
102 raise remote_device_helper.RemoteDeviceError( 131 test_output = self._Collect(test_run_id=test_run_id)
103 'Timeout while in %s state for %s seconds' 132 self._DownloadTestResults(test_output, download_results_file.name)
104 % (current_status, timeout), 133 parsed_results.AddTestRunResults(self._ParseTestResults(
105 is_infra_error=True) 134 test_output, download_results_file.name))
106 time.sleep(self.WAIT_TIME)
107 timeout_counter += self.WAIT_TIME
108 heartbeat_counter += self.WAIT_TIME
109 self._DownloadTestResults(self._env.results_path)
110 135
111 if self._results['results']['exception']: 136 workers = reraiser_thread.ReraiserThreadGroup(
112 raise remote_device_helper.RemoteDeviceError( 137 [reraiser_thread.ReraiserThread(
113 self._results['results']['exception'], is_infra_error=True) 138 collect, args=[test_run_id],
114 139 name='collect test %s' % test_run_id)
115 return self._ParseTestResults() 140 for test_run_id in self._test_run_ids])
141 workers.StartAll()
142 workers.JoinAll()
143 return parsed_results
116 144
117 #override 145 #override
118 def TearDown(self): 146 def TearDown(self):
119 """Tear down the test run.""" 147 """Tear down the test run."""
148
120 if self._env.collect: 149 if self._env.collect:
121 self._CollectTearDown() 150 self._CollectTearDown()
122 elif self._env.trigger: 151 elif self._env.trigger:
123 assert isinstance(self._env.trigger, basestring), ( 152 assert isinstance(self._env.trigger, basestring), (
124 'File for storing test_run_id must be a string.') 153 'File for storing test_run_id must be a string.')
125 with open(self._env.trigger, 'w') as persisted_data_file: 154 with open(self._env.trigger, 'w') as persisted_data_file:
126 persisted_data = {} 155 persisted_data = {}
127 self.DumpTo(persisted_data) 156 self._DumpTo(persisted_data)
128 self._env.DumpTo(persisted_data)
129 persisted_data_file.write(json.dumps(persisted_data)) 157 persisted_data_file.write(json.dumps(persisted_data))
130 158
159 def _Collect(self, test_run_id):
160 current_status = ''
161 timeout_counter = 0
162 heartbeat_counter = 0
163 results = self._CheckTestResults(test_run_id)
164 while results['status'] != self.COMPLETE:
165 if results['detailed_status'] != current_status:
166 logging.info('Test status: %s', results['detailed_status'])
167 current_status = results['detailed_status']
168 timeout_counter = 0
169 heartbeat_counter = 0
170 if heartbeat_counter > self.HEARTBEAT_INTERVAL:
171 logging.info('Test status: %s', results['detailed_status'])
172 heartbeat_counter = 0
173
174 timeout = self._env.timeouts.get(
175 current_status, self._env.timeouts['unknown'])
176 if timeout_counter > timeout:
177 raise remote_device_helper.RemoteDeviceError(
178 'Timeout while in %s state for %s seconds'
179 % (current_status, timeout),
180 is_infra_error=True)
181 time.sleep(self.WAIT_TIME)
182 timeout_counter += self.WAIT_TIME
183 heartbeat_counter += self.WAIT_TIME
184 results = self._CheckTestResults(test_run_id)
185 if results['results']['exception']:
186 raise remote_device_helper.RemoteDeviceError(
187 results['results']['exception'],
188 is_infra_error=True)
189 return results
190
131 def _CollectTearDown(self): 191 def _CollectTearDown(self):
132 if self._GetTestStatus(self._test_run_id) != self.COMPLETE: 192 if self._test_run_ids:
133 with appurify_sanitized.SanitizeLogging(self._env.verbose_count, 193 workers = reraiser_thread.ReraiserThreadGroup(
134 logging.WARNING): 194 [reraiser_thread.ReraiserThread(
135 test_abort_res = appurify_sanitized.api.tests_abort( 195 self._AbortTestRun, args=[test_run_id],
136 self._env.token, self._test_run_id, reason='Test runner exiting.') 196 name='aborting test %s' % test_run_id)
137 remote_device_helper.TestHttpResponse(test_abort_res, 197 for test_run_id in self._test_run_ids])
138 'Unable to abort test.') 198 workers.StartAll()
139 if self._results_temp_dir: 199 workers.JoinAll()
140 shutil.rmtree(self._results_temp_dir)
141 200
142 def __enter__(self): 201 def __enter__(self):
143 """Set up the test run when used as a context manager.""" 202 """Set up the test run when used as a context manager."""
144 self.SetUp() 203 self.SetUp()
145 return self 204 return self
146 205
147 def __exit__(self, exc_type, exc_val, exc_tb): 206 def __exit__(self, exc_type, exc_val, exc_tb):
148 """Tear down the test run when used as a context manager.""" 207 """Tear down the test run when used as a context manager."""
149 self.TearDown() 208 self.TearDown()
150 209
151 def DumpTo(self, persisted_data): 210 def _DumpTo(self, persisted_data):
152 test_run_data = { 211 """Dump test run information to dict."""
153 self._TEST_RUN_ID_KEY: self._test_run_id, 212 test_run_data = {self._TEST_RUN_IDS_KEY: self._test_run_ids}
154 }
155 persisted_data[self._TEST_RUN_KEY] = test_run_data 213 persisted_data[self._TEST_RUN_KEY] = test_run_data
156 214
157 def LoadFrom(self, persisted_data): 215 def _LoadFrom(self, persisted_data):
216 """Load test run information."""
158 test_run_data = persisted_data[self._TEST_RUN_KEY] 217 test_run_data = persisted_data[self._TEST_RUN_KEY]
159 self._test_run_id = test_run_data[self._TEST_RUN_ID_KEY] 218 self._test_run_ids = test_run_data[self._TEST_RUN_IDS_KEY]
160 219
161 def _ParseTestResults(self): 220 def _ParseTestResults(self, test_output, results_zip):
162 raise NotImplementedError 221 raise NotImplementedError
163 222
164 def _GetTestByName(self, test_name): 223 def _DownloadTestResults(self, results, download_path):
165 """Gets test_id for specific test.
166
167 Args:
168 test_name: Test to find the ID of.
169 """
170 with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
171 logging.WARNING):
172 test_list_res = appurify_sanitized.api.tests_list(self._env.token)
173 remote_device_helper.TestHttpResponse(test_list_res,
174 'Unable to get tests list.')
175 for test in test_list_res.json()['response']:
176 if test['test_type'] == test_name:
177 return test['test_id']
178 raise remote_device_helper.RemoteDeviceError(
179 'No test found with name %s' % (test_name))
180
181 def _DownloadTestResults(self, results_path):
182 """Download the test results from remote device service. 224 """Download the test results from remote device service.
183 225
184 Downloads results in temporary location, and then copys results
185 to results_path if results_path is not set to None.
186
187 Args:
188 results_path: Path to download appurify results zipfile.
189
190 Returns: 226 Returns:
191 Path to downloaded file. 227 Path to downloaded file.
192 """ 228 """
229 logging.info('Downloading results to %s.', download_path)
230 with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
231 logging.WARNING):
232 appurify_sanitized.utils.wget(
233 url=results['results']['url'], path=download_path)
234 if self._env.results_dir:
235 logging.info('Copying results to %s from %s',
236 self._env.results_dir, download_path)
237 if not os.path.exists(os.path.dirname(self._env.results_dir)):
238 os.makedirs(self._env.results_dir)
239 shutil.copy(download_path, self._env.results_dir)
193 240
194 if self._results_temp_dir is None: 241 def _CheckTestResults(self, test_run_id):
195 self._results_temp_dir = tempfile.mkdtemp() 242 """Checks the state of the test.
196 logging.info('Downloading results to %s.', self._results_temp_dir)
197 with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
198 logging.WARNING):
199 appurify_sanitized.utils.wget(self._results['results']['url'],
200 self._results_temp_dir + '/results')
201 if results_path:
202 logging.info('Copying results to %s', results_path)
203 if not os.path.exists(os.path.dirname(results_path)):
204 os.makedirs(os.path.dirname(results_path))
205 shutil.copy(self._results_temp_dir + '/results', results_path)
206 return self._results_temp_dir + '/results'
207
208 def _GetTestStatus(self, test_run_id):
209 """Checks the state of the test, and sets self._results
210 243
211 Args: 244 Args:
212 test_run_id: Id of test on on remote service. 245 test_run_id: Id of test on on remote service.
213 """ 246 """
214
215 with appurify_sanitized.SanitizeLogging(self._env.verbose_count, 247 with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
216 logging.WARNING): 248 logging.WARNING):
217 test_check_res = appurify_sanitized.api.tests_check_result( 249 test_check_response = appurify_sanitized.api.tests_check_result(
218 self._env.token, test_run_id) 250 access_token=self._env.token, test_run_id=test_run_id)
219 remote_device_helper.TestHttpResponse(test_check_res, 251 remote_device_helper.TestHttpResponse(test_check_response,
220 'Unable to get test status.') 252 'Unable to get test status.')
221 self._results = test_check_res.json()['response'] 253 return test_check_response.json()['response']
222 return self._results['status']
223
224 def _AmInstrumentTestSetup(self, app_path, test_path, runner_package,
225 environment_variables, extra_apks=None):
226 config = {'runner': runner_package}
227 if environment_variables:
228 config['environment_vars'] = ','.join(
229 '%s=%s' % (k, v) for k, v in environment_variables.iteritems())
230
231 self._app_id = self._UploadAppToDevice(app_path)
232
233 data_deps = self._test_instance.GetDataDependencies()
234 if data_deps:
235 with tempfile.NamedTemporaryFile(suffix='.zip') as test_with_deps:
236 sdcard_files = []
237 additional_apks = []
238 host_test = os.path.basename(test_path)
239 with zipfile.ZipFile(test_with_deps.name, 'w') as zip_file:
240 zip_file.write(test_path, host_test, zipfile.ZIP_DEFLATED)
241 for h, _ in data_deps:
242 if os.path.isdir(h):
243 zip_utils.WriteToZipFile(zip_file, h, '.')
244 sdcard_files.extend(os.listdir(h))
245 else:
246 zip_utils.WriteToZipFile(zip_file, h, os.path.basename(h))
247 sdcard_files.append(os.path.basename(h))
248 for a in extra_apks or ():
249 zip_utils.WriteToZipFile(zip_file, a, os.path.basename(a))
250 additional_apks.append(os.path.basename(a))
251
252 config['sdcard_files'] = ','.join(sdcard_files)
253 config['host_test'] = host_test
254 if additional_apks:
255 config['additional_apks'] = ','.join(additional_apks)
256 self._test_id = self._UploadTestToDevice(
257 'robotium', test_with_deps.name, app_id=self._app_id)
258 else:
259 self._test_id = self._UploadTestToDevice('robotium', test_path)
260
261 logging.info('Setting config: %s', config)
262 appurify_configs = {}
263 if self._env.network_config:
264 appurify_configs['network'] = self._env.network_config
265 self._SetTestConfig('robotium', config, **appurify_configs)
266 254
267 def _UploadAppToDevice(self, app_path): 255 def _UploadAppToDevice(self, app_path):
268 """Upload app to device.""" 256 """Upload app to device."""
269 logging.info('Uploading %s to remote service as %s.', app_path, 257 logging.info('Uploading %s to remote service as %s.', app_path,
270 self._test_instance.suite) 258 self._test_instance.suite)
271 with open(app_path, 'rb') as apk_src: 259 with open(app_path, 'rb') as apk_src:
272 with appurify_sanitized.SanitizeLogging(self._env.verbose_count, 260 with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
273 logging.WARNING): 261 logging.WARNING):
274 upload_results = appurify_sanitized.api.apps_upload( 262 upload_results = appurify_sanitized.api.apps_upload(
275 self._env.token, apk_src, 'raw', name=self._test_instance.suite) 263 self._env.token, apk_src, 'raw', name=self._test_instance.suite)
276 remote_device_helper.TestHttpResponse( 264 remote_device_helper.TestHttpResponse(upload_results,
277 upload_results, 'Unable to upload %s.' % app_path) 265 'Unable to upload %s.' % app_path)
278 return upload_results.json()['response']['app_id'] 266 return upload_results.json()['response']['app_id']
279 267
280 def _UploadTestToDevice(self, test_type, test_path, app_id=None): 268 def _UploadTestToDevice(self, test_path):
281 """Upload test to device 269 """Upload test to device."""
282 Args: 270 logging.info('Shard uploading %s to remote service.', test_path)
283 test_type: Type of test that is being uploaded. Ex. uirobot, gtest..
284 """
285 logging.info('Uploading %s to remote service.', test_path)
286 with open(test_path, 'rb') as test_src: 271 with open(test_path, 'rb') as test_src:
287 with appurify_sanitized.SanitizeLogging(self._env.verbose_count, 272 with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
288 logging.WARNING): 273 logging.WARNING):
289 upload_results = appurify_sanitized.api.tests_upload( 274 upload_results_response = appurify_sanitized.api.tests_upload(
290 self._env.token, test_src, 'raw', test_type, app_id=app_id) 275 access_token=self._env.token, test_source=test_src,
291 remote_device_helper.TestHttpResponse(upload_results, 276 test_source_type='raw', test_type=self._GetTestFramework(),
292 'Unable to upload %s.' % test_path) 277 app_id=self._app_id)
293 return upload_results.json()['response']['test_id'] 278 remote_device_helper.TestHttpResponse(
279 upload_results_response, 'Unable to upload %s.' % test_path)
280 return upload_results_response.json()['response']['test_id']
294 281
295 def _SetTestConfig(self, runner_type, runner_configs, 282 def _UploadTestConfigToDevice(
296 network=appurify_constants.NETWORK.WIFI_1_BAR, 283 self, test_id, framework_configs, appurify_configs):
297 pcap=0, profiler=0, videocapture=0): 284 """Generates and uploads config file for test."""
298 """Generates and uploads config file for test.
299 Args:
300 runner_configs: Configs specific to the runner you are using.
301 network: Config to specify the network environment the devices running
302 the tests will be in.
303 pcap: Option to set the recording the of network traffic from the device.
304 profiler: Option to set the recording of CPU, memory, and network
305 transfer usage in the tests.
306 videocapture: Option to set video capture during the tests.
307
308 """
309 logging.info('Generating config file for test.') 285 logging.info('Generating config file for test.')
286 config_data = ['[appurify]']
287 config_data.extend(
288 '%s=%s' % (k, v) for k, v in appurify_configs.iteritems())
289 config_data.append('[%s]' % self._GetTestFramework())
290 config_data.extend(
291 '%s=%s' % (k, v) for k, v in framework_configs.iteritems())
310 with tempfile.TemporaryFile() as config: 292 with tempfile.TemporaryFile() as config:
311 config_data = [
312 '[appurify]',
313 'network=%s' % network,
314 'pcap=%s' % pcap,
315 'profiler=%s' % profiler,
316 'videocapture=%s' % videocapture,
317 '[%s]' % runner_type
318 ]
319 config_data.extend(
320 '%s=%s' % (k, v) for k, v in runner_configs.iteritems())
321 config.write(''.join('%s\n' % l for l in config_data)) 293 config.write(''.join('%s\n' % l for l in config_data))
322 config.flush() 294 config.flush()
323 config.seek(0) 295 config.seek(0)
324 with appurify_sanitized.SanitizeLogging(self._env.verbose_count, 296 with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
325 logging.WARNING): 297 logging.WARNING):
326 config_response = appurify_sanitized.api.config_upload( 298 config_upload_response = appurify_sanitized.api.config_upload(
327 self._env.token, config, self._test_id) 299 access_token=self._env.token, config_src=config, test_id=test_id)
328 remote_device_helper.TestHttpResponse( 300 remote_device_helper.TestHttpResponse(config_upload_response,
329 config_response, 'Unable to upload test config.') 301 'Unable to upload test config.')
330 302
331 def _LogLogcat(self, level=logging.CRITICAL): 303 def _AbortTestRun(self, test_run_id):
332 """Prints out logcat downloaded from remote service. 304 logging.info('Aborting test run %s.', test_run_id)
333 Args: 305 if self._CheckTestResults(test_run_id)['status'] != self.COMPLETE:
334 level: logging level to print at. 306 with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
307 logging.WARNING):
308 test_abort_response = appurify_sanitized.api.tests_abort(
309 access_token=self._env.token, test_run_id=test_run_id,
310 reason='Test runner exiting.')
311 remote_device_helper.TestHttpResponse(test_abort_response,
312 'Unable to abort test.')
335 313
336 Raises: 314 def DetectPlatformErrors(results, test_output, results_zip):
337 KeyError: If appurify_results/logcat.txt file cannot be found in 315 if not test_output['results']['pass']:
338 downloaded zip. 316 crash_msg = None
339 """ 317 for line in test_output['results']['output'].splitlines():
340 zip_file = self._DownloadTestResults(None) 318 m = _LONG_MSG_RE.search(line)
341 with zipfile.ZipFile(zip_file) as z: 319 if m:
342 try: 320 crash_msg = m.group(1)
343 logcat = z.read('appurify_results/logcat.txt') 321 break
344 printable_logcat = ''.join(c for c in logcat if c in string.printable) 322 m = _SHORT_MSG_RE.search(line)
345 for line in printable_logcat.splitlines(): 323 if m:
346 logging.log(level, line) 324 crash_msg = m.group(1)
347 except KeyError: 325 if crash_msg:
348 logging.error('No logcat found.') 326 _LogLogcat(results_zip)
327 results.AddResult(base_test_result.BaseTestResult(
328 crash_msg, base_test_result.ResultType.CRASH))
329 elif _DidDeviceGoOffline(results_zip):
330 _LogLogcat(results_zip)
331 _LogAdbTraceLog(results_zip)
332 raise remote_device_helper.RemoteDeviceError(
333 'Remote service unable to reach device.',
334 is_infra_error=True)
335 else:
336 # Remote service is reporting a failure, but no failure in results obj.
337 if results.DidRunPass():
338 results.AddResult(base_test_result.BaseTestResult(
339 'Remote service detected error.',
340 base_test_result.ResultType.UNKNOWN))
349 341
350 def _LogAdbTraceLog(self): 342 def _LogLogcat(results_zip, level=logging.CRITICAL):
351 zip_file = self._DownloadTestResults(None) 343 """Prints out logcat downloaded from remote service.
352 with zipfile.ZipFile(zip_file) as z: 344 Args:
353 adb_trace_log = z.read('adb_trace.log') 345 results_zip: path to zipfile containing the results files.
354 for line in adb_trace_log.splitlines(): 346 level: logging level to print at.
355 logging.critical(line)
356 347
357 def _DidDeviceGoOffline(self): 348 Raises:
358 zip_file = self._DownloadTestResults(None) 349 KeyError: If appurify_results/logcat.txt file cannot be found in
359 with zipfile.ZipFile(zip_file) as z: 350 downloaded zip.
360 adb_trace_log = z.read('adb_trace.log') 351 """
361 if any(_DEVICE_OFFLINE_RE.search(l) for l in adb_trace_log.splitlines()): 352 with zipfile.ZipFile(results_zip) as z:
362 return True 353 try:
363 return False 354 logcat = z.read('appurify_results/logcat.txt')
355 printable_logcat = ''.join(c for c in logcat if c in string.printable)
356 for line in printable_logcat.splitlines():
357 logging.log(level, line)
358 except KeyError:
359 logging.error('No logcat found.')
364 360
365 def _DetectPlatformErrors(self, results): 361 def _LogAdbTraceLog(results_zip):
366 if not self._results['results']['pass']: 362 with zipfile.ZipFile(results_zip) as z:
367 crash_msg = None 363 adb_trace_log = z.read('adb_trace.log')
368 for line in self._results['results']['output'].splitlines(): 364 for line in adb_trace_log.splitlines():
369 m = _LONG_MSG_RE.search(line) 365 logging.critical(line)
370 if m: 366
371 crash_msg = m.group(1) 367 def _DidDeviceGoOffline(results_zip):
372 break 368 with zipfile.ZipFile(results_zip) as z:
373 m = _SHORT_MSG_RE.search(line) 369 adb_trace_log = z.read('adb_trace.log')
374 if m: 370 if any(_DEVICE_OFFLINE_RE.search(l) for l in adb_trace_log.splitlines()):
375 crash_msg = m.group(1) 371 return True
376 if crash_msg: 372 return False
377 self._LogLogcat()
378 results.AddResult(base_test_result.BaseTestResult(
379 crash_msg, base_test_result.ResultType.CRASH))
380 elif self._DidDeviceGoOffline():
381 self._LogLogcat()
382 self._LogAdbTraceLog()
383 raise remote_device_helper.RemoteDeviceError(
384 'Remote service unable to reach device.', is_infra_error=True)
385 else:
386 # Remote service is reporting a failure, but no failure in results obj.
387 if results.DidRunPass():
388 results.AddResult(base_test_result.BaseTestResult(
389 'Remote service detected error.',
390 base_test_result.ResultType.UNKNOWN))
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698