AI 144412: am: CL 144340 Added support to run native tests on the device.

The tests name must start with 'test_'.
  Tests should return 0 on success, 1 on failure.
  * development/testrunner/test_defs.xml:
  Added new element to represent native tests.
  * development/testrunner/test_defs.py:
  Added handling of the new <test-native> element.
  The testsuite has new IsNative method.
  TestDefinition's iterator is ordered by test names.
  Added GetDescription() method to access the optional description.
  * development/testrunner/runtest.py:
  Print the description next to the test name if applicable
  (runtest_py -l)
  Added a _RunNativeTest method to run a test on the target, report
  the status and clean up the test after the run.
  Added
  Original author: niko

Automated import of CL 144412
This commit is contained in:
Niko Catania
2009-04-02 23:33:53 -07:00
committed by The Android Open Source Project
parent 2962188689
commit 247286697f
3 changed files with 157 additions and 31 deletions

View File

@@ -23,6 +23,7 @@ Based on previous <androidroot>/development/tools/runtest shell script.
import glob import glob
import optparse import optparse
import os import os
import re
from sets import Set from sets import Set
import sys import sys
@@ -58,6 +59,7 @@ class TestRunner(object):
def __init__(self): def __init__(self):
# disable logging of timestamp # disable logging of timestamp
self._root_path = android_build.GetTop()
logger.SetTimestampLogging(False) logger.SetTimestampLogging(False)
def _ProcessOptions(self): def _ProcessOptions(self):
@@ -137,8 +139,6 @@ class TestRunner(object):
if self._options.verbose: if self._options.verbose:
logger.SetVerbose(True) logger.SetVerbose(True)
self._root_path = android_build.GetTop()
self._known_tests = self._ReadTests() self._known_tests = self._ReadTests()
self._coverage_gen = coverage.CoverageGenerator( self._coverage_gen = coverage.CoverageGenerator(
@@ -172,7 +172,7 @@ class TestRunner(object):
"""Prints out set of defined tests.""" """Prints out set of defined tests."""
print "The following tests are currently defined:" print "The following tests are currently defined:"
for test in self._known_tests: for test in self._known_tests:
print test.GetName() print "%-15s %s" % (test.GetName(), test.GetDescription())
def _DoBuild(self): def _DoBuild(self):
logger.SilentLog("Building tests...") logger.SilentLog("Building tests...")
@@ -261,6 +261,37 @@ class TestRunner(object):
if coverage_file is not None: if coverage_file is not None:
logger.Log("Coverage report generated at %s" % coverage_file) logger.Log("Coverage report generated at %s" % coverage_file)
def _RunNativeTest(self, test_suite):
"""Run the provided *native* test suite.
The test_suite must contain a build path where the native test files are.
Each test's name must start with 'test_' and have a .cc or .cpp extension.
A successful test must return 0. Any other value will be considered
as an error.
Args:
test_suite: TestSuite to run
"""
# find all test files, convert unicode names to ascii, take the basename
# and drop the .cc/.cpp extension.
file_pattern = os.path.join(test_suite.GetBuildPath(), "test_*")
file_list = []
for f in map(str, glob.glob(file_pattern)):
f = os.path.basename(f)
f = re.split(".[cp]+$", f)[0]
file_list.append(f)
for f in file_list:
full_path = "/system/bin/%s" % f
# Run
status = self._adb.SendShellCommand("%s >/dev/null 2>&1;echo -n $?" %
full_path)
logger.Log("%s... %s" % (f, status == "0" and "ok" or "failed"))
# Cleanup
self._adb.SendShellCommand("rm %s" % full_path)
def RunTests(self): def RunTests(self):
"""Main entry method - executes the tests according to command line args.""" """Main entry method - executes the tests according to command line args."""
try: try:
@@ -278,7 +309,10 @@ class TestRunner(object):
self._DoBuild() self._DoBuild()
for test_suite in self._GetTestsToRun(): for test_suite in self._GetTestsToRun():
self._RunTest(test_suite) if test_suite.IsNative():
self._RunNativeTest(test_suite)
else:
self._RunTest(test_suite)
except KeyboardInterrupt: except KeyboardInterrupt:
logger.Log("Exiting...") logger.Log("Exiting...")
except errors.AbortError: except errors.AbortError:

View File

@@ -38,7 +38,14 @@ class TestDefinitions(object):
[class=""] [class=""]
[coverage_target=""] [coverage_target=""]
[build_path=""] [build_path=""]
[continuous] [continuous=false]
[description=""]
/>
<test-native
name=""
build_path=""
[continuous=false]
[description=""]
/> />
<test ... <test ...
</test-definitions> </test-definitions>
@@ -48,13 +55,17 @@ class TestDefinitions(object):
# tag/attribute constants # tag/attribute constants
_TEST_TAG_NAME = "test" _TEST_TAG_NAME = "test"
_TEST_NATIVE_TAG_NAME = "test-native"
def __init__(self): def __init__(self):
# dictionary of test name to tests # dictionary of test name to tests
self._testname_map = {} self._testname_map = {}
def __iter__(self): def __iter__(self):
return iter(self._testname_map.values()) ordered_list = []
for k in sorted(self._testname_map):
ordered_list.append(self._testname_map[k])
return iter(ordered_list)
def Parse(self, file_path): def Parse(self, file_path):
"""Parse the test suite data from from given file path. """Parse the test suite data from from given file path.
@@ -87,6 +98,12 @@ class TestDefinitions(object):
test = self._ParseTestSuite(suite_element) test = self._ParseTestSuite(suite_element)
self._AddTest(test) self._AddTest(test)
suite_elements = doc.getElementsByTagName(self._TEST_NATIVE_TAG_NAME)
for suite_element in suite_elements:
test = self._ParseNativeTestSuite(suite_element)
self._AddTest(test)
def _ParseTestSuite(self, suite_element): def _ParseTestSuite(self, suite_element):
"""Parse the suite element. """Parse the suite element.
@@ -96,6 +113,17 @@ class TestDefinitions(object):
test = TestSuite(suite_element) test = TestSuite(suite_element)
return test return test
def _ParseNativeTestSuite(self, suite_element):
"""Parse the native test element.
Returns:
a TestSuite object, populated with parsed data
Raises:
ParseError if some required attribute is missing.
"""
test = TestSuite(suite_element, native=True)
return test
def _AddTest(self, test): def _AddTest(self, test):
"""Adds a test to this TestManifest. """Adds a test to this TestManifest.
@@ -129,13 +157,27 @@ class TestSuite(object):
_TARGET_ATTR = "coverage_target" _TARGET_ATTR = "coverage_target"
_BUILD_ATTR = "build_path" _BUILD_ATTR = "build_path"
_CONTINUOUS_ATTR = "continuous" _CONTINUOUS_ATTR = "continuous"
_DESCRIPTION_ATTR = "description"
_DEFAULT_RUNNER = "android.test.InstrumentationTestRunner" _DEFAULT_RUNNER = "android.test.InstrumentationTestRunner"
def __init__(self, suite_element): def __init__(self, suite_element, native=False):
"""Populates this instance's data from given suite xml element.""" """Populates this instance's data from given suite xml element.
Raises:
ParseError if some required attribute is missing.
"""
self._native = native
self._name = suite_element.getAttribute(self._NAME_ATTR) self._name = suite_element.getAttribute(self._NAME_ATTR)
self._package = suite_element.getAttribute(self._PKG_ATTR)
if self._native:
# For native runs, _BUILD_ATTR is required
if not suite_element.hasAttribute(self._BUILD_ATTR):
logger.Log("Error: %s is missing required build_path attribute" %
self._name)
raise errors.ParseError
else:
self._package = suite_element.getAttribute(self._PKG_ATTR)
if suite_element.hasAttribute(self._RUNNER_ATTR): if suite_element.hasAttribute(self._RUNNER_ATTR):
self._runner = suite_element.getAttribute(self._RUNNER_ATTR) self._runner = suite_element.getAttribute(self._RUNNER_ATTR)
else: else:
@@ -156,6 +198,10 @@ class TestSuite(object):
self._continuous = suite_element.getAttribute(self._CONTINUOUS_ATTR) self._continuous = suite_element.getAttribute(self._CONTINUOUS_ATTR)
else: else:
self._continuous = False self._continuous = False
if suite_element.hasAttribute(self._DESCRIPTION_ATTR):
self._description = suite_element.getAttribute(self._DESCRIPTION_ATTR)
else:
self._description = ""
def GetName(self): def GetName(self):
return self._name return self._name
@@ -184,6 +230,13 @@ class TestSuite(object):
"""Returns true if test is flagged as being part of the continuous tests""" """Returns true if test is flagged as being part of the continuous tests"""
return self._continuous return self._continuous
def IsNative(self):
"""Returns true if test is a native one."""
return self._native
def GetDescription(self):
return self._description
def Parse(file_path): def Parse(file_path):
"""Parses out a TestDefinitions from given path to xml file. """Parses out a TestDefinitions from given path to xml file.

View File

@@ -17,32 +17,65 @@
<!-- <!--
This file contains standard test definitions for the Android platform This file contains standard test definitions for the Android platform
Tests are defined by <test> tags with the following attributes Java tests are defined by <test> tags and native ones (C/C++) are defined by
<test-native> tags.
name package [class runner build_path coverage_target continuous] JAVA/application tests:
=======================
The java <test> element has the following attributes
Where: name package [class runner build_path coverage_target continuous description]
name: Self-descriptive name used to uniquely identify the test
build_path: File system path, relative to Android build root, to this package's
Android.mk file. If omitted, build/sync step for this test will be skipped
package: Android application package that contains the tests
class: Optional. Fully qualified Java test class to run.
runner: Fully qualified InstrumentationTestRunner to execute. If omitted,
will default to android.test.InstrumentationTestRunner
coverage_target: Build name of Android package this test targets - these targets
are defined in the coverage_targets.xml file. Used as basis for code
coverage metrics. If omitted, code coverage will not be supported for this
test
continuous: Optional boolean. Default is false. Set to true if tests are known
to be reliable, and should be included in a continuous test system. false if
they are under development.
These attributes map to the following commands: Where:
(if class is defined) name: Self-descriptive name used to uniquely identify the test
adb shell am instrument -w <package>/<runner> build_path: File system path, relative to Android build root, to this
(else) package's Android.mk file. If omitted, build/sync step for this test will
adb shell am instrument -w -e class <class> <package>/<runner> be skipped.
package: Android application package that contains the tests
class: Optional. Fully qualified Java test class to run.
runner: Fully qualified InstrumentationTestRunner to execute. If omitted,
will default to android.test.InstrumentationTestRunner.
coverage_target: Build name of Android package this test targets - these
targets are defined in the coverage_targets.xml file. Used as basis for
code coverage metrics. If omitted, code coverage will not be supported for
this test.
continuous: Optional boolean. Default is false. Set to true if tests are known
to be reliable, and should be included in a continuous test system. false if
they are under development.
description: Optional string. Default is empty. Short description (typically
less than 60 characters) about this test.
These attributes map to the following commands:
(if class is defined)
adb shell am instrument -w <package>/<runner>
(else)
adb shell am instrument -w -e class <class> <package>/<runner>
Native tests:
=============
The <test-native> element has the following attributes
name build_path [continuous description]
Where:
name: Self-descriptive name used to uniquely identify the test
build_path: File system path, relative to Android build root, to this
package's Android.mk file. By convention the name of a test starts with
'test_'.
continuous: Optional boolean. Default is false. Set to true if tests are known
to be reliable, and should be included in a continuous test system.
false if they are under development.
description: Optional string. Default is empty. Short description (typically
less than 60 characters) about this test.
These attributes map to the following commands:
make <build_path>/Android.mk
adb sync
for test_prog in <tests built>; do
adb shell "/system/bin/${test_prog} >/dev/null 2>&1;echo \$?"
adb shell "rm /system/bin/${test_prog}"
done
--> -->
<test-definitions version="1"> <test-definitions version="1">
@@ -223,4 +256,10 @@ These attributes map to the following commands:
coverage_target="Settings" /> coverage_target="Settings" />
--> -->
<!-- native tests -->
<test-native name="libstdcpp"
build_path="system/extras/tests/bionic/libstdc++"
description="Bionic libstdc++." />
</test-definitions> </test-definitions>