def GenerateCoverageReportIfNeeded(self): """Uses the Emma to generate a coverage report and a html page.""" if not self.coverage: return cmd = [ 'java', '-classpath', TestRunner._EMMA_JAR, 'emma', 'report', '-r', 'html', '-in', TestRunner._COVERAGE_MERGED_FILENAME, '-in', TestRunner._COVERAGE_META_INFO_PATH ] cmd_helper.RunCmd(cmd) new_dir = os.path.join(TestRunner._COVERAGE_WEB_ROOT_DIR, time.strftime('Coverage_for_%Y_%m_%d_%a_%H:%M')) shutil.copytree('coverage', new_dir) latest_dir = os.path.join(TestRunner._COVERAGE_WEB_ROOT_DIR, 'Latest_Coverage_Run') if os.path.exists(latest_dir): shutil.rmtree(latest_dir) os.mkdir(latest_dir) webserver_new_index = os.path.join(new_dir, 'index.html') webserver_new_files = os.path.join(new_dir, '_files') webserver_latest_index = os.path.join(latest_dir, 'index.html') webserver_latest_files = os.path.join(latest_dir, '_files') # Setup new softlinks to last result. os.symlink(webserver_new_index, webserver_latest_index) os.symlink(webserver_new_files, webserver_latest_files) cmd_helper.RunCmd(['chmod', '755', '-R', latest_dir, new_dir])
def ZipAndCleanResults(dest_dir, dump_file_name, debug_info_list): """A helper method to zip all debug information results into a dump file. Args: dest-dir: Dir path in where we put the dump file. dump_file_name: Desired name of the dump file. This method makes sure '.zip' will be added as ext name. debug_info_list: List of all debug info objects. """ if not dest_dir or not dump_file_name or not debug_info_list: return cmd_helper.RunCmd(['mkdir', '-p', dest_dir]) log_basename = os.path.basename(dump_file_name) log_file = os.path.join(dest_dir, os.path.splitext(log_basename)[0] + '.zip') logging.info('Zipping debug dumps into %s ...' % log_file) for d in debug_info_list: d.ArchiveNewCrashFiles() # Add new dumps into the zip file. The zip may exist already if previous # gtest also dumps the debug information. It's OK since we clean up the old # dumps in each build step. cmd_helper.RunCmd([ 'zip', '-q', '-r', log_file, ' '.join([d.GetStoragePath() for d in debug_info_list]) ]) assert os.path.exists(log_file) for debug_info in debug_info_list: debug_info.CleanupStorage()
def _KillHostForwarderBlocking(self, host_pattern, timeout_sec): """Kills any existing host forwarders using the provided pattern. Note that this waits until the process terminates. """ cmd_helper.RunCmd(['pkill', '-f', host_pattern]) elapsed = 0 wait_period = 0.1 while not cmd_helper.RunCmd(['pgrep', '-f', host_pattern]) and ( elapsed < timeout_sec): time.sleep(wait_period) elapsed += wait_period if elapsed >= timeout_sec: raise Exception('Timed out while killing ' + host_pattern)
def SaveCoverageData(self, test): """Saves the Emma coverage data before it's overwritten by the next test. Args: test: the test whose coverage data is collected. """ if not self.coverage: return if not self.adb.Adb().Pull(TestRunner._COVERAGE_RESULT_PATH, constants.CHROME_DIR): logging.error('ERROR: Unable to find file ' + TestRunner._COVERAGE_RESULT_PATH + ' on the device for test ' + test) pulled_coverage_file = os.path.join(constants.CHROME_DIR, TestRunner._COVERAGE_FILENAME) if os.path.exists(TestRunner._COVERAGE_MERGED_FILENAME): cmd = [ 'java', '-classpath', TestRunner._EMMA_JAR, 'emma', 'merge', '-in', pulled_coverage_file, '-in', TestRunner._COVERAGE_MERGED_FILENAME, '-out', TestRunner._COVERAGE_MERGED_FILENAME ] cmd_helper.RunCmd(cmd) else: shutil.copy(pulled_coverage_file, TestRunner._COVERAGE_MERGED_FILENAME) os.remove(pulled_coverage_file)
def CreateTestRunnerScript(self, gtest_filter, test_arguments): """Creates a test runner script and pushes to the device. Args: gtest_filter: A gtest_filter flag. test_arguments: Additional arguments to pass to the test binary. """ tool_wrapper = self.tool.GetTestWrapper() sh_script_file = tempfile.NamedTemporaryFile() # We need to capture the exit status from the script since adb shell won't # propagate to us. sh_script_file.write( 'cd /data/local\n' '%s' '%s /data/local/%s --gtest_filter=%s %s\n' 'echo $? > %s' % (self._AddNativeCoverageExports(), tool_wrapper, self.test_suite_basename, gtest_filter, test_arguments, TestPackageExecutable._TEST_RUNNER_RET_VAL_FILE)) sh_script_file.flush() cmd_helper.RunCmd(['chmod', '+x', sh_script_file.name]) self.adb.PushIfNeeded(sh_script_file.name, '/data/local/chrome_test_runner.sh') logging.info('Conents of the test runner script: ') for line in open(sh_script_file.name).readlines(): logging.info(' ' + line.rstrip())
def StripAndCopyExecutable(self): """Strips and copies the executable to the device.""" if self.tool.NeedsDebugInfo(): target_name = self.test_suite else: target_name = self.test_suite + '_' + self.device + '_stripped' should_strip = True if os.path.isfile(target_name): logging.info('Found target file %s' % target_name) target_mtime = os.stat(target_name).st_mtime source_mtime = os.stat(self.test_suite).st_mtime if target_mtime > source_mtime: logging.info( 'Target mtime (%d) is newer than source (%d), assuming ' 'no change.' % (target_mtime, source_mtime)) should_strip = False if should_strip: logging.info( 'Did not find up-to-date stripped binary. Generating a ' 'new one (%s).' % target_name) # Whenever we generate a stripped binary, copy to the symbols dir. If we # aren't stripping a new binary, assume it's there. if self.symbols_dir: if not os.path.exists(self.symbols_dir): os.makedirs(self.symbols_dir) shutil.copy(self.test_suite, self.symbols_dir) strip = os.environ['STRIP'] cmd_helper.RunCmd([strip, self.test_suite, '-o', target_name]) test_binary = constants.TEST_EXECUTABLE_DIR + '/' + self.test_suite_basename self.adb.PushIfNeeded(target_name, test_binary)
def Run(self, port_pairs, tool, host_name): """Runs the forwarder. Args: port_pairs: A list of tuples (device_port, host_port) to forward. Note that you can specify 0 as a device_port, in which case a port will by dynamically assigned on the device. You can get the number of the assigned port using the DevicePortForHostPort method. tool: Tool class to use to get wrapper, if necessary, for executing the forwarder (see valgrind_tools.py). host_name: Address to forward to, must be addressable from the host machine. Usually use loopback '127.0.0.1'. Raises: Exception on failure to forward the port. """ host_adb_control_port = ports.AllocateTestServerPort() if not host_adb_control_port: raise Exception('Failed to allocate a TCP port in the host machine.') self._adb.PushIfNeeded( self._device_forwarder_path, Forwarder._DEVICE_FORWARDER_PATH) redirection_commands = [ '%d:%d:%d:%s' % (host_adb_control_port, device, host, host_name) for device, host in port_pairs] logging.info('Command format: <ADB port>:<Device port>' + '[:<Forward to port>:<Forward to address>]') logging.info('Forwarding using commands: %s', redirection_commands) if cmd_helper.RunCmd( ['adb', '-s', self._adb._adb.GetSerialNumber(), 'forward', 'tcp:%s' % host_adb_control_port, 'localabstract:%s' % Forwarder._DEVICE_ADB_CONTROL_PORT]) != 0: raise Exception('Error while running adb forward.') (exit_code, output) = self._adb.GetShellCommandStatusAndOutput( '%s %s %s' % (tool.GetUtilWrapper(), Forwarder._DEVICE_FORWARDER_PATH, Forwarder._DEVICE_ADB_CONTROL_PORT)) if exit_code != 0: raise Exception( 'Failed to start device forwarder:\n%s' % '\n'.join(output)) for redirection_command in redirection_commands: (exit_code, output) = cmd_helper.GetCmdStatusAndOutput( [self._host_forwarder_path, redirection_command]) if exit_code != 0: raise Exception('%s exited with %d:\n%s' % ( self._host_forwarder_path, exit_code, '\n'.join(output))) tokens = output.split(':') if len(tokens) != 2: raise Exception('Unexpected host forwarder output "%s", ' + 'expected "device_port:host_port"' % output) device_port = int(tokens[0]) host_port = int(tokens[1]) self._host_to_device_port_map[host_port] = device_port logging.info('Forwarding device port: %d to host port: %d.', device_port, host_port)
def _TakeScreenshot(self, test): """Takes a screenshot from the device.""" screenshot_tool = os.path.join(os.getenv('ANDROID_HOST_OUT'), 'bin', 'screenshot2') screenshot_path = os.path.join(constants.CHROME_DIR, 'out_screenshots') if not os.path.exists(screenshot_path): os.mkdir(screenshot_path) screenshot_name = os.path.join(screenshot_path, test + '.png') logging.info('Taking screenshot named %s', screenshot_name) cmd_helper.RunCmd( [screenshot_tool, '-s', self.device, screenshot_name])
def ZipAndCleanResults(dest_dir, dump_file_name): """A helper method to zip all debug information results into a dump file. Args: dest_dir: Dir path in where we put the dump file. dump_file_name: Desired name of the dump file. This method makes sure '.zip' will be added as ext name. """ if not dest_dir or not dump_file_name: return cmd_helper.RunCmd(['mkdir', '-p', dest_dir]) log_basename = os.path.basename(dump_file_name) log_zip_file = os.path.join(dest_dir, os.path.splitext(log_basename)[0] + '.zip') logging.info('Zipping debug dumps into %s ...', log_zip_file) # Add new dumps into the zip file. The zip may exist already if previous # gtest also dumps the debug information. It's OK since we clean up the old # dumps in each build step. log_src_dir = os.path.join(tempfile.gettempdir(), 'gtest_debug_info') cmd_helper.RunCmd(['zip', '-q', '-r', log_zip_file, log_src_dir]) assert os.path.exists(log_zip_file) assert os.path.exists(log_src_dir) shutil.rmtree(log_src_dir)
def _TakeScreenshot(self, test): """Takes a screenshot from the device.""" screenshot_tool = os.path.join(constants.CHROME_DIR, 'third_party/android_tools/sdk/tools/monkeyrunner') screenshot_script = os.path.join(constants.CHROME_DIR, 'build/android/monkeyrunner_screenshot.py') screenshot_path = os.path.join(constants.CHROME_DIR, 'out_screenshots') if not os.path.exists(screenshot_path): os.mkdir(screenshot_path) screenshot_name = os.path.join(screenshot_path, test + '.png') logging.info('Taking screenshot named %s', screenshot_name) cmd_helper.RunCmd([screenshot_tool, screenshot_script, '--serial', self.device, '--file', screenshot_name])
def _InitHostLocked(self): """Initializes the host forwarder process (only once).""" if self._host_adb_control_port: return self._host_adb_control_port = ports.AllocateTestServerPort() if not self._host_adb_control_port: raise Exception( 'Failed to allocate a TCP port in the host machine.') if cmd_helper.RunCmd([ 'adb', '-s', self._adb._adb.GetSerialNumber(), 'forward', 'tcp:%s' % self._host_adb_control_port, 'localabstract:%s' % Forwarder._DEVICE_ADB_CONTROL_PORT ]) != 0: raise Exception('Error while running adb forward.')
def StartRecordingLog(self, clear=True, filters=['*:v']): """Starts recording logcat output to a file. This call should come before running test, with calling StopRecordingLog following the tests. Args: clear: True if existing log output should be cleared. filters: A list of logcat filters to be used. """ self.StopRecordingLog() if clear: cmd_helper.RunCmd(['adb', '-s', self.device, 'logcat', '-c']) logging.info('Start dumping log to %s ...', self.log_file_name) command = 'adb -s %s logcat -v threadtime %s > %s' % ( self.device, ' '.join(filters), self.log_file_name) self.logcat_process = subprocess.Popen(command, shell=True)
def _CopyLibraryAndJars(self): """Copy the shlib and jars into the apk source tree (if relevant)""" if self._native_library: destdir = os.path.join(self._output_directory, 'libs/' + self._target_abi) if not os.path.exists(destdir): os.makedirs(destdir) dest = os.path.join(destdir, os.path.basename(self._native_library)) logging.warn('strip %s --> %s' % (self._native_library, dest)) strip = os.environ['STRIP'] cmd_helper.RunCmd( [strip, '--strip-unneeded', self._native_library, '-o', dest]) if self._jars: destdir = os.path.join(self._output_directory, 'libs') if not os.path.exists(destdir): os.makedirs(destdir) for jar in self._jars: dest = os.path.join(destdir, os.path.basename(jar)) logging.warn('%s --> %s' % (jar, dest)) shutil.copyfile(jar, dest)
def StripAndCopyExecutable(self): """Strips and copies the executable to the device.""" if self.tool.NeedsDebugInfo(): target_name = self.test_suite elif self.test_suite_basename == 'webkit_unit_tests': # webkit_unit_tests has been stripped in build step. target_name = self.test_suite else: target_name = self.test_suite + '_' + self.device + '_stripped' should_strip = True if os.path.isfile(target_name): logging.info('Found target file %s' % target_name) target_mtime = os.stat(target_name).st_mtime source_mtime = os.stat(self.test_suite).st_mtime if target_mtime > source_mtime: logging.info( 'Target mtime (%d) is newer than source (%d), assuming ' 'no change.' % (target_mtime, source_mtime)) should_strip = False if should_strip: logging.info( 'Did not find up-to-date stripped binary. Generating a ' 'new one (%s).' % target_name) # Whenever we generate a stripped binary, copy to the symbols dir. If we # aren't stripping a new binary, assume it's there. if self.symbols_dir: if not os.path.exists(self.symbols_dir): os.makedirs(self.symbols_dir) shutil.copy(self.test_suite, self.symbols_dir) strip = os.environ['STRIP'] cmd_helper.RunCmd([strip, self.test_suite, '-o', target_name]) test_binary = '/data/local/' + self.test_suite_basename self.adb.PushIfNeeded(target_name, test_binary) if self.test_suite_basename == 'ui_unittests': self.adb.PushIfNeeded(self.test_suite_dirname + '/chrome.pak', '/data/local/tmp/paks/chrome.pak') self.adb.PushIfNeeded( self.test_suite_dirname + '/locales/en-US.pak', '/data/local/tmp/paks/en-US.pak')
def StartAdbServer(self): """Start adb server.""" adb_cmd = ['adb', 'start-server'] return cmd_helper.RunCmd(adb_cmd)
def KillAdbServer(self): """Kill adb server.""" adb_cmd = ['adb', 'kill-server'] return cmd_helper.RunCmd(adb_cmd)