eclair snapshot

This commit is contained in:
Jean-Baptiste Queru
2009-11-12 18:45:17 -08:00
parent 50992e805e
commit 2c8ead32c7
3250 changed files with 153970 additions and 72935 deletions

View File

@@ -80,7 +80,7 @@ def _ParseInstrumentationFinishedBundle(result):
code.
"""
re_result = re.compile(r'INSTRUMENTATION_RESULT: ([^=]+)=(.+)$')
re_result = re.compile(r'INSTRUMENTATION_RESULT: ([^=]+)=(.*)$')
re_code = re.compile(r'INSTRUMENTATION_CODE: (\-?\d)$')
result_dict = {}
key = ''
@@ -135,38 +135,26 @@ class TestResult(object):
self._test_name = None
self._status_code = None
self._failure_reason = None
self._fields_map = {}
re_start_block = re.compile(
r'\s*INSTRUMENTATION_STATUS: stream=(?P<stream>.*)'
'INSTRUMENTATION_STATUS: test=(?P<test>\w+)\s+'
'INSTRUMENTATION_STATUS: class=(?P<class>[\w\.]+)\s+'
'INSTRUMENTATION_STATUS: current=(?P<current>\d+)\s+'
'INSTRUMENTATION_STATUS: numtests=(?P<numtests>\d+)\s+'
'INSTRUMENTATION_STATUS: id=.*\s+'
'INSTRUMENTATION_STATUS_CODE: 1\s*', re.DOTALL)
re_status_code = re.search(r'INSTRUMENTATION_STATUS_CODE: '
'(?P<status_code>1|0|-1|-2)', result_block_string)
re_fields = re.compile(r'INSTRUMENTATION_STATUS: '
'(?P<key>[\w.]+)=(?P<value>.*?)(?=\nINSTRUMENTATION_STATUS)', re.DOTALL)
re_end_block = re.compile(
r'\s*INSTRUMENTATION_STATUS: stream=(?P<stream>.*)'
'INSTRUMENTATION_STATUS: test=(?P<test>\w+)\s+'
'(INSTRUMENTATION_STATUS: stack=(?P<stack>.*))?'
'INSTRUMENTATION_STATUS: class=(?P<class>[\w\.]+)\s+'
'INSTRUMENTATION_STATUS: current=(?P<current>\d+)\s+'
'INSTRUMENTATION_STATUS: numtests=(?P<numtests>\d+)\s+'
'INSTRUMENTATION_STATUS: id=.*\s+'
'INSTRUMENTATION_STATUS_CODE: (?P<status_code>0|-1|-2)\s*', re.DOTALL)
for field in re_fields.finditer(result_block_string):
key, value = (field.group('key').strip(), field.group('value').strip())
if key.startswith('performance.'):
key = key[len('performance.'):]
self._fields_map[key] = value
self._fields_map.setdefault('class')
self._fields_map.setdefault('test')
start_block_match = re_start_block.match(result_block_string)
end_block_match = re_end_block.match(result_block_string)
if start_block_match:
self._test_name = "%s:%s" % (start_block_match.group('class'),
start_block_match.group('test'))
self._status_code = 1
elif end_block_match:
self._test_name = "%s:%s" % (end_block_match.group('class'),
end_block_match.group('test'))
self._status_code = int(end_block_match.group('status_code'))
self._failure_reason = end_block_match.group('stack')
self._test_name = '%s:%s' % (self._fields_map['class'],
self._fields_map['test'])
self._status_code = int(re_status_code.group('status_code'))
if 'stack' in self._fields_map:
self._failure_reason = self._fields_map['stack']
def GetTestName(self):
return self._test_name
@@ -176,3 +164,6 @@ class TestResult(object):
def GetFailureReason(self):
return self._failure_reason
def GetResultFields(self):
return self._fields_map

View File

@@ -22,6 +22,7 @@ http://developer.android.com/guide/topics/manifest/manifest-intro.html
"""
# python imports
import os
import xml.dom.minidom
import xml.parsers
@@ -29,22 +30,26 @@ import xml.parsers
class AndroidManifest(object):
"""In memory representation of AndroidManifest.xml file."""
FILENAME = "AndroidManifest.xml"
FILENAME = 'AndroidManifest.xml'
def __init__(self, app_path=None):
if app_path:
self.ParseManifest(app_path)
def GetAppPath(self):
"""Retrieve file system path to this manifest file's directory."""
return self._app_path
def GetPackageName(self):
"""Retrieve package name defined at <manifest package="...">.
Returns:
Package name if defined, otherwise None
"""
manifests = self._dom.getElementsByTagName("manifest")
if not manifests or not manifests[0].getAttribute("package"):
manifest = self._GetManifestElement()
if not manifest or not manifest.hasAttribute('package'):
return None
return manifests[0].getAttribute("package")
return manifest.getAttribute('package')
def ParseManifest(self, app_path):
"""Parse AndroidManifest.xml at the specified path.
@@ -55,6 +60,51 @@ class AndroidManifest(object):
IOError: AndroidManifest.xml cannot be found at given path, or cannot be
opened for reading
"""
self.app_path = app_path.rstrip("/")
self.manifest_path = "%s/%s" % (self.app_path, self.FILENAME)
self._dom = xml.dom.minidom.parse(self.manifest_path)
self._app_path = app_path
self._manifest_path = os.path.join(app_path, self.FILENAME)
self._dom = xml.dom.minidom.parse(self._manifest_path)
def AddUsesSdk(self, min_sdk_version):
"""Adds a uses-sdk element to manifest.
Args:
min_sdk_version: value to provide for minSdkVersion attribute.
"""
manifest = self._GetManifestElement()
uses_sdk_elements = manifest.getElementsByTagName('uses-sdk')
if uses_sdk_elements:
uses_sdk_element = uses_sdk_elements[0]
else:
uses_sdk_element = self._dom.createElement('uses-sdk')
manifest.appendChild(uses_sdk_element)
uses_sdk_element.setAttribute('android:minSdkVersion', min_sdk_version)
self._SaveXml()
def GetInstrumentationNames(self):
"""Get the instrumentation names from manifest.
Returns:
list of names, might be empty
"""
instr_elements = self._dom.getElementsByTagName('instrumentation')
instrs = []
for element in instr_elements:
instrs.append(element.getAttribute('android:name'))
return instrs
def _GetManifestElement(self):
"""Retrieve the root manifest element.
Returns:
the DOM element for manifest or None.
"""
manifests = self._dom.getElementsByTagName('manifest')
if not manifests:
return None
return manifests[0]
def _SaveXml(self):
"""Saves the manifest to disk."""
self._dom.writexml(open(self._manifest_path, mode='w'), encoding='utf-8')

View File

@@ -79,7 +79,6 @@
type="APPS" />
<coverage_target name="Launcher" build_path="packages/apps/Home"
type="APPS" />
<coverage_target name="IM" build_path="packages/apps/IM" type="APPS" />
<coverage_target name="Mms" build_path="packages/apps/Mms" type="APPS" />
<coverage_target name="Music" build_path="packages/apps/Music"
type="APPS" />

View File

@@ -34,16 +34,25 @@ def SetAbortOnError(abort=True):
global _abort_on_error
_abort_on_error = abort
def RunCommand(cmd, timeout_time=None, retry_count=3, return_output=True):
"""Spawns a subprocess to run the given shell command, and checks for
timeout_time. If return_output is True, the output of the command is returned
as a string. Otherwise, output of command directed to stdout """
def RunCommand(cmd, timeout_time=None, retry_count=3, return_output=True,
stdin_input=None):
"""Spawn and retry a subprocess to run the given shell command.
Args:
cmd: shell command to run
timeout_time: time in seconds to wait for command to run before aborting.
retry_count: number of times to retry command
return_output: if True return output of command as string. Otherwise,
direct output of command to stdout.
stdin_input: data to feed to stdin
Returns:
output of command
"""
result = None
while True:
try:
result = RunOnce(cmd, timeout_time=timeout_time,
return_output=return_output)
return_output=return_output, stdin_input=stdin_input)
except errors.WaitForResponseTimedOutError:
if retry_count == 0:
raise
@@ -53,7 +62,22 @@ def RunCommand(cmd, timeout_time=None, retry_count=3, return_output=True):
# Success
return result
def RunOnce(cmd, timeout_time=None, return_output=True):
def RunOnce(cmd, timeout_time=None, return_output=True, stdin_input=None):
"""Spawns a subprocess to run the given shell command.
Args:
cmd: shell command to run
timeout_time: time in seconds to wait for command to run before aborting.
return_output: if True return output of command as string. Otherwise,
direct output of command to stdout.
stdin_input: data to feed to stdin
Returns:
output of command
Raises:
errors.WaitForResponseTimedOutError if command did not complete within
timeout_time seconds.
errors.AbortError is command returned error code and SetAbortOnError is on.
"""
start_time = time.time()
so = []
pid = []
@@ -67,15 +91,20 @@ def RunOnce(cmd, timeout_time=None, return_output=True):
else:
# None means direct to stdout
output_dest = None
if stdin_input:
stdin_dest = subprocess.PIPE
else:
stdin_dest = None
pipe = subprocess.Popen(
cmd,
executable='/bin/bash',
stdin=stdin_dest,
stdout=output_dest,
stderr=subprocess.STDOUT,
shell=True)
pid.append(pipe.pid)
try:
output = pipe.communicate()[0]
output = pipe.communicate(input=stdin_input)[0]
if output is not None and len(output) > 0:
so.append(output)
except OSError, e:
@@ -83,7 +112,7 @@ def RunOnce(cmd, timeout_time=None, return_output=True):
logger.Log(e)
so.append("ERROR")
error_occurred = True
if pipe.returncode != 0:
if pipe.returncode:
logger.SilentLog("Error: %s returned %d error code" %(cmd,
pipe.returncode))
error_occurred = True
@@ -144,7 +173,7 @@ def RunHostCommand(binary, valgrind=False):
else:
# Need the full path to valgrind to avoid other versions on the system.
subproc = subprocess.Popen(["/usr/bin/valgrind", "--tool=memcheck",
"--leak-check=yes", "-q", full_path],
"--leak-check=yes", "-q", binary],
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
# Cannot rely on the retcode of valgrind. Instead look for an empty output.
valgrind_out = subproc.communicate()[0].strip()

View File

@@ -14,9 +14,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.
"""Command line utility for running a pre-defined test.
"""Command line utility for running Android tests
Based on previous <androidroot>/development/tools/runtest shell script.
runtest helps automate the instructions for building and running tests
- It builds the corresponding test package for the code you want to test
- It pushes the test package to your device or emulator
- It launches InstrumentationTestRunner (or similar) to run the tests you
specify.
runtest supports running tests whose attributes have been pre-defined in
_TEST_FILE_NAME files, (runtest <testname>), or by specifying the file
system path to the test to run (runtest --path <path>).
Do runtest --help to see full list of options.
"""
# Python imports
@@ -34,6 +44,7 @@ import errors
import logger
import run_command
from test_defs import test_defs
from test_defs import test_walker
class TestRunner(object):
@@ -56,6 +67,9 @@ class TestRunner(object):
"The runtest script works in two ways. You can query it "
"for a list of tests, or you can launch one or more tests.")
# default value for make -jX
_DEFAULT_JOBS = 4
def __init__(self):
# disable logging of timestamp
self._root_path = android_build.GetTop()
@@ -64,6 +78,7 @@ class TestRunner(object):
self._known_tests = None
self._options = None
self._test_args = None
self._tests_to_run = None
def _ProcessOptions(self):
"""Processes command-line options."""
@@ -78,6 +93,9 @@ class TestRunner(object):
help="To view the list of tests")
parser.add_option("-b", "--skip-build", dest="skip_build", default=False,
action="store_true", help="Skip build - just launch")
parser.add_option("-j", "--jobs", dest="make_jobs",
metavar="X", default=self._DEFAULT_JOBS,
help="Number of make jobs to use when building")
parser.add_option("-n", "--skip_execute", dest="preview", default=False,
action="store_true",
help="Do not execute, just preview commands")
@@ -108,6 +126,8 @@ class TestRunner(object):
parser.add_option("-o", "--coverage", dest="coverage",
default=False, action="store_true",
help="Generate code coverage metrics for test(s)")
parser.add_option("-x", "--path", dest="test_path",
help="Run test(s) at given file system path")
parser.add_option("-t", "--all-tests", dest="all_tests",
default=False, action="store_true",
help="Run all defined tests")
@@ -139,6 +159,7 @@ class TestRunner(object):
and not self._options.all_tests
and not self._options.continuous_tests
and not self._options.cts_tests
and not self._options.test_path
and len(self._test_args) < 1):
parser.print_help()
logger.SilentLog("at least one test name must be specified")
@@ -186,26 +207,46 @@ class TestRunner(object):
def _DumpTests(self):
"""Prints out set of defined tests."""
print "The following tests are currently defined:"
print "The following tests are currently defined:\n"
print "%-25s %-40s %s" % ("name", "build path", "description")
print "-" * 80
for test in self._known_tests:
print "%-15s %s" % (test.GetName(), test.GetDescription())
print "%-25s %-40s %s" % (test.GetName(), test.GetBuildPath(),
test.GetDescription())
print "\nSee %s for more information" % self._TEST_FILE_NAME
def _DoBuild(self):
logger.SilentLog("Building tests...")
target_set = Set()
extra_args_set = Set()
for test_suite in self._GetTestsToRun():
tests = self._GetTestsToRun()
for test_suite in tests:
self._AddBuildTarget(test_suite, target_set, extra_args_set)
if target_set:
if self._options.coverage:
coverage.EnableCoverageBuild()
# hack to build cts dependencies
# TODO: remove this when build dependency support added to runtest or
# cts dependencies are removed
if self._IsCtsTests(tests):
# need to use make since these fail building with ONE_SHOT_MAKEFILE
cmd = ('make -j%s CtsTestStubs android.core.tests.runner' %
self._options.make_jobs)
logger.Log(cmd)
if not self._options.preview:
old_dir = os.getcwd()
os.chdir(self._root_path)
run_command.RunCommand(cmd, return_output=False)
os.chdir(old_dir)
target_build_string = " ".join(list(target_set))
extra_args_string = " ".join(list(extra_args_set))
# mmm cannot be used from python, so perform a similar operation using
# ONE_SHOT_MAKEFILE
cmd = 'ONE_SHOT_MAKEFILE="%s" make -C "%s" files %s' % (
target_build_string, self._root_path, extra_args_string)
cmd = 'ONE_SHOT_MAKEFILE="%s" make -j%s -C "%s" files %s' % (
target_build_string, self._options.make_jobs, self._root_path,
extra_args_string)
logger.Log(cmd)
if self._options.preview:
@@ -230,25 +271,41 @@ class TestRunner(object):
if os.path.isfile(os.path.join(self._root_path, build_file_path)):
target_set.add(build_file_path)
return True
else:
logger.Log("%s has no Android.mk, skipping" % build_dir)
return False
def _GetTestsToRun(self):
"""Get a list of TestSuite objects to run, based on command line args."""
if self._tests_to_run:
return self._tests_to_run
self._tests_to_run = []
if self._options.all_tests:
return self._known_tests.GetTests()
self._tests_to_run = self._known_tests.GetTests()
elif self._options.continuous_tests:
return self._known_tests.GetContinuousTests()
self._tests_to_run = self._known_tests.GetContinuousTests()
elif self._options.cts_tests:
return self._known_tests.GetCtsTests()
tests = []
self._tests_to_run = self._known_tests.GetCtsTests()
elif self._options.test_path:
walker = test_walker.TestWalker()
self._tests_to_run = walker.FindTests(self._options.test_path)
for name in self._test_args:
test = self._known_tests.GetTest(name)
if test is None:
logger.Log("Error: Could not find test %s" % name)
self._DumpTests()
raise errors.AbortError
tests.append(test)
return tests
self._tests_to_run.append(test)
return self._tests_to_run
def _IsCtsTests(self, test_list):
"""Check if any cts tests are included in given list of tests to run."""
for test in test_list:
if test.IsCts():
return True
return False
def RunTests(self):
"""Main entry method - executes the tests according to command line args."""

View File

@@ -44,6 +44,12 @@ See test_defs.xsd for more information.
coverage_target="framework"
continuous="true" />
<test name="account"
build_path="frameworks/base/tests/AndroidTests"
package="com.android.unit_tests"
class="com.android.unit_tests.accounts.AccountManagerServiceTest"
coverage_target="framework" />
<test name="smoke"
build_path="frameworks/base/tests/SmokeTest"
package="com.android.smoketest.tests"
@@ -66,8 +72,7 @@ See test_defs.xsd for more information.
<test name="apidemos"
build_path="development/samples/ApiDemos"
package="com.example.android.apis.tests"
coverage_target="ApiDemos"
continuous="true" />
coverage_target="ApiDemos" />
<test name="launchperf"
build_path="development/apps/launchperf"
@@ -88,6 +93,13 @@ See test_defs.xsd for more information.
class="com.android.unit_tests.activity.ActivityTests"
coverage_target="framework" />
<test name="keystore-unit"
build_path="frameworks/base/keystore/tests"
package="android.security.tests"
runner=".KeyStoreTestRunner"
coverage_target="framework"
continuous="true" />
<test name="vpntests"
build_path="frameworks/base/tests/AndroidTests"
package="com.android.unit_tests"
@@ -103,6 +115,12 @@ See test_defs.xsd for more information.
-->
<test name="contentprovideroperation"
build_path="frameworks/base/tests/FrameworkTest"
package="com.android.frameworktest.tests"
class="android.content.ContentProviderOperationTest"
coverage_target="framework" />
<test name="tablemerger"
build_path="frameworks/base/tests/FrameworkTest"
package="com.android.frameworktest.tests"
@@ -125,7 +143,7 @@ See test_defs.xsd for more information.
<!-- cts tests -->
<test name="cts-permission"
build_path="cts/tests"
build_path="cts/tests/tests/permission"
package="com.android.cts.permission"
runner="android.test.InstrumentationTestRunner"
coverage_target="framework"
@@ -141,49 +159,49 @@ See test_defs.xsd for more information.
cts="true" />
<test name="cts-process"
build_path="cts/tests"
build_path="cts/tests/tests/process"
package="com.android.cts.process"
coverage_target="framework"
cts="true" />
<test name="cts-api-signature"
build_path="cts/tests"
build_path="cts/tests/SignatureTest"
package="android.tests.sigtest"
runner=".InstrumentationRunner"
cts="true" />
<test name="cts-api-signature-func"
build_path="cts/tests"
build_path="cts/tests/SignatureTest"
package="android.tests.sigtest.tests"
cts="true" />
<test name="cts-apidemos"
build_path="cts/tests"
build_path="cts/tests/ApiDemosReferenceTest"
package="android.apidemos.cts"
coverage_target="ApiDemos"
cts="true" />
<test name="cts-app"
build_path="cts/tests"
build_path="cts/tests/tests/app"
package="com.android.cts.app"
runner="android.test.InstrumentationCtsTestRunner"
coverage_target="framework"
cts="true" />
<test name="cts-content"
build_path="cts/tests"
build_path="cts/tests/tests/content"
package="com.android.cts.content"
runner="android.test.InstrumentationCtsTestRunner"
coverage_target="framework"
cts="true" />
<test name="cts-database"
build_path="cts/tests"
build_path="cts/tests/tests/database"
package="com.android.cts.database"
runner="android.test.InstrumentationCtsTestRunner"
coverage_target="framework"
cts="true" />
<test name="cts-gesture"
build_path="cts/tests/tests/gesture"
package="com.android.cts.gesture"
@@ -192,107 +210,121 @@ See test_defs.xsd for more information.
cts="true" />
<test name="cts-graphics"
build_path="cts/tests"
build_path="cts/tests/tests/graphics"
package="com.android.cts.graphics"
runner="android.test.InstrumentationCtsTestRunner"
coverage_target="framework"
cts="true" />
<test name="cts-hardware"
build_path="cts/tests"
build_path="cts/tests/tests/hardware"
package="com.android.cts.hardware"
runner="android.test.InstrumentationCtsTestRunner"
coverage_target="framework"
cts="true" />
<test name="cts-location"
build_path="cts/tests"
build_path="cts/tests/tests/location"
package="com.android.cts.location"
runner="android.test.InstrumentationCtsTestRunner"
coverage_target="framework"
cts="true" />
<test name="cts-media"
build_path="cts/tests/tests/media"
package="com.android.cts.media"
runner="android.test.InstrumentationCtsTestRunner"
coverage_target="framework"
cts="true" />
<test name="cts-net"
build_path="cts/tests"
build_path="cts/tests/tests/net"
package="com.android.cts.net"
runner="android.test.InstrumentationCtsTestRunner"
coverage_target="framework"
cts="true" />
<test name="cts-os"
build_path="cts/tests"
build_path="cts/tests/tests/os"
package="com.android.cts.os"
runner="android.test.InstrumentationCtsTestRunner"
coverage_target="framework"
cts="true" />
<test name="cts-perf1"
build_path="cts/tests"
build_path="cts/tests/tests/performance"
package="com.android.cts.performance"
runner="android.test.InstrumentationCtsTestRunner"
cts="true" />
<test name="cts-perf2"
build_path="cts/tests"
build_path="cts/tests/tests/performance2"
package="com.android.cts.performance2"
runner="android.test.InstrumentationCtsTestRunner"
cts="true" />
<test name="cts-perf3"
build_path="cts/tests"
build_path="cts/tests/tests/performance3"
package="com.android.cts.performance3"
runner="android.test.InstrumentationCtsTestRunner"
cts="true" />
<test name="cts-perf4"
build_path="cts/tests"
build_path="cts/tests/tests/performance4"
package="com.android.cts.performance4"
runner="android.test.InstrumentationCtsTestRunner"
cts="true" />
<test name="cts-perf5"
build_path="cts/tests"
build_path="cts/tests/tests/performance5"
package="com.android.cts.performance5"
runner="android.test.InstrumentationCtsTestRunner"
cts="true" />
<test name="cts-provider"
build_path="cts/tests"
build_path="cts/tests/tests/provider"
package="com.android.cts.provider"
runner="android.test.InstrumentationCtsTestRunner"
coverage_target="framework"
cts="true" />
<test name="cts-text"
build_path="cts/tests"
build_path="cts/tests/tests/text"
package="com.android.cts.text"
runner="android.test.InstrumentationCtsTestRunner"
coverage_target="framework"
cts="true" />
<test name="cts-telephony"
build_path="cts/tests"
build_path="cts/tests/tests/telephony"
package="com.android.cts.telephony"
runner="android.test.InstrumentationCtsTestRunner"
coverage_target="framework"
cts="true" />
<test name="cts-util"
build_path="cts/tests"
build_path="cts/tests/tests/util"
package="com.android.cts.util"
runner="android.test.InstrumentationCtsTestRunner"
coverage_target="framework"
cts="true" />
<test name="cts-view"
build_path="cts/tests"
build_path="cts/tests/tests/view"
package="com.android.cts.view"
runner="android.test.InstrumentationCtsTestRunner"
coverage_target="framework"
cts="true" />
<test name="cts-webkit"
build_path="cts/tests/tests/webkit"
package="com.android.cts.webkit"
runner="android.test.InstrumentationCtsTestRunner"
coverage_target="framework"
cts="true" />
<test name="cts-widget"
build_path="cts/tests"
build_path="cts/tests/tests/widget"
package="com.android.cts.widget"
runner="android.test.InstrumentationCtsTestRunner"
coverage_target="framework"
@@ -322,8 +354,7 @@ See test_defs.xsd for more information.
<test name="calprov"
build_path="packages/providers/CalendarProvider/tests"
package="com.android.providers.calendar.tests"
coverage_target="CalendarProvider"
continuous="true" />
coverage_target="CalendarProvider" />
<test name="camerastress"
build_path="packages/apps/Camera"
@@ -345,9 +376,23 @@ See test_defs.xsd for more information.
coverage_target="Camera" />
<test name="contactsprov"
build_path="packages/providers/ContactsProvider/tests"
package="com.android.providers.contacts.tests"
coverage_target="ContactsProvider"
continuous="true" />
<test name="contacts"
build_path="packages/apps/Contacts"
package="com.android.contacts.tests"
runner="android.test.InstrumentationTestRunner"
coverage_target="Contacts"
description="Tests for the Contacts app."
continuous="true" />
<test name="gcontactsprov"
build_path="packages/providers/GoogleContactsProvider/tests"
package="com.android.providers.contactstests"
coverage_target="ContactsProvider" />
coverage_target="GoogleContactsProvider" />
<test name="downloadprovider-permission"
build_path="packages/providers/DownloadProvider/tests/permission"
@@ -441,7 +486,6 @@ See test_defs.xsd for more information.
<test name="mms"
build_path="packages/apps/Mms"
package="com.android.mms.tests"
runner="com.android.mms.ui.MMSInstrumentationTestRunner"
coverage_target="Mms" />
<test name="mmslaunch"
@@ -450,6 +494,11 @@ See test_defs.xsd for more information.
runner="com.android.mms.SmsLaunchPerformance"
coverage_target="Mms" />
<test name="telephony-unit"
build_path="frameworks/base/telephony/tests/TelephonyTest"
package="com.android.telephonytest"
runner=".TelephonyUnitTestRunner"
coverage_target="framework" />
<!-- obsolete?
<test name="ringtone"
@@ -467,18 +516,16 @@ See test_defs.xsd for more information.
description="Bionic libstdc++."
extra_build_args="BIONIC_TESTS=1" />
<test-native name="libskia"
build_path="external/skia/tests"
description="Skia tests." />
<!-- Android STL tests -->
<test-native name="astl"
build_path="external/astl/tests"
description="Android STL."
extra_build_args="ASTL_TESTS=1" />
<!-- Android Keystore tests -->
<test-native name="netkeystore_test"
build_path="frameworks/base/cmds/keystore/tests"
description="Android keystore."
extra_build_args="KEYSTORE_TESTS=1" />
<!-- pending patch 820
<test-native name="gtest"
build_path="external/gtest"

View File

@@ -1 +1 @@
__all__ = ['test_defs']
__all__ = ['test_defs', 'test_walker']

View File

@@ -1,113 +0,0 @@
#!/usr/bin/python2.4
#
#
# Copyright 2009, The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Abstract Android test suite."""
# Python imports
import xml.dom.minidom
import xml.parsers
# local imports
import errors
class AbstractTestSuite(object):
"""Represents a generic test suite definition parsed from xml.
This class will parse the XML attributes common to all TestSuite's.
"""
# name of xml tag a test suite handles. subclasses must define this.
TAG_NAME = "unspecified"
_NAME_ATTR = "name"
_BUILD_ATTR = "build_path"
_CONTINUOUS_ATTR = "continuous"
_CTS_ATTR = "cts"
_DESCRIPTION_ATTR = "description"
_EXTRA_BUILD_ARGS_ATTR = "extra_build_args"
def __init__(self):
self._attr_map = {}
def Parse(self, suite_element):
"""Populates this instance's data from given suite xml element.
Raises:
ParseError if a required attribute is missing.
"""
# parse name first so it can be used for error reporting
self._ParseAttribute(suite_element, self._NAME_ATTR, True)
self._ParseAttribute(suite_element, self._BUILD_ATTR, True)
self._ParseAttribute(suite_element, self._CONTINUOUS_ATTR, False,
default_value=False)
self._ParseAttribute(suite_element, self._CTS_ATTR, False,
default_value=False)
self._ParseAttribute(suite_element, self._DESCRIPTION_ATTR, False,
default_value="")
self._ParseAttribute(suite_element, self._EXTRA_BUILD_ARGS_ATTR, False,
default_value="")
def _ParseAttribute(self, suite_element, attribute_name, mandatory,
default_value=None):
if suite_element.hasAttribute(attribute_name):
self._attr_map[attribute_name] = \
suite_element.getAttribute(attribute_name)
elif mandatory:
error_msg = ("Could not find attribute %s in %s %s" %
(attribute_name, self.TAG_NAME, self.GetName()))
raise errors.ParseError(msg=error_msg)
else:
self._attr_map[attribute_name] = default_value
def GetName(self):
return self._GetAttribute(self._NAME_ATTR)
def GetBuildPath(self):
"""Returns the build path of this test, relative to source tree root."""
return self._GetAttribute(self._BUILD_ATTR)
def GetBuildDependencies(self, options):
"""Returns a list of dependent build paths."""
return []
def IsContinuous(self):
"""Returns true if test is flagged as being part of the continuous tests"""
return self._GetAttribute(self._CONTINUOUS_ATTR)
def IsCts(self):
"""Returns true if test is part of the compatibility test suite"""
return self._GetAttribute(self._CTS_ATTR)
def GetDescription(self):
"""Returns a description if available, an empty string otherwise."""
return self._GetAttribute(self._DESCRIPTION_ATTR)
def GetExtraBuildArgs(self):
"""Returns the extra build args if available, an empty string otherwise."""
return self._GetAttribute(self._EXTRA_BUILD_ARGS_ATTR)
def _GetAttribute(self, attribute_name):
return self._attr_map.get(attribute_name)
def Run(self, options, adb):
"""Runs the test.
Subclasses must implement this.
Args:
options: global command line options
"""
raise NotImplementedError

View File

@@ -20,23 +20,15 @@
# python imports
import os
# local imports
from abstract_test import AbstractTestSuite
import errors
import logger
import run_command
import test_suite
class HostTestSuite(AbstractTestSuite):
class HostTestSuite(test_suite.AbstractTestSuite):
"""A test suite for running hosttestlib java tests."""
TAG_NAME = "test-host"
_CLASS_ATTR = "class"
# TODO: consider obsoleting in favor of parsing the Android.mk to find the
# jar name
_JAR_ATTR = "jar_name"
_JUNIT_JAR_NAME = "junit.jar"
_HOSTTESTLIB_NAME = "hosttestlib.jar"
_DDMLIB_NAME = "ddmlib.jar"
@@ -54,21 +46,29 @@ class HostTestSuite(AbstractTestSuite):
# the test suite?
_TEST_RUNNER = "com.android.hosttest.DeviceTestRunner"
def Parse(self, suite_element):
super(HostTestSuite, self).Parse(suite_element)
self._ParseAttribute(suite_element, self._CLASS_ATTR, True)
self._ParseAttribute(suite_element, self._JAR_ATTR, True)
def __init__(self):
test_suite.AbstractTestSuite.__init__(self)
self._jar_name = None
self._class_name = None
def GetBuildDependencies(self, options):
"""Override parent to tag on building host libs."""
return self._LIB_BUILD_PATHS
def GetClass(self):
return self._GetAttribute(self._CLASS_ATTR)
def GetClassName(self):
return self._class_name
def SetClassName(self, class_name):
self._class_name = class_name
return self
def GetJarName(self):
"""Returns the name of the host jar that contains the tests."""
return self._GetAttribute(self._JAR_ATTR)
return self._jar_name
def SetJarName(self, jar_name):
self._jar_name = jar_name
return self
def Run(self, options, adb_interface):
"""Runs the host test.
@@ -77,11 +77,14 @@ class HostTestSuite(AbstractTestSuite):
Args:
options: command line options for running host tests. Expected member
fields:
fields:
host_lib_path: path to directory that contains host library files
test_data_path: path to directory that contains test data files
preview: if true, do not execute, display commands only
adb_interface: reference to device under test
Raises:
errors.AbortError: if fatal error occurs
"""
# get the serial number of the device under test, so it can be passed to
# hosttestlib.
@@ -100,7 +103,7 @@ class HostTestSuite(AbstractTestSuite):
# -p <test data path>
cmd = "java -cp %s %s %s -s %s -p %s" % (":".join(full_lib_paths),
self._TEST_RUNNER,
self.GetClass(), serial_number,
self.GetClassName(), serial_number,
options.test_data_path)
logger.Log(cmd)
if not options.preview:

View File

@@ -21,59 +21,75 @@
import os
# local imports
from abstract_test import AbstractTestSuite
import coverage
import errors
import logger
import test_suite
class InstrumentationTestSuite(AbstractTestSuite):
"""Represents a java instrumentation test suite definition run on Android device."""
class InstrumentationTestSuite(test_suite.AbstractTestSuite):
"""Represents a java instrumentation test suite definition run on device."""
# for legacy reasons, the xml tag name for java (device) tests is "test:
TAG_NAME = "test"
_PKG_ATTR = "package"
_RUNNER_ATTR = "runner"
_CLASS_ATTR = "class"
_TARGET_ATTR = "coverage_target"
_DEFAULT_RUNNER = "android.test.InstrumentationTestRunner"
DEFAULT_RUNNER = "android.test.InstrumentationTestRunner"
# build path to Emma target Makefile
_EMMA_BUILD_PATH = os.path.join("external", "emma")
def _GetTagName(self):
return self._TAG_NAME
def __init__(self):
test_suite.AbstractTestSuite.__init__(self)
self._package_name = None
self._runner_name = self.DEFAULT_RUNNER
self._class_name = None
self._target_name = None
self._java_package = None
def GetPackageName(self):
return self._GetAttribute(self._PKG_ATTR)
return self._package_name
def SetPackageName(self, package_name):
self._package_name = package_name
return self
def GetRunnerName(self):
return self._GetAttribute(self._RUNNER_ATTR)
return self._runner_name
def SetRunnerName(self, runner_name):
self._runner_name = runner_name
return self
def GetClassName(self):
return self._GetAttribute(self._CLASS_ATTR)
return self._class_name
def SetClassName(self, class_name):
self._class_name = class_name
return self
def GetJavaPackageFilter(self):
return self._java_package
def SetJavaPackageFilter(self, java_package_name):
"""Configure the suite to only run tests in given java package."""
self._java_package = java_package_name
return self
def GetTargetName(self):
"""Retrieve module that this test is targeting.
Used for generating code coverage metrics.
Returns:
the module target name
"""
return self._GetAttribute(self._TARGET_ATTR)
return self._target_name
def SetTargetName(self, target_name):
self._target_name = target_name
return self
def GetBuildDependencies(self, options):
if options.coverage:
return [self._EMMA_BUILD_PATH]
return []
def Parse(self, suite_element):
super(InstrumentationTestSuite, self).Parse(suite_element)
self._ParseAttribute(suite_element, self._PKG_ATTR, True)
self._ParseAttribute(suite_element, self._RUNNER_ATTR, False, self._DEFAULT_RUNNER)
self._ParseAttribute(suite_element, self._CLASS_ATTR, False)
self._ParseAttribute(suite_element, self._TARGET_ATTR, False)
def Run(self, options, adb):
"""Run the provided test suite.
@@ -82,6 +98,9 @@ class InstrumentationTestSuite(AbstractTestSuite):
Args:
options: command line options to provide to test run
adb: adb_interface to device under test
Raises:
errors.AbortError: if fatal error occurs
"""
test_class = self.GetClassName()
@@ -92,11 +111,18 @@ class InstrumentationTestSuite(AbstractTestSuite):
if options.test_method is not None:
test_class = "%s#%s" % (test_class, options.test_method)
test_package = self.GetJavaPackageFilter()
if options.test_package:
test_package = options.test_package
if test_class and test_package:
logger.Log('Error: both class and java package options are specified')
instrumentation_args = {}
if test_class is not None:
instrumentation_args["class"] = test_class
if options.test_package:
instrumentation_args["package"] = options.test_package
if test_package:
instrumentation_args["package"] = test_package
if options.test_size:
instrumentation_args["size"] = options.test_size
if options.wait_for_debugger:
@@ -122,10 +148,10 @@ class InstrumentationTestSuite(AbstractTestSuite):
logger.Log("Running in coverage mode, suppressing test output")
try:
(test_results, status_map) = adb.StartInstrumentationForPackage(
package_name=self.GetPackageName(),
runner_name=self.GetRunnerName(),
timeout_time=60*60,
instrumentation_args=instrumentation_args)
package_name=self.GetPackageName(),
runner_name=self.GetRunnerName(),
timeout_time=60*60,
instrumentation_args=instrumentation_args)
except errors.InstrumentationError, errors.DeviceUnresponsiveError:
return
self._PrintTestResults(test_results)
@@ -156,11 +182,11 @@ class InstrumentationTestSuite(AbstractTestSuite):
error_count = 0
fail_count = 0
for test_result in test_results:
if test_result.GetStatusCode() == -1: # error
if test_result.GetStatusCode() == -1: # error
logger.Log("Error in %s: %s" % (test_result.GetTestName(),
test_result.GetFailureReason()))
error_count+=1
elif test_result.GetStatusCode() == -2: # failure
elif test_result.GetStatusCode() == -2: # failure
logger.Log("Failure in %s: %s" % (test_result.GetTestName(),
test_result.GetFailureReason()))
fail_count+=1

View File

@@ -18,28 +18,19 @@
"""TestSuite for running native Android tests."""
# python imports
import re
import os
import re
# local imports
from abstract_test import AbstractTestSuite
import android_build
import logger
import run_command
import test_suite
class NativeTestSuite(AbstractTestSuite):
class NativeTestSuite(test_suite.AbstractTestSuite):
"""A test suite for running native aka C/C++ tests on device."""
TAG_NAME = "test-native"
def _GetTagName(self):
return self._TAG_NAME
def Parse(self, suite_element):
super(NativeTestSuite, self).Parse(suite_element)
def Run(self, options, adb):
"""Run the provided *native* test suite.
@@ -61,7 +52,7 @@ class NativeTestSuite(AbstractTestSuite):
# find all test files, convert unicode names to ascii, take the basename
# and drop the .cc/.cpp extension.
source_list = []
build_path = self.GetBuildPath()
build_path = os.path.join(android_build.GetTop(), self.GetBuildPath())
os.path.walk(build_path, self._CollectTestSources, source_list)
logger.SilentLog("Tests source %s" % source_list)

View File

@@ -24,9 +24,7 @@ import xml.parsers
# local imports
import errors
import logger
from instrumentation_test import InstrumentationTestSuite
from native_test import NativeTestSuite
from host_test import HostTestSuite
import xml_suite_helper
class TestDefinitions(object):
@@ -74,21 +72,13 @@ class TestDefinitions(object):
def _ParseDoc(self, doc):
root_element = self._GetRootElement(doc)
suite_parser = xml_suite_helper.XmlSuiteParser()
for element in root_element.childNodes:
if element.nodeType != xml.dom.Node.ELEMENT_NODE:
continue
test_suite = None
if element.nodeName == InstrumentationTestSuite.TAG_NAME:
test_suite = InstrumentationTestSuite()
elif element.nodeName == NativeTestSuite.TAG_NAME:
test_suite = NativeTestSuite()
elif element.nodeName == HostTestSuite.TAG_NAME:
test_suite = HostTestSuite()
else:
logger.Log("Unrecognized tag %s found" % element.nodeName)
continue
test_suite.Parse(element)
self._AddTest(test_suite)
test_suite = suite_parser.Parse(element)
if test_suite:
self._AddTest(test_suite)
def _GetRootElement(self, doc):
root_elements = doc.getElementsByTagName("test-definitions")

View File

@@ -0,0 +1,96 @@
#!/usr/bin/python2.4
#
#
# Copyright 2009, The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Abstract Android test suite."""
class AbstractTestSuite(object):
"""Represents a generic test suite definition."""
def __init__(self):
self._name = None
self._build_path = None
self._build_dependencies = []
self._is_continuous = False
self._is_cts = False
self._description = ''
self._extra_build_args = ''
def GetName(self):
return self._name
def SetName(self, name):
self._name = name
return self
def GetBuildPath(self):
"""Returns the build path of this test, relative to source tree root."""
return self._build_path
def SetBuildPath(self, build_path):
self._build_path = build_path
return self
def GetBuildDependencies(self, options):
"""Returns a list of dependent build paths."""
return self._build_dependencies
def SetBuildDependencies(self, build_dependencies):
self._build_dependencies = build_dependencies
return self
def IsContinuous(self):
"""Returns true if test is part of the continuous test."""
return self._is_continuous
def SetContinuous(self, continuous):
self._is_continuous = continuous
return self._is_continuous
def IsCts(self):
"""Returns true if test is part of the compatibility test suite"""
return self._is_cts
def SetCts(self, cts):
self._is_cts = cts
return self
def GetDescription(self):
"""Returns a description if available, an empty string otherwise."""
return self._description
def SetDescription(self, desc):
self._description = desc
return self
def GetExtraBuildArgs(self):
"""Returns the extra build args if available, an empty string otherwise."""
return self._extra_build_args
def SetExtraBuildArgs(self, build_args):
self._extra_build_args = build_args
return self
def Run(self, options, adb):
"""Runs the test.
Subclasses must implement this.
Args:
options: global command line options
adb: asdb_interface to device under test
"""
raise NotImplementedError

View File

@@ -0,0 +1,296 @@
#!/usr/bin/python2.4
#
#
# Copyright 2009, The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Utility to find instrumentation test definitions from file system."""
# python imports
import os
import re
# local imports
import android_build
import android_manifest
import android_mk
import instrumentation_test
import logger
class TestWalker(object):
"""Finds instrumentation tests from filesystem."""
def FindTests(self, path):
"""Gets list of Android instrumentation tests found at given path.
Tests are created from the <instrumentation> tags found in
AndroidManifest.xml files relative to the given path.
FindTests will first scan sub-folders of path for tests. If none are found,
it will scan the file system upwards until a AndroidManifest.xml is found
or the Android build root is reached.
Some sample values for path:
- a parent directory containing many tests:
ie development/samples will return tests for instrumentation's in ApiDemos,
ApiDemos/tests, Notepad/tests etc
- a java test class file
ie ApiDemos/tests/src/../ApiDemosTest.java will return a test for
the instrumentation in ApiDemos/tests, with the class name filter set to
ApiDemosTest
- a java package directory
ie ApiDemos/tests/src/com/example/android/apis will return a test for
the instrumentation in ApiDemos/tests, with the java package filter set
to com.example.android.apis.
Args:
path: file system path to search
Returns:
list of test suites that support operations defined by
test_suite.AbstractTestSuite
"""
if not os.path.exists(path):
logger.Log('%s does not exist' % path)
return []
abspath = os.path.abspath(path)
# ensure path is in ANDROID_BUILD_ROOT
self._build_top = android_build.GetTop()
if not self._IsPathInBuildTree(abspath):
logger.Log('%s is not a sub-directory of build root %s' %
(path, self._build_top))
return []
# first, assume path is a parent directory, which specifies to run all
# tests within this directory
tests = self._FindSubTests(abspath, [])
if not tests:
logger.SilentLog('No tests found within %s, searching upwards' % path)
tests = self._FindUpstreamTests(abspath)
return tests
def _IsPathInBuildTree(self, path):
"""Return true if given path is within current Android build tree.
Args:
path: absolute file system path
Returns:
True if path is within Android build tree
"""
return os.path.commonprefix([self._build_top, path]) == self._build_top
def _MakePathRelativeToBuild(self, path):
"""Convert given path to one relative to build tree root.
Args:
path: absolute file system path to convert.
Returns:
The converted path relative to build tree root.
Raises:
ValueError: if path is not within build tree
"""
if not self._IsPathInBuildTree(path):
raise ValueError
build_path_len = len(self._build_top) + 1
# return string with common build_path removed
return path[build_path_len:]
def _FindSubTests(self, path, tests, build_path=None):
"""Recursively finds all tests within given path.
Args:
path: absolute file system path to check
tests: current list of found tests
build_path: the parent directory where Android.mk was found
Returns:
updated list of tests
"""
if not os.path.isdir(path):
return tests
filenames = os.listdir(path)
# Try to build as much of original path as possible, so
# keep track of upper-most parent directory where Android.mk was found
# this is also necessary in case of overlapping tests
# ie if a test exists at 'foo' directory and 'foo/sub', attempting to
# build both 'foo' and 'foo/sub' will fail.
if not build_path and filenames.count(android_mk.AndroidMK.FILENAME):
build_path = self._MakePathRelativeToBuild(path)
if filenames.count(android_manifest.AndroidManifest.FILENAME):
# found a manifest! now parse it to find the test definition(s)
manifest = android_manifest.AndroidManifest(app_path=path)
tests.extend(self._CreateSuitesFromManifest(manifest, build_path))
for filename in filenames:
self._FindSubTests(os.path.join(path, filename), tests, build_path)
return tests
def _FindUpstreamTests(self, path):
"""Find tests defined upward from given path.
Args:
path: the location to start searching. If it points to a java class file
or java package dir, the appropriate test suite filters will be set
Returns:
list of test_suite.AbstractTestSuite found, may be empty
"""
class_name_arg = None
package_name = None
# if path is java file, populate class name
if self._IsJavaFile(path):
class_name_arg = self._GetClassNameFromFile(path)
logger.SilentLog('Using java test class %s' % class_name_arg)
elif self._IsJavaPackage(path):
package_name = self._GetPackageNameFromDir(path)
logger.SilentLog('Using java package %s' % package_name)
manifest = self._FindUpstreamManifest(path)
if manifest:
logger.SilentLog('Found AndroidManifest at %s' % manifest.GetAppPath())
build_path = self._MakePathRelativeToBuild(manifest.GetAppPath())
return self._CreateSuitesFromManifest(manifest,
build_path,
class_name=class_name_arg,
java_package_name=package_name)
def _IsJavaFile(self, path):
"""Returns true if given file system path is a java file."""
return os.path.isfile(path) and self._IsJavaFileName(path)
def _IsJavaFileName(self, filename):
"""Returns true if given file name is a java file name."""
return os.path.splitext(filename)[1] == '.java'
def _IsJavaPackage(self, path):
"""Returns true if given file path is a java package.
Currently assumes if any java file exists in this directory, than it
represents a java package.
Args:
path: file system path of directory to check
Returns:
True if path is a java package
"""
if not os.path.isdir(path):
return False
for file_name in os.listdir(path):
if self._IsJavaFileName(file_name):
return True
return False
def _GetClassNameFromFile(self, java_file_path):
"""Gets the fully qualified java class name from path.
Args:
java_file_path: file system path of java file
Returns:
fully qualified java class name or None.
"""
package_name = self._GetPackageNameFromFile(java_file_path)
if package_name:
filename = os.path.basename(java_file_path)
class_name = os.path.splitext(filename)[0]
return '%s.%s' % (package_name, class_name)
return None
def _GetPackageNameFromDir(self, path):
"""Gets the java package name associated with given directory path.
Caveat: currently just parses defined java package name from first java
file found in directory.
Args:
path: file system path of directory
Returns:
the java package name or None
"""
for filename in os.listdir(path):
if self._IsJavaFileName(filename):
return self._GetPackageNameFromFile(os.path.join(path, filename))
def _GetPackageNameFromFile(self, java_file_path):
"""Gets the java package name associated with given java file path.
Args:
java_file_path: file system path of java file
Returns:
the java package name or None
"""
logger.SilentLog('Looking for java package name in %s' % java_file_path)
re_package = re.compile(r'package\s+(.*);')
file_handle = open(java_file_path, 'r')
for line in file_handle:
match = re_package.match(line)
if match:
return match.group(1)
return None
def _FindUpstreamManifest(self, path):
"""Recursively searches filesystem upwards for a AndroidManifest file.
Args:
path: file system path to search
Returns:
the AndroidManifest found or None
"""
if (os.path.isdir(path) and
os.listdir(path).count(android_manifest.AndroidManifest.FILENAME)):
return android_manifest.AndroidManifest(app_path=path)
dirpath = os.path.dirname(path)
if self._IsPathInBuildTree(path):
return self._FindUpstreamManifest(dirpath)
logger.Log('AndroidManifest.xml not found')
return None
def _CreateSuitesFromManifest(self, manifest, build_path, class_name=None,
java_package_name=None):
"""Creates TestSuites from a AndroidManifest.
Args:
manifest: the AndroidManifest
build_path: the build path to use for test
class_name: optionally, the class filter for the suite
java_package_name: optionally, the java package filter for the suite
Returns:
the list of tests created
"""
tests = []
for instr_name in manifest.GetInstrumentationNames():
pkg_name = manifest.GetPackageName()
logger.SilentLog('Found instrumentation %s/%s' % (pkg_name, instr_name))
suite = instrumentation_test.InstrumentationTestSuite()
suite.SetPackageName(pkg_name)
suite.SetBuildPath(build_path)
suite.SetRunnerName(instr_name)
suite.SetName(pkg_name)
suite.SetClassName(class_name)
suite.SetJavaPackageFilter(java_package_name)
# this is a bit of a hack, assume if 'com.android.cts' is in
# package name, this is a cts test
# this logic can be removed altogether when cts tests no longer require
# custom build steps
suite.SetCts(suite.GetPackageName().startswith('com.android.cts'))
tests.append(suite)
return tests

View File

@@ -0,0 +1,152 @@
#!/usr/bin/python2.4
#
#
# Copyright 2009, The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Utility to parse suite info from xml."""
# Python imports
import xml.dom.minidom
import xml.parsers
# local imports
import errors
import logger
import host_test
import instrumentation_test
import native_test
class XmlSuiteParser(object):
"""Parses XML attributes common to all TestSuite's."""
# common attributes
_NAME_ATTR = 'name'
_BUILD_ATTR = 'build_path'
_CONTINUOUS_ATTR = 'continuous'
_CTS_ATTR = 'cts'
_DESCRIPTION_ATTR = 'description'
_EXTRA_BUILD_ARGS_ATTR = 'extra_build_args'
def Parse(self, element):
"""Populates common suite attributes from given suite xml element.
Args:
element: xml node to parse
Raises:
ParseError if a required attribute is missing.
Returns:
parsed test suite or None
"""
parser = None
if element.nodeName == InstrumentationParser.TAG_NAME:
parser = InstrumentationParser()
elif element.nodeName == NativeParser.TAG_NAME:
parser = NativeParser()
elif element.nodeName == HostParser.TAG_NAME:
parser = HostParser()
else:
logger.Log('Unrecognized tag %s found' % element.nodeName)
return None
test_suite = parser.Parse(element)
return test_suite
def _ParseCommonAttributes(self, suite_element, test_suite):
test_suite.SetName(self._ParseAttribute(suite_element, self._NAME_ATTR,
True))
test_suite.SetBuildPath(self._ParseAttribute(suite_element,
self._BUILD_ATTR, True))
test_suite.SetContinuous(self._ParseAttribute(suite_element,
self._CONTINUOUS_ATTR,
False, default_value=False))
test_suite.SetCts(self._ParseAttribute(suite_element, self._CTS_ATTR, False,
default_value=False))
test_suite.SetDescription(self._ParseAttribute(suite_element,
self._DESCRIPTION_ATTR,
False,
default_value=''))
test_suite.SetExtraBuildArgs(self._ParseAttribute(
suite_element, self._EXTRA_BUILD_ARGS_ATTR, False, default_value=''))
def _ParseAttribute(self, suite_element, attribute_name, mandatory,
default_value=None):
if suite_element.hasAttribute(attribute_name):
value = suite_element.getAttribute(attribute_name)
elif mandatory:
error_msg = ('Could not find attribute %s in %s' %
(attribute_name, self.TAG_NAME))
raise errors.ParseError(msg=error_msg)
else:
value = default_value
return value
class InstrumentationParser(XmlSuiteParser):
"""Parses instrumentation suite attributes from xml."""
# for legacy reasons, the xml tag name for java (device) tests is 'test'
TAG_NAME = 'test'
_PKG_ATTR = 'package'
_RUNNER_ATTR = 'runner'
_CLASS_ATTR = 'class'
_TARGET_ATTR = 'coverage_target'
def Parse(self, suite_element):
"""Creates suite and populate with data from xml element."""
suite = instrumentation_test.InstrumentationTestSuite()
XmlSuiteParser._ParseCommonAttributes(self, suite_element, suite)
suite.SetPackageName(self._ParseAttribute(suite_element, self._PKG_ATTR,
True))
suite.SetRunnerName(self._ParseAttribute(
suite_element, self._RUNNER_ATTR, False,
instrumentation_test.InstrumentationTestSuite.DEFAULT_RUNNER))
suite.SetClassName(self._ParseAttribute(suite_element, self._CLASS_ATTR,
False))
suite.SetTargetName(self._ParseAttribute(suite_element, self._TARGET_ATTR,
False))
return suite
class NativeParser(XmlSuiteParser):
"""Parses native suite attributes from xml."""
TAG_NAME = 'test-native'
def Parse(self, suite_element):
"""Creates suite and populate with data from xml element."""
suite = native_test.NativeTestSuite()
XmlSuiteParser._ParseCommonAttributes(self, suite_element, suite)
return suite
class HostParser(XmlSuiteParser):
"""Parses host suite attributes from xml."""
TAG_NAME = 'test-host'
_CLASS_ATTR = 'class'
# TODO: consider obsoleting in favor of parsing the Android.mk to find the
# jar name
_JAR_ATTR = 'jar_name'
def Parse(self, suite_element):
"""Creates suite and populate with data from xml element."""
suite = host_test.HostTestSuite()
XmlSuiteParser._ParseCommonAttributes(self, suite_element, suite)
suite.SetClassName(self._ParseAttribute(suite_element, self._CLASS_ATTR,
True))
suite.SetJarName(self._ParseAttribute(suite_element, self._JAR_ATTR, True))
return suite

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- Sample manifest file used for unit testing -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.tests">
<application>
<uses-library android:name="android.test.runner" />
</application>
<instrumentation android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.example.android"
android:label="Tests"/>
</manifest>

View File

@@ -0,0 +1,201 @@
#!/usr/bin/python2.4
#
#
# Copyright 2009, The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import sys
import unittest
sys.path.append('../..')
from testrunner import am_instrument_parser
class AmParserTest(unittest.TestCase):
def testParseAmInstResult(self):
result="""INSTRUMENTATION_RESULT: performance.java_size=4871
INSTRUMENTATION_RESULT: stream=
Error: Failed to generate emma coverage.
INSTRUMENTATION_RESULT: performance.cpu_time=33846
INSTRUMENTATION_CODE: -1
"""
bundle_dict = \
am_instrument_parser._ParseInstrumentationFinishedBundle(result)
self.assertEquals(4871, bundle_dict['java_size'])
self.assertEquals(33846, bundle_dict['cpu_time'])
self.assertEquals("\nError: Failed to generate emma coverage.",
bundle_dict['stream'])
def testParseAmInstStatus(self):
# numtests before id
segment1 = """INSTRUMENTATION_STATUS: stream=
INSTRUMENTATION_STATUS: test=testLaunchComplexActivity
INSTRUMENTATION_STATUS: class=LaunchPerformanceTest
INSTRUMENTATION_STATUS: current=1
INSTRUMENTATION_STATUS: numtests=2
INSTRUMENTATION_STATUS: id=InstrumentationTestRunner
INSTRUMENTATION_STATUS_CODE: 1"""
segment2 = """INSTRUMENTATION_STATUS: stream=.
INSTRUMENTATION_STATUS: test=testLaunchComplexActivity
INSTRUMENTATION_STATUS: performance.cpu_time=866
INSTRUMENTATION_STATUS: performance.execution_time=1242
INSTRUMENTATION_STATUS: class=LaunchPerformanceTest
INSTRUMENTATION_STATUS: current=1
INSTRUMENTATION_STATUS: numtests=2
INSTRUMENTATION_STATUS: id=InstrumentationTestRunner
INSTRUMENTATION_STATUS_CODE: 0"""
# numtests after id
segment3 = """INSTRUMENTATION_STATUS: stream=
INSTRUMENTATION_STATUS: test=testLaunchSimpleActivity
INSTRUMENTATION_STATUS: class=LaunchPerformanceTest
INSTRUMENTATION_STATUS: current=2
INSTRUMENTATION_STATUS: id=InstrumentationTestRunner
INSTRUMENTATION_STATUS: numtests=8
INSTRUMENTATION_STATUS_CODE: 1"""
segment4 = """INSTRUMENTATION_STATUS: stream=.
INSTRUMENTATION_STATUS: test=testLaunchSimpleActivity
INSTRUMENTATION_STATUS: performance.cpu_time=590
INSTRUMENTATION_STATUS: performance.execution_time=1122
INSTRUMENTATION_STATUS: class=LaunchPerformanceTest
INSTRUMENTATION_STATUS: current=2
INSTRUMENTATION_STATUS: id=InstrumentationTestRunner
INSTRUMENTATION_STATUS: numtests=8
INSTRUMENTATION_STATUS_CODE: 0"""
result = am_instrument_parser.TestResult(segment1)
map = result.GetResultFields()
self.assertEquals('testLaunchComplexActivity', map['test'])
self.assertEquals('LaunchPerformanceTest', map['class'])
self.assertEquals('1', map['current'])
self.assertEquals('2', map['numtests'])
self.assertEquals('InstrumentationTestRunner', map['id'])
self.assertEquals(1, result.GetStatusCode())
result = am_instrument_parser.TestResult(segment2)
map = result.GetResultFields()
self.assertEquals('testLaunchComplexActivity', map['test'])
self.assertEquals('866', map['cpu_time'])
self.assertEquals('1242', map['execution_time'])
self.assertEquals('LaunchPerformanceTest', map['class'])
self.assertEquals('1', map['current'])
self.assertEquals('2', map['numtests'])
self.assertEquals('InstrumentationTestRunner', map['id'])
self.assertEquals(0, result.GetStatusCode())
result = am_instrument_parser.TestResult(segment3)
map = result.GetResultFields()
self.assertEquals('testLaunchSimpleActivity', map['test'])
self.assertEquals('LaunchPerformanceTest', map['class'])
self.assertEquals('2', map['current'])
self.assertEquals('8', map['numtests'])
self.assertEquals('InstrumentationTestRunner', map['id'])
self.assertEquals(1, result.GetStatusCode())
result = am_instrument_parser.TestResult(segment4)
map = result.GetResultFields()
self.assertEquals('testLaunchSimpleActivity', map['test'])
self.assertEquals('590', map['cpu_time'])
self.assertEquals('1122', map['execution_time'])
self.assertEquals('LaunchPerformanceTest', map['class'])
self.assertEquals('2', map['current'])
self.assertEquals('8', map['numtests'])
self.assertEquals('InstrumentationTestRunner', map['id'])
self.assertEquals(0, result.GetStatusCode())
def testParseAmInstOutput(self):
result = """INSTRUMENTATION_STATUS: class=LaunchPerformanceTestCase
INSTRUMENTATION_STATUS: current=1
INSTRUMENTATION_STATUS: id=InstrumentationTestRunner
INSTRUMENTATION_STATUS: numtests=2
INSTRUMENTATION_STATUS: stream=
LaunchPerformanceTestCase:
INSTRUMENTATION_STATUS: test=testLaunchComplexActivity
INSTRUMENTATION_STATUS_CODE: 1
INSTRUMENTATION_STATUS: class=LaunchPerformanceTestCase
INSTRUMENTATION_STATUS: current=1
INSTRUMENTATION_STATUS: id=InstrumentationTestRunner
INSTRUMENTATION_STATUS: numtests=2
INSTRUMENTATION_STATUS: performance.cpu_time=866
INSTRUMENTATION_STATUS: performance.execution_time=1242
INSTRUMENTATION_STATUS: stream=.
INSTRUMENTATION_STATUS: test=testLaunchComplexActivity
INSTRUMENTATION_STATUS_CODE: 0
INSTRUMENTATION_STATUS: class=LaunchPerformanceTestCase
INSTRUMENTATION_STATUS: current=2
INSTRUMENTATION_STATUS: id=InstrumentationTestRunner
INSTRUMENTATION_STATUS: numtests=2
INSTRUMENTATION_STATUS: stream=
INSTRUMENTATION_STATUS: test=testLaunchSimpleActivity
INSTRUMENTATION_STATUS_CODE: 1
INSTRUMENTATION_STATUS: class=LaunchPerformanceTestCase
INSTRUMENTATION_STATUS: current=2
INSTRUMENTATION_STATUS: id=InstrumentationTestRunner
INSTRUMENTATION_STATUS: numtests=2
INSTRUMENTATION_STATUS: performance.cpu_time=590
INSTRUMENTATION_STATUS: performance.execution_time=1122
INSTRUMENTATION_STATUS: stream=.
INSTRUMENTATION_STATUS: test=testLaunchSimpleActivity
INSTRUMENTATION_STATUS_CODE: 0
INSTRUMENTATION_RESULT: performance.cpu_time=829
INSTRUMENTATION_RESULT: performance.execution_time=1708
INSTRUMENTATION_RESULT: performance.gc_invocation_count=0
INSTRUMENTATION_RESULT: performance.global_alloc_count=2848
INSTRUMENTATION_RESULT: performance.global_alloc_size=193079
INSTRUMENTATION_RESULT: performance.global_freed_count=1207
INSTRUMENTATION_RESULT: performance.global_freed_size=93040
INSTRUMENTATION_RESULT: performance.java_allocated=2175
INSTRUMENTATION_RESULT: performance.java_free=580
INSTRUMENTATION_RESULT: performance.java_private_dirty=740
INSTRUMENTATION_RESULT: performance.java_pss=1609
INSTRUMENTATION_RESULT: performance.java_shared_dirty=3860
INSTRUMENTATION_RESULT: performance.java_size=2755
INSTRUMENTATION_RESULT: performance.native_allocated=2585
INSTRUMENTATION_RESULT: performance.native_free=34
INSTRUMENTATION_RESULT: performance.native_private_dirty=632
INSTRUMENTATION_RESULT: performance.native_pss=701
INSTRUMENTATION_RESULT: performance.native_shared_dirty=1164
INSTRUMENTATION_RESULT: performance.native_size=2620
INSTRUMENTATION_RESULT: performance.other_private_dirty=896
INSTRUMENTATION_RESULT: performance.other_pss=1226
INSTRUMENTATION_RESULT: performance.other_shared_dirty=804
INSTRUMENTATION_RESULT: performance.pre_received_transactions=-1
INSTRUMENTATION_RESULT: performance.pre_sent_transactions=-1
INSTRUMENTATION_RESULT: performance.received_transactions=-1
INSTRUMENTATION_RESULT: performance.sent_transactions=-1
INSTRUMENTATION_RESULT: stream=
Test results for InstrumentationTestRunner=..
Time: 2.413
OK (2 tests)
INSTRUMENTATION_CODE: -1
"""
(results_list, perf_dict) = \
am_instrument_parser.ParseAmInstrumentOutput(result)
self.assertEquals(829, perf_dict['cpu_time'])
self.assertEquals(2848, perf_dict['global_alloc_count'])
self.assertEquals(93040, perf_dict['global_freed_size'])
self.assertEquals(740, perf_dict['java_private_dirty'])
self.assertEquals(2755, perf_dict['java_size'])
self.assertEquals(632, perf_dict['native_private_dirty'])
self.assertEquals(2620, perf_dict['native_size'])
self.assertEquals(804, perf_dict['other_shared_dirty'])
self.assertEquals(-1, perf_dict['received_transactions'])
self.assertTrue(len(perf_dict['stream']) > 50)
self.assertEquals('-1', perf_dict['code'])
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,42 @@
#!/usr/bin/python2.4
#
#
# Copyright 2009, The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import sys
import unittest
sys.path.append('../..')
from testrunner import android_manifest
class AndroidManifestTest(unittest.TestCase):
"""Unit tests for AndroidManifest."""
def setUp(self):
"""Create android_mainfest for testing from sample file."""
self._manifest = android_manifest.AndroidManifest(app_path='.')
def testGetPackageName(self):
self.assertEquals('com.example.android.tests',
self._manifest.GetPackageName())
def testGetInstrumentationNames(self):
self.assertEquals(['android.test.InstrumentationTestRunner'],
self._manifest.GetInstrumentationNames())
if __name__ == '__main__':
unittest.main()