blob: 080cdda0cb4e0319e63ddda43e5e17ba4208d88e [file] [log] [blame]
#!/usr/bin/env vpython3
# Copyright 2022 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""File for testing compatible_utils.py."""
import io
import os
import stat
import tempfile
import unittest
import unittest.mock as mock
import compatible_utils
class CompatibleUtilsTest(unittest.TestCase):
"""Test compatible_utils.py methods."""
def test_running_unattended_returns_true_if_headless_set(self) -> None:
"""Test |running_unattended| returns True if CHROME_HEADLESS is set."""
with mock.patch('os.environ', {'CHROME_HEADLESS': 0}):
self.assertTrue(compatible_utils.running_unattended())
with mock.patch('os.environ', {'FOO_HEADLESS': 0}):
self.assertFalse(compatible_utils.running_unattended())
def test_get_host_arch(self) -> None:
"""Test |get_host_arch| gets the host architecture and throws
exceptions on errors."""
supported_arches = ['x86_64', 'AMD64', 'aarch64']
with mock.patch('platform.machine', side_effect=supported_arches):
self.assertEqual(compatible_utils.get_host_arch(), 'x64')
self.assertEqual(compatible_utils.get_host_arch(), 'x64')
self.assertEqual(compatible_utils.get_host_arch(), 'arm64')
with mock.patch('platform.machine', return_value=['fake-arch']), \
self.assertRaises(NotImplementedError):
compatible_utils.get_host_arch()
def test_add_exec_to_file(self) -> None:
"""Test |add_exec_to_file| adds executable bit to file."""
with tempfile.NamedTemporaryFile() as f:
original_stat = os.stat(f.name).st_mode
self.assertFalse(original_stat & stat.S_IXUSR)
compatible_utils.add_exec_to_file(f.name)
new_stat = os.stat(f.name).st_mode
self.assertTrue(new_stat & stat.S_IXUSR)
# pylint: disable=no-self-use
def test_pave_adds_exec_to_binary_files(self) -> None:
"""Test |pave| calls |add_exec_to_file| on necessary files."""
with mock.patch('os.path.exists', return_value=True), \
mock.patch('compatible_utils.add_exec_to_file') as mock_exec, \
mock.patch('platform.machine', return_value='x86_64'), \
mock.patch('subprocess.run'):
compatible_utils.pave('some/path/to/dir', 'some-target')
mock_exec.assert_has_calls([
mock.call('some/path/to/dir/pave.sh'),
mock.call('some/path/to/dir/host_x64/bootserver')
],
any_order=True)
def test_pave_adds_exec_to_binary_files_if_pb_set_not_found(self) -> None:
"""Test |pave| calls |add_exec_to_file| on necessary files.
Checks if current product-bundle files exist. If not, defaults to
prebuilt-images set.
"""
with mock.patch('os.path.exists', return_value=False), \
mock.patch('compatible_utils.add_exec_to_file') as mock_exec, \
mock.patch('platform.machine', return_value='x86_64'), \
mock.patch('subprocess.run'):
compatible_utils.pave('some/path/to/dir', 'some-target')
mock_exec.assert_has_calls([
mock.call('some/path/to/dir/pave.sh'),
mock.call('some/path/to/dir/bootserver.exe.linux-x64')
],
any_order=True)
def test_pave_adds_target_id_if_given(self) -> None:
"""Test |pave| adds target-id to the arguments."""
with mock.patch('os.path.exists', return_value=False), \
mock.patch('compatible_utils.add_exec_to_file'), \
mock.patch('platform.machine', return_value='x86_64'), \
mock.patch('compatible_utils.get_ssh_keys',
return_value='authorized-keys-file'), \
mock.patch('subprocess.run') as mock_subproc:
mock_subproc.reset_mock()
compatible_utils.pave('some/path/to/dir', 'some-target')
mock_subproc.assert_called_once_with([
'some/path/to/dir/pave.sh', '--authorized-keys',
'authorized-keys-file', '-1', '-n', 'some-target'
],
check=True,
text=True,
timeout=300)
# pylint: disable=no-self-use
def test_parse_host_port_splits_address_and_strips_brackets(self) -> None:
"""Test |parse_host_port| splits ipv4 and ipv6 addresses correctly."""
self.assertEqual(compatible_utils.parse_host_port('hostname:55'),
('hostname', 55))
self.assertEqual(compatible_utils.parse_host_port('192.168.42.40:443'),
('192.168.42.40', 443))
self.assertEqual(
compatible_utils.parse_host_port('[2001:db8::1]:8080'),
('2001:db8::1', 8080))
def test_map_filter_filter_file_throws_value_error_if_wrong_path(self
) -> None:
"""Test |map_filter_file| throws ValueError if path is missing
FILTER_DIR."""
with self.assertRaises(ValueError):
compatible_utils.map_filter_file_to_package_file('foo')
with self.assertRaises(ValueError):
compatible_utils.map_filter_file_to_package_file('some/other/path')
with self.assertRaises(ValueError):
compatible_utils.map_filter_file_to_package_file('filters/file')
# No error.
compatible_utils.map_filter_file_to_package_file(
'testing/buildbot/filters/some.filter')
def test_map_filter_filter_replaces_filter_dir_with_pkg_path(self) -> None:
"""Test |map_filter_file| throws ValueError if path is missing
FILTER_DIR."""
self.assertEqual(
'/pkg/testing/buildbot/filters/some.filter',
compatible_utils.map_filter_file_to_package_file(
'foo/testing/buildbot/filters/some.filter'))
def test_get_sdk_hash_fallsback_to_args_file_if_buildargs_dne(self
) -> None:
"""Test |get_sdk_hash| checks if buildargs.gn exists.
If it does not, fallsback to args.gn. This should raise an exception
as it does not exist.
"""
with mock.patch('os.path.exists', return_value=False) as mock_exists, \
self.assertRaises(compatible_utils.VersionNotFoundError):
compatible_utils.get_sdk_hash('some/image/dir')
mock_exists.assert_has_calls([
mock.call('some/image/dir/buildargs.gn'),
mock.call('some/image/dir/args.gn')
])
def test_get_sdk_hash_parse_contents_of_args_file(self) -> None:
"""Test |get_sdk_hash| parses buildargs contents correctly."""
build_args_test_contents = """
build_info_board = "chromebook-x64"
build_info_product = "workstation_eng"
build_info_version = "10.20221114.2.1"
universe_package_labels += []
"""
with mock.patch('os.path.exists', return_value=True), \
mock.patch('builtins.open',
return_value=io.StringIO(build_args_test_contents)):
self.assertEqual(compatible_utils.get_sdk_hash('some/dir'),
('workstation_eng', '10.20221114.2.1'))
def test_get_sdk_hash_raises_error_if_keys_missing(self) -> None:
"""Test |get_sdk_hash| raises VersionNotFoundError if missing keys"""
build_args_test_contents = """
import("//boards/chromebook-x64.gni")
import("//products/workstation_eng.gni")
cxx_rbe_enable = true
host_labels += [ "//bundles/infra/build" ]
universe_package_labels += []
"""
with mock.patch('os.path.exists', return_value=True), \
mock.patch(
'builtins.open',
return_value=io.StringIO(build_args_test_contents)), \
self.assertRaises(compatible_utils.VersionNotFoundError):
compatible_utils.get_sdk_hash('some/dir')
def test_get_sdk_hash_raises_error_if_contents_empty(self) -> None:
"""Test |get_sdk_hash| raises VersionNotFoundError if no contents."""
with mock.patch('os.path.exists', return_value=True), \
mock.patch('builtins.open', return_value=io.StringIO("")), \
self.assertRaises(compatible_utils.VersionNotFoundError):
compatible_utils.get_sdk_hash('some/dir')
def test_find_in_dir_returns_file_or_dir_if_searching(self) -> None:
"""Test |find_in_dir| returns files if searching for file, or None."""
# Make the directory structure.
with tempfile.TemporaryDirectory() as tmp_dir:
with tempfile.NamedTemporaryFile(dir=tmp_dir) as tmp_file, \
tempfile.TemporaryDirectory(dir=tmp_dir) as inner_tmp_dir:
# Structure is now:
# temp_dir/
# temp_dir/inner_dir1
# temp_dir/tempfile1
self.assertEqual(
compatible_utils.find_in_dir(
os.path.basename(tmp_file.name),
parent_dir=tmp_dir,
search_for_dir=False), tmp_file.name)
# File is not a dir, so returns None.
self.assertIsNone(
compatible_utils.find_in_dir(os.path.basename(
tmp_file.name),
parent_dir=tmp_dir,
search_for_dir=True))
# Repeat for directory.
self.assertEqual(
compatible_utils.find_in_dir(inner_tmp_dir,
parent_dir=tmp_dir,
search_for_dir=True),
inner_tmp_dir)
self.assertIsNone(
compatible_utils.find_in_dir(inner_tmp_dir,
parent_dir=tmp_dir,
search_for_dir=False))
with tempfile.NamedTemporaryFile(
dir=inner_tmp_dir) as inner_tmp_file:
self.assertEqual(
compatible_utils.find_in_dir(
os.path.basename(inner_tmp_file.name),
parent_dir=tmp_dir,
search_for_dir=False), inner_tmp_file.name)
self.assertEqual(
compatible_utils.find_in_dir(
os.path.basename(inner_tmp_file.name),
parent_dir=inner_tmp_dir,
search_for_dir=False), inner_tmp_file.name)
def test_find_image_in_sdk_searches_images_in_product_bundle(self):
"""Test |find_image_in_sdk| searches for 'images' if product-bundle."""
with tempfile.TemporaryDirectory() as tmp_dir:
os.makedirs(os.path.join(tmp_dir, 'images', 'workstation-product',
'images'),
exist_ok=True)
self.assertEqual(
compatible_utils.find_image_in_sdk('workstation-product',
product_bundle=True,
sdk_root=tmp_dir),
os.path.join(tmp_dir, 'images', 'workstation-product',
'images'))
def test_find_image_in_sdk_searches_images_in_prebuilt(self):
"""Test |find_image_in_sdk| searches dir if not product-bundle."""
with tempfile.TemporaryDirectory() as tmp_dir:
os.makedirs(os.path.join(tmp_dir, 'images-internal',
'chromebook-x64', 'workstation_eng'),
exist_ok=True)
self.assertEqual(
compatible_utils.find_image_in_sdk(
'workstation_eng.chromebook-x64',
product_bundle=False,
sdk_root=tmp_dir),
os.path.join(tmp_dir, 'images-internal', 'chromebook-x64',
'workstation_eng'))
if __name__ == '__main__':
unittest.main()