| Index: build/android/pylib/base/test_dispatcher_unittest.py
|
| diff --git a/build/android/pylib/base/test_dispatcher_unittest.py b/build/android/pylib/base/test_dispatcher_unittest.py
|
| new file mode 100755
|
| index 0000000000000000000000000000000000000000..cace9a627a28985350d69a6729e5f0e2a2994690
|
| --- /dev/null
|
| +++ b/build/android/pylib/base/test_dispatcher_unittest.py
|
| @@ -0,0 +1,241 @@
|
| +#!/usr/bin/env python
|
| +# Copyright 2013 The Chromium Authors. All rights reserved.
|
| +# Use of this source code is governed by a BSD-style license that can be
|
| +# found in the LICENSE file.
|
| +
|
| +"""Unittests for test_dispatcher.py."""
|
| +# pylint: disable=R0201
|
| +# pylint: disable=W0212
|
| +
|
| +import os
|
| +import sys
|
| +import unittest
|
| +
|
| +
|
| +from pylib import constants
|
| +from pylib.base import base_test_result
|
| +from pylib.base import test_collection
|
| +from pylib.base import test_dispatcher
|
| +from pylib.device import adb_wrapper
|
| +from pylib.device import device_utils
|
| +from pylib.utils import watchdog_timer
|
| +
|
| +sys.path.append(
|
| + os.path.join(constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
|
| +import mock
|
| +
|
| +
|
| +class TestException(Exception):
|
| + pass
|
| +
|
| +
|
| +def _MockDevice(serial):
|
| + d = mock.MagicMock(spec=device_utils.DeviceUtils)
|
| + d.__str__.return_value = serial
|
| + d.adb = mock.MagicMock(spec=adb_wrapper.AdbWrapper)
|
| + d.adb.GetDeviceSerial = mock.MagicMock(return_value=serial)
|
| + d.IsOnline = mock.MagicMock(return_value=True)
|
| + return d
|
| +
|
| +
|
| +class MockRunner(object):
|
| + """A mock TestRunner."""
|
| + def __init__(self, device=None, shard_index=0):
|
| + self.device = device or _MockDevice('0')
|
| + self.device_serial = self.device.adb.GetDeviceSerial()
|
| + self.shard_index = shard_index
|
| + self.setups = 0
|
| + self.teardowns = 0
|
| +
|
| + def RunTest(self, test):
|
| + results = base_test_result.TestRunResults()
|
| + results.AddResult(
|
| + base_test_result.BaseTestResult(test, base_test_result.ResultType.PASS))
|
| + return (results, None)
|
| +
|
| + def SetUp(self):
|
| + self.setups += 1
|
| +
|
| + def TearDown(self):
|
| + self.teardowns += 1
|
| +
|
| +
|
| +class MockRunnerFail(MockRunner):
|
| + def RunTest(self, test):
|
| + results = base_test_result.TestRunResults()
|
| + results.AddResult(
|
| + base_test_result.BaseTestResult(test, base_test_result.ResultType.FAIL))
|
| + return (results, test)
|
| +
|
| +
|
| +class MockRunnerFailTwice(MockRunner):
|
| + def __init__(self, device=None, shard_index=0):
|
| + super(MockRunnerFailTwice, self).__init__(device, shard_index)
|
| + self._fails = 0
|
| +
|
| + def RunTest(self, test):
|
| + self._fails += 1
|
| + results = base_test_result.TestRunResults()
|
| + if self._fails <= 2:
|
| + results.AddResult(base_test_result.BaseTestResult(
|
| + test, base_test_result.ResultType.FAIL))
|
| + return (results, test)
|
| + else:
|
| + results.AddResult(base_test_result.BaseTestResult(
|
| + test, base_test_result.ResultType.PASS))
|
| + return (results, None)
|
| +
|
| +
|
| +class MockRunnerException(MockRunner):
|
| + def RunTest(self, test):
|
| + raise TestException
|
| +
|
| +
|
| +class TestFunctions(unittest.TestCase):
|
| + """Tests test_dispatcher._RunTestsFromQueue."""
|
| + @staticmethod
|
| + def _RunTests(mock_runner, tests):
|
| + results = []
|
| + tests = test_collection.TestCollection(
|
| + [test_dispatcher._Test(t) for t in tests])
|
| + test_dispatcher._RunTestsFromQueue(mock_runner, tests, results,
|
| + watchdog_timer.WatchdogTimer(None), 2)
|
| + run_results = base_test_result.TestRunResults()
|
| + for r in results:
|
| + run_results.AddTestRunResults(r)
|
| + return run_results
|
| +
|
| + def testRunTestsFromQueue(self):
|
| + results = TestFunctions._RunTests(MockRunner(), ['a', 'b'])
|
| + self.assertEqual(len(results.GetPass()), 2)
|
| + self.assertEqual(len(results.GetNotPass()), 0)
|
| +
|
| + def testRunTestsFromQueueRetry(self):
|
| + results = TestFunctions._RunTests(MockRunnerFail(), ['a', 'b'])
|
| + self.assertEqual(len(results.GetPass()), 0)
|
| + self.assertEqual(len(results.GetFail()), 2)
|
| +
|
| + def testRunTestsFromQueueFailTwice(self):
|
| + results = TestFunctions._RunTests(MockRunnerFailTwice(), ['a', 'b'])
|
| + self.assertEqual(len(results.GetPass()), 2)
|
| + self.assertEqual(len(results.GetNotPass()), 0)
|
| +
|
| + def testSetUp(self):
|
| + runners = []
|
| + counter = test_dispatcher._ThreadSafeCounter()
|
| + test_dispatcher._SetUp(MockRunner, _MockDevice('0'), runners, counter)
|
| + self.assertEqual(len(runners), 1)
|
| + self.assertEqual(runners[0].setups, 1)
|
| +
|
| + def testThreadSafeCounter(self):
|
| + counter = test_dispatcher._ThreadSafeCounter()
|
| + for i in xrange(5):
|
| + self.assertEqual(counter.GetAndIncrement(), i)
|
| +
|
| + def testApplyMaxPerRun(self):
|
| + self.assertEqual(
|
| + ['A:B', 'C:D', 'E', 'F:G', 'H:I'],
|
| + test_dispatcher.ApplyMaxPerRun(['A:B', 'C:D:E', 'F:G:H:I'], 2))
|
| +
|
| +
|
| +class TestThreadGroupFunctions(unittest.TestCase):
|
| + """Tests test_dispatcher._RunAllTests and test_dispatcher._CreateRunners."""
|
| + def setUp(self):
|
| + self.tests = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
|
| + shared_test_collection = test_collection.TestCollection(
|
| + [test_dispatcher._Test(t) for t in self.tests])
|
| + self.test_collection_factory = lambda: shared_test_collection
|
| +
|
| + def testCreate(self):
|
| + runners = test_dispatcher._CreateRunners(
|
| + MockRunner, [_MockDevice('0'), _MockDevice('1')])
|
| + for runner in runners:
|
| + self.assertEqual(runner.setups, 1)
|
| + self.assertEqual(set([r.device_serial for r in runners]),
|
| + set(['0', '1']))
|
| + self.assertEqual(set([r.shard_index for r in runners]),
|
| + set([0, 1]))
|
| +
|
| + def testRun(self):
|
| + runners = [MockRunner(_MockDevice('0')), MockRunner(_MockDevice('1'))]
|
| + results, exit_code = test_dispatcher._RunAllTests(
|
| + runners, self.test_collection_factory, 0)
|
| + self.assertEqual(len(results.GetPass()), len(self.tests))
|
| + self.assertEqual(exit_code, 0)
|
| +
|
| + def testTearDown(self):
|
| + runners = [MockRunner(_MockDevice('0')), MockRunner(_MockDevice('1'))]
|
| + test_dispatcher._TearDownRunners(runners)
|
| + for runner in runners:
|
| + self.assertEqual(runner.teardowns, 1)
|
| +
|
| + def testRetry(self):
|
| + runners = test_dispatcher._CreateRunners(
|
| + MockRunnerFail, [_MockDevice('0'), _MockDevice('1')])
|
| + results, exit_code = test_dispatcher._RunAllTests(
|
| + runners, self.test_collection_factory, 0)
|
| + self.assertEqual(len(results.GetFail()), len(self.tests))
|
| + self.assertEqual(exit_code, constants.ERROR_EXIT_CODE)
|
| +
|
| + def testReraise(self):
|
| + runners = test_dispatcher._CreateRunners(
|
| + MockRunnerException, [_MockDevice('0'), _MockDevice('1')])
|
| + with self.assertRaises(TestException):
|
| + test_dispatcher._RunAllTests(runners, self.test_collection_factory, 0)
|
| +
|
| +
|
| +class TestShard(unittest.TestCase):
|
| + """Tests test_dispatcher.RunTests with sharding."""
|
| + @staticmethod
|
| + def _RunShard(runner_factory):
|
| + return test_dispatcher.RunTests(
|
| + ['a', 'b', 'c'], runner_factory, [_MockDevice('0'), _MockDevice('1')],
|
| + shard=True)
|
| +
|
| + def testShard(self):
|
| + results, exit_code = TestShard._RunShard(MockRunner)
|
| + self.assertEqual(len(results.GetPass()), 3)
|
| + self.assertEqual(exit_code, 0)
|
| +
|
| + def testFailing(self):
|
| + results, exit_code = TestShard._RunShard(MockRunnerFail)
|
| + self.assertEqual(len(results.GetPass()), 0)
|
| + self.assertEqual(len(results.GetFail()), 3)
|
| + self.assertEqual(exit_code, constants.ERROR_EXIT_CODE)
|
| +
|
| + def testNoTests(self):
|
| + results, exit_code = test_dispatcher.RunTests(
|
| + [], MockRunner, [_MockDevice('0'), _MockDevice('1')], shard=True)
|
| + self.assertEqual(len(results.GetAll()), 0)
|
| + self.assertEqual(exit_code, constants.ERROR_EXIT_CODE)
|
| +
|
| +
|
| +class TestReplicate(unittest.TestCase):
|
| + """Tests test_dispatcher.RunTests with replication."""
|
| + @staticmethod
|
| + def _RunReplicate(runner_factory):
|
| + return test_dispatcher.RunTests(
|
| + ['a', 'b', 'c'], runner_factory, [_MockDevice('0'), _MockDevice('1')],
|
| + shard=False)
|
| +
|
| + def testReplicate(self):
|
| + results, exit_code = TestReplicate._RunReplicate(MockRunner)
|
| + # We expect 6 results since each test should have been run on every device
|
| + self.assertEqual(len(results.GetPass()), 6)
|
| + self.assertEqual(exit_code, 0)
|
| +
|
| + def testFailing(self):
|
| + results, exit_code = TestReplicate._RunReplicate(MockRunnerFail)
|
| + self.assertEqual(len(results.GetPass()), 0)
|
| + self.assertEqual(len(results.GetFail()), 6)
|
| + self.assertEqual(exit_code, constants.ERROR_EXIT_CODE)
|
| +
|
| + def testNoTests(self):
|
| + results, exit_code = test_dispatcher.RunTests(
|
| + [], MockRunner, [_MockDevice('0'), _MockDevice('1')], shard=False)
|
| + self.assertEqual(len(results.GetAll()), 0)
|
| + self.assertEqual(exit_code, constants.ERROR_EXIT_CODE)
|
| +
|
| +
|
| +if __name__ == '__main__':
|
| + unittest.main()
|
|
|