0

Update ios/build/bots/scripts to python3

Bug: 1262335
Change-Id: Ie3b32c64ef7369ecd915ae751197e230af0ee275
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3273475
Reviewed-by: Dirk Pranke <dpranke@google.com>
Reviewed-by: Zhaoyang Li <zhaoyangli@chromium.org>
Commit-Queue: Matt Reichhoff <mreichhoff@chromium.org>
Cr-Commit-Position: refs/heads/main@{#942247}
This commit is contained in:
Matt Reichhoff
2021-11-16 19:10:34 +00:00
committed by Chromium LUCI CQ
parent 5b70019f42
commit 165bb2e839
21 changed files with 128 additions and 86 deletions

@ -15,7 +15,13 @@ def _RunTestRunnerUnitTests(input_api, output_api):
files = ['.*_test.py$']
return input_api.canned_checks.RunUnitTestsInDirectory(
input_api, output_api, '.', files_to_check=files)
input_api,
output_api,
'.',
files_to_check=files,
run_on_python2=not USE_PYTHON3,
run_on_python3=USE_PYTHON3,
skip_shebang_check=True)
def CheckChange(input_api, output_api):

@ -123,7 +123,7 @@ class GTestResult(object):
self._crashed = True
# At most one test can crash the entire app in a given parsing.
for test, log_lines in self._failed_tests.iteritems():
for test, log_lines in self._failed_tests.items():
# A test with no output would have crashed. No output is replaced
# by the GTestLogParser by a sentence indicating non-completion.
if 'Did not complete.' in log_lines:
@ -131,7 +131,7 @@ class GTestResult(object):
self._crashed_test = test
# A test marked as flaky may also have crashed the app.
for test, log_lines in self._flaked_tests.iteritems():
for test, log_lines in self._flaked_tests.items():
if 'Did not complete.' in log_lines:
self._crashed = True
self._crashed_test = test

@ -18,7 +18,9 @@ def _compose_simulator_name(platform, version):
def get_simulator_list():
"""Gets list of available simulator as a dictionary."""
return json.loads(subprocess.check_output(['xcrun', 'simctl', 'list', '-j']))
return json.loads(
subprocess.check_output(['xcrun', 'simctl', 'list',
'-j']).decode('utf-8'))
def get_simulator(platform, version):
@ -127,7 +129,8 @@ def create_device_by_platform_and_version(platform, version):
runtime = get_simulator_runtime_by_version(simulators, version)
try:
udid = subprocess.check_output(
['xcrun', 'simctl', 'create', name, device_type, runtime]).rstrip()
['xcrun', 'simctl', 'create', name, device_type,
runtime]).decode('utf-8').rstrip()
LOGGER.info('Created simulator in first attempt with UDID: %s', udid)
# Sometimes above command fails to create a simulator. Verify it and retry
# once if first attempt failed.
@ -135,7 +138,8 @@ def create_device_by_platform_and_version(platform, version):
# Try to delete once to avoid duplicate in case of race condition.
delete_simulator_by_udid(udid)
udid = subprocess.check_output(
['xcrun', 'simctl', 'create', name, device_type, runtime]).rstrip()
['xcrun', 'simctl', 'create', name, device_type,
runtime]).decode('utf-8').rstrip()
LOGGER.info('Created simulator in second attempt with UDID: %s', udid)
return udid
except subprocess.CalledProcessError as e:
@ -152,7 +156,7 @@ def delete_simulator_by_udid(udid):
LOGGER.info('Deleting simulator %s', udid)
try:
subprocess.check_output(['xcrun', 'simctl', 'delete', udid],
stderr=subprocess.STDOUT)
stderr=subprocess.STDOUT).decode('utf-8')
except subprocess.CalledProcessError as e:
# Logging error instead of throwing so we don't cause failures in case
# this was indeed failing to clean up.
@ -188,7 +192,7 @@ def get_home_directory(platform, version):
"""
return subprocess.check_output(
['xcrun', 'simctl', 'getenv',
get_simulator(platform, version), 'HOME']).rstrip()
get_simulator(platform, version), 'HOME']).decode('utf-8').rstrip()
def boot_simulator_if_not_booted(sim_udid):
@ -207,7 +211,8 @@ def boot_simulator_if_not_booted(sim_udid):
continue
if device['state'] == 'Booted':
return
subprocess.check_output(['xcrun', 'simctl', 'boot', sim_udid])
subprocess.check_output(['xcrun', 'simctl', 'boot',
sim_udid]).decode('utf-8')
return
raise test_runner.SimulatorNotFoundError(
'Not found simulator with "%s" UDID in devices %s' %
@ -223,7 +228,7 @@ def get_app_data_directory(app_bundle_id, sim_udid):
"""
return subprocess.check_output(
['xcrun', 'simctl', 'get_app_container', sim_udid, app_bundle_id,
'data']).rstrip()
'data']).decode('utf-8').rstrip()
def is_device_with_udid_simulator(device_udid):

@ -166,7 +166,7 @@ class GetiOSSimUtil(test_runner_test.TestCase):
@mock.patch('subprocess.check_output', autospec=True)
def test_create_device_by_platform_and_version(self, subprocess_mock, _):
"""Ensures that command is correct."""
subprocess_mock.return_value = 'NEW_UDID'
subprocess_mock.return_value = b'NEW_UDID'
self.assertEqual(
'NEW_UDID',
iossim_util.create_device_by_platform_and_version(
@ -195,7 +195,7 @@ class GetiOSSimUtil(test_runner_test.TestCase):
@mock.patch('subprocess.check_output', autospec=True)
def test_get_home_directory(self, subprocess_mock, _):
"""Ensures that command is correct."""
subprocess_mock.return_value = 'HOME_DIRECTORY'
subprocess_mock.return_value = b'HOME_DIRECTORY'
self.assertEqual('HOME_DIRECTORY',
iossim_util.get_home_directory('iPhone 11', '13.2.2'))
self.assertEqual([

@ -9,6 +9,7 @@ import json
import logging
import os
import requests
import sys
LOGGER = logging.getLogger(__name__)
# VALID_STATUSES is a list of valid status values for test_result['status'].
@ -71,10 +72,17 @@ def _compose_test_result(test_id,
} for name in file_artifacts
}
if test_log:
message = ''
if sys.version_info.major < 3:
message = base64.b64encode(test_log)
else:
# Python3 b64encode takes and returns bytes. The result must be
# serializable in order for the eventual json.dumps to succeed
message = base64.b64encode(test_log.encode('utf-8')).decode('utf-8')
test_result['summaryHtml'] = '<text-artifact artifact-id="Test Log" />'
test_result['artifacts'].update({
'Test Log': {
'contents': base64.b64encode(test_log)
'contents': message
},
})
if not test_result['artifacts']:

@ -62,7 +62,8 @@ class UnitTest(unittest.TestCase):
'summaryHtml': '<text-artifact artifact-id="Test Log" />',
'artifacts': {
'Test Log': {
'contents': base64.b64encode(short_log)
'contents':
base64.b64encode(short_log.encode('utf-8')).decode('utf-8')
},
'name': {
'filePath': '/path/to/name'
@ -89,7 +90,9 @@ class UnitTest(unittest.TestCase):
'summaryHtml': '<text-artifact artifact-id="Test Log" />',
'artifacts': {
'Test Log': {
'contents': base64.b64encode(len_4128_str)
'contents':
base64.b64encode(len_4128_str.encode('utf-8')
).decode('utf-8')
},
},
'tags': [],

@ -283,6 +283,7 @@ class RunnerInstallXcodeTest(test_runner_test.TestCase):
self.runner.args.xcode_build_version = 'testXcodeVersion'
self.runner.args.runtime_cache_prefix = 'test/runtime-ios-'
self.runner.args.version = '14.4'
self.runner.args.out_dir = 'out/dir'
@mock.patch('test_runner.defaults_delete')
@mock.patch('json.dump')

@ -7,6 +7,7 @@ import logging
import os
import re
import subprocess
import sys
import test_runner_errors
@ -119,7 +120,7 @@ def fetch_test_names_for_release(stdout):
//build/scripts/slave/recipe_modules/ios/api.py
Args:
stdout: (string) response of 'otool -ov'
stdout: (bytes) response of 'otool -ov'
Returns:
(list) a list of (TestCase, testMethod), containing disabled tests.
@ -130,6 +131,10 @@ def fetch_test_names_for_release(stdout):
# 1. Parse test class names.
# 2. If they are not in ignored list, parse test method names.
# 3. Calculate test count per test class.
# |stdout| will be bytes on python3, and therefore must be decoded prior
# to running a regex.
if sys.version_info.major == 3:
stdout = stdout.decode('utf-8')
res = re.split(TEST_CLASS_RELEASE_APP_PATTERN, stdout)
# Ignore 1st element in split since it does not have any test class data
test_classes_output = res[1:]
@ -163,16 +168,18 @@ def fetch_test_names_for_debug(stdout):
format of (TestCase, testMethod) including disabled tests, in debug app.
Args:
stdout: (string) response of 'otool -ov'
stdout: (bytes) response of 'otool -ov'
Returns:
(list) a list of (TestCase, testMethod), containing disabled tests.
"""
test_names = TEST_NAMES_DEBUG_APP_PATTERN.findall(stdout.decode('utf-8'))
# |stdout| will be bytes on python3, and therefore must be decoded prior
# to running a regex.
if sys.version_info.major == 3:
stdout = stdout.decode('utf-8')
test_names = TEST_NAMES_DEBUG_APP_PATTERN.findall(stdout)
test_names = list(
map(
lambda test_name: (test_name[0].encode('utf-8'), test_name[1].encode(
'utf-8')), test_names))
map(lambda test_name: (test_name[0], test_name[1]), test_names))
return list(
filter(lambda test_name: test_name[0] not in IGNORED_CLASSES, test_names))

@ -27,7 +27,7 @@ DEBUG_APP_OTOOL_OUTPUT = '\n'.join([
'imp 0x1075e6887 -[ToolBarTestCase testH]',
'imp 0x1075e6887 -[ToolBarTestCase DISABLED_testI]',
'imp 0x1075e6887 -[ToolBarTestCase FLAKY_testJ]', 'version 0'
])
]).encode('utf-8')
# Debug app otool output format in Xcode 11.4 toolchain.
DEBUG_APP_OTOOL_OUTPUT_114 = '\n'.join([
@ -49,7 +49,7 @@ DEBUG_APP_OTOOL_OUTPUT_114 = '\n'.join([
' imp 0x1075e6887 -[ToolBarTestCase testH]',
' imp 0x1075e6887 -[ToolBarTestCase DISABLED_testI]',
' imp 0x1075e6887 -[ToolBarTestCase FLAKY_testJ]', 'version 0'
])
]).encode('utf-8')
RELEASE_APP_OTOOL_OUTPUT = '\n'.join([
'Meta Class', 'name 0x1064b8438 CacheTestCase',
@ -73,7 +73,7 @@ RELEASE_APP_OTOOL_OUTPUT = '\n'.join([
'name 0x1075e6887 testG', 'name 0x1075e6887 testH',
'name 0x1075e6887 DISABLED_testI', 'name 0x1075e6887 FLAKY_testJ',
'name 0x1064b8438 ToolBarTestCase', 'baseProtocols 0x0', 'version 0'
])
]).encode('utf-8')
RELEASE_APP_OTOOL_OUTPUT_CLASS_NOT_IN_PAIRS = '\n'.join([
'Meta Class', 'name 0x1064b8438 CacheTestCase',
@ -96,7 +96,7 @@ RELEASE_APP_OTOOL_OUTPUT_CLASS_NOT_IN_PAIRS = '\n'.join([
'name 0x1075e6887 testG', 'name 0x1075e6887 testH',
'name 0x1075e6887 DISABLED_testI', 'name 0x1075e6887 FLAKY_testJ',
'name 0x1064b8438 ToolBarTestCase', 'baseProtocols 0x0', 'version 0'
])
]).encode('utf-8')
# Release app otool output format in Xcode 11.4 toolchain.
RELEASE_APP_OTOOL_OUTPUT_114 = '\n'.join([
@ -123,7 +123,7 @@ RELEASE_APP_OTOOL_OUTPUT_114 = '\n'.join([
' name 0x1075e6887 DISABLED_testI',
' name 0x1075e6887 FLAKY_testJ',
' name 0x1064b8438 ToolBarTestCase', 'baseProtocols 0x0', 'version 0'
])
]).encode('utf-8')
class TestShardUtil(unittest.TestCase):
@ -179,13 +179,14 @@ class TestShardUtil(unittest.TestCase):
for test_name in expected_test_names:
self.assertTrue(test_name in resp)
test_cases = map(lambda (test_case, test_method): test_case, resp)
test_cases = [test_case for (test_case, _) in resp]
# ({'CacheTestCase': 3, 'TabUITestCase': 2, 'PasswordsTestCase': 1,
# 'KeyboardTestCase': 1, 'ToolBarTestCase': 3})
counts = collections.Counter(test_cases).most_common()
name, _ = counts[0]
self.assertEqual(name, 'ToolBarTestCase')
# CacheTestCase and ToolBarTestCase each have 3 entries.
# In case of ties, most_common() returns the first encountered at index 0.
self.assertEqual(name, 'CacheTestCase')
def test_fetch_test_counts_release(self):
"""Ensures that the release output is formatted correctly"""
@ -207,7 +208,7 @@ class TestShardUtil(unittest.TestCase):
for test_name in expected_test_names:
self.assertTrue(test_name in resp)
test_cases = map(lambda (test_case, test_method): test_case, resp)
test_cases = [test_case for (test_case, _) in resp]
# ({'KeyboardTest': 3, 'CacheTestCase': 3,
# 'ToolBarTestCase': 4})
counts = collections.Counter(test_cases).most_common()
@ -243,13 +244,15 @@ class TestShardUtil(unittest.TestCase):
for test_name in expected_test_names:
self.assertTrue(test_name in resp)
test_cases = map(lambda (test_case, test_method): test_case, resp)
test_cases = [test_case for (test_case, _) in resp]
# ({'CacheTestCase': 3, 'TabUITestCase': 2, 'PasswordsTestCase': 1,
# 'KeyboardTestCase': 1, 'ToolBarTestCase': 3})
counts = collections.Counter(test_cases).most_common()
name, _ = counts[0]
self.assertEqual(name, 'ToolBarTestCase')
# CacheTestCase and ToolBarTestCase each have 3 entries.
# In case of ties, most_common() returns the first encountered at index 0.
self.assertEqual(name, 'CacheTestCase')
def test_fetch_test_counts_release_114(self):
"""Test the release output from otool in Xcode 11.4"""
@ -271,7 +274,7 @@ class TestShardUtil(unittest.TestCase):
for test_name in expected_test_names:
self.assertTrue(test_name in resp)
test_cases = map(lambda (test_case, test_method): test_case, resp)
test_cases = [test_case for (test_case, _) in resp]
# ({'KeyboardTest': 3, 'CacheTestCase': 3,
# 'ToolBarTestCase': 4})
counts = collections.Counter(test_cases).most_common()
@ -281,7 +284,7 @@ class TestShardUtil(unittest.TestCase):
def test_balance_into_sublists_debug(self):
"""Ensure the balancing algorithm works"""
resp = shard_util.fetch_test_names_for_debug(DEBUG_APP_OTOOL_OUTPUT)
test_cases = map(lambda (test_case, test_method): test_case, resp)
test_cases = [test_case for (test_case, _) in resp]
test_counts = collections.Counter(test_cases)
sublists_1 = shard_util.balance_into_sublists(test_counts, 1)
@ -304,7 +307,7 @@ class TestShardUtil(unittest.TestCase):
def test_balance_into_sublists_release(self):
"""Ensure the balancing algorithm works"""
resp = shard_util.fetch_test_names_for_release(RELEASE_APP_OTOOL_OUTPUT)
test_cases = map(lambda (test_case, test_method): test_case, resp)
test_cases = [test_case for (test_case, _) in resp]
test_counts = collections.Counter(test_cases)
sublists_3 = shard_util.balance_into_sublists(test_counts, 3)

@ -49,7 +49,7 @@ def get_bundle_id(app_path):
'-c',
'Print:CFBundleIdentifier',
os.path.join(app_path, 'Info.plist'),
]).rstrip().decode("utf-8")
]).decode("utf-8").rstrip()
def is_running_rosetta():
@ -61,7 +61,7 @@ def is_running_rosetta():
running on an Intel machine.
"""
translated = subprocess.check_output(
['sysctl', '-i', '-b', 'sysctl.proc_translated'])
['sysctl', '-i', '-b', 'sysctl.proc_translated']).decode('utf-8')
# "sysctl -b" is expected to return a 4-byte integer response. 1 means the
# current process is running under Rosetta, 0 means it is not. On x86_64
# machines, this variable does not exist at all, so "-i" is used to return a

@ -400,9 +400,9 @@ class ResultCollection(object):
logs['flaked tests'] = flaked
if failed:
logs['failed tests'] = failed
for test, log_lines in failed.iteritems():
for test, log_lines in failed.items():
logs[test] = log_lines
for test, log_lines in flaked.iteritems():
for test, log_lines in flaked.items():
logs[test] = log_lines
return logs

@ -39,13 +39,12 @@ class UtilTest(test_runner_test.TestCase):
"""Tests _validate_kwargs."""
with self.assertRaises(AssertionError) as context:
TestResult('name', TestStatus.PASS, unknown='foo')
expected_message = (
'Invalid keyword argument(s) in set([\'unknown\']) passed in!')
expected_message = ("Invalid keyword argument(s) in {'unknown'} passed in!")
self.assertTrue(expected_message in str(context.exception))
with self.assertRaises(AssertionError) as context:
ResultCollection(test_log='foo')
expected_message = (
'Invalid keyword argument(s) in set([\'test_log\']) passed in!')
"Invalid keyword argument(s) in {'test_log'} passed in!")
self.assertTrue(expected_message in str(context.exception))
def test_validate_test_status(self):

@ -148,9 +148,9 @@ def get_device_ios_version(udid):
Returns:
Device UDID.
"""
return subprocess.check_output(['ideviceinfo',
'--udid', udid,
'-k', 'ProductVersion']).strip()
return subprocess.check_output(
['ideviceinfo', '--udid', udid, '-k',
'ProductVersion']).decode('utf-8').strip()
def defaults_write(d, key, value):
@ -254,6 +254,10 @@ def print_process_output(proc,
timer.cancel()
if not line:
break
# |line| will be bytes on python3, and therefore must be decoded prior
# to rstrip.
if sys.version_info.major == 3:
line = line.decode('utf-8')
line = line.rstrip()
out.append(line)
if parser:
@ -263,9 +267,6 @@ def print_process_output(proc,
if parser:
parser.Finalize()
if sys.version_info.major == 3:
for index in range(len(out)):
out[index] = out[index].decode('utf-8')
LOGGER.debug('Finished print_process_output.')
return out
@ -282,7 +283,8 @@ def get_current_xcode_info():
try:
out = subprocess.check_output(['xcodebuild', '-version']).splitlines()
version, build_version = out[0].split(' ')[-1], out[1].split(' ')[-1]
path = subprocess.check_output(['xcode-select', '--print-path']).rstrip()
path = subprocess.check_output(['xcode-select',
'--print-path']).decode('utf-8').rstrip()
except subprocess.CalledProcessError:
version = build_version = path = None
@ -368,7 +370,8 @@ class TestRunner(object):
"""removes any proxy settings which may remain from a previous run."""
LOGGER.info('Removing any proxy settings.')
network_services = subprocess.check_output(
['networksetup', '-listallnetworkservices']).strip().split('\n')
['networksetup',
'-listallnetworkservices']).decode('utf-8').strip().split('\n')
if len(network_services) > 1:
# We ignore the first line as it is a description of the command's output.
network_services = network_services[1:]
@ -610,7 +613,7 @@ class TestRunner(object):
if self.retries and never_expected_tests:
LOGGER.warning('%s tests failed and will be retried.\n',
len(never_expected_tests))
for i in xrange(self.retries):
for i in range(self.retries):
tests_to_retry = list(overall_result.never_expected_tests())
for test in tests_to_retry:
LOGGER.info('Retry #%s for %s.\n', i + 1, test)
@ -761,9 +764,10 @@ class SimulatorTestRunner(TestRunner):
if os.path.exists(docs_dir) and os.path.exists(metadata_plist):
cfbundleid = subprocess.check_output([
'/usr/libexec/PlistBuddy',
'-c', 'Print:MCMMetadataIdentifier',
'-c',
'Print:MCMMetadataIdentifier',
metadata_plist,
]).rstrip()
]).decode('utf-8').rstrip()
if cfbundleid == self.cfbundleid:
shutil.copytree(docs_dir, os.path.join(self.out_dir, 'Documents'))
return
@ -917,7 +921,8 @@ class DeviceTestRunner(TestRunner):
"""
super(DeviceTestRunner, self).__init__(app_path, out_dir, **kwargs)
self.udid = subprocess.check_output(['idevice_id', '--list']).rstrip()
self.udid = subprocess.check_output(['idevice_id',
'--list']).decode('utf-8').rstrip()
if len(self.udid.splitlines()) != 1:
raise DeviceDetectionError(self.udid)

@ -47,7 +47,7 @@ class TestCase(unittest.TestCase):
super(TestCase, self).tearDown(*args, **kwargs)
for obj in self._mocks:
for member, original_value in self._mocks[obj].iteritems():
for member, original_value in self._mocks[obj].items():
setattr(obj, member, original_value)
@ -281,8 +281,8 @@ class DeviceTestRunnerTest(TestCase):
self.mock(test_runner, 'get_current_xcode_info', lambda: {
'version': 'test version', 'build': 'test build', 'path': 'test/path'})
self.mock(test_runner, 'install_xcode', install_xcode)
self.mock(test_runner.subprocess, 'check_output',
lambda _: 'fake-bundle-id')
self.mock(test_runner.subprocess,
'check_output', lambda _: b'fake-bundle-id')
self.mock(os.path, 'abspath', lambda path: '/abs/path/to/%s' % path)
self.mock(os.path, 'exists', lambda _: True)
self.mock(os, 'listdir', lambda _: [])

@ -380,7 +380,8 @@ class WprProxySimulatorTestRunner(test_runner.SimulatorTestRunner):
# We route all network adapters through the proxy, since it is easier than
# determining which network adapter is being used currently.
network_services = subprocess.check_output(
['networksetup', '-listallnetworkservices']).strip().split('\n')
['networksetup',
'-listallnetworkservices']).decode('utf-8').strip().split('\n')
if len(network_services) > 1:
# We ignore the first line as it is a description of the command's output.
network_services = network_services[1:]

@ -24,8 +24,8 @@ class WprProxySimulatorTestRunnerTest(test_runner_test.TestCase):
self.mock(test_runner, 'get_current_xcode_info', lambda: {
'version': 'test version', 'build': 'test build', 'path': 'test/path'})
self.mock(test_runner.subprocess, 'check_output',
lambda _: 'fake-bundle-id')
self.mock(test_runner.subprocess,
'check_output', lambda _: b'fake-bundle-id')
self.mock(os.path, 'abspath', lambda path: '/abs/path/to/%s' % path)
self.mock(os.path, 'exists', lambda _: True)
self.mock(test_runner.TestRunner, 'set_sigterm_handler',
@ -113,14 +113,14 @@ class WprProxySimulatorTestRunnerTest(test_runner_test.TestCase):
def __init__(self):
self.line_index = 0
self.lines = [
'Test Case \'-[a 1]\' started.',
'Test Case \'-[a 1]\' has uninteresting logs.',
'Test Case \'-[a 1]\' passed (0.1 seconds)',
'Test Case \'-[b 2]\' started.',
'Test Case \'-[b 2]\' passed (0.1 seconds)',
'Test Case \'-[c 3]\' started.',
'Test Case \'-[c 3]\' has interesting failure info.',
'Test Case \'-[c 3]\' failed (0.1 seconds)',
b'Test Case \'-[a 1]\' started.',
b'Test Case \'-[a 1]\' has uninteresting logs.',
b'Test Case \'-[a 1]\' passed (0.1 seconds)',
b'Test Case \'-[b 2]\' started.',
b'Test Case \'-[b 2]\' passed (0.1 seconds)',
b'Test Case \'-[c 3]\' started.',
b'Test Case \'-[c 3]\' has interesting failure info.',
b'Test Case \'-[c 3]\' failed (0.1 seconds)',
]
def readline(self):

@ -169,7 +169,7 @@ class Xcode11LogParser(object):
id_params = ['--id', ref_id] if ref_id else []
xcresult_command = ['xcresulttool', 'get', '--format', 'json',
'--path', xcresult_path] + id_params
return subprocess.check_output(xcresult_command).strip()
return subprocess.check_output(xcresult_command).decode('utf-8').strip()
@staticmethod
def _list_of_failed_tests(actions_invocation_record, excluded=None):
@ -388,7 +388,7 @@ class Xcode11LogParser(object):
test['identifier']
['_value']] = test['summaryRef']['id']['_value']
for test, summary_ref_id in test_summary_refs.iteritems():
for test, summary_ref_id in test_summary_refs.items():
# See SINGLE_TEST_SUMMARY_REF in xcode_log_parser_test.py for an example
# of |test_summary|.
test_summary = json.loads(
@ -457,7 +457,7 @@ class Xcode11LogParser(object):
'xcresulttool', 'export', '--type', output_type, '--id', ref_id,
'--path', xcresult, '--output-path', output_path
]
subprocess.check_output(export_command).strip()
subprocess.check_output(export_command).decode('utf-8').strip()
@staticmethod
def _extract_attachments(test,

@ -85,7 +85,7 @@ XCRESULT_ROOT = """
}
}"""
REF_ID = """
REF_ID = b"""
{
"actions": {
"_values": [{
@ -435,7 +435,7 @@ class XCode11LogParserTest(test_runner_test.TestCase):
@mock.patch('subprocess.check_output', autospec=True)
def testXcresulttoolGetRoot(self, mock_process):
mock_process.return_value = '%JSON%'
mock_process.return_value = b'%JSON%'
xcode_log_parser.Xcode11LogParser()._xcresulttool_get('xcresult_path')
self.assertTrue(
os.path.join(XCODE11_DICT['path'], 'usr', 'bin') in os.environ['PATH'])
@ -445,7 +445,7 @@ class XCode11LogParserTest(test_runner_test.TestCase):
@mock.patch('subprocess.check_output', autospec=True)
def testXcresulttoolGetRef(self, mock_process):
mock_process.side_effect = [REF_ID, 'JSON']
mock_process.side_effect = [REF_ID, b'JSON']
xcode_log_parser.Xcode11LogParser()._xcresulttool_get('xcresult_path',
'testsRef')
self.assertEqual(

@ -32,7 +32,8 @@ def _using_new_mac_toolchain(mac_toolchain):
mac_toolchain,
'help',
]
output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
output = subprocess.check_output(
cmd, stderr=subprocess.STDOUT).decode('utf-8')
# "install-runtime" presents as a command line switch in help output in the
# new mac_toolchain.
@ -181,12 +182,14 @@ def select(xcode_app_path):
xcode_app_path,
]
LOGGER.debug('Selecting XCode with command %s and "xcrun simctl list".' % cmd)
output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
output = subprocess.check_output(
cmd, stderr=subprocess.STDOUT).decode('utf-8')
# This is to avoid issues caused by mixed usage of different Xcode versions on
# one machine.
xcrun_simctl_cmd = ['xcrun', 'simctl', 'list']
output += subprocess.check_output(xcrun_simctl_cmd, stderr=subprocess.STDOUT)
output += subprocess.check_output(
xcrun_simctl_cmd, stderr=subprocess.STDOUT).decode('utf-8')
return output
@ -316,15 +319,16 @@ def version():
]
LOGGER.debug('Checking XCode version with command: %s' % cmd)
output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
output = subprocess.check_output(
cmd, stderr=subprocess.STDOUT).decode('utf-8')
output = output.splitlines()
# output sample:
# Xcode 12.0
# Build version 12A6159
LOGGER.info(output)
version = output[0].decode('UTF-8').split(' ')[1]
build_version = output[1].decode('UTF-8').split(' ')[2].lower()
version = output[0].split(' ')[1]
build_version = output[1].split(' ')[2].lower()
return version, build_version

@ -14,10 +14,10 @@ import test_runner_test
import xcode_util
_XCODEBUILD_VERSION_OUTPUT_12 = """Xcode 12.4
_XCODEBUILD_VERSION_OUTPUT_12 = b"""Xcode 12.4
Build version 12D4e
"""
_XCODEBUILD_VERSION_OUTPUT_13 = """Xcode 13.0
_XCODEBUILD_VERSION_OUTPUT_13 = b"""Xcode 13.0
Build version 13A5155e
"""
@ -189,7 +189,7 @@ class HelperFunctionTests(XcodeUtilTest):
@mock.patch('subprocess.check_output', autospec=True)
def test_using_new_mac_toolchain(self, mock_check_output):
mock_check_output.return_value = """
mock_check_output.return_value = b"""
Mac OS / iOS toolchain management
Usage: mac_toolchain [command] [arguments]
@ -207,7 +207,7 @@ Use "mac_toolchain help [command]" for more information about a command."""
@mock.patch('subprocess.check_output', autospec=True)
def test_using_new_legacy_toolchain(self, mock_check_output):
mock_check_output.return_value = """
mock_check_output.return_value = b"""
Mac OS / iOS toolchain management
Usage: mac_toolchain [command] [arguments]

@ -141,8 +141,8 @@ class DeviceXcodeTestRunnerTest(test_runner_test.TestCase):
self.mock(result_sink_util.ResultSinkClient,
'post', lambda *args, **kwargs: None)
self.mock(test_runner.subprocess, 'check_output', lambda _: 'fake-output')
self.mock(test_runner.subprocess, 'check_call', lambda _: 'fake-out')
self.mock(test_runner.subprocess, 'check_output', lambda _: b'fake-output')
self.mock(test_runner.subprocess, 'check_call', lambda _: b'fake-out')
self.mock(test_runner.subprocess,
'Popen', lambda cmd, env, stdout, stderr: 'fake-out')
self.mock(test_runner.TestRunner, 'set_sigterm_handler',