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,6 +309,9 @@ class TestRunner(object):
self._DoBuild() self._DoBuild()
for test_suite in self._GetTestsToRun(): for test_suite in self._GetTestsToRun():
if test_suite.IsNative():
self._RunNativeTest(test_suite)
else:
self._RunTest(test_suite) self._RunTest(test_suite)
except KeyboardInterrupt: except KeyboardInterrupt:
logger.Log("Exiting...") logger.Log("Exiting...")

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)
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) 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
name package [class runner build_path coverage_target continuous description]
Where: Where:
name: Self-descriptive name used to uniquely identify the test name: Self-descriptive name used to uniquely identify the test
build_path: File system path, relative to Android build root, to this package's build_path: File system path, relative to Android build root, to this
Android.mk file. If omitted, build/sync step for this test will be skipped package's Android.mk file. If omitted, build/sync step for this test will
be skipped.
package: Android application package that contains the tests package: Android application package that contains the tests
class: Optional. Fully qualified Java test class to run. class: Optional. Fully qualified Java test class to run.
runner: Fully qualified InstrumentationTestRunner to execute. If omitted, runner: Fully qualified InstrumentationTestRunner to execute. If omitted,
will default to android.test.InstrumentationTestRunner will default to android.test.InstrumentationTestRunner.
coverage_target: Build name of Android package this test targets - these targets coverage_target: Build name of Android package this test targets - these
are defined in the coverage_targets.xml file. Used as basis for code targets are defined in the coverage_targets.xml file. Used as basis for
coverage metrics. If omitted, code coverage will not be supported for this code coverage metrics. If omitted, code coverage will not be supported for
test this test.
continuous: Optional boolean. Default is false. Set to true if tests are known 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 to be reliable, and should be included in a continuous test system. false if
they are under development. 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: These attributes map to the following commands:
(if class is defined) (if class is defined)
adb shell am instrument -w <package>/<runner> adb shell am instrument -w <package>/<runner>
(else) (else)
adb shell am instrument -w -e class <class> <package>/<runner> 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>