eclair snapshot
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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."""
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1 +1 @@
|
||||
__all__ = ['test_defs']
|
||||
__all__ = ['test_defs', 'test_walker']
|
||||
|
||||
@@ -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
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
96
testrunner/test_defs/test_suite.py
Normal file
96
testrunner/test_defs/test_suite.py
Normal 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
|
||||
296
testrunner/test_defs/test_walker.py
Executable file
296
testrunner/test_defs/test_walker.py
Executable 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
|
||||
|
||||
152
testrunner/test_defs/xml_suite_helper.py
Normal file
152
testrunner/test_defs/xml_suite_helper.py
Normal 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
|
||||
30
testrunner/tests/AndroidManifest.xml
Normal file
30
testrunner/tests/AndroidManifest.xml
Normal 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>
|
||||
201
testrunner/tests/am_instrument_parser_tests.py
Executable file
201
testrunner/tests/am_instrument_parser_tests.py
Executable 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()
|
||||
42
testrunner/tests/android_manifest_tests.py
Executable file
42
testrunner/tests/android_manifest_tests.py
Executable 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()
|
||||
Reference in New Issue
Block a user