From d6afc6d3a1f88614e5a8156a001980ef95ce70bc Mon Sep 17 00:00:00 2001 From: John Richardson Date: Mon, 6 Jun 2016 09:43:14 +0100 Subject: [PATCH] Dump hierarchy view on error Dump window hierarchy view from uiautomator to a file when WA fails during execution. Note: the xml file are pre-formatted after dump. Implementation specific to android.device. --- wlauto/common/android/device.py | 14 +++++++++++++- wlauto/common/gem5/device.py | 3 +++ wlauto/common/linux/device.py | 3 +++ wlauto/core/device.py | 4 ++++ wlauto/core/execution.py | 8 ++++++++ 5 files changed, 31 insertions(+), 1 deletion(-) diff --git a/wlauto/common/android/device.py b/wlauto/common/android/device.py index 33551af7..e416ae8c 100644 --- a/wlauto/common/android/device.py +++ b/wlauto/common/android/device.py @@ -21,6 +21,7 @@ import time import tempfile import shutil import threading +import xml.dom.minidom from subprocess import CalledProcessError from wlauto.core.extension import Parameter @@ -597,12 +598,23 @@ class AndroidDevice(BaseLinuxDevice): # pylint: disable=W0223 raise DeviceError("Invalid swipe direction: {}".format(self.swipe_to_unlock)) def capture_screen(self, filepath): - """Caputers the current device screen into the specified file in a PNG format.""" + """Captures the current device screen into the specified file in a PNG format.""" on_device_file = self.path.join(self.working_directory, 'screen_capture.png') self.execute('screencap -p {}'.format(on_device_file)) self.pull_file(on_device_file, filepath) self.delete_file(on_device_file) + def capture_view_hierachy(self, filepath): + """Captures the current view hierarchy into the specified file in a XML format.""" + on_device_file = self.path.join(self.working_directory, 'screen_capture.xml') + self.execute('uiautomator dump {}'.format(on_device_file)) + self.pull_file(on_device_file, filepath) + self.delete_file(on_device_file) + + parsed_xml = xml.dom.minidom.parse(filepath) + with open(filepath, 'w') as f: + f.write(parsed_xml.toprettyxml()) + def is_screen_on(self): """Returns ``True`` if the device screen is currently on, ``False`` otherwise.""" output = self.execute('dumpsys power') diff --git a/wlauto/common/gem5/device.py b/wlauto/common/gem5/device.py index 83a1d5df..534b3251 100644 --- a/wlauto/common/gem5/device.py +++ b/wlauto/common/gem5/device.py @@ -494,6 +494,9 @@ class BaseGem5Device(object): pass return False + def capture_view_hierachy(self, filepath): + pass # TODO + # pylint: disable=W0613 def execute(self, command, timeout=1000, check_exit_code=True, background=False, as_root=False, busybox=False, **kwargs): diff --git a/wlauto/common/linux/device.py b/wlauto/common/linux/device.py index 38ae38af..4ca1ac51 100644 --- a/wlauto/common/linux/device.py +++ b/wlauto/common/linux/device.py @@ -882,6 +882,9 @@ class LinuxDevice(BaseLinuxDevice): message = e.message.split('OUTPUT:', 1)[1].strip() self.logger.debug('Could not take screenshot: {}'.format(message)) + def capture_view_hierachy(self, filepath): + pass # TODO + def is_screen_on(self): pass # TODO diff --git a/wlauto/core/device.py b/wlauto/core/device.py index 18ae643e..2a3ee373 100644 --- a/wlauto/core/device.py +++ b/wlauto/core/device.py @@ -318,6 +318,10 @@ class Device(Extension): """Captures the current device screen into the specified file in a PNG format.""" raise NotImplementedError() + def capture_view_hierachy(self, filepath): + """Captures the current view hierarchy into the specified file in a XML format.""" + raise NotImplementedError() + def get_properties(self, output_path): """Captures and saves the device configuration properties version and any other relevant information. Return them in a dict""" diff --git a/wlauto/core/execution.py b/wlauto/core/execution.py index 652816fc..207bcbd6 100644 --- a/wlauto/core/execution.py +++ b/wlauto/core/execution.py @@ -731,6 +731,13 @@ class Runner(object): filepath = os.path.join(settings.output_directory, filename) self.device.capture_screen(filepath) + def _take_uiautomator_dump(self, filename): + if self.context.output_directory: + filepath = os.path.join(self.context.output_directory, filename) + else: + filepath = os.path.join(settings.output_directory, filename) + self.device.capture_view_hierachy(filepath) + @contextmanager def _handle_errors(self, action, on_error_status=IterationResult.FAILED): try: @@ -746,6 +753,7 @@ class Runner(object): self.current_job.result.add_event(str(we)) try: self._take_screenshot('error.png') + self._take_uiautomator_dump('error.xml') except Exception, e: # pylint: disable=W0703 # We're already in error state, so the fact that taking a # screenshot failed is not surprising...