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