Home | History | Annotate | Download | only in base
      1 # Copyright 2013 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.
      4 
      5 """Unittests for test_dispatcher.py."""
      6 # pylint: disable=R0201
      7 # pylint: disable=W0212
      8 
      9 import os
     10 import sys
     11 import unittest
     12 
     13 sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)),
     14                 os.pardir, os.pardir))
     15 
     16 # Mock out android_commands.GetAttachedDevices().
     17 from pylib import android_commands
     18 android_commands.GetAttachedDevices = lambda: ['0', '1']
     19 from pylib import constants
     20 from pylib.base import base_test_result
     21 from pylib.base import test_dispatcher
     22 from pylib.utils import watchdog_timer
     23 
     24 
     25 class TestException(Exception):
     26   pass
     27 
     28 
     29 class MockRunner(object):
     30   """A mock TestRunner."""
     31   def __init__(self, device='0', shard_index=0):
     32     self.device_serial = device
     33     self.shard_index = shard_index
     34     self.setups = 0
     35     self.teardowns = 0
     36 
     37   def RunTest(self, test):
     38     results = base_test_result.TestRunResults()
     39     results.AddResult(
     40         base_test_result.BaseTestResult(test, base_test_result.ResultType.PASS))
     41     return (results, None)
     42 
     43   def SetUp(self):
     44     self.setups += 1
     45 
     46   def TearDown(self):
     47     self.teardowns += 1
     48 
     49 
     50 class MockRunnerFail(MockRunner):
     51   def RunTest(self, test):
     52     results = base_test_result.TestRunResults()
     53     results.AddResult(
     54         base_test_result.BaseTestResult(test, base_test_result.ResultType.FAIL))
     55     return (results, test)
     56 
     57 
     58 class MockRunnerFailTwice(MockRunner):
     59   def __init__(self, device='0', shard_index=0):
     60     super(MockRunnerFailTwice, self).__init__(device, shard_index)
     61     self._fails = 0
     62 
     63   def RunTest(self, test):
     64     self._fails += 1
     65     results = base_test_result.TestRunResults()
     66     if self._fails <= 2:
     67       results.AddResult(base_test_result.BaseTestResult(
     68           test, base_test_result.ResultType.FAIL))
     69       return (results, test)
     70     else:
     71       results.AddResult(base_test_result.BaseTestResult(
     72           test, base_test_result.ResultType.PASS))
     73       return (results, None)
     74 
     75 
     76 class MockRunnerException(MockRunner):
     77   def RunTest(self, test):
     78     raise TestException
     79 
     80 
     81 class TestFunctions(unittest.TestCase):
     82   """Tests test_dispatcher._RunTestsFromQueue."""
     83   @staticmethod
     84   def _RunTests(mock_runner, tests):
     85     results = []
     86     tests = test_dispatcher._TestCollection(
     87         [test_dispatcher._Test(t) for t in tests])
     88     test_dispatcher._RunTestsFromQueue(mock_runner, tests, results,
     89                                        watchdog_timer.WatchdogTimer(None), 2)
     90     run_results = base_test_result.TestRunResults()
     91     for r in results:
     92       run_results.AddTestRunResults(r)
     93     return run_results
     94 
     95   def testRunTestsFromQueue(self):
     96     results = TestFunctions._RunTests(MockRunner(), ['a', 'b'])
     97     self.assertEqual(len(results.GetPass()), 2)
     98     self.assertEqual(len(results.GetNotPass()), 0)
     99 
    100   def testRunTestsFromQueueRetry(self):
    101     results = TestFunctions._RunTests(MockRunnerFail(), ['a', 'b'])
    102     self.assertEqual(len(results.GetPass()), 0)
    103     self.assertEqual(len(results.GetFail()), 2)
    104 
    105   def testRunTestsFromQueueFailTwice(self):
    106     results = TestFunctions._RunTests(MockRunnerFailTwice(), ['a', 'b'])
    107     self.assertEqual(len(results.GetPass()), 2)
    108     self.assertEqual(len(results.GetNotPass()), 0)
    109 
    110   def testSetUp(self):
    111     runners = []
    112     counter = test_dispatcher._ThreadSafeCounter()
    113     test_dispatcher._SetUp(MockRunner, '0', runners, counter)
    114     self.assertEqual(len(runners), 1)
    115     self.assertEqual(runners[0].setups, 1)
    116 
    117   def testThreadSafeCounter(self):
    118     counter = test_dispatcher._ThreadSafeCounter()
    119     for i in xrange(5):
    120       self.assertEqual(counter.GetAndIncrement(), i)
    121 
    122   def testApplyMaxPerRun(self):
    123     self.assertEqual(
    124         ['A:B', 'C:D', 'E', 'F:G', 'H:I'],
    125         test_dispatcher.ApplyMaxPerRun(['A:B', 'C:D:E', 'F:G:H:I'], 2))
    126 
    127 
    128 class TestThreadGroupFunctions(unittest.TestCase):
    129   """Tests test_dispatcher._RunAllTests and test_dispatcher._CreateRunners."""
    130   def setUp(self):
    131     self.tests = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
    132     shared_test_collection = test_dispatcher._TestCollection(
    133         [test_dispatcher._Test(t) for t in self.tests])
    134     self.test_collection_factory = lambda: shared_test_collection
    135 
    136   def testCreate(self):
    137     runners = test_dispatcher._CreateRunners(MockRunner, ['0', '1'])
    138     for runner in runners:
    139       self.assertEqual(runner.setups, 1)
    140     self.assertEqual(set([r.device_serial for r in runners]),
    141                      set(['0', '1']))
    142     self.assertEqual(set([r.shard_index for r in runners]),
    143                      set([0, 1]))
    144 
    145   def testRun(self):
    146     runners = [MockRunner('0'), MockRunner('1')]
    147     results, exit_code = test_dispatcher._RunAllTests(
    148         runners, self.test_collection_factory, 0)
    149     self.assertEqual(len(results.GetPass()), len(self.tests))
    150     self.assertEqual(exit_code, 0)
    151 
    152   def testTearDown(self):
    153     runners = [MockRunner('0'), MockRunner('1')]
    154     test_dispatcher._TearDownRunners(runners)
    155     for runner in runners:
    156       self.assertEqual(runner.teardowns, 1)
    157 
    158   def testRetry(self):
    159     runners = test_dispatcher._CreateRunners(MockRunnerFail, ['0', '1'])
    160     results, exit_code = test_dispatcher._RunAllTests(
    161         runners, self.test_collection_factory, 0)
    162     self.assertEqual(len(results.GetFail()), len(self.tests))
    163     self.assertEqual(exit_code, constants.ERROR_EXIT_CODE)
    164 
    165   def testReraise(self):
    166     runners = test_dispatcher._CreateRunners(MockRunnerException, ['0', '1'])
    167     with self.assertRaises(TestException):
    168       test_dispatcher._RunAllTests(runners, self.test_collection_factory, 0)
    169 
    170 
    171 class TestShard(unittest.TestCase):
    172   """Tests test_dispatcher.RunTests with sharding."""
    173   @staticmethod
    174   def _RunShard(runner_factory):
    175     return test_dispatcher.RunTests(
    176         ['a', 'b', 'c'], runner_factory, ['0', '1'], shard=True)
    177 
    178   def testShard(self):
    179     results, exit_code = TestShard._RunShard(MockRunner)
    180     self.assertEqual(len(results.GetPass()), 3)
    181     self.assertEqual(exit_code, 0)
    182 
    183   def testFailing(self):
    184     results, exit_code = TestShard._RunShard(MockRunnerFail)
    185     self.assertEqual(len(results.GetPass()), 0)
    186     self.assertEqual(len(results.GetFail()), 3)
    187     self.assertEqual(exit_code, constants.ERROR_EXIT_CODE)
    188 
    189   def testNoTests(self):
    190     results, exit_code = test_dispatcher.RunTests(
    191         [], MockRunner, ['0', '1'], shard=True)
    192     self.assertEqual(len(results.GetAll()), 0)
    193     self.assertEqual(exit_code, constants.ERROR_EXIT_CODE)
    194 
    195 
    196 class TestReplicate(unittest.TestCase):
    197   """Tests test_dispatcher.RunTests with replication."""
    198   @staticmethod
    199   def _RunReplicate(runner_factory):
    200     return test_dispatcher.RunTests(
    201         ['a', 'b', 'c'], runner_factory, ['0', '1'], shard=False)
    202 
    203   def testReplicate(self):
    204     results, exit_code = TestReplicate._RunReplicate(MockRunner)
    205     # We expect 6 results since each test should have been run on every device
    206     self.assertEqual(len(results.GetPass()), 6)
    207     self.assertEqual(exit_code, 0)
    208 
    209   def testFailing(self):
    210     results, exit_code = TestReplicate._RunReplicate(MockRunnerFail)
    211     self.assertEqual(len(results.GetPass()), 0)
    212     self.assertEqual(len(results.GetFail()), 6)
    213     self.assertEqual(exit_code, constants.ERROR_EXIT_CODE)
    214 
    215   def testNoTests(self):
    216     results, exit_code = test_dispatcher.RunTests(
    217         [], MockRunner, ['0', '1'], shard=False)
    218     self.assertEqual(len(results.GetAll()), 0)
    219     self.assertEqual(exit_code, constants.ERROR_EXIT_CODE)
    220 
    221 
    222 if __name__ == '__main__':
    223   unittest.main()
    224