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