OLD | NEW |
1 # Copyright 2016 The Chromium Authors. All rights reserved. | 1 # Copyright 2016 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """Test runners for iOS.""" | 5 """Test runners for iOS.""" |
6 | 6 |
7 import argparse | 7 import argparse |
8 import collections | 8 import collections |
9 import errno | 9 import errno |
10 import os | 10 import os |
| 11 import plistlib |
11 import shutil | 12 import shutil |
12 import subprocess | 13 import subprocess |
13 import sys | 14 import sys |
14 import tempfile | 15 import tempfile |
15 import time | 16 import time |
16 | 17 |
17 import find_xcode | 18 import find_xcode |
18 import gtest_utils | 19 import gtest_utils |
19 import xctest_utils | 20 import xctest_utils |
20 | 21 |
21 | 22 |
22 DERIVED_DATA = os.path.expanduser('~/Library/Developer/Xcode/DerivedData') | 23 DERIVED_DATA = os.path.expanduser('~/Library/Developer/Xcode/DerivedData') |
23 | 24 |
24 | 25 |
25 XCTEST_PROJECT = os.path.abspath(os.path.join( | |
26 os.path.dirname(__file__), | |
27 'TestProject', | |
28 'TestProject.xcodeproj', | |
29 )) | |
30 | |
31 XCTEST_SCHEME = 'TestProject' | |
32 | |
33 | |
34 class Error(Exception): | 26 class Error(Exception): |
35 """Base class for errors.""" | 27 """Base class for errors.""" |
36 pass | 28 pass |
37 | 29 |
38 | 30 |
39 class TestRunnerError(Error): | 31 class TestRunnerError(Error): |
40 """Base class for TestRunner-related errors.""" | 32 """Base class for TestRunner-related errors.""" |
41 pass | 33 pass |
42 | 34 |
43 | 35 |
(...skipping 606 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
650 out_dir, | 642 out_dir, |
651 env_vars=env_vars, | 643 env_vars=env_vars, |
652 retries=retries, | 644 retries=retries, |
653 test_args=test_args, | 645 test_args=test_args, |
654 xctest=xctest, | 646 xctest=xctest, |
655 ) | 647 ) |
656 | 648 |
657 self.udid = subprocess.check_output(['idevice_id', '--list']).rstrip() | 649 self.udid = subprocess.check_output(['idevice_id', '--list']).rstrip() |
658 if len(self.udid.splitlines()) != 1: | 650 if len(self.udid.splitlines()) != 1: |
659 raise DeviceDetectionError(self.udid) | 651 raise DeviceDetectionError(self.udid) |
| 652 if xctest: |
| 653 self.xctestrun_file = tempfile.mkstemp()[1] |
| 654 self.xctestrun_data = { |
| 655 'TestTargetName': { |
| 656 'IsAppHostedTestBundle': True, |
| 657 'TestBundlePath': '%s' % self.xctest_path, |
| 658 'TestHostPath': '%s' % self.app_path, |
| 659 'TestingEnvironmentVariables': { |
| 660 'DYLD_INSERT_LIBRARIES': |
| 661 '__PLATFORMS__/iPhoneOS.platform/Developer/Library/' |
| 662 'PrivateFrameworks/IDEBundleInjection.framework/IDEBundleInjection', |
| 663 'DYLD_LIBRARY_PATH': |
| 664 '__PLATFORMS__/iPhoneOS.platform/Developer/Library', |
| 665 'DYLD_FRAMEWORK_PATH': |
| 666 '__PLATFORMS__/iPhoneOS.platform/Developer/Library/Frameworks', |
| 667 'XCInjectBundleInto':'__TESTHOST__/%s' % self.app_name |
| 668 } |
| 669 } |
| 670 } |
660 | 671 |
661 def uninstall_apps(self): | 672 def uninstall_apps(self): |
662 """Uninstalls all apps found on the device.""" | 673 """Uninstalls all apps found on the device.""" |
663 for app in subprocess.check_output( | 674 for app in subprocess.check_output( |
664 ['idevicefs', '--udid', self.udid, 'ls', '@']).splitlines(): | 675 ['idevicefs', '--udid', self.udid, 'ls', '@']).splitlines(): |
665 subprocess.check_call( | 676 subprocess.check_call( |
666 ['ideviceinstaller', '--udid', self.udid, '--uninstall', app]) | 677 ['ideviceinstaller', '--udid', self.udid, '--uninstall', app]) |
667 | 678 |
668 def install_app(self): | 679 def install_app(self): |
669 """Installs the app.""" | 680 """Installs the app.""" |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
716 | 727 |
717 Args: | 728 Args: |
718 test_filter: List of test cases to filter. | 729 test_filter: List of test cases to filter. |
719 invert: Whether to invert the filter or not. Inverted, the filter will | 730 invert: Whether to invert the filter or not. Inverted, the filter will |
720 match everything except the given test cases. | 731 match everything except the given test cases. |
721 | 732 |
722 Returns: | 733 Returns: |
723 A list of strings forming the command to launch the test. | 734 A list of strings forming the command to launch the test. |
724 """ | 735 """ |
725 if self.xctest_path: | 736 if self.xctest_path: |
| 737 if test_filter: |
| 738 if invert: |
| 739 self.xctestrun_data['TestTargetName'].update( |
| 740 {'SkipTestIdentifiers': test_filter}) |
| 741 else: |
| 742 self.xctestrun_data['TestTargetName'].update( |
| 743 {'OnlyTestIdentifiers': test_filter}) |
| 744 plistlib.writePlist(self.xctestrun_data, self.xctestrun_file) |
726 return [ | 745 return [ |
727 'xcodebuild', | 746 'xcodebuild', |
728 'test-without-building', | 747 'test-without-building', |
729 'BUILT_PRODUCTS_DIR=%s' % os.path.dirname(self.app_path), | 748 '-xctestrun', self.xctestrun_file, |
730 '-destination', 'id=%s' % self.udid, | 749 '-destination', 'id=%s' % self.udid, |
731 '-project', XCTEST_PROJECT, | |
732 '-scheme', XCTEST_SCHEME, | |
733 ] | 750 ] |
734 | 751 |
735 cmd = [ | 752 cmd = [ |
736 'idevice-app-runner', | 753 'idevice-app-runner', |
737 '--udid', self.udid, | 754 '--udid', self.udid, |
738 '--start', self.cfbundleid, | 755 '--start', self.cfbundleid, |
739 ] | 756 ] |
740 args = [] | 757 args = [] |
741 | 758 |
742 if test_filter: | 759 if test_filter: |
(...skipping 20 matching lines...) Expand all Loading... |
763 """ | 780 """ |
764 env = super(DeviceTestRunner, self).get_launch_env() | 781 env = super(DeviceTestRunner, self).get_launch_env() |
765 if self.xctest_path: | 782 if self.xctest_path: |
766 env['NSUnbufferedIO'] = 'YES' | 783 env['NSUnbufferedIO'] = 'YES' |
767 # e.g. ios_web_shell_egtests | 784 # e.g. ios_web_shell_egtests |
768 env['APP_TARGET_NAME'] = os.path.splitext( | 785 env['APP_TARGET_NAME'] = os.path.splitext( |
769 os.path.basename(self.app_path))[0] | 786 os.path.basename(self.app_path))[0] |
770 # e.g. ios_web_shell_egtests_module | 787 # e.g. ios_web_shell_egtests_module |
771 env['TEST_TARGET_NAME'] = env['APP_TARGET_NAME'] + '_module' | 788 env['TEST_TARGET_NAME'] = env['APP_TARGET_NAME'] + '_module' |
772 return env | 789 return env |
OLD | NEW |