Revision: 11975
Author:   [email protected]
Date:     Tue Jul  3 00:45:58 2012
Log:      Add Makefile targets for running tests on Android.

This allows to run tests on the attached Android device using
make android.check
make android.debug.check
make android.release.check
ANDROID_V8=/data/local/v8 TESTJOBS=-j4 make android.release.check -j10

Tests and binaries are copied to device location specified by the ANDROID_V8
variable and then tests are executed using the 'adb shell' program.

[email protected]

Review URL: https://chromiumcodereview.appspot.com/10696048
http://code.google.com/p/v8/source/detail?r=11975

Added:
 /branches/bleeding_edge/tools/android-run.py
 /branches/bleeding_edge/tools/android-sync.sh
Modified:
 /branches/bleeding_edge/Makefile
 /branches/bleeding_edge/test/cctest/cctest.status
 /branches/bleeding_edge/test/cctest/testcfg.py
 /branches/bleeding_edge/test/mjsunit/mjsunit.status
 /branches/bleeding_edge/tools/test-wrapper-gypbuild.py
 /branches/bleeding_edge/tools/test.py

=======================================
--- /dev/null
+++ /branches/bleeding_edge/tools/android-run.py        Tue Jul  3 00:45:58 2012
@@ -0,0 +1,108 @@
+#!/usr/bin/env python
+#
+# Copyright 2012 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# This script executes the passed command line on Android device
+# using 'adb shell' command. Unfortunately, 'adb shell' always
+# returns exit code 0, ignoring the exit code of executed command.
+# Since we need to return non-zero exit code if the command failed,
+# we augment the passed command line with exit code checking statement
+# and output special error string in case of non-zero exit code.
+# Then we parse the output of 'adb shell' and look for that error string.
+
+import os
+from os.path import join, dirname, abspath
+import subprocess
+import sys
+import tempfile
+
+def Check(output, errors):
+  failed = any([s.startswith('/system/bin/sh:') or s.startswith('Error')
+                for s in output.split('\n')])
+  return 1 if failed else 0
+
+def Execute(cmdline):
+  (fd_out, outname) = tempfile.mkstemp()
+  (fd_err, errname) = tempfile.mkstemp()
+  process = subprocess.Popen(
+    args=cmdline,
+    shell=True,
+    stdout=fd_out,
+    stderr=fd_err,
+  )
+  exit_code = process.wait()
+  os.close(fd_out)
+  os.close(fd_err)
+  output = file(outname).read()
+  errors = file(errname).read()
+  os.unlink(outname)
+  os.unlink(errname)
+  sys.stdout.write(output)
+  sys.stderr.write(errors)
+  return exit_code or Check(output, errors)
+
+def Escape(arg):
+  def ShouldEscape():
+    for x in arg:
+      if not x.isalnum() and x != '-' and x != '_':
+        return True
+    return False
+
+  return arg if not ShouldEscape() else '"%s"' % (arg.replace('"', '\\"'))
+
+def WriteToTemporaryFile(data):
+  (fd, fname) = tempfile.mkstemp()
+  os.close(fd)
+  tmp_file = open(fname, "w")
+  tmp_file.write(data)
+  tmp_file.close()
+  return fname
+
+def Main():
+  if (len(sys.argv) == 1):
+    print("Usage: %s <command-to-run-on-device>" % sys.argv[0])
+    return 1
+  workspace = abspath(join(dirname(sys.argv[0]), '..'))
+  android_workspace = os.getenv("ANDROID_V8", "/data/local/v8")
+  args = [Escape(arg) for arg in sys.argv[1:]]
+  script = (" ".join(args) + "\n"
+            "if [ $? -ne 0 ]\n"
+            "  then echo \"Error returned by test\";\n"
+            "fi\n")
+  script = script.replace(workspace, android_workspace)
+  script_file = WriteToTemporaryFile(script)
+  android_script_file = android_workspace + "/" + script_file
+  command =  ("adb push '%s' %s;" % (script_file, android_script_file) +
+              "adb shell 'sh %s';" % android_script_file +
+              "adb shell 'rm %s'" % android_script_file)
+  error_code = Execute(command)
+  os.unlink(script_file)
+  return error_code
+
+if __name__ == '__main__':
+  sys.exit(Main())
=======================================
--- /dev/null
+++ /branches/bleeding_edge/tools/android-sync.sh       Tue Jul  3 00:45:58 2012
@@ -0,0 +1,79 @@
+#!/bin/bash
+# Copyright 2012 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# This script pushes android binaries and test data to the device.
+# The first argument can be either "android.release" or "android.debug".
+# The second argument is a relative path to the output directory with binaries.
+# The third argument is the absolute path to the V8 directory on the host.
+# The fourth argument is the absolute path to the V8 directory on the device.
+
+if [ ${#@} -lt 4 ] ; then
+  echo "Error: need 4 arguments"
+  exit 1
+fi
+
+ARCH_MODE=$1
+OUTDIR=$2
+HOST_V8=$3
+ANDROID_V8=$4
+
+function sync_file {
+  local FILE=$1
+  local ANDROID_HASH=$(adb shell "md5 \"$ANDROID_V8/$FILE\"")
+  local HOST_HASH=$(md5sum "$HOST_V8/$FILE")
+  if [ "${ANDROID_HASH%% *}" != "${HOST_HASH%% *}" ]; then
+    adb push "$HOST_V8/$FILE" "$ANDROID_V8/$FILE" &> /dev/null
+  fi
+  echo -n "."
+}
+
+function sync_dir {
+  local DIR=$1
+  echo -n "sync to $ANDROID_V8/$DIR"
+  for FILE in $(find "$HOST_V8/$DIR" -type f); do
+    local RELATIVE_FILE=${FILE:${#HOST_V8}}
+    sync_file "$RELATIVE_FILE"
+  done
+  echo ""
+}
+
+echo -n "sync to $ANDROID_V8/$OUTDIR/$ARCH_MODE"
+sync_file "$OUTDIR/$ARCH_MODE/cctest"
+sync_file "$OUTDIR/$ARCH_MODE/d8"
+sync_file "$OUTDIR/$ARCH_MODE/preparser"
+echo ""
+echo -n "sync to $ANDROID_V8/tools"
+sync_file tools/consarray.js
+sync_file tools/codemap.js
+sync_file tools/csvparser.js
+sync_file tools/profile.js
+sync_file tools/splaytree.js
+echo ""
+sync_dir test/message
+sync_dir test/mjsunit
+sync_dir test/preparser
=======================================
--- /branches/bleeding_edge/Makefile    Thu Jun 14 01:01:05 2012
+++ /branches/bleeding_edge/Makefile    Tue Jul  3 00:45:58 2012
@@ -35,6 +35,7 @@
 TESTFLAGS ?=
 ANDROID_NDK_ROOT ?=
ANDROID_TOOL_PREFIX = $(ANDROID_NDK_ROOT)/toolchain/bin/arm-linux-androideabi
+ANDROID_V8 ?= /data/local/v8

 # Special build flags. Use them like this: "make library=shared"

@@ -107,7 +108,7 @@
 # - every combination <arch>.<mode>, e.g. "ia32.release"
 # - "native": current host's architecture, release mode
 # - any of the above with .check appended, e.g. "ia32.release.check"
-# - "android": cross-compile for Android/ARM (release mode)
+# - "android": cross-compile for Android/ARM
 # - default (no target specified): build all DEFAULT_ARCHES and MODES
 # - "check": build all targets and run all tests
 # - "<arch>.clean" for any <arch> in ARCHES
@@ -120,6 +121,7 @@
 ARCHES = ia32 x64 arm mips
 DEFAULT_ARCHES = ia32 x64 arm
 MODES = release debug
+ANDROID_MODES = android.release android.debug

 # List of files that trigger Makefile regeneration:
 GYPFILES = build/all.gyp build/common.gypi build/standalone.gypi \
@@ -166,8 +168,9 @@
                 CXX="$(CXX)" LINK="$(LINK)" BUILDTYPE=Release \
                 builddir="$(shell pwd)/$(OUTDIR)/$@"

-# TODO(jkummerow): add "android.debug" when we need it.
-android android.release: $(OUTDIR)/Makefile.android
+android: $(ANDROID_MODES)
+
+$(ANDROID_MODES): $(OUTDIR)/Makefile.android
        @$(MAKE) -C "$(OUTDIR)" -f Makefile.android \
                CXX="$(ANDROID_TOOL_PREFIX)-g++" \
                AR="$(ANDROID_TOOL_PREFIX)-ar" \
@@ -175,8 +178,9 @@
                CC="$(ANDROID_TOOL_PREFIX)-gcc" \
                LD="$(ANDROID_TOOL_PREFIX)-ld" \
                LINK="$(ANDROID_TOOL_PREFIX)-g++" \
-               BUILDTYPE=Release \
-               builddir="$(shell pwd)/$(OUTDIR)/android.release"
+               BUILDTYPE=$(shell echo $(subst .,,$(suffix $@)) | \
+                           python -c "print raw_input().capitalize()") \
+               builddir="$(shell pwd)/$(OUTDIR)/$@"

 # Test targets.
 check: all
@@ -196,6 +200,17 @@
        @tools/test-wrapper-gypbuild.py $(TESTJOBS) --outdir=$(OUTDIR) \
            --arch-and-mode=$(basename $@) $(TESTFLAGS)

+$(addsuffix .sync, $(ANDROID_MODES)): $$(basename $$@)
+       @tools/android-sync.sh $(basename $@) $(OUTDIR) \
+                              $(shell pwd) $(ANDROID_V8)
+
+$(addsuffix .check, $(ANDROID_MODES)): $$(basename $$@).sync
+       @tools/test-wrapper-gypbuild.py $(TESTJOBS) --outdir=$(OUTDIR) \
+            --arch-and-mode=$(basename $@) \
+            --special-command="tools/android-run.py @"
+
+android.check: android.release.check android.debug.check
+
 native.check: native
        @tools/test-wrapper-gypbuild.py $(TESTJOBS) --outdir=$(OUTDIR)/native \
            --arch-and-mode=. $(TESTFLAGS)
=======================================
--- /branches/bleeding_edge/test/cctest/cctest.status Fri Jun 8 07:47:12 2012 +++ /branches/bleeding_edge/test/cctest/cctest.status Tue Jul 3 00:45:58 2012
@@ -54,7 +54,7 @@
 test-weakmaps/Shrinking: FAIL

##############################################################################
-[ $arch == arm ]
+[ $arch == arm || $arch == android ]

# We cannot assume that we can throw OutOfMemory exceptions in all situations. # Apparently our ARM box is in such a state. Skip the test as it also runs for
=======================================
--- /branches/bleeding_edge/test/cctest/testcfg.py      Fri May 11 05:18:09 2012
+++ /branches/bleeding_edge/test/cctest/testcfg.py      Tue Jul  3 00:45:58 2012
@@ -93,7 +93,8 @@
       if utils.IsWindows():
         executable += '.exe'
       executable = join(self.context.buildspace, executable)
-    output = test.Execute([executable, '--list'], self.context)
+    full_command = self.context.processor([executable, '--list'])
+    output = test.Execute(full_command, self.context)
     if output.exit_code != 0:
       print output.stdout
       print output.stderr
=======================================
--- /branches/bleeding_edge/test/mjsunit/mjsunit.status Tue Jun 26 00:48:04 2012 +++ /branches/bleeding_edge/test/mjsunit/mjsunit.status Tue Jul 3 00:45:58 2012
@@ -49,28 +49,27 @@
##############################################################################
 # This one uses a built-in that's only present in debug mode. It takes
 # too long to run in debug mode on ARM and MIPS.
-fuzz-natives: PASS, SKIP if ($mode == release || $arch == arm || $arch == mips)
-
-big-object-literal: PASS, SKIP if ($arch == arm)
+fuzz-natives: PASS, SKIP if ($mode == release || $arch == arm || $arch == android || $arch == mips)
+
+big-object-literal: PASS, SKIP if ($arch == arm || $arch == android)

 # Issue 488: this test sometimes times out.
 array-constructor: PASS || TIMEOUT

 # Very slow on ARM and MIPS, contains no architecture dependent code.
-unicode-case-overoptimization: PASS, TIMEOUT if ($arch == arm || $arch == mips) +unicode-case-overoptimization: PASS, TIMEOUT if ($arch == arm || $arch == android || $arch == mips)

# Test Crankshaft compilation time. Expected to take too long in debug mode.
 regress/regress-1969: PASS, SKIP if $mode == debug

##############################################################################
-[ $isolates ]
-
 # This test sets the umask on a per-process basis and hence cannot be
 # used in multi-threaded runs.
-d8-os: SKIP
+# On android there is no /tmp directory.
+d8-os: PASS, SKIP if ($isolates || $arch == android)

##############################################################################
-[ $arch == arm ]
+[ $arch == arm || $arch == android ]

 # Slow tests which times out in debug mode.
 try: PASS, SKIP if $mode == debug
=======================================
--- /branches/bleeding_edge/tools/test-wrapper-gypbuild.py Thu Jun 28 07:31:03 2012 +++ /branches/bleeding_edge/tools/test-wrapper-gypbuild.py Tue Jul 3 00:45:58 2012
@@ -148,7 +148,7 @@
       print "Unknown mode %s" % mode
       return False
   for arch in options.arch:
-    if not arch in ['ia32', 'x64', 'arm', 'mips']:
+    if not arch in ['ia32', 'x64', 'arm', 'mips', 'android']:
       print "Unknown architecture %s" % arch
       return False
   if options.buildbot:
=======================================
--- /branches/bleeding_edge/tools/test.py       Fri Jun  8 07:47:12 2012
+++ /branches/bleeding_edge/tools/test.py       Tue Jul  3 00:45:58 2012
@@ -140,9 +140,9 @@
   parts = []
   for part in command:
     if ' ' in part:
-      # Escape spaces.  We may need to escape more characters for this
-      # to work properly.
-      parts.append('"%s"' % part)
+ # Escape spaces and double quotes. We may need to escape more characters
+      # for this to work properly.
+      parts.append('"%s"' % part.replace('"', '\\"'))
     else:
       parts.append(part)
   return " ".join(parts)
@@ -1283,7 +1283,7 @@
     options.scons_flags.append("arch=" + options.arch)
   # Simulators are slow, therefore allow a longer default timeout.
   if options.timeout == -1:
-    if options.arch == 'arm' or options.arch == 'mips':
+    if options.arch in ['android', 'arm', 'mips']:
       options.timeout = 2 * TIMEOUT_DEFAULT;
     else:
       options.timeout = TIMEOUT_DEFAULT;

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to