Port iOS test runner from chromium/tools/build
BUG=608537
Review-Url: https://codereview.chromium.org/1949123004
Cr-Commit-Position: refs/heads/master@{#392215}
diff --git a/ios/build/bots/scripts/test_runner_test.py b/ios/build/bots/scripts/test_runner_test.py
new file mode 100755
index 0000000..0d7c8b1
--- /dev/null
+++ b/ios/build/bots/scripts/test_runner_test.py
@@ -0,0 +1,289 @@
+#!/usr/bin/python
+# Copyright 2016 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_runner.py."""
+
+import collections
+import json
+import os
+import sys
+import unittest
+
+import test_runner
+
+
+class TestCase(unittest.TestCase):
+ """Test case which supports installing mocks. Uninstalls on tear down."""
+
+ def __init__(self, *args, **kwargs):
+ """Initializes a new instance of this class."""
+ super(TestCase, self).__init__(*args, **kwargs)
+
+ # Maps object to a dict which maps names of mocked members to their
+ # original values.
+ self._mocks = collections.OrderedDict()
+
+ def mock(self, obj, member, mock):
+ """Installs mock in place of the named member of the given obj.
+
+ Args:
+ obj: Any object.
+ member: String naming the attribute of the object to mock.
+ mock: The mock to install.
+ """
+ self._mocks.setdefault(obj, collections.OrderedDict()).setdefault(
+ member, getattr(obj, member))
+ setattr(obj, member, mock)
+
+ def tearDown(self, *args, **kwargs):
+ """Uninstalls mocks."""
+ super(TestCase, self).tearDown(*args, **kwargs)
+
+ for obj in self._mocks:
+ for member, original_value in self._mocks[obj].iteritems():
+ setattr(obj, member, original_value)
+
+
+class GetKIFTestFilterTest(TestCase):
+ """Tests for test_runner.get_kif_test_filter."""
+
+ def test_correct(self):
+ """Ensures correctness of filter."""
+ tests = [
+ 'KIF.test1',
+ 'KIF.test2',
+ ]
+ expected = 'NAME:test1|test2'
+
+ self.assertEqual(test_runner.get_kif_test_filter(tests), expected)
+
+ def test_correct_inverted(self):
+ """Ensures correctness of inverted filter."""
+ tests = [
+ 'KIF.test1',
+ 'KIF.test2',
+ ]
+ expected = '-NAME:test1|test2'
+
+ self.assertEqual(
+ test_runner.get_kif_test_filter(tests, invert=True), expected)
+
+
+class GetGTestFilterTest(TestCase):
+ """Tests for test_runner.get_gtest_filter."""
+
+ def test_correct(self):
+ """Ensures correctness of filter."""
+ tests = [
+ 'test.1',
+ 'test.2',
+ ]
+ expected = 'test.1:test.2'
+
+ self.assertEqual(test_runner.get_gtest_filter(tests), expected)
+
+ def test_correct_inverted(self):
+ """Ensures correctness of inverted filter."""
+ tests = [
+ 'test.1',
+ 'test.2',
+ ]
+ expected = '-test.1:test.2'
+
+ self.assertEqual(
+ test_runner.get_gtest_filter(tests, invert=True), expected)
+
+
+class SimulatorTestRunnerTest(TestCase):
+ """Tests for test_runner.SimulatorTestRunner."""
+
+ def test_app_not_found(self):
+ """Ensures AppNotFoundError is raised."""
+ def exists(path):
+ if path == 'fake-app':
+ return False
+ return True
+
+ def find_xcode(version):
+ return {'found': True}
+
+ def check_output(command):
+ return 'fake-bundle-id'
+
+ self.mock(test_runner.os.path, 'exists', exists)
+ self.mock(test_runner.find_xcode, 'find_xcode', find_xcode)
+ self.mock(test_runner.subprocess, 'check_output', check_output)
+
+ self.assertRaises(
+ test_runner.AppNotFoundError,
+ test_runner.SimulatorTestRunner,
+ 'fake-app',
+ 'fake-iossim',
+ 'platform',
+ 'os',
+ 'xcode-version',
+ 'out-dir',
+ )
+
+ def test_iossim_not_found(self):
+ """Ensures SimulatorNotFoundError is raised."""
+ def exists(path):
+ if path == 'fake-iossim':
+ return False
+ return True
+
+ def find_xcode(version):
+ return {'found': True}
+
+ def check_output(command):
+ return 'fake-bundle-id'
+
+ self.mock(test_runner.os.path, 'exists', exists)
+ self.mock(test_runner.find_xcode, 'find_xcode', find_xcode)
+ self.mock(test_runner.subprocess, 'check_output', check_output)
+
+ self.assertRaises(
+ test_runner.SimulatorNotFoundError,
+ test_runner.SimulatorTestRunner,
+ 'fake-app',
+ 'fake-iossim',
+ 'platform',
+ 'os',
+ 'xcode-version',
+ 'out-dir',
+ )
+
+ def test_init(self):
+ """Ensures instance is created."""
+ def exists(path):
+ return True
+
+ def find_xcode(version):
+ return {'found': True}
+
+ def check_output(command):
+ return 'fake-bundle-id'
+
+ self.mock(test_runner.os.path, 'exists', exists)
+ self.mock(test_runner.find_xcode, 'find_xcode', find_xcode)
+ self.mock(test_runner.subprocess, 'check_output', check_output)
+
+ tr = test_runner.SimulatorTestRunner(
+ 'fake-app',
+ 'fake-iossim',
+ 'platform',
+ 'os',
+ 'xcode-version',
+ 'out-dir',
+ )
+
+ self.failUnless(tr)
+
+ def test_startup_crash(self):
+ """Ensures test is relaunched once on startup crash."""
+ def exists(path):
+ return True
+
+ def find_xcode(version):
+ return {'found': True}
+
+ def check_output(command):
+ return 'fake-bundle-id'
+
+ def set_up(self):
+ return
+
+ @staticmethod
+ def _run(command):
+ return collections.namedtuple('result', ['crashed', 'crashed_test'])(
+ crashed=True, crashed_test=None)
+
+ def tear_down(self):
+ return
+
+ self.mock(test_runner.os.path, 'exists', exists)
+ self.mock(test_runner.find_xcode, 'find_xcode', find_xcode)
+ self.mock(test_runner.subprocess, 'check_output', check_output)
+ self.mock(test_runner.SimulatorTestRunner, 'set_up', set_up)
+ self.mock(test_runner.TestRunner, '_run', _run)
+ self.mock(test_runner.SimulatorTestRunner, 'tear_down', tear_down)
+
+ tr = test_runner.SimulatorTestRunner(
+ 'fake-app',
+ 'fake-iossim',
+ 'platform',
+ 'os',
+ 'xcode-version',
+ 'out-dir',
+ )
+ self.assertRaises(test_runner.AppLaunchError, tr.launch)
+
+ def test_relaunch(self):
+ """Ensures test is relaunched on test crash until tests complete."""
+ def exists(path):
+ return True
+
+ def find_xcode(version):
+ return {'found': True}
+
+ def check_output(command):
+ return 'fake-bundle-id'
+
+ def set_up(self):
+ return
+
+ @staticmethod
+ def _run(command):
+ result = collections.namedtuple(
+ 'result', [
+ 'crashed',
+ 'crashed_test',
+ 'failed_tests',
+ 'flaked_tests',
+ 'passed_tests',
+ ],
+ )
+ if '-e' not in command:
+ # First run, has no test filter supplied. Mock a crash.
+ return result(
+ crashed=True,
+ crashed_test='c',
+ failed_tests={'b': ['b-out'], 'c': ['Did not complete.']},
+ flaked_tests={'d': ['d-out']},
+ passed_tests=['a'],
+ )
+ else:
+ return result(
+ crashed=False,
+ crashed_test=None,
+ failed_tests={},
+ flaked_tests={},
+ passed_tests=[],
+ )
+
+ def tear_down(self):
+ return
+
+ self.mock(test_runner.os.path, 'exists', exists)
+ self.mock(test_runner.find_xcode, 'find_xcode', find_xcode)
+ self.mock(test_runner.subprocess, 'check_output', check_output)
+ self.mock(test_runner.SimulatorTestRunner, 'set_up', set_up)
+ self.mock(test_runner.TestRunner, '_run', _run)
+ self.mock(test_runner.SimulatorTestRunner, 'tear_down', tear_down)
+
+ tr = test_runner.SimulatorTestRunner(
+ 'fake-app',
+ 'fake-iossim',
+ 'platform',
+ 'os',
+ 'xcode-version',
+ 'out-dir',
+ )
+ tr.launch()
+ self.failUnless(tr.summary['logs'])
+
+
+if __name__ == '__main__':
+ unittest.main()