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

Unified 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, 2 months 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 side-by-side diff with in-line comments
Download patch
Index: build/android/pylib/remote/device/remote_device_test_run.py
diff --git a/build/android/pylib/remote/device/remote_device_test_run.py b/build/android/pylib/remote/device/remote_device_test_run.py
index ec29b554464dc4850d10a7421eb568fd0875e30c..b7c389c4438b9370c2286a4a57306ee296297e77 100644
--- a/build/android/pylib/remote/device/remote_device_test_run.py
+++ b/build/android/pylib/remote/device/remote_device_test_run.py
@@ -7,6 +7,7 @@
import json
import logging
import os
+import random
import re
import shutil
import string
@@ -14,10 +15,10 @@ import tempfile
import time
import zipfile
+from devil.utils import parallelizer
from devil.utils import zip_utils
from pylib.base import base_test_result
from pylib.base import test_run
-from pylib.remote.device import appurify_constants
from pylib.remote.device import appurify_sanitized
from pylib.remote.device import remote_device_helper
@@ -28,13 +29,13 @@ _SHORT_MSG_RE = re.compile('shortMsg=(.*)$')
class RemoteDeviceTestRun(test_run.TestRun):
"""Run tests on a remote device."""
- _TEST_RUN_KEY = 'test_run'
- _TEST_RUN_ID_KEY = 'test_run_id'
-
- WAIT_TIME = 5
+ WAIT_TIME = 10
COMPLETE = 'complete'
HEARTBEAT_INTERVAL = 300
+ _TEST_RUN_KEY = 'test_run'
+ _TEST_RUN_IDS_KEY = 'test_run_ids'
+
def __init__(self, env, test_instance):
"""Constructor.
@@ -43,17 +44,45 @@ class RemoteDeviceTestRun(test_run.TestRun):
test_instance: The test that will be run.
"""
super(RemoteDeviceTestRun, self).__init__(env, test_instance)
+ self._app_id = None
+ self._appurify_configs = None
+ self._base_tempfile_dir = ''
+ self._device_ids = None
self._env = env
self._test_instance = test_instance
- self._app_id = ''
- self._test_id = ''
- self._results = ''
- self._test_run_id = ''
- self._results_temp_dir = None
+ self._test_package = None
+ self._shard_framework_configs = None
+ self._test_run_ids = []
+
+ # pylint: disable=no-self-use
+ def _GetAdditionalApks(self):
+ return NotImplementedError
+
+ def _GetAppPath(self):
+ raise NotImplementedError
+
+ def _GetTestPath(self):
+ raise NotImplementedError
+
+ def _GetTestRunnerName(self):
+ raise NotImplementedError
+
+ # pylint: disable=no-self-use
+ def _GetTestFramework(self):
+ raise NotImplementedError
+
+ # pylint: disable=no-self-use
+ def _GetFrameworkConfigs(self):
+ return NotImplementedError
+
+ # pylint: disable=unused-argument
+ def _GetShardEnvironmentVars(self, num_shards):
+ return NotImplementedError
#override
def SetUp(self):
"""Set up a test run."""
+ self._base_tempfile_dir = tempfile.mkdtemp()
if self._env.trigger:
self._TriggerSetUp()
elif self._env.collect:
@@ -61,62 +90,110 @@ class RemoteDeviceTestRun(test_run.TestRun):
'File for storing test_run_id must be a string.')
with open(self._env.collect, 'r') as persisted_data_file:
persisted_data = json.loads(persisted_data_file.read())
- self._env.LoadFrom(persisted_data)
- self.LoadFrom(persisted_data)
+ self._LoadFrom(persisted_data)
+
+ def _ShouldShard(self):
+ raise NotImplementedError
def _TriggerSetUp(self):
"""Set up the triggering of a test run."""
- raise NotImplementedError
+ self._app_id = self._UploadAppToDevice(self._GetAppPath())
+
+ if self._ShouldShard():
+ num_shards = min(self._env.num_shards, len(self._env.device_ids))
+ # TODO(mikecase): Change to always run with the number of shards passed.
+ # Will need some shards to wait for new devices to become available.
+ if num_shards < self._env.num_shards:
+ logging.warning(
+ 'Requested to shard across %s devices, only %s devices availible.',
+ self._env.num_shards, num_shards)
+ else:
+ num_shards = 1
+ logging.critical('Sharding test run across %s device(s).', num_shards)
jbudorick 2015/10/26 22:23:30 This is info, not critical.
mikecase (-- gone --) 2015/10/27 01:27:43 Done.
+ self._device_ids = random.sample(self._env.device_ids, num_shards)
+
+ shard_env_vars = (self._GetShardEnvironmentVars(num_shards)
jbudorick 2015/10/26 22:23:30 I don't think this is structured properly. Most of
mikecase (-- gone --) 2015/10/27 01:27:43 Yeah, but it even gets messier if you want some of
+ or [{} for _ in range(num_shards)])
jbudorick 2015/10/26 22:23:30 :/ this is ugly. Maybe [{}] * num_shards also: wh
mikecase (-- gone --) 2015/10/27 01:27:43 Done.
+ framework_configs = self._GetFrameworkConfigs() or {}
+
+ if self._GetTestPath():
+ self._test_package, test_package_configs = self._PackageTest(
+ test_path=self._GetTestPath(),
+ extra_apks=self._GetAdditionalApks())
+ else:
+ test_package_configs = {}
+ framework_configs.update(test_package_configs)
+
+ self._appurify_configs = {
+ 'network': self._env.network_config,
+ 'pcap': self._env.pcap_config,
+ 'profiler': self._env.profiler_config,
+ 'videocapture': self._env.videocapture_config,
+ }
+
+ self._shard_framework_configs = []
+ for env_vars in shard_env_vars:
+ shard_framework_config = dict(framework_configs)
+ shard_framework_config['environment_vars'] = ','.join(
+ '%s=%s' % (k, v) for k, v in env_vars.iteritems())
+ self._shard_framework_configs.append(shard_framework_config)
+
+ def _Trigger(self, device_id, test_id):
+ with appurify_sanitized.SanitizeLogging(
+ verbose_count=self._env.verbose_count,
+ level=logging.WARNING):
+ test_start_response = appurify_sanitized.api.tests_run(
+ access_token=self._env.token,
+ device_type_id=device_id,
+ app_id=self._app_id,
+ test_id=test_id)
+ remote_device_helper.TestHttpResponse(
+ response=test_start_response,
+ error_msg='Unable to run test.')
+ return test_start_response.json()['response']['test_run_id']
- #override
def RunTests(self):
"""Run the test."""
- if self._env.trigger:
- with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
- logging.WARNING):
- test_start_res = appurify_sanitized.api.tests_run(
- self._env.token, self._env.device_type_id, self._app_id,
- self._test_id)
- remote_device_helper.TestHttpResponse(
- test_start_res, 'Unable to run test.')
- self._test_run_id = test_start_res.json()['response']['test_run_id']
- logging.info('Test run id: %s', self._test_run_id)
- if self._env.collect:
- current_status = ''
- timeout_counter = 0
- heartbeat_counter = 0
- while self._GetTestStatus(self._test_run_id) != self.COMPLETE:
- if self._results['detailed_status'] != current_status:
- logging.info('Test status: %s', self._results['detailed_status'])
- current_status = self._results['detailed_status']
- timeout_counter = 0
- heartbeat_counter = 0
- if heartbeat_counter > self.HEARTBEAT_INTERVAL:
- logging.info('Test status: %s', self._results['detailed_status'])
- heartbeat_counter = 0
-
- timeout = self._env.timeouts.get(
- current_status, self._env.timeouts['unknown'])
- if timeout_counter > timeout:
- raise remote_device_helper.RemoteDeviceError(
- 'Timeout while in %s state for %s seconds'
- % (current_status, timeout),
- is_infra_error=True)
- time.sleep(self.WAIT_TIME)
- timeout_counter += self.WAIT_TIME
- heartbeat_counter += self.WAIT_TIME
- self._DownloadTestResults(self._env.results_path)
-
- if self._results['results']['exception']:
- raise remote_device_helper.RemoteDeviceError(
- self._results['results']['exception'], is_infra_error=True)
+ def trigger(trigger_args):
jbudorick 2015/10/26 22:23:30 these should be defined in their respective if blo
+ device_id = trigger_args[0]
+ configs = trigger_args[1]
+ test_id = self._UploadTestToDevice()
+ self._UploadTestConfigToDevice(
+ test_id=test_id,
+ framework_configs=configs,
+ appurify_configs=self._appurify_configs)
+ test_run_id = self._Trigger(
+ device_id=device_id,
+ test_id=test_id)
+ self._test_run_ids.append(test_run_id)
+
+ def collect(test_run_id, parsed_results):
+ download_results_file = tempfile.NamedTemporaryFile(
+ suffix='.zip',
+ dir=self._base_tempfile_dir,
+ delete=False)
+ test_output = self._Collect(test_run_id=test_run_id)
+ self._DownloadTestResults(test_output, download_results_file.name)
+ parsed_results.AddTestRunResults(self._ParseTestResults(
+ test_output=test_output,
+ results_zip=download_results_file.name))
- return self._ParseTestResults()
+ if self._env.trigger:
+ parallelizer.SyncParallelizer(
+ zip(self._device_ids, self._shard_framework_configs)).pMap(trigger)
jbudorick 2015/10/26 22:23:30 O_O I... I don't know how I feel about this.
mikecase (-- gone --) 2015/10/27 01:27:43 Ack
+ if self._env.collect:
+ parsed_results = base_test_result.TestRunResults()
+ parallelizer.SyncParallelizer(
+ self._test_run_ids).pMap(collect, parsed_results)
jbudorick 2015/10/26 22:23:30 or, unsurprisingly, this.
mikecase (-- gone --) 2015/10/27 01:27:43 Ack
+ return parsed_results
#override
def TearDown(self):
"""Tear down the test run."""
+ if self._base_tempfile_dir:
+ shutil.rmtree(self._base_tempfile_dir)
+
if self._env.collect:
self._CollectTearDown()
elif self._env.trigger:
@@ -124,20 +201,46 @@ class RemoteDeviceTestRun(test_run.TestRun):
'File for storing test_run_id must be a string.')
with open(self._env.trigger, 'w') as persisted_data_file:
persisted_data = {}
- self.DumpTo(persisted_data)
- self._env.DumpTo(persisted_data)
+ self._DumpTo(persisted_data)
persisted_data_file.write(json.dumps(persisted_data))
+ def _Collect(self, test_run_id):
+ current_status = ''
+ timeout_counter = 0
+ heartbeat_counter = 0
+ results = self._CheckTestResults(test_run_id)
+ while results['status'] != self.COMPLETE:
+ if results['detailed_status'] != current_status:
+ logging.info('Test status: %s', results['detailed_status'])
+ current_status = results['detailed_status']
+ timeout_counter = 0
+ heartbeat_counter = 0
+ if heartbeat_counter > self.HEARTBEAT_INTERVAL:
+ logging.info('Test status: %s', results['detailed_status'])
+ heartbeat_counter = 0
+
+ timeout = self._env.timeouts.get(
+ current_status, self._env.timeouts['unknown'])
+ if timeout_counter > timeout:
+ raise remote_device_helper.RemoteDeviceError(
+ message='Timeout while in %s state for %s seconds'
+ % (current_status, timeout),
+ is_infra_error=True)
+ time.sleep(self.WAIT_TIME)
+ timeout_counter += self.WAIT_TIME
+ heartbeat_counter += self.WAIT_TIME
+ results = self._CheckTestResults(test_run_id)
+ if results['results']['exception']:
+ raise remote_device_helper.RemoteDeviceError(
+ message=results['results']['exception'],
+ is_infra_error=True)
+ return results
+
def _CollectTearDown(self):
- if self._GetTestStatus(self._test_run_id) != self.COMPLETE:
- with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
- logging.WARNING):
- test_abort_res = appurify_sanitized.api.tests_abort(
- self._env.token, self._test_run_id, reason='Test runner exiting.')
- remote_device_helper.TestHttpResponse(test_abort_res,
- 'Unable to abort test.')
- if self._results_temp_dir:
- shutil.rmtree(self._results_temp_dir)
+ def abort_test_run(test_run_id):
rnephew (Reviews Here) 2015/10/26 20:42:18 Is there a reason you can't just pass self._AbortT
mikecase (-- gone --) 2015/10/27 01:27:43 Hmmmmmmmmmm, it seems to work your way. I assumed
+ self._AbortTestRun(test_run_id)
+ if self._test_run_ids:
+ parallelizer.SyncParallelizer(self._test_run_ids).pMap(abort_test_run)
def __enter__(self):
"""Set up the test run when used as a context manager."""
@@ -148,121 +251,87 @@ class RemoteDeviceTestRun(test_run.TestRun):
"""Tear down the test run when used as a context manager."""
self.TearDown()
- def DumpTo(self, persisted_data):
- test_run_data = {
- self._TEST_RUN_ID_KEY: self._test_run_id,
- }
+ def _DumpTo(self, persisted_data):
+ """Dump test run information to dict."""
+ test_run_data = {self._TEST_RUN_IDS_KEY: self._test_run_ids}
persisted_data[self._TEST_RUN_KEY] = test_run_data
- def LoadFrom(self, persisted_data):
+ def _LoadFrom(self, persisted_data):
+ """Load test run information."""
test_run_data = persisted_data[self._TEST_RUN_KEY]
- self._test_run_id = test_run_data[self._TEST_RUN_ID_KEY]
+ self._test_run_ids = test_run_data[self._TEST_RUN_IDS_KEY]
- def _ParseTestResults(self):
+ def _ParseTestResults(self, test_output, results_zip):
raise NotImplementedError
- def _GetTestByName(self, test_name):
- """Gets test_id for specific test.
-
- Args:
- test_name: Test to find the ID of.
- """
- with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
- logging.WARNING):
- test_list_res = appurify_sanitized.api.tests_list(self._env.token)
- remote_device_helper.TestHttpResponse(test_list_res,
- 'Unable to get tests list.')
- for test in test_list_res.json()['response']:
- if test['test_type'] == test_name:
- return test['test_id']
- raise remote_device_helper.RemoteDeviceError(
- 'No test found with name %s' % (test_name))
-
- def _DownloadTestResults(self, results_path):
+ def _DownloadTestResults(self, results, download_path):
"""Download the test results from remote device service.
- Downloads results in temporary location, and then copys results
- to results_path if results_path is not set to None.
-
- Args:
- results_path: Path to download appurify results zipfile.
-
Returns:
Path to downloaded file.
"""
+ logging.info('Downloading results to %s.', download_path)
+ with appurify_sanitized.SanitizeLogging(
+ verbose_count=self._env.verbose_count,
+ level=logging.WARNING):
+ appurify_sanitized.utils.wget(
+ url=results['results']['url'],
+ path=download_path)
- if self._results_temp_dir is None:
- self._results_temp_dir = tempfile.mkdtemp()
- logging.info('Downloading results to %s.', self._results_temp_dir)
- with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
- logging.WARNING):
- appurify_sanitized.utils.wget(self._results['results']['url'],
- self._results_temp_dir + '/results')
- if results_path:
- logging.info('Copying results to %s', results_path)
- if not os.path.exists(os.path.dirname(results_path)):
- os.makedirs(os.path.dirname(results_path))
- shutil.copy(self._results_temp_dir + '/results', results_path)
- return self._results_temp_dir + '/results'
-
- def _GetTestStatus(self, test_run_id):
- """Checks the state of the test, and sets self._results
+ def _CheckTestResults(self, test_run_id):
+ """Checks the state of the test.
Args:
test_run_id: Id of test on on remote service.
"""
+ with appurify_sanitized.SanitizeLogging(
+ verbose_count=self._env.verbose_count,
+ level=logging.WARNING):
+ test_check_response = appurify_sanitized.api.tests_check_result(
+ access_token=self._env.token,
+ test_run_id=test_run_id)
+ remote_device_helper.TestHttpResponse(
+ response=test_check_response,
+ error_msg='Unable to get test status.')
+ return test_check_response.json()['response']
+
+ def _PackageTest(self, test_path, extra_apks):
+ """Packages the test and dependencies into a zip.
- with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
- logging.WARNING):
- test_check_res = appurify_sanitized.api.tests_check_result(
- self._env.token, test_run_id)
- remote_device_helper.TestHttpResponse(test_check_res,
- 'Unable to get test status.')
- self._results = test_check_res.json()['response']
- return self._results['status']
-
- def _AmInstrumentTestSetup(self, app_path, test_path, runner_package,
- environment_variables, extra_apks=None):
- config = {'runner': runner_package}
- if environment_variables:
- config['environment_vars'] = ','.join(
- '%s=%s' % (k, v) for k, v in environment_variables.iteritems())
-
- self._app_id = self._UploadAppToDevice(app_path)
-
+ Returns:
+ A tuple of the path to the packaged test and a dictionary containing
+ configs about how the test was packaged.
+ """
+ package_configs = {}
data_deps = self._test_instance.GetDataDependencies()
if data_deps:
- with tempfile.NamedTemporaryFile(suffix='.zip') as test_with_deps:
- sdcard_files = []
- additional_apks = []
- host_test = os.path.basename(test_path)
- with zipfile.ZipFile(test_with_deps.name, 'w') as zip_file:
- zip_file.write(test_path, host_test, zipfile.ZIP_DEFLATED)
- for h, _ in data_deps:
- if os.path.isdir(h):
- zip_utils.WriteToZipFile(zip_file, h, '.')
- sdcard_files.extend(os.listdir(h))
- else:
- zip_utils.WriteToZipFile(zip_file, h, os.path.basename(h))
- sdcard_files.append(os.path.basename(h))
- for a in extra_apks or ():
- zip_utils.WriteToZipFile(zip_file, a, os.path.basename(a))
- additional_apks.append(os.path.basename(a))
-
- config['sdcard_files'] = ','.join(sdcard_files)
- config['host_test'] = host_test
- if additional_apks:
- config['additional_apks'] = ','.join(additional_apks)
- self._test_id = self._UploadTestToDevice(
- 'robotium', test_with_deps.name, app_id=self._app_id)
+ test_package = tempfile.NamedTemporaryFile(
+ suffix='.zip',
+ delete=False,
+ dir=self._base_tempfile_dir)
jbudorick 2015/10/26 22:23:30 oh. This is how you're deleting the temporary file
mikecase (-- gone --) 2015/10/27 01:27:43 Ack. All my temporary files are put into _base_tem
+ sdcard_files = []
+ additional_apks = []
+ host_test = os.path.basename(test_path)
+ with zipfile.ZipFile(test_package.name, 'w') as zip_file:
+ zip_file.write(self._GetTestPath(), host_test, zipfile.ZIP_DEFLATED)
+ for h, _ in data_deps:
+ if os.path.isdir(h):
+ zip_utils.WriteToZipFile(zip_file, h, '.')
+ sdcard_files.extend(os.listdir(h))
+ else:
+ zip_utils.WriteToZipFile(zip_file, h, os.path.basename(h))
+ sdcard_files.append(os.path.basename(h))
+ for a in extra_apks or ():
+ zip_utils.WriteToZipFile(zip_file, a, os.path.basename(a))
+ additional_apks.append(os.path.basename(a))
+
+ package_configs['sdcard_files'] = ','.join(sdcard_files)
+ package_configs['host_test'] = host_test
+ if additional_apks:
+ package_configs['additional_apks'] = ','.join(additional_apks)
+ return (test_package.name, package_configs)
else:
- self._test_id = self._UploadTestToDevice('robotium', test_path)
-
- logging.info('Setting config: %s', config)
- appurify_configs = {}
- if self._env.network_config:
- appurify_configs['network'] = self._env.network_config
- self._SetTestConfig('robotium', config, **appurify_configs)
+ return (self._GetTestPath(), package_configs)
def _UploadAppToDevice(self, app_path):
"""Upload app to device."""
@@ -277,68 +346,102 @@ class RemoteDeviceTestRun(test_run.TestRun):
upload_results, 'Unable to upload %s.' % app_path)
return upload_results.json()['response']['app_id']
- def _UploadTestToDevice(self, test_type, test_path, app_id=None):
- """Upload test to device
- Args:
- test_type: Type of test that is being uploaded. Ex. uirobot, gtest..
- """
- logging.info('Uploading %s to remote service.', test_path)
- with open(test_path, 'rb') as test_src:
- with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
- logging.WARNING):
- upload_results = appurify_sanitized.api.tests_upload(
- self._env.token, test_src, 'raw', test_type, app_id=app_id)
- remote_device_helper.TestHttpResponse(upload_results,
- 'Unable to upload %s.' % test_path)
- return upload_results.json()['response']['test_id']
-
- def _SetTestConfig(self, runner_type, runner_configs,
- network=appurify_constants.NETWORK.WIFI_1_BAR,
- pcap=0, profiler=0, videocapture=0):
- """Generates and uploads config file for test.
- Args:
- runner_configs: Configs specific to the runner you are using.
- network: Config to specify the network environment the devices running
- the tests will be in.
- pcap: Option to set the recording the of network traffic from the device.
- profiler: Option to set the recording of CPU, memory, and network
- transfer usage in the tests.
- videocapture: Option to set video capture during the tests.
+ def _UploadTestToDevice(self):
+ """Upload test to device."""
+ logging.info('Shard uploading %s to remote service.', self._test_package)
+ with open(self._test_package, 'rb') as test_src:
+ with appurify_sanitized.SanitizeLogging(
+ verbose_count=self._env.verbose_count,
+ level=logging.WARNING):
+ upload_results_response = appurify_sanitized.api.tests_upload(
+ access_token=self._env.token,
jbudorick 2015/10/26 22:23:30 You sure added a lot of kwarg labels. Are they rea
mikecase (-- gone --) 2015/10/27 01:27:43 Added them because it made reading the code far ea
jbudorick 2015/10/27 01:30:32 to be fair, you were also outvoted 2-1 :P
+ test_source=test_src,
+ test_source_type='raw',
+ test_type=self._GetTestFramework(),
+ app_id=self._app_id)
+ remote_device_helper.TestHttpResponse(
+ response=upload_results_response,
+ error_msg='Unable to upload %s.' % self._test_package)
+ return upload_results_response.json()['response']['test_id']
- """
+ def _UploadTestConfigToDevice(
+ self, test_id, framework_configs, appurify_configs):
+ """Generates and uploads config file for test."""
logging.info('Generating config file for test.')
+ config_data = ['[appurify]']
+ config_data.extend(
+ '%s=%s' % (k, v) for k, v in appurify_configs.iteritems())
+ config_data.append('[%s]' % self._GetTestFramework())
+ config_data.extend(
+ '%s=%s' % (k, v) for k, v in framework_configs.iteritems())
with tempfile.TemporaryFile() as config:
- config_data = [
- '[appurify]',
- 'network=%s' % network,
- 'pcap=%s' % pcap,
- 'profiler=%s' % profiler,
- 'videocapture=%s' % videocapture,
- '[%s]' % runner_type
- ]
- config_data.extend(
- '%s=%s' % (k, v) for k, v in runner_configs.iteritems())
config.write(''.join('%s\n' % l for l in config_data))
config.flush()
config.seek(0)
- with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
- logging.WARNING):
- config_response = appurify_sanitized.api.config_upload(
- self._env.token, config, self._test_id)
+ with appurify_sanitized.SanitizeLogging(
+ verbose_count=self._env.verbose_count,
+ level=logging.WARNING):
+ config_upload_response = appurify_sanitized.api.config_upload(
+ access_token=self._env.token,
+ config_src=config,
+ test_id=test_id)
+ remote_device_helper.TestHttpResponse(
+ response=config_upload_response,
+ error_msg='Unable to upload test config.')
+
+ def _DetectPlatformErrors(self, results, test_output, results_zip):
+ if not test_output['results']['pass']:
+ crash_msg = None
+ for line in test_output['results']['output'].splitlines():
+ m = _LONG_MSG_RE.search(line)
+ if m:
+ crash_msg = m.group(1)
+ break
+ m = _SHORT_MSG_RE.search(line)
+ if m:
+ crash_msg = m.group(1)
+ if crash_msg:
+ self._LogLogcat(results_zip)
+ results.AddResult(base_test_result.BaseTestResult(
+ crash_msg, base_test_result.ResultType.CRASH))
+ elif self._DidDeviceGoOffline(results_zip):
+ self._LogLogcat(results_zip)
+ self._LogAdbTraceLog(results_zip)
+ raise remote_device_helper.RemoteDeviceError(
+ message='Remote service unable to reach device.',
+ is_infra_error=True)
+ else:
+ # Remote service is reporting a failure, but no failure in results obj.
+ if results.DidRunPass():
+ results.AddResult(base_test_result.BaseTestResult(
+ 'Remote service detected error.',
+ base_test_result.ResultType.UNKNOWN))
+
+ def _AbortTestRun(self, test_run_id):
+ if self._CheckTestResults(test_run_id)['status'] != self.COMPLETE:
+ with appurify_sanitized.SanitizeLogging(
+ verbose_count=self._env.verbose_count,
+ level=logging.WARNING):
+ test_abort_response = appurify_sanitized.api.tests_abort(
+ access_token=self._env.token,
+ test_run_id=test_run_id,
+ reason='Test runner exiting.')
remote_device_helper.TestHttpResponse(
- config_response, 'Unable to upload test config.')
+ response=test_abort_response,
+ error_msg='Unable to abort test.')
- def _LogLogcat(self, level=logging.CRITICAL):
+ # pylint: disable=no-self-use
+ def _LogLogcat(self, results_zip, level=logging.CRITICAL):
jbudorick 2015/10/26 22:23:30 methods that don't use self should usually be move
mikecase (-- gone --) 2015/10/27 01:27:43 Will do. Was kinda unsure since only this class re
"""Prints out logcat downloaded from remote service.
Args:
+ results_zip: path to zipfile containing the results files.
level: logging level to print at.
Raises:
KeyError: If appurify_results/logcat.txt file cannot be found in
downloaded zip.
"""
- zip_file = self._DownloadTestResults(None)
- with zipfile.ZipFile(zip_file) as z:
+ with zipfile.ZipFile(results_zip) as z:
try:
logcat = z.read('appurify_results/logcat.txt')
printable_logcat = ''.join(c for c in logcat if c in string.printable)
@@ -347,44 +450,17 @@ class RemoteDeviceTestRun(test_run.TestRun):
except KeyError:
logging.error('No logcat found.')
- def _LogAdbTraceLog(self):
- zip_file = self._DownloadTestResults(None)
- with zipfile.ZipFile(zip_file) as z:
+ # pylint: disable=no-self-use
+ def _LogAdbTraceLog(self, results_zip):
+ with zipfile.ZipFile(results_zip) as z:
adb_trace_log = z.read('adb_trace.log')
for line in adb_trace_log.splitlines():
logging.critical(line)
- def _DidDeviceGoOffline(self):
- zip_file = self._DownloadTestResults(None)
- with zipfile.ZipFile(zip_file) as z:
+ # pylint: disable=no-self-use
+ def _DidDeviceGoOffline(self, results_zip):
+ with zipfile.ZipFile(results_zip) as z:
adb_trace_log = z.read('adb_trace.log')
if any(_DEVICE_OFFLINE_RE.search(l) for l in adb_trace_log.splitlines()):
return True
return False
-
- def _DetectPlatformErrors(self, results):
- if not self._results['results']['pass']:
- crash_msg = None
- for line in self._results['results']['output'].splitlines():
- m = _LONG_MSG_RE.search(line)
- if m:
- crash_msg = m.group(1)
- break
- m = _SHORT_MSG_RE.search(line)
- if m:
- crash_msg = m.group(1)
- if crash_msg:
- self._LogLogcat()
- results.AddResult(base_test_result.BaseTestResult(
- crash_msg, base_test_result.ResultType.CRASH))
- elif self._DidDeviceGoOffline():
- self._LogLogcat()
- self._LogAdbTraceLog()
- raise remote_device_helper.RemoteDeviceError(
- 'Remote service unable to reach device.', is_infra_error=True)
- else:
- # Remote service is reporting a failure, but no failure in results obj.
- if results.DidRunPass():
- results.AddResult(base_test_result.BaseTestResult(
- 'Remote service detected error.',
- base_test_result.ResultType.UNKNOWN))

Powered by Google App Engine
This is Rietveld 408576698