blob: bd7532a288c18d551e324e88a078aca813bf7257 [file] [log] [blame]
smut64cb9422016-05-07 00:24:201#!/usr/bin/python
2# Copyright 2016 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Unittests for test_runner.py."""
7
8import collections
9import json
10import os
11import sys
12import unittest
13
14import test_runner
15
16
17class TestCase(unittest.TestCase):
18 """Test case which supports installing mocks. Uninstalls on tear down."""
19
20 def __init__(self, *args, **kwargs):
21 """Initializes a new instance of this class."""
22 super(TestCase, self).__init__(*args, **kwargs)
23
24 # Maps object to a dict which maps names of mocked members to their
25 # original values.
26 self._mocks = collections.OrderedDict()
27
28 def mock(self, obj, member, mock):
29 """Installs mock in place of the named member of the given obj.
30
31 Args:
32 obj: Any object.
33 member: String naming the attribute of the object to mock.
34 mock: The mock to install.
35 """
36 self._mocks.setdefault(obj, collections.OrderedDict()).setdefault(
37 member, getattr(obj, member))
38 setattr(obj, member, mock)
39
40 def tearDown(self, *args, **kwargs):
41 """Uninstalls mocks."""
42 super(TestCase, self).tearDown(*args, **kwargs)
43
44 for obj in self._mocks:
45 for member, original_value in self._mocks[obj].iteritems():
46 setattr(obj, member, original_value)
47
48
49class GetKIFTestFilterTest(TestCase):
50 """Tests for test_runner.get_kif_test_filter."""
51
52 def test_correct(self):
53 """Ensures correctness of filter."""
54 tests = [
55 'KIF.test1',
56 'KIF.test2',
57 ]
58 expected = 'NAME:test1|test2'
59
60 self.assertEqual(test_runner.get_kif_test_filter(tests), expected)
61
62 def test_correct_inverted(self):
63 """Ensures correctness of inverted filter."""
64 tests = [
65 'KIF.test1',
66 'KIF.test2',
67 ]
68 expected = '-NAME:test1|test2'
69
70 self.assertEqual(
71 test_runner.get_kif_test_filter(tests, invert=True), expected)
72
73
74class GetGTestFilterTest(TestCase):
75 """Tests for test_runner.get_gtest_filter."""
76
77 def test_correct(self):
78 """Ensures correctness of filter."""
79 tests = [
80 'test.1',
81 'test.2',
82 ]
83 expected = 'test.1:test.2'
84
85 self.assertEqual(test_runner.get_gtest_filter(tests), expected)
86
87 def test_correct_inverted(self):
88 """Ensures correctness of inverted filter."""
89 tests = [
90 'test.1',
91 'test.2',
92 ]
93 expected = '-test.1:test.2'
94
95 self.assertEqual(
96 test_runner.get_gtest_filter(tests, invert=True), expected)
97
98
Sergey Berezin1f457882017-11-20 21:05:3999class InstallXcodeTest(TestCase):
100 """Tests install_xcode."""
101
102 def setUp(self):
103 super(InstallXcodeTest, self).setUp()
104 self.mock(test_runner, 'xcode_select', lambda _: None)
105 self.mock(os.path, 'exists', lambda _: True)
106
107 def test_success(self):
108 self.assertTrue(test_runner.install_xcode('test_build', 'true', 'path'))
109
110 def test_failure(self):
111 self.assertFalse(test_runner.install_xcode('test_build', 'false', 'path'))
112
113
smut64cb9422016-05-07 00:24:20114class SimulatorTestRunnerTest(TestCase):
115 """Tests for test_runner.SimulatorTestRunner."""
116
Sergey Berezin1f457882017-11-20 21:05:39117 def setUp(self):
118 super(SimulatorTestRunnerTest, self).setUp()
119
120 def install_xcode(build, mac_toolchain_cmd, xcode_app_path):
smut64cb9422016-05-07 00:24:20121 return True
122
Sergey Berezin7f9b4bf2018-05-21 19:49:07123 self.mock(test_runner, 'get_current_xcode_info', lambda: {
Sergey Berezin8263e5f2017-11-29 22:51:36124 'version': 'test version', 'build': 'test build', 'path': 'test/path'})
Sergey Berezin1f457882017-11-20 21:05:39125 self.mock(test_runner, 'install_xcode', install_xcode)
126 self.mock(test_runner.subprocess, 'check_output',
127 lambda _: 'fake-bundle-id')
128 self.mock(os.path, 'abspath', lambda path: '/abs/path/to/%s' % path)
129 self.mock(os.path, 'exists', lambda _: True)
smut64cb9422016-05-07 00:24:20130
Sergey Berezin1f457882017-11-20 21:05:39131 def test_app_not_found(self):
132 """Ensures AppNotFoundError is raised."""
smut64cb9422016-05-07 00:24:20133
Sergey Berezin1f457882017-11-20 21:05:39134 self.mock(os.path, 'exists', lambda p: not p.endswith('fake-app'))
smut64cb9422016-05-07 00:24:20135
Sergey Berezin1f457882017-11-20 21:05:39136 with self.assertRaises(test_runner.AppNotFoundError):
137 test_runner.SimulatorTestRunner(
smut64cb9422016-05-07 00:24:20138 'fake-app',
139 'fake-iossim',
140 'platform',
141 'os',
142 'xcode-version',
Sergey Berezin1f457882017-11-20 21:05:39143 '', # Empty xcode-build
smut64cb9422016-05-07 00:24:20144 'out-dir',
Sergey Berezin1f457882017-11-20 21:05:39145 )
smut64cb9422016-05-07 00:24:20146
147 def test_iossim_not_found(self):
148 """Ensures SimulatorNotFoundError is raised."""
Sergey Berezin1f457882017-11-20 21:05:39149 self.mock(os.path, 'exists', lambda p: not p.endswith('fake-iossim'))
smut64cb9422016-05-07 00:24:20150
Sergey Berezin1f457882017-11-20 21:05:39151 with self.assertRaises(test_runner.SimulatorNotFoundError):
152 test_runner.SimulatorTestRunner(
smut64cb9422016-05-07 00:24:20153 'fake-app',
154 'fake-iossim',
155 'platform',
156 'os',
157 'xcode-version',
Sergey Berezin1f457882017-11-20 21:05:39158 'xcode-build',
smut64cb9422016-05-07 00:24:20159 'out-dir',
Sergey Berezin1f457882017-11-20 21:05:39160 )
smut64cb9422016-05-07 00:24:20161
162 def test_init(self):
163 """Ensures instance is created."""
smut64cb9422016-05-07 00:24:20164 tr = test_runner.SimulatorTestRunner(
165 'fake-app',
166 'fake-iossim',
167 'platform',
168 'os',
169 'xcode-version',
Sergey Berezin1f457882017-11-20 21:05:39170 'xcode-build',
smut64cb9422016-05-07 00:24:20171 'out-dir',
172 )
173
Sergey Berezin1f457882017-11-20 21:05:39174 self.assertTrue(tr)
smut64cb9422016-05-07 00:24:20175
176 def test_startup_crash(self):
177 """Ensures test is relaunched once on startup crash."""
smut64cb9422016-05-07 00:24:20178 def set_up(self):
179 return
180
181 @staticmethod
Menglu Huang89909a8e2018-02-21 00:06:42182 def _run(cmd, shards=None):
smut64cb9422016-05-07 00:24:20183 return collections.namedtuple('result', ['crashed', 'crashed_test'])(
184 crashed=True, crashed_test=None)
185
186 def tear_down(self):
187 return
188
smut64cb9422016-05-07 00:24:20189 self.mock(test_runner.SimulatorTestRunner, 'set_up', set_up)
190 self.mock(test_runner.TestRunner, '_run', _run)
191 self.mock(test_runner.SimulatorTestRunner, 'tear_down', tear_down)
192
193 tr = test_runner.SimulatorTestRunner(
194 'fake-app',
195 'fake-iossim',
196 'platform',
197 'os',
198 'xcode-version',
Sergey Berezin1f457882017-11-20 21:05:39199 'xcode-build',
smut64cb9422016-05-07 00:24:20200 'out-dir',
201 )
Sergey Berezin1f457882017-11-20 21:05:39202 with self.assertRaises(test_runner.AppLaunchError):
203 tr.launch()
smut64cb9422016-05-07 00:24:20204
Menglu Huang89909a8e2018-02-21 00:06:42205 def test_run(self):
206 """Ensures the _run method is correct with test sharding."""
207 def shard_xctest(object_path, shards, test_cases=None):
208 return [['a/1', 'b/2'], ['c/3', 'd/4'], ['e/5']]
209
210 def run_tests(self, test_shard=None):
211 out = []
212 for test in test_shard:
213 testname = test.split('/')
214 out.append('Test Case \'-[%s %s]\' started.' %
215 (testname[0], testname[1]))
216 out.append('Test Case \'-[%s %s]\' passed (0.1 seconds)' %
217 (testname[0], testname[1]))
218 return (out, 0, 0)
219
220 tr = test_runner.SimulatorTestRunner(
221 'fake-app',
222 'fake-iossim',
223 'platform',
224 'os',
225 'xcode-version',
226 'xcode-build',
227 'out-dir',
228 )
229 self.mock(test_runner, 'shard_xctest', shard_xctest)
230 self.mock(test_runner.SimulatorTestRunner, 'run_tests', run_tests)
231
232 tr.xctest_path = 'fake.xctest'
233 cmd = tr.get_launch_command()
234 result = tr._run(cmd=cmd, shards=3)
235 self.assertIn('a/1', result.passed_tests)
236 self.assertIn('b/2', result.passed_tests)
237 self.assertIn('c/3', result.passed_tests)
238 self.assertIn('d/4', result.passed_tests)
239 self.assertIn('e/5', result.passed_tests)
240
Menglu Huangeb4d7572018-05-21 18:37:58241 def test_run_with_system_alert(self):
242 """Ensures SystemAlertPresentError is raised when warning 'System alert
243 view is present, so skipping all tests' is in the output."""
244 with self.assertRaises(test_runner.SystemAlertPresentError):
245 tr = test_runner.SimulatorTestRunner(
246 'fake-app',
247 'fake-iossim',
248 'platform',
249 'os',
250 'xcode-version',
251 'xcode-build',
252 'out-dir',
253 )
254 tr.xctest_path = 'fake.xctest'
255 cmd = ['echo', 'System alert view is present, so skipping all tests!']
256 result = tr._run(cmd=cmd)
257
Menglu Huang0f569612017-12-08 06:35:07258 def test_get_launch_command(self):
Menglu Huang89909a8e2018-02-21 00:06:42259 """Ensures launch command is correct with test_filters, test sharding and
260 test_cases."""
Menglu Huang0f569612017-12-08 06:35:07261 tr = test_runner.SimulatorTestRunner(
262 'fake-app',
263 'fake-iossim',
264 'platform',
265 'os',
266 'xcode-version',
267 'xcode-build',
268 'out-dir',
269 )
270 tr.xctest_path = 'fake.xctest'
271 # Cases test_filter is not empty, with empty/non-empty self.test_cases.
272 tr.test_cases = []
273 cmd = tr.get_launch_command(['a'], invert=False)
274 self.assertIn('-t', cmd)
275 self.assertIn('a', cmd)
276
277 tr.test_cases = ['a', 'b']
278 cmd = tr.get_launch_command(['a'], invert=False)
279 self.assertIn('-t', cmd)
280 self.assertIn('a', cmd)
281 self.assertNotIn('b', cmd)
282
283 # Cases test_filter is empty, with empty/non-empty self.test_cases.
284 tr.test_cases = []
285 cmd = tr.get_launch_command(test_filter=None, invert=False)
286 self.assertNotIn('-t', cmd)
287
288 tr.test_cases = ['a', 'b']
289 cmd = tr.get_launch_command(test_filter=None, invert=False)
290 self.assertIn('-t', cmd)
291 self.assertIn('a', cmd)
292 self.assertIn('b', cmd)
293
smut64cb9422016-05-07 00:24:20294 def test_relaunch(self):
295 """Ensures test is relaunched on test crash until tests complete."""
smut64cb9422016-05-07 00:24:20296 def set_up(self):
297 return
298
299 @staticmethod
Menglu Huang89909a8e2018-02-21 00:06:42300 def _run(cmd, shards=None):
smut64cb9422016-05-07 00:24:20301 result = collections.namedtuple(
302 'result', [
303 'crashed',
304 'crashed_test',
305 'failed_tests',
306 'flaked_tests',
307 'passed_tests',
308 ],
309 )
Menglu Huang89909a8e2018-02-21 00:06:42310 if '-e' not in cmd:
smut64cb9422016-05-07 00:24:20311 # First run, has no test filter supplied. Mock a crash.
312 return result(
313 crashed=True,
314 crashed_test='c',
315 failed_tests={'b': ['b-out'], 'c': ['Did not complete.']},
316 flaked_tests={'d': ['d-out']},
317 passed_tests=['a'],
318 )
319 else:
320 return result(
321 crashed=False,
322 crashed_test=None,
323 failed_tests={},
324 flaked_tests={},
325 passed_tests=[],
326 )
327
328 def tear_down(self):
329 return
330
smut64cb9422016-05-07 00:24:20331 self.mock(test_runner.SimulatorTestRunner, 'set_up', set_up)
332 self.mock(test_runner.TestRunner, '_run', _run)
333 self.mock(test_runner.SimulatorTestRunner, 'tear_down', tear_down)
334
335 tr = test_runner.SimulatorTestRunner(
336 'fake-app',
337 'fake-iossim',
338 'platform',
339 'os',
340 'xcode-version',
Sergey Berezin1f457882017-11-20 21:05:39341 'xcode-build',
smut64cb9422016-05-07 00:24:20342 'out-dir',
343 )
344 tr.launch()
Sergey Berezin1f457882017-11-20 21:05:39345 self.assertTrue(tr.logs)
smut64cb9422016-05-07 00:24:20346
347
Menglu Huang0f569612017-12-08 06:35:07348class DeviceTestRunnerTest(TestCase):
349 def setUp(self):
350 super(DeviceTestRunnerTest, self).setUp()
351
352 def install_xcode(build, mac_toolchain_cmd, xcode_app_path):
353 return True
354
Sergey Berezin7f9b4bf2018-05-21 19:49:07355 self.mock(test_runner, 'get_current_xcode_info', lambda: {
Menglu Huang0f569612017-12-08 06:35:07356 'version': 'test version', 'build': 'test build', 'path': 'test/path'})
357 self.mock(test_runner, 'install_xcode', install_xcode)
358 self.mock(test_runner.subprocess, 'check_output',
359 lambda _: 'fake-bundle-id')
360 self.mock(os.path, 'abspath', lambda path: '/abs/path/to/%s' % path)
361 self.mock(os.path, 'exists', lambda _: True)
362
363 self.tr = test_runner.DeviceTestRunner(
364 'fake-app',
365 'xcode-version',
366 'xcode-build',
367 'out-dir',
368 )
369 self.tr.xctestrun_data = {'TestTargetName':{}}
370
371 def test_with_test_filter_without_test_cases(self):
372 """Ensures tests in the run with test_filter and no test_cases."""
373 self.tr.set_xctest_filters(['a', 'b'], invert=False)
374 self.assertEqual(
375 self.tr.xctestrun_data['TestTargetName']['OnlyTestIdentifiers'],
376 ['a', 'b']
377 )
378
379 def test_invert_with_test_filter_without_test_cases(self):
380 """Ensures tests in the run invert with test_filter and no test_cases."""
381 self.tr.set_xctest_filters(['a', 'b'], invert=True)
382 self.assertEqual(
383 self.tr.xctestrun_data['TestTargetName']['SkipTestIdentifiers'],
384 ['a', 'b']
385 )
386
387 def test_with_test_filter_with_test_cases(self):
388 """Ensures tests in the run with test_filter and test_cases."""
389 self.tr.test_cases = ['a', 'b', 'c', 'd']
390 self.tr.set_xctest_filters(['a', 'b', 'irrelevant test'], invert=False)
391 self.assertEqual(
392 self.tr.xctestrun_data['TestTargetName']['OnlyTestIdentifiers'],
393 ['a', 'b']
394 )
395
396 def test_invert_with_test_filter_with_test_cases(self):
397 """Ensures tests in the run invert with test_filter and test_cases."""
398 self.tr.test_cases = ['a', 'b', 'c', 'd']
399 self.tr.set_xctest_filters(['a', 'b', 'irrelevant test'], invert=True)
400 self.assertEqual(
401 self.tr.xctestrun_data['TestTargetName']['OnlyTestIdentifiers'],
402 ['c', 'd']
403 )
404
405 def test_without_test_filter_without_test_cases(self):
406 """Ensures tests in the run with no test_filter and no test_cases."""
407 self.tr.set_xctest_filters(test_filter=None, invert=False)
408 self.assertIsNone(
409 self.tr.xctestrun_data['TestTargetName'].get('OnlyTestIdentifiers'))
410
411 def test_invert_without_test_filter_without_test_cases(self):
412 """Ensures tests in the run invert with no test_filter and no test_cases."""
413 self.tr.set_xctest_filters(test_filter=None, invert=True)
414 self.assertIsNone(
415 self.tr.xctestrun_data['TestTargetName'].get('OnlyTestIdentifiers'))
416
417 def test_without_test_filter_with_test_cases(self):
418 """Ensures tests in the run with no test_filter but test_cases."""
419 self.tr.test_cases = ['a', 'b', 'c', 'd']
420 self.tr.set_xctest_filters(test_filter=None, invert=False)
421 self.assertEqual(
422 self.tr.xctestrun_data['TestTargetName']['OnlyTestIdentifiers'],
423 ['a', 'b', 'c', 'd']
424 )
425
426 def test_invert_without_test_filter_with_test_cases(self):
427 """Ensures tests in the run invert with no test_filter but test_cases."""
428 self.tr.test_cases = ['a', 'b', 'c', 'd']
429 self.tr.set_xctest_filters(test_filter=None, invert=True)
430 self.assertEqual(
431 self.tr.xctestrun_data['TestTargetName']['OnlyTestIdentifiers'],
432 ['a', 'b', 'c', 'd']
433 )
434
435
smut64cb9422016-05-07 00:24:20436if __name__ == '__main__':
437 unittest.main()