media/webrtc/trunk/build/android/pylib/python_test_base.py

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
     2 # Use of this source code is governed by a BSD-style license that can be
     3 # found in the LICENSE file.
     5 """Base class for Android Python-driven tests.
     7 This test case is intended to serve as the base class for any Python-driven
     8 tests. It is similar to the Python unitttest module in that the user's tests
     9 inherit from this case and add their tests in that case.
    11 When a PythonTestBase object is instantiated, its purpose is to run only one of
    12 its tests. The test runner gives it the name of the test the instance will
    13 run. The test runner calls SetUp with the Android device ID which the test will
    14 run against. The runner runs the test method itself, collecting the result,
    15 and calls TearDown.
    17 Tests can basically do whatever they want in the test methods, such as call
    18 Java tests using _RunJavaTests. Those methods have the advantage of massaging
    19 the Java test results into Python test results.
    20 """
    22 import logging
    23 import os
    24 import time
    26 import android_commands
    27 import apk_info
    28 from run_java_tests import TestRunner
    29 from test_result import SingleTestResult, TestResults
    32 # aka the parent of com.google.android
    33 BASE_ROOT = 'src' + os.sep
    36 class PythonTestBase(object):
    37   """Base class for Python-driven tests."""
    39   def __init__(self, test_name):
    40     # test_name must match one of the test methods defined on a subclass which
    41     # inherits from this class.
    42     # It's stored so we can do the attr lookup on demand, allowing this class
    43     # to be pickled, a requirement for the multiprocessing module.
    44     self.test_name = test_name
    45     class_name = self.__class__.__name__
    46     self.qualified_name = class_name + '.' + self.test_name
    48   def SetUp(self, options):
    49     self.options = options
    50     self.shard_index = self.options.shard_index
    51     self.device_id = self.options.device_id
    52     self.adb = android_commands.AndroidCommands(self.device_id)
    53     self.ports_to_forward = []
    55   def TearDown(self):
    56     pass
    58   def Run(self):
    59     logging.warning('Running Python-driven test: %s', self.test_name)
    60     return getattr(self, self.test_name)()
    62   def _RunJavaTest(self, fname, suite, test):
    63     """Runs a single Java test with a Java TestRunner.
    65     Args:
    66       fname: filename for the test (e.g. foo/bar/baz/tests/FooTest.py)
    67       suite: name of the Java test suite (e.g. FooTest)
    68       test: name of the test method to run (e.g. testFooBar)
    70     Returns:
    71       TestResults object with a single test result.
    72     """
    73     test = self._ComposeFullTestName(fname, suite, test)
    74     apks = [apk_info.ApkInfo(self.options.test_apk_path,
    75             self.options.test_apk_jar_path)]
    76     java_test_runner = TestRunner(self.options, self.device_id, [test], False,
    77                                   self.shard_index,
    78                                   apks,
    79                                   self.ports_to_forward)
    80     return java_test_runner.Run()
    82   def _RunJavaTests(self, fname, tests):
    83     """Calls a list of tests and stops at the first test failure.
    85     This method iterates until either it encounters a non-passing test or it
    86     exhausts the list of tests. Then it returns the appropriate Python result.
    88     Args:
    89       fname: filename for the Python test
    90       tests: a list of Java test names which will be run
    92     Returns:
    93       A TestResults object containing a result for this Python test.
    94     """
    95     start_ms = int(time.time()) * 1000
    97     result = None
    98     for test in tests:
    99       # We're only running one test at a time, so this TestResults object will
   100       # hold only one result.
   101       suite, test_name = test.split('.')
   102       result = self._RunJavaTest(fname, suite, test_name)
   103       # A non-empty list means the test did not pass.
   104       if result.GetAllBroken():
   105         break
   107     duration_ms = int(time.time()) * 1000 - start_ms
   109     # Do something with result.
   110     return self._ProcessResults(result, start_ms, duration_ms)
   112   def _ProcessResults(self, result, start_ms, duration_ms):
   113     """Translates a Java test result into a Python result for this test.
   115     The TestRunner class that we use under the covers will return a test result
   116     for that specific Java test. However, to make reporting clearer, we have
   117     this method to abstract that detail and instead report that as a failure of
   118     this particular test case while still including the Java stack trace.
   120     Args:
   121       result: TestResults with a single Java test result
   122       start_ms: the time the test started
   123       duration_ms: the length of the test
   125     Returns:
   126       A TestResults object containing a result for this Python test.
   127     """
   128     test_results = TestResults()
   130     # If our test is in broken, then it crashed/failed.
   131     broken = result.GetAllBroken()
   132     if broken:
   133       # Since we have run only one test, take the first and only item.
   134       single_result = broken[0]
   136       log = single_result.log
   137       if not log:
   138         log = 'No logging information.'
   140       python_result = SingleTestResult(self.qualified_name, start_ms,
   141                                        duration_ms,
   142                                        log)
   144       # Figure out where the test belonged. There's probably a cleaner way of
   145       # doing this.
   146       if single_result in result.crashed:
   147         test_results.crashed = [python_result]
   148       elif single_result in result.failed:
   149         test_results.failed = [python_result]
   150       elif single_result in result.unknown:
   151         test_results.unknown = [python_result]
   153     else:
   154       python_result = SingleTestResult(self.qualified_name, start_ms,
   155                                        duration_ms)
   156       test_results.ok = [python_result]
   158     return test_results
   160   def _ComposeFullTestName(self, fname, suite, test):
   161     package_name = self._GetPackageName(fname)
   162     return package_name + '.' + suite + '#' + test
   164   def _GetPackageName(self, fname):
   165     """Extracts the package name from the test file path."""
   166     dirname = os.path.dirname(fname)
   167     package = dirname[dirname.rfind(BASE_ROOT) + len(BASE_ROOT):]
   168     return package.replace(os.sep, '.')

mercurial