1#!/usr/bin/env vpython3 2# Copyright 2022 The Chromium Authors 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5"""File for testing compatible_utils.py.""" 6 7import io 8import json 9import os 10import stat 11import tempfile 12import unittest 13import unittest.mock as mock 14 15import compatible_utils 16 17# Allow access to constants for testing. 18# pylint: disable=protected-access 19 20@unittest.skipIf(os.name == 'nt', 'Fuchsia tests not supported on Windows') 21class CompatibleUtilsTest(unittest.TestCase): 22 """Test compatible_utils.py methods.""" 23 24 def test_running_unattended_returns_true_if_headless_set(self) -> None: 25 """Test |running_unattended| returns True if CHROME_HEADLESS is set.""" 26 with mock.patch('os.environ', {compatible_utils._CHROME_HEADLESS: 0}): 27 self.assertTrue(compatible_utils.running_unattended()) 28 29 with mock.patch('os.environ', {'FOO_HEADLESS': 0}): 30 self.assertFalse(compatible_utils.running_unattended()) 31 32 def test_get_host_arch(self) -> None: 33 """Test |get_host_arch| gets the host architecture and throws 34 exceptions on errors.""" 35 supported_arches = ['x86_64', 'AMD64', 'aarch64'] 36 with mock.patch('platform.machine', side_effect=supported_arches): 37 self.assertEqual(compatible_utils.get_host_arch(), 'x64') 38 self.assertEqual(compatible_utils.get_host_arch(), 'x64') 39 self.assertEqual(compatible_utils.get_host_arch(), 'arm64') 40 41 with mock.patch('platform.machine', return_value=['fake-arch']), \ 42 self.assertRaises(NotImplementedError): 43 compatible_utils.get_host_arch() 44 45 def test_add_exec_to_file(self) -> None: 46 """Test |add_exec_to_file| adds executable bit to file.""" 47 with tempfile.NamedTemporaryFile() as f: 48 original_stat = os.stat(f.name).st_mode 49 self.assertFalse(original_stat & stat.S_IXUSR) 50 51 compatible_utils.add_exec_to_file(f.name) 52 53 new_stat = os.stat(f.name).st_mode 54 self.assertTrue(new_stat & stat.S_IXUSR) 55 56 def test_map_filter_filter_file_throws_value_error_if_wrong_path(self 57 ) -> None: 58 """Test |map_filter_file| throws ValueError if path is missing 59 FILTER_DIR.""" 60 with self.assertRaises(ValueError): 61 compatible_utils.map_filter_file_to_package_file('foo') 62 63 with self.assertRaises(ValueError): 64 compatible_utils.map_filter_file_to_package_file('some/other/path') 65 66 with self.assertRaises(ValueError): 67 compatible_utils.map_filter_file_to_package_file('filters/file') 68 69 # No error. 70 compatible_utils.map_filter_file_to_package_file( 71 'testing/buildbot/filters/some.filter') 72 73 def test_map_filter_filter_replaces_filter_dir_with_pkg_path(self) -> None: 74 """Test |map_filter_file| throws ValueError if path is missing 75 FILTER_DIR.""" 76 self.assertEqual( 77 '/pkg/testing/buildbot/filters/some.filter', 78 compatible_utils.map_filter_file_to_package_file( 79 'foo/testing/buildbot/filters/some.filter')) 80 81 def test_get_sdk_hash_success(self) -> None: 82 """Test |get_sdk_hash| reads product_bundle.json.""" 83 with mock.patch('builtins.open', 84 return_value=io.StringIO( 85 json.dumps({'product_version': '12345'}))): 86 self.assertEqual( 87 compatible_utils.get_sdk_hash( 88 'third_party/fuchsia-sdk/images-internal/sherlock-release/' 89 'smart_display_max_eng_arrested/'), 90 ('smart_display_max_eng_arrested', '12345')) 91 92 def test_get_sdk_hash_normalize_path(self) -> None: 93 """Test |get_sdk_hash| uses path as product.""" 94 with mock.patch('builtins.open', 95 return_value=io.StringIO( 96 json.dumps({'product_version': '23456'}))): 97 self.assertEqual( 98 compatible_utils.get_sdk_hash( 99 'third_party/fuchsia-sdk/images-internal/sherlock-release/' 100 'smart_display_max_eng_arrested'), 101 ('smart_display_max_eng_arrested', '23456')) 102 103 def test_get_sdk_hash_not_found(self) -> None: 104 """Test |get_sdk_hash| fails if the product_bundle.json does not exist. 105 """ 106 with mock.patch('builtins.open', side_effect=IOError()): 107 self.assertRaises(IOError, compatible_utils.get_sdk_hash, 108 'some/image/dir') 109 110 def test_install_symbols(self): 111 """Test |install_symbols|.""" 112 def trim_noop_prefixes(path): 113 """Helper function to trim no-op path name prefixes that are 114 introduced by os.path.realpath on some platforms. These break 115 the unit tests, but have no actual effect on behavior.""" 116 # These must all end in the path separator character for the 117 # string length computation to be correct on all platforms. 118 noop_prefixes = ['/private/'] 119 for prefix in noop_prefixes: 120 if path.startswith(prefix): 121 return path[len(prefix) - 1:] 122 return path 123 124 with tempfile.TemporaryDirectory() as fuchsia_out_dir: 125 build_id = 'test_build_id' 126 symbol_file = os.path.join(fuchsia_out_dir, '.build-id', 127 build_id[:2], build_id[2:] + '.debug') 128 id_path = os.path.join(fuchsia_out_dir, 'ids.txt') 129 try: 130 binary_relpath = 'path/to/binary' 131 with open(id_path, 'w') as f: 132 f.write(f'{build_id} {binary_relpath}') 133 compatible_utils.install_symbols([id_path], fuchsia_out_dir) 134 self.assertTrue(os.path.islink(symbol_file)) 135 self.assertEqual( 136 trim_noop_prefixes(os.path.realpath(symbol_file)), 137 os.path.join(fuchsia_out_dir, binary_relpath)) 138 139 new_binary_relpath = 'path/to/new/binary' 140 with open(id_path, 'w') as f: 141 f.write(f'{build_id} {new_binary_relpath}') 142 compatible_utils.install_symbols([id_path], fuchsia_out_dir) 143 self.assertTrue(os.path.islink(symbol_file)) 144 self.assertEqual( 145 trim_noop_prefixes(os.path.realpath(symbol_file)), 146 os.path.join(fuchsia_out_dir, new_binary_relpath)) 147 finally: 148 os.remove(id_path) 149 150 151 def test_ssh_keys(self): 152 """Ensures the get_ssh_keys won't return a None.""" 153 self.assertIsNotNone(compatible_utils.get_ssh_keys()) 154 155 156 def test_force_running_unattended(self) -> None: 157 """Test |force_running_unattended|.""" 158 # force switching the states twice no matter which state we start in. 159 for _ in range(2): 160 compatible_utils.force_running_attended() 161 self.assertFalse(compatible_utils.running_unattended()) 162 compatible_utils.force_running_unattended() 163 self.assertTrue(compatible_utils.running_unattended()) 164 165 166if __name__ == '__main__': 167 unittest.main() 168