Bug 921676 - mochitest screenshots fallout from bug 746243;r=ted
authorJeff Hammel <jhammel@mozilla.com>
Sat, 05 Oct 2013 15:28:34 -0700
changeset 149984 ef2d30255b7a36799fcb5d2729375cb6bb6911c4
parent 149983 8434bf06134c7284d28c365be764a13292d1be49
child 149985 9a98b8d47e3c85a768f6f683d15fa4ae1548427b
push id34713
push userjhammel@mozilla.com
push dateSat, 05 Oct 2013 22:32:22 +0000
treeherdermozilla-inbound@ef2d30255b7a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersted
bugs921676, 746243
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 921676 - mochitest screenshots fallout from bug 746243;r=ted
build/automationutils.py
build/dumpScreen.py
testing/mochitest/runtests.py
--- a/build/automationutils.py
+++ b/build/automationutils.py
@@ -1,15 +1,16 @@
 #
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import with_statement
 import glob, logging, os, platform, shutil, subprocess, sys, tempfile, urllib2, zipfile
+import base64
 import re
 from urlparse import urlparse
 
 try:
   import mozinfo
 except ImportError:
   # Stub out fake mozinfo since this is not importable on Android 4.0 Opt.
   # This should be fixed; see
@@ -38,17 +39,18 @@ except ImportError:
   "processLeakLog",
   "getDebuggerInfo",
   "DEBUGGER_INFO",
   "replaceBackSlashes",
   "wrapCommand",
   'KeyValueParseError',
   'parseKeyValue',
   'systemMemory',
-  'environment'
+  'environment',
+  'dumpScreen',
   ]
 
 # Map of debugging programs to information about them, like default arguments
 # and whether or not they are interactive.
 DEBUGGER_INFO = {
   # gdb requires that you supply the '--args' flag in order to pass arguments
   # after the executable name to the executable.
   "gdb": {
@@ -468,8 +470,61 @@ def environment(xrePath, env=None, crash
     except OSError,err:
       log.info("Failed determine available memory, disabling ASan low-memory configuration: %s", err.strerror)
     except:
       log.info("Failed determine available memory, disabling ASan low-memory configuration")
     else:
       log.info(message)
 
   return env
+
+
+def dumpScreen(utilityPath):
+  """dumps the screen to the log file as a data URI"""
+
+  # Need to figure out what tool and whether it write to a file or stdout
+  if mozinfo.isUnix:
+    utility = [os.path.join(utilityPath, "screentopng")]
+    imgoutput = 'stdout'
+  elif mozinfo.isMac:
+    utility = ['/usr/sbin/screencapture', '-C', '-x', '-t', 'png']
+    imgoutput = 'file'
+  elif mozinfo.isWin:
+    utility = [os.path.join(utilityPath, "screenshot.exe")]
+    imgoutput = 'file'
+  else:
+    log.warn("Unable to dump screen on platform '%s'", sys.platform)
+
+  # Run the capture correctly for the type of capture
+  kwargs = {'stdout': subprocess.PIPE}
+  if imgoutput == 'file':
+    tmpfd, imgfilename = tempfile.mkstemp(prefix='mozilla-test-fail_')
+    os.close(tmpfd)
+    utility.append(imgfilename)
+  elif imgoutput == 'stdout':
+    kwargs.update(dict(bufsize=-1, close_fds=True))
+  try:
+    dumper = subprocess.Popen(utility, **kwargs)
+  except OSError, err:
+    log.info("Failed to start %s for screenshot: %s",
+             utility[0], err.strerror)
+    return
+
+  # Check whether the capture utility ran successfully
+  stdout, _ = dumper.communicate()
+  returncode = dumper.poll()
+  if returncode:
+    log.info("%s exited with code %d", utility, returncode)
+    return
+
+  try:
+    if imgoutput == 'stdout':
+      image = stdout
+    elif imgoutput == 'file':
+      with open(imgfilename, 'rb') as imgfile:
+        image = imgfile.read()
+  except IOError, err:
+    log.info("Failed to read image from %s", imgoutput)
+
+  encoded = base64.b64encode(image)
+  uri = "data:image/png;base64,%s" %  encoded
+  log.info("SCREENSHOT: %s", uri)
+  return uri
new file mode 100644
--- /dev/null
+++ b/build/dumpScreen.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+"""
+test dumpScreen functionality
+"""
+
+import automationutils
+import optparse
+import os
+import sys
+
+
+def main(args=sys.argv[1:]):
+
+    # parse CLI options
+    usage = '%prog [options] path/to/OBJDIR/dist/bin'
+    parser = optparse.OptionParser(usage=usage)
+    options, args = parser.parse_args(args)
+    if len(args) != 1:
+        parser.error("Please provide utility path")
+    utilityPath = args[0]
+
+    # dump the screen to a data: URL
+    uri = automationutils.dumpScreen(utilityPath)
+
+    # print the uri
+    print uri
+
+if __name__ == '__main__':
+    main()
--- a/testing/mochitest/runtests.py
+++ b/testing/mochitest/runtests.py
@@ -7,34 +7,33 @@ Runs the Mochitest test harness.
 """
 
 from __future__ import with_statement
 import os
 import sys
 SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(__file__)))
 sys.path.insert(0, SCRIPT_DIR);
 
-import base64
 import json
 import mozcrash
 import mozinfo
 import mozlog
 import mozprocess
 import mozrunner
 import optparse
 import re
 import shutil
 import signal
 import subprocess
 import tempfile
 import time
 import traceback
 import urllib2
 
-from automationutils import environment, getDebuggerInfo, isURL, KeyValueParseError, parseKeyValue, processLeakLog, systemMemory
+from automationutils import environment, getDebuggerInfo, isURL, KeyValueParseError, parseKeyValue, processLeakLog, systemMemory, dumpScreen
 from datetime import datetime
 from manifestparser import TestManifest
 from mochitest_options import MochitestOptions
 from mozprofile import Profile, Preferences
 from mozprofile.permissions import ServerLocations
 from urllib import quote_plus as encodeURIComponent
 
 # This should use the `which` module already in tree, but it is
@@ -645,69 +644,21 @@ class Mochitest(MochitestUtilsMixin):
     return browserEnv
 
   def cleanup(self, manifest, options):
     """ remove temporary files and profile """
     os.remove(manifest)
     del self.profile
 
   def dumpScreen(self, utilityPath):
-    # TODO: this code may be moved to automationutils.py
-    # see also: https://bugzilla.mozilla.org/show_bug.cgi?id=749421
-
     if self.haveDumpedScreen:
       log.info("Not taking screenshot here: see the one that was previously logged")
       return
-
     self.haveDumpedScreen = True
-
-    # Need to figure out what tool and whether it write to a file or stdout
-    if mozinfo.isUnix:
-      utility = [os.path.join(utilityPath, "screentopng")]
-      imgoutput = 'stdout'
-    elif mozinfo.isMac:
-      utility = ['/usr/sbin/screencapture', '-C', '-x', '-t', 'png']
-      imgoutput = 'file'
-    elif mozinfo.isWin:
-      utility = [os.path.join(utilityPath, "screenshot.exe")]
-      imgoutput = 'file'
-
-    # Run the capture correctly for the type of capture
-    if imgoutput == 'file':
-      tmpfd, imgfilename = tempfile.mkstemp(prefix='mozilla-test-fail_')
-      os.close(tmpfd)
-      utility.append(imgfilename)
-      kwargs = {}
-    elif imgoutput == 'stdout':
-      kwargs=dict(bufsize=-1, close_fds=True)
-    try:
-      dumper = mozprocess.ProcessHandler(utility, **kwargs)
-      dumper.run()
-    except OSError, err:
-      log.info("Failed to start %s for screenshot: %s",
-               utility[0], err.strerror)
-      return
-
-    # Check whether the capture utility ran successfully
-    returncode = dumper.wait()
-    if returncode:
-      log.info("%s exited with code %d", utility, returncode)
-      return
-
-    try:
-      if imgoutput == 'stdout':
-        image = '\n'.join(dumper.output)
-      elif imgoutput == 'file':
-        with open(imgfilename, 'rb') as imgfile:
-          image = imgfile.read()
-    except IOError, err:
-        log.info("Failed to read image from %s", imgoutput)
-
-    encoded = base64.b64encode(image)
-    log.info("SCREENSHOT: data:image/png;base64,%s", encoded)
+    dumpScreen(utilityPath)
 
   def killAndGetStack(self, processPID, utilityPath, debuggerInfo, dump_screen=False):
     """
     Kill the process, preferrably in a way that gets us a stack trace.
     Also attempts to obtain a screenshot before killing the process
     if specified.
     """