blob: a54e1f1ca45baf8cef70717a7f424b35b070ad6d [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
Eric Aleshirece66b9f2019-02-08 08:00:319import logging
Maksym Onufriienkobe3cccb2019-07-09 23:07:3010import mock
smut64cb9422016-05-07 00:24:2011import os
Maksym Onufriienko148bbd952019-09-23 22:20:0812import tempfile
smut64cb9422016-05-07 00:24:2013import unittest
14
Maksym Onufriienko85a333ec2020-02-19 19:54:0515import iossim_util
smut64cb9422016-05-07 00:24:2016import test_runner
17
Maksym Onufriienko85a333ec2020-02-19 19:54:0518SIMULATORS_LIST = {
19 'devices': {
20 'com.apple.CoreSimulator.SimRuntime.iOS-11-4': [{
21 'isAvailable': True,
22 'name': 'iPhone 5s',
23 'state': 'Shutdown',
24 'udid': 'E4E66320-177A-450A-9BA1-488D85B7278E'
25 }],
26 'com.apple.CoreSimulator.SimRuntime.iOS-13-2': [
27 {
28 'isAvailable': True,
29 'name': 'iPhone X',
30 'state': 'Shutdown',
31 'udid': 'E4E66321-177A-450A-9BA1-488D85B7278E'
32 },
33 {
34 'isAvailable': True,
35 'name': 'iPhone 11',
36 'state': 'Shutdown',
37 'udid': 'A4E66321-177A-450A-9BA1-488D85B7278E'
38 }
39 ]
40 },
41 'devicetypes': [
42 {
43 'name': 'iPhone 5s',
44 'bundlePath': '/path/iPhone 4s/Content',
45 'identifier': 'com.apple.CoreSimulator.SimDeviceType.iPhone-5s'
46 },
47 {
48 'name': 'iPhone X',
49 'bundlePath': '/path/iPhone X/Content',
50 'identifier': 'com.apple.CoreSimulator.SimDeviceType.iPhone-X'
51 },
52 {
53 'name': 'iPhone 11',
54 'bundlePath': '/path/iPhone 11/Content',
55 'identifier': 'com.apple.CoreSimulator.SimDeviceType.iPhone-11'
56 },
57 ],
58 'pairs': [],
59 'runtimes': [
60 {
61 "buildversion": "15F79",
62 "bundlePath": "/path/Runtimes/iOS 11.4.simruntime",
63 "identifier": "com.apple.CoreSimulator.SimRuntime.iOS-11-4",
64 "isAvailable": True,
65 "name": "iOS 11.4",
66 "version": "11.4"
67 },
68 {
69 "buildversion": "17A844",
70 "bundlePath": "/path/Runtimes/iOS 13.1.simruntime",
71 "identifier": "com.apple.CoreSimulator.SimRuntime.iOS-13-1",
72 "isAvailable": True,
73 "name": "iOS 13.1",
74 "version": "13.1"
75 },
76 {
77 "buildversion": "17B102",
78 "bundlePath": "/path/Runtimes/iOS.simruntime",
79 "identifier": "com.apple.CoreSimulator.SimRuntime.iOS-13-2",
80 "isAvailable": True,
81 "name": "iOS 13.2",
82 "version": "13.2.2"
83 },
84 ]
85}
86
smut64cb9422016-05-07 00:24:2087
88class TestCase(unittest.TestCase):
89 """Test case which supports installing mocks. Uninstalls on tear down."""
90
91 def __init__(self, *args, **kwargs):
92 """Initializes a new instance of this class."""
93 super(TestCase, self).__init__(*args, **kwargs)
94
95 # Maps object to a dict which maps names of mocked members to their
96 # original values.
97 self._mocks = collections.OrderedDict()
98
99 def mock(self, obj, member, mock):
100 """Installs mock in place of the named member of the given obj.
101
102 Args:
103 obj: Any object.
104 member: String naming the attribute of the object to mock.
105 mock: The mock to install.
106 """
107 self._mocks.setdefault(obj, collections.OrderedDict()).setdefault(
108 member, getattr(obj, member))
109 setattr(obj, member, mock)
110
111 def tearDown(self, *args, **kwargs):
112 """Uninstalls mocks."""
113 super(TestCase, self).tearDown(*args, **kwargs)
114
115 for obj in self._mocks:
116 for member, original_value in self._mocks[obj].iteritems():
117 setattr(obj, member, original_value)
118
119
Sergey Berezin1f457882017-11-20 21:05:39120class InstallXcodeTest(TestCase):
121 """Tests install_xcode."""
122
123 def setUp(self):
124 super(InstallXcodeTest, self).setUp()
125 self.mock(test_runner, 'xcode_select', lambda _: None)
126 self.mock(os.path, 'exists', lambda _: True)
127
128 def test_success(self):
129 self.assertTrue(test_runner.install_xcode('test_build', 'true', 'path'))
130
131 def test_failure(self):
132 self.assertFalse(test_runner.install_xcode('test_build', 'false', 'path'))
133
134
smut64cb9422016-05-07 00:24:20135class SimulatorTestRunnerTest(TestCase):
136 """Tests for test_runner.SimulatorTestRunner."""
137
Sergey Berezin1f457882017-11-20 21:05:39138 def setUp(self):
139 super(SimulatorTestRunnerTest, self).setUp()
Maksym Onufriienko85a333ec2020-02-19 19:54:05140 self.mock(iossim_util, 'get_simulator_list', lambda: SIMULATORS_LIST)
Sergey Berezin1f457882017-11-20 21:05:39141
142 def install_xcode(build, mac_toolchain_cmd, xcode_app_path):
smut64cb9422016-05-07 00:24:20143 return True
144
Sergey Berezin7f9b4bf2018-05-21 19:49:07145 self.mock(test_runner, 'get_current_xcode_info', lambda: {
Sergey Berezin8263e5f2017-11-29 22:51:36146 'version': 'test version', 'build': 'test build', 'path': 'test/path'})
Sergey Berezin1f457882017-11-20 21:05:39147 self.mock(test_runner, 'install_xcode', install_xcode)
148 self.mock(test_runner.subprocess, 'check_output',
149 lambda _: 'fake-bundle-id')
150 self.mock(os.path, 'abspath', lambda path: '/abs/path/to/%s' % path)
151 self.mock(os.path, 'exists', lambda _: True)
Eric Aleshiref22c7efb2019-02-04 23:41:26152 self.mock(test_runner.TestRunner, 'set_sigterm_handler',
153 lambda self, handler: 0)
Maksym Onufriienko148bbd952019-09-23 22:20:08154 self.mock(os, 'listdir', lambda _: [])
smut64cb9422016-05-07 00:24:20155
Sergey Berezin1f457882017-11-20 21:05:39156 def test_app_not_found(self):
157 """Ensures AppNotFoundError is raised."""
smut64cb9422016-05-07 00:24:20158
Sergey Berezin1f457882017-11-20 21:05:39159 self.mock(os.path, 'exists', lambda p: not p.endswith('fake-app'))
smut64cb9422016-05-07 00:24:20160
Sergey Berezin1f457882017-11-20 21:05:39161 with self.assertRaises(test_runner.AppNotFoundError):
162 test_runner.SimulatorTestRunner(
smut64cb9422016-05-07 00:24:20163 'fake-app',
Garrett Beatyee3d9cb2020-02-28 01:35:32164 'fake-iossim',
smut64cb9422016-05-07 00:24:20165 'platform',
166 'os',
167 'xcode-version',
Sergey Berezin1f457882017-11-20 21:05:39168 '', # Empty xcode-build
smut64cb9422016-05-07 00:24:20169 'out-dir',
Sergey Berezin1f457882017-11-20 21:05:39170 )
smut64cb9422016-05-07 00:24:20171
Garrett Beatyee3d9cb2020-02-28 01:35:32172 def test_iossim_not_found(self):
173 """Ensures SimulatorNotFoundError is raised."""
174 self.mock(os.path, 'exists', lambda p: not p.endswith('fake-iossim'))
175
176 with self.assertRaises(test_runner.SimulatorNotFoundError):
177 test_runner.SimulatorTestRunner(
178 'fake-app',
179 'fake-iossim',
180 'iPhone X',
181 '11.4',
182 'xcode-version',
183 'xcode-build',
184 'out-dir',
185 )
186
smut64cb9422016-05-07 00:24:20187 def test_init(self):
188 """Ensures instance is created."""
smut64cb9422016-05-07 00:24:20189 tr = test_runner.SimulatorTestRunner(
190 'fake-app',
Garrett Beatyee3d9cb2020-02-28 01:35:32191 'fake-iossim',
Maksym Onufriienko85a333ec2020-02-19 19:54:05192 'iPhone X',
193 '11.4',
smut64cb9422016-05-07 00:24:20194 'xcode-version',
Sergey Berezin1f457882017-11-20 21:05:39195 'xcode-build',
smut64cb9422016-05-07 00:24:20196 'out-dir',
197 )
198
Sergey Berezin1f457882017-11-20 21:05:39199 self.assertTrue(tr)
smut64cb9422016-05-07 00:24:20200
201 def test_startup_crash(self):
202 """Ensures test is relaunched once on startup crash."""
smut64cb9422016-05-07 00:24:20203 def set_up(self):
204 return
205
206 @staticmethod
Menglu Huang89909a8e2018-02-21 00:06:42207 def _run(cmd, shards=None):
smut64cb9422016-05-07 00:24:20208 return collections.namedtuple('result', ['crashed', 'crashed_test'])(
209 crashed=True, crashed_test=None)
210
211 def tear_down(self):
212 return
213
smut64cb9422016-05-07 00:24:20214 self.mock(test_runner.SimulatorTestRunner, 'set_up', set_up)
215 self.mock(test_runner.TestRunner, '_run', _run)
216 self.mock(test_runner.SimulatorTestRunner, 'tear_down', tear_down)
217
218 tr = test_runner.SimulatorTestRunner(
219 'fake-app',
Garrett Beatyee3d9cb2020-02-28 01:35:32220 'fake-iossim',
Maksym Onufriienko85a333ec2020-02-19 19:54:05221 'iPhone X',
222 '11.4',
smut64cb9422016-05-07 00:24:20223 'xcode-version',
Sergey Berezin1f457882017-11-20 21:05:39224 'xcode-build',
smut64cb9422016-05-07 00:24:20225 'out-dir',
Maksym Onufriienko148bbd952019-09-23 22:20:08226 xctest=True,
smut64cb9422016-05-07 00:24:20227 )
Sergey Berezin1f457882017-11-20 21:05:39228 with self.assertRaises(test_runner.AppLaunchError):
229 tr.launch()
smut64cb9422016-05-07 00:24:20230
Menglu Huang89909a8e2018-02-21 00:06:42231 def test_run(self):
232 """Ensures the _run method is correct with test sharding."""
Menglu Huang89909a8e2018-02-21 00:06:42233
234 def run_tests(self, test_shard=None):
235 out = []
236 for test in test_shard:
237 testname = test.split('/')
238 out.append('Test Case \'-[%s %s]\' started.' %
239 (testname[0], testname[1]))
240 out.append('Test Case \'-[%s %s]\' passed (0.1 seconds)' %
241 (testname[0], testname[1]))
242 return (out, 0, 0)
243
244 tr = test_runner.SimulatorTestRunner(
245 'fake-app',
Garrett Beatyee3d9cb2020-02-28 01:35:32246 'fake-iossim',
Maksym Onufriienko85a333ec2020-02-19 19:54:05247 'iPhone X',
248 '11.4',
Menglu Huang89909a8e2018-02-21 00:06:42249 'xcode-version',
250 'xcode-build',
251 'out-dir',
Maksym Onufriienko148bbd952019-09-23 22:20:08252 xctest=True,
Menglu Huang89909a8e2018-02-21 00:06:42253 )
Menglu Huang89909a8e2018-02-21 00:06:42254 self.mock(test_runner.SimulatorTestRunner, 'run_tests', run_tests)
255
256 tr.xctest_path = 'fake.xctest'
257 cmd = tr.get_launch_command()
258 result = tr._run(cmd=cmd, shards=3)
259 self.assertIn('a/1', result.passed_tests)
260 self.assertIn('b/2', result.passed_tests)
261 self.assertIn('c/3', result.passed_tests)
262 self.assertIn('d/4', result.passed_tests)
263 self.assertIn('e/5', result.passed_tests)
264
Menglu Huangeb4d7572018-05-21 18:37:58265 def test_run_with_system_alert(self):
266 """Ensures SystemAlertPresentError is raised when warning 'System alert
267 view is present, so skipping all tests' is in the output."""
268 with self.assertRaises(test_runner.SystemAlertPresentError):
269 tr = test_runner.SimulatorTestRunner(
270 'fake-app',
Garrett Beatyee3d9cb2020-02-28 01:35:32271 'fake-iossim',
Maksym Onufriienko85a333ec2020-02-19 19:54:05272 'iPhone X',
273 '11.4',
Menglu Huangeb4d7572018-05-21 18:37:58274 'xcode-version',
275 'xcode-build',
276 'out-dir',
Maksym Onufriienko148bbd952019-09-23 22:20:08277 xctest=True,
Menglu Huangeb4d7572018-05-21 18:37:58278 )
279 tr.xctest_path = 'fake.xctest'
280 cmd = ['echo', 'System alert view is present, so skipping all tests!']
281 result = tr._run(cmd=cmd)
282
Menglu Huang0f569612017-12-08 06:35:07283 def test_get_launch_command(self):
Menglu Huang89909a8e2018-02-21 00:06:42284 """Ensures launch command is correct with test_filters, test sharding and
285 test_cases."""
Menglu Huang0f569612017-12-08 06:35:07286 tr = test_runner.SimulatorTestRunner(
287 'fake-app',
Garrett Beatyee3d9cb2020-02-28 01:35:32288 'fake-iossim',
Maksym Onufriienko85a333ec2020-02-19 19:54:05289 'iPhone X',
290 '11.4',
Menglu Huang0f569612017-12-08 06:35:07291 'xcode-version',
292 'xcode-build',
293 'out-dir',
294 )
295 tr.xctest_path = 'fake.xctest'
296 # Cases test_filter is not empty, with empty/non-empty self.test_cases.
297 tr.test_cases = []
Maksym Onufriienko85a333ec2020-02-19 19:54:05298 cmd = tr.get_launch_command(['a'])
Menglu Huang0f569612017-12-08 06:35:07299 self.assertIn('-t', cmd)
300 self.assertIn('a', cmd)
301
302 tr.test_cases = ['a', 'b']
Maksym Onufriienko85a333ec2020-02-19 19:54:05303 cmd = tr.get_launch_command(['a'])
Menglu Huang0f569612017-12-08 06:35:07304 self.assertIn('-t', cmd)
305 self.assertIn('a', cmd)
306 self.assertNotIn('b', cmd)
307
308 # Cases test_filter is empty, with empty/non-empty self.test_cases.
309 tr.test_cases = []
310 cmd = tr.get_launch_command(test_filter=None, invert=False)
311 self.assertNotIn('-t', cmd)
312
313 tr.test_cases = ['a', 'b']
314 cmd = tr.get_launch_command(test_filter=None, invert=False)
315 self.assertIn('-t', cmd)
316 self.assertIn('a', cmd)
317 self.assertIn('b', cmd)
318
smut64cb9422016-05-07 00:24:20319 def test_relaunch(self):
320 """Ensures test is relaunched on test crash until tests complete."""
smut64cb9422016-05-07 00:24:20321 def set_up(self):
322 return
323
324 @staticmethod
Menglu Huang89909a8e2018-02-21 00:06:42325 def _run(cmd, shards=None):
smut64cb9422016-05-07 00:24:20326 result = collections.namedtuple(
327 'result', [
328 'crashed',
329 'crashed_test',
330 'failed_tests',
331 'flaked_tests',
332 'passed_tests',
333 ],
334 )
Menglu Huang89909a8e2018-02-21 00:06:42335 if '-e' not in cmd:
smut64cb9422016-05-07 00:24:20336 # First run, has no test filter supplied. Mock a crash.
337 return result(
338 crashed=True,
339 crashed_test='c',
340 failed_tests={'b': ['b-out'], 'c': ['Did not complete.']},
341 flaked_tests={'d': ['d-out']},
342 passed_tests=['a'],
343 )
344 else:
345 return result(
346 crashed=False,
347 crashed_test=None,
348 failed_tests={},
349 flaked_tests={},
350 passed_tests=[],
351 )
352
353 def tear_down(self):
354 return
355
smut64cb9422016-05-07 00:24:20356 self.mock(test_runner.SimulatorTestRunner, 'set_up', set_up)
357 self.mock(test_runner.TestRunner, '_run', _run)
358 self.mock(test_runner.SimulatorTestRunner, 'tear_down', tear_down)
359
360 tr = test_runner.SimulatorTestRunner(
361 'fake-app',
Garrett Beatyee3d9cb2020-02-28 01:35:32362 'fake-iossim',
Maksym Onufriienko85a333ec2020-02-19 19:54:05363 'iPhone X',
364 '11.4',
smut64cb9422016-05-07 00:24:20365 'xcode-version',
Sergey Berezin1f457882017-11-20 21:05:39366 'xcode-build',
smut64cb9422016-05-07 00:24:20367 'out-dir',
368 )
369 tr.launch()
Sergey Berezin1f457882017-11-20 21:05:39370 self.assertTrue(tr.logs)
smut64cb9422016-05-07 00:24:20371
372
Menglu Huang0f569612017-12-08 06:35:07373class DeviceTestRunnerTest(TestCase):
374 def setUp(self):
375 super(DeviceTestRunnerTest, self).setUp()
376
377 def install_xcode(build, mac_toolchain_cmd, xcode_app_path):
378 return True
379
Sergey Berezin7f9b4bf2018-05-21 19:49:07380 self.mock(test_runner, 'get_current_xcode_info', lambda: {
Menglu Huang0f569612017-12-08 06:35:07381 'version': 'test version', 'build': 'test build', 'path': 'test/path'})
382 self.mock(test_runner, 'install_xcode', install_xcode)
383 self.mock(test_runner.subprocess, 'check_output',
384 lambda _: 'fake-bundle-id')
385 self.mock(os.path, 'abspath', lambda path: '/abs/path/to/%s' % path)
386 self.mock(os.path, 'exists', lambda _: True)
Maksym Onufriienko148bbd952019-09-23 22:20:08387 self.mock(os, 'listdir', lambda _: [])
388 self.mock(tempfile, 'mkstemp', lambda: '/tmp/tmp_file')
Menglu Huang0f569612017-12-08 06:35:07389
390 self.tr = test_runner.DeviceTestRunner(
391 'fake-app',
392 'xcode-version',
393 'xcode-build',
394 'out-dir',
395 )
396 self.tr.xctestrun_data = {'TestTargetName':{}}
397
Menglu Huang0f569612017-12-08 06:35:07398
smut64cb9422016-05-07 00:24:20399if __name__ == '__main__':
Eric Aleshirece66b9f2019-02-08 08:00:31400 logging.basicConfig(format='[%(asctime)s:%(levelname)s] %(message)s',
401 level=logging.DEBUG, datefmt='%I:%M:%S')
smut64cb9422016-05-07 00:24:20402 unittest.main()