blob: 8600a62b00f56c59f5f656eadc242249943ec551 [file] [log] [blame]
# Copyright 2018 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 xcodebuild_runner.py."""
import logging
import mock
import os
import shutil
import unittest
import iossim_util
import plistlib
import tempfile
import test_apps
import test_runner
import test_runner_test
import xcode_log_parser
import xcodebuild_runner
_ROOT_FOLDER_PATH = 'root/folder'
_XCODE_BUILD_VERSION = '10B61'
_DESTINATION = 'A4E66321-177A-450A-9BA1-488D85B7278E'
_OUT_DIR = 'out/dir'
_XTEST_RUN = '/tmp/temp_file.xctestrun'
_EGTESTS_APP_PATH = '%s/any_egtests.app' % _ROOT_FOLDER_PATH
class XCodebuildRunnerTest(test_runner_test.TestCase):
"""Test case to test xcodebuild_runner."""
def setUp(self):
super(XCodebuildRunnerTest, self).setUp()
self.mock(os.path, 'exists', lambda _: True)
self.mock(xcode_log_parser.XcodeLogParser, 'copy_screenshots',
lambda _1, _2: None)
self.mock(os, 'listdir', lambda _: ['any_egtests.xctest'])
self.mock(xcodebuild_runner, 'get_all_tests',
lambda _1, _2: ['Class1/passedTest1', 'Class1/passedTest2'])
self.tmpdir = tempfile.mkdtemp()
self.mock(iossim_util, 'get_simulator_list',
lambda: test_runner_test.SIMULATORS_LIST)
self.mock(test_apps, 'get_bundle_id', lambda _: "fake-bundle-id")
def tearDown(self):
shutil.rmtree(self.tmpdir, ignore_errors=True)
super(XCodebuildRunnerTest, self).tearDown()
def fake_launch_attempt(self, obj, statuses):
attempt = [0]
info_plist_statuses = {
'not_started': {
'Actions': [{'ActionResult': {}}],
'TestsCount': 0, 'TestsFailedCount': 0
},
'fail': {
'Actions': [
{'ActionResult': {
'TestSummaryPath': '1_Test/TestSummaries.plist'}
}
],
'TestsCount': 99,
'TestsFailedCount': 1},
'pass': {
'Actions': [
{'ActionResult': {
'TestSummaryPath': '1_Test/TestSummaries.plist'}
}
],
'TestsCount': 100,
'TestsFailedCount': 0}
}
test_summary = {
'TestableSummaries': [
{'TargetName': 'egtests',
'Tests': [
{'Subtests': [
{'Subtests': [
{'Subtests': [
{'TestIdentifier': 'passed_test',
'TestStatus': 'Success'
}
]
}
]
}
]
}
]
}
]
}
def the_fake(cmd):
index = attempt[0]
attempt[0] += 1
attempt_outdir = os.path.join(self.tmpdir, 'attempt_%d' % index)
self.assertEqual(1, cmd.count(attempt_outdir))
os.mkdir(attempt_outdir)
with open(os.path.join(attempt_outdir, 'Info.plist'), 'w') as f:
plistlib.writePlist(info_plist_statuses[statuses[index]], f)
summary_folder = os.path.join(attempt_outdir, '1_Test')
os.mkdir(summary_folder)
with open(os.path.join(summary_folder, 'TestSummaries.plist'), 'w') as f:
plistlib.writePlist(test_summary, f)
return (-6, 'Output for attempt_%d' % index)
obj.launch_attempt = the_fake
def testEgtests_not_found_egtests_app(self):
self.mock(os.path, 'exists', lambda _: False)
with self.assertRaises(test_runner.AppNotFoundError):
test_apps.EgtestsApp(_EGTESTS_APP_PATH)
def testEgtests_not_found_plugins(self):
egtests = test_apps.EgtestsApp(_EGTESTS_APP_PATH)
self.mock(os.path, 'exists', lambda _: False)
with self.assertRaises(test_runner.PlugInsNotFoundError):
egtests._xctest_path()
def testEgtests_found_xctest(self):
self.assertEqual('/PlugIns/any_egtests.xctest',
test_apps.EgtestsApp(_EGTESTS_APP_PATH)._xctest_path())
@mock.patch('os.listdir', autospec=True)
def testEgtests_not_found_xctest(self, mock_listdir):
mock_listdir.return_value = ['random_file']
egtest = test_apps.EgtestsApp(_EGTESTS_APP_PATH)
with self.assertRaises(test_runner.XCTestPlugInNotFoundError):
egtest._xctest_path()
def testEgtests_xctestRunNode_without_filter(self):
egtest_node = test_apps.EgtestsApp(
_EGTESTS_APP_PATH).fill_xctestrun_node()['any_egtests_module']
self.assertNotIn('OnlyTestIdentifiers', egtest_node)
self.assertNotIn('SkipTestIdentifiers', egtest_node)
def testEgtests_xctestRunNode_with_filter_only_identifiers(self):
filtered_tests = ['TestCase1/testMethod1', 'TestCase1/testMethod2',
'TestCase2/testMethod1', 'TestCase1/testMethod2']
egtest_node = test_apps.EgtestsApp(
_EGTESTS_APP_PATH, included_tests=filtered_tests).fill_xctestrun_node(
)['any_egtests_module']
self.assertEqual(filtered_tests, egtest_node['OnlyTestIdentifiers'])
self.assertNotIn('SkipTestIdentifiers', egtest_node)
def testEgtests_xctestRunNode_with_filter_skip_identifiers(self):
skipped_tests = ['TestCase1/testMethod1', 'TestCase1/testMethod2',
'TestCase2/testMethod1', 'TestCase1/testMethod2']
egtest_node = test_apps.EgtestsApp(
_EGTESTS_APP_PATH, excluded_tests=skipped_tests).fill_xctestrun_node(
)['any_egtests_module']
self.assertEqual(skipped_tests, egtest_node['SkipTestIdentifiers'])
self.assertNotIn('OnlyTestIdentifiers', egtest_node)
@mock.patch('test_runner.get_current_xcode_info', autospec=True)
@mock.patch('xcode_log_parser.XcodeLogParser.collect_test_results')
def testLaunchCommand_restartFailed1stAttempt(self, mock_collect_results,
xcode_version):
egtests = test_apps.EgtestsApp(_EGTESTS_APP_PATH)
xcode_version.return_value = {'version': '10.2.1'}
mock_collect_results.side_effect = [
{'failed': {'TESTS_DID_NOT_START': ['not started']}, 'passed': []},
{'failed': {}, 'passed': ['Class1/passedTest1', 'Class1/passedTest2']}
]
launch_command = xcodebuild_runner.LaunchCommand(egtests,
_DESTINATION,
shards=1,
retries=3,
out_dir=self.tmpdir)
self.fake_launch_attempt(launch_command, ['not_started', 'pass'])
launch_command.launch()
self.assertEqual(1, len(launch_command.test_results))
@mock.patch('test_runner.get_current_xcode_info', autospec=True)
@mock.patch('xcode_log_parser.XcodeLogParser.collect_test_results')
def testLaunchCommand_notRestartPassedTest(self, mock_collect_results,
xcode_version):
egtests = test_apps.EgtestsApp(_EGTESTS_APP_PATH)
xcode_version.return_value = {'version': '10.2.1'}
mock_collect_results.side_effect = [
{'failed': {'BUILD_INTERRUPTED': 'BUILD_INTERRUPTED: attempt # 0'},
'passed': ['Class1/passedTest1', 'Class1/passedTest2']}
]
launch_command = xcodebuild_runner.LaunchCommand(egtests,
_DESTINATION,
shards=1,
retries=3,
out_dir=self.tmpdir)
self.fake_launch_attempt(launch_command, ['pass'])
launch_command.launch()
self.assertEqual(1, len(launch_command.test_results['attempts']))
class DeviceXcodeTestRunnerTest(test_runner_test.TestCase):
"""Test case to test xcodebuild_runner.DeviceXcodeTestRunner."""
def setUp(self):
super(DeviceXcodeTestRunnerTest, self).setUp()
self.mock(os.path, 'exists', lambda _: True)
self.mock(test_runner, 'get_current_xcode_info', lambda: {
'version': 'test version', 'build': 'test build', 'path': 'test/path'})
self.mock(os.path, 'abspath', lambda path: '/abs/path/to/%s' % path)
self.mock(test_runner.subprocess, 'check_output', lambda _: 'fake-output')
self.mock(test_runner.subprocess, 'check_call', lambda _: 'fake-out')
self.mock(test_runner.TestRunner, 'set_sigterm_handler',
lambda self, handler: 0)
self.mock(os, 'listdir', lambda _: [])
self.mock(test_runner, 'print_process_output', lambda _: [])
self.mock(test_runner.TestRunner, 'start_proc', lambda self, cmd: 0)
self.mock(test_runner.DeviceTestRunner, 'get_installed_packages',
lambda self: [])
self.mock(test_runner.DeviceTestRunner, 'wipe_derived_data', lambda _: None)
self.mock(test_runner.TestRunner, 'retrieve_derived_data', lambda _: None)
def test_launch(self):
"""Tests launch method in DeviceXcodeTestRunner"""
self.mock(xcodebuild_runner.pool.ThreadPool, 'imap_unordered',
lambda _1, _2, _3: [])
self.mock(xcodebuild_runner, 'get_all_tests', lambda _1, _2: [])
tr = xcodebuild_runner.DeviceXcodeTestRunner(
"fake-app-path", "fake-host-app-path", "fake-out-dir")
self.assertTrue(tr.launch())
def test_tear_down(self):
tr = xcodebuild_runner.DeviceXcodeTestRunner(
"fake-app-path", "fake-host-app-path", "fake-out-dir")
tr.tear_down()
if __name__ == '__main__':
logging.basicConfig(
format='[%(asctime)s:%(levelname)s] %(message)s',
level=logging.DEBUG,
datefmt='%I:%M:%S')
unittest.main()