Daniel Norman | 2465fc8 | 2022-03-02 12:01:20 -0800 | [diff] [blame] | 1 | # |
| 2 | # Copyright (C) 2017 The Android Open Source Project |
| 3 | # |
| 4 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | # you may not use this file except in compliance with the License. |
| 6 | # You may obtain a copy of the License at |
| 7 | # |
| 8 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | # |
| 10 | # Unless required by applicable law or agreed to in writing, software |
| 11 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | # See the License for the specific language governing permissions and |
| 14 | # limitations under the License. |
| 15 | # |
| 16 | |
| 17 | import os.path |
| 18 | |
| 19 | import common |
| 20 | import merge_target_files |
| 21 | import merge_utils |
| 22 | import test_utils |
Daniel Norman | 2465fc8 | 2022-03-02 12:01:20 -0800 | [diff] [blame] | 23 | |
| 24 | |
| 25 | class MergeUtilsTest(test_utils.ReleaseToolsTestCase): |
| 26 | |
| 27 | def setUp(self): |
| 28 | self.OPTIONS = merge_target_files.OPTIONS |
Daniel Norman | 2465fc8 | 2022-03-02 12:01:20 -0800 | [diff] [blame] | 29 | |
| 30 | def test_CopyItems_CopiesItemsMatchingPatterns(self): |
| 31 | |
| 32 | def createEmptyFile(path): |
| 33 | if not os.path.exists(os.path.dirname(path)): |
| 34 | os.makedirs(os.path.dirname(path)) |
| 35 | open(path, 'a').close() |
| 36 | return path |
| 37 | |
Dennis Song | 5bfa43e | 2023-03-30 18:28:00 +0800 | [diff] [blame^] | 38 | def createEmptyFolder(path): |
| 39 | os.makedirs(path) |
| 40 | return path |
| 41 | |
Daniel Norman | 2465fc8 | 2022-03-02 12:01:20 -0800 | [diff] [blame] | 42 | def createSymLink(source, dest): |
| 43 | os.symlink(source, dest) |
| 44 | return dest |
| 45 | |
| 46 | def getRelPaths(start, filepaths): |
| 47 | return set( |
Dennis Song | 5bfa43e | 2023-03-30 18:28:00 +0800 | [diff] [blame^] | 48 | os.path.relpath(path=filepath, start=start) |
| 49 | for filepath in filepaths) |
Daniel Norman | 2465fc8 | 2022-03-02 12:01:20 -0800 | [diff] [blame] | 50 | |
| 51 | input_dir = common.MakeTempDir() |
| 52 | output_dir = common.MakeTempDir() |
| 53 | expected_copied_items = [] |
| 54 | actual_copied_items = [] |
Dennis Song | 5bfa43e | 2023-03-30 18:28:00 +0800 | [diff] [blame^] | 55 | patterns = ['*.cpp', 'subdir/*.txt', 'subdir/empty_dir'] |
Daniel Norman | 2465fc8 | 2022-03-02 12:01:20 -0800 | [diff] [blame] | 56 | |
Dennis Song | 5bfa43e | 2023-03-30 18:28:00 +0800 | [diff] [blame^] | 57 | # Create various files and empty directories that we expect to get copied |
| 58 | # because they match one of the patterns. |
Daniel Norman | 2465fc8 | 2022-03-02 12:01:20 -0800 | [diff] [blame] | 59 | expected_copied_items.extend([ |
| 60 | createEmptyFile(os.path.join(input_dir, 'a.cpp')), |
| 61 | createEmptyFile(os.path.join(input_dir, 'b.cpp')), |
| 62 | createEmptyFile(os.path.join(input_dir, 'subdir', 'c.txt')), |
| 63 | createEmptyFile(os.path.join(input_dir, 'subdir', 'd.txt')), |
| 64 | createEmptyFile( |
| 65 | os.path.join(input_dir, 'subdir', 'subsubdir', 'e.txt')), |
Dennis Song | 5bfa43e | 2023-03-30 18:28:00 +0800 | [diff] [blame^] | 66 | createEmptyFolder(os.path.join(input_dir, 'subdir', 'empty_dir')), |
Daniel Norman | 2465fc8 | 2022-03-02 12:01:20 -0800 | [diff] [blame] | 67 | createSymLink('a.cpp', os.path.join(input_dir, 'a_link.cpp')), |
| 68 | ]) |
| 69 | # Create some more files that we expect to not get copied. |
| 70 | createEmptyFile(os.path.join(input_dir, 'a.h')) |
| 71 | createEmptyFile(os.path.join(input_dir, 'b.h')) |
| 72 | createEmptyFile(os.path.join(input_dir, 'subdir', 'subsubdir', 'f.gif')) |
| 73 | createSymLink('a.h', os.path.join(input_dir, 'a_link.h')) |
| 74 | |
| 75 | # Copy items. |
| 76 | merge_utils.CopyItems(input_dir, output_dir, patterns) |
| 77 | |
| 78 | # Assert the actual copied items match the ones we expected. |
Dennis Song | 5bfa43e | 2023-03-30 18:28:00 +0800 | [diff] [blame^] | 79 | for root_dir, dirs, files in os.walk(output_dir): |
Daniel Norman | 2465fc8 | 2022-03-02 12:01:20 -0800 | [diff] [blame] | 80 | actual_copied_items.extend( |
Dennis Song | 5bfa43e | 2023-03-30 18:28:00 +0800 | [diff] [blame^] | 81 | os.path.join(root_dir, filename) for filename in files) |
| 82 | for dirname in dirs: |
| 83 | dir_path = os.path.join(root_dir, dirname) |
| 84 | if not os.listdir(dir_path): |
| 85 | actual_copied_items.append(dir_path) |
Daniel Norman | 2465fc8 | 2022-03-02 12:01:20 -0800 | [diff] [blame] | 86 | self.assertEqual( |
| 87 | getRelPaths(output_dir, actual_copied_items), |
| 88 | getRelPaths(input_dir, expected_copied_items)) |
| 89 | self.assertEqual( |
| 90 | os.readlink(os.path.join(output_dir, 'a_link.cpp')), 'a.cpp') |
| 91 | |
| 92 | def test_ValidateConfigLists_ReturnsFalseIfSharedExtractedPartition(self): |
Daniel Norman | 5f47677 | 2022-03-02 15:46:34 -0800 | [diff] [blame] | 93 | self.OPTIONS.system_item_list = [ |
| 94 | 'SYSTEM/*', |
| 95 | ] |
| 96 | self.OPTIONS.vendor_item_list = [ |
| 97 | 'SYSTEM/my_system_file', |
| 98 | 'VENDOR/*', |
| 99 | ] |
Daniel Norman | 2465fc8 | 2022-03-02 12:01:20 -0800 | [diff] [blame] | 100 | self.OPTIONS.vendor_item_list.append('SYSTEM/my_system_file') |
| 101 | self.assertFalse(merge_utils.ValidateConfigLists()) |
| 102 | |
| 103 | def test_ValidateConfigLists_ReturnsFalseIfSharedExtractedPartitionImage( |
| 104 | self): |
Daniel Norman | 5f47677 | 2022-03-02 15:46:34 -0800 | [diff] [blame] | 105 | self.OPTIONS.system_item_list = [ |
| 106 | 'SYSTEM/*', |
| 107 | ] |
| 108 | self.OPTIONS.vendor_item_list = [ |
| 109 | 'IMAGES/system.img', |
| 110 | 'VENDOR/*', |
| 111 | ] |
Daniel Norman | 2465fc8 | 2022-03-02 12:01:20 -0800 | [diff] [blame] | 112 | self.assertFalse(merge_utils.ValidateConfigLists()) |
| 113 | |
| 114 | def test_ValidateConfigLists_ReturnsFalseIfBadSystemMiscInfoKeys(self): |
| 115 | for bad_key in ['dynamic_partition_list', 'super_partition_groups']: |
Daniel Norman | 5f47677 | 2022-03-02 15:46:34 -0800 | [diff] [blame] | 116 | self.OPTIONS.framework_misc_info_keys = [bad_key] |
Daniel Norman | 2465fc8 | 2022-03-02 12:01:20 -0800 | [diff] [blame] | 117 | self.assertFalse(merge_utils.ValidateConfigLists()) |
| 118 | |
| 119 | def test_ItemListToPartitionSet(self): |
| 120 | item_list = [ |
Daniel Norman | 679242b | 2022-03-18 15:46:27 -0700 | [diff] [blame] | 121 | 'IMAGES/system_ext.img', |
Daniel Norman | 2465fc8 | 2022-03-02 12:01:20 -0800 | [diff] [blame] | 122 | 'META/apexkeys.txt', |
| 123 | 'META/apkcerts.txt', |
| 124 | 'META/filesystem_config.txt', |
| 125 | 'PRODUCT/*', |
| 126 | 'SYSTEM/*', |
Daniel Norman | 679242b | 2022-03-18 15:46:27 -0700 | [diff] [blame] | 127 | 'SYSTEM/system_ext/*', |
Daniel Norman | 2465fc8 | 2022-03-02 12:01:20 -0800 | [diff] [blame] | 128 | ] |
| 129 | partition_set = merge_utils.ItemListToPartitionSet(item_list) |
| 130 | self.assertEqual(set(['product', 'system', 'system_ext']), partition_set) |
Daniel Norman | 5f47677 | 2022-03-02 15:46:34 -0800 | [diff] [blame] | 131 | |
| 132 | def test_InferItemList_Framework(self): |
| 133 | zip_namelist = [ |
Daniel Norman | 679242b | 2022-03-18 15:46:27 -0700 | [diff] [blame] | 134 | 'IMAGES/product.img', |
| 135 | 'IMAGES/product.map', |
| 136 | 'IMAGES/system.img', |
| 137 | 'IMAGES/system.map', |
Daniel Norman | 5f47677 | 2022-03-02 15:46:34 -0800 | [diff] [blame] | 138 | 'SYSTEM/my_system_file', |
| 139 | 'PRODUCT/my_product_file', |
Daniel Norman | 679242b | 2022-03-18 15:46:27 -0700 | [diff] [blame] | 140 | # Device does not use a separate system_ext partition. |
| 141 | 'SYSTEM/system_ext/system_ext_file', |
Daniel Norman | 5f47677 | 2022-03-02 15:46:34 -0800 | [diff] [blame] | 142 | ] |
| 143 | |
| 144 | item_list = merge_utils.InferItemList(zip_namelist, framework=True) |
| 145 | |
| 146 | expected_framework_item_list = [ |
| 147 | 'IMAGES/product.img', |
| 148 | 'IMAGES/product.map', |
| 149 | 'IMAGES/system.img', |
| 150 | 'IMAGES/system.map', |
| 151 | 'META/filesystem_config.txt', |
| 152 | 'META/liblz4.so', |
| 153 | 'META/postinstall_config.txt', |
| 154 | 'META/product_filesystem_config.txt', |
Daniel Norman | 5f47677 | 2022-03-02 15:46:34 -0800 | [diff] [blame] | 155 | 'META/zucchini_config.txt', |
| 156 | 'PRODUCT/*', |
| 157 | 'SYSTEM/*', |
| 158 | ] |
| 159 | |
| 160 | self.assertEqual(item_list, expected_framework_item_list) |
| 161 | |
| 162 | def test_InferItemList_Vendor(self): |
| 163 | zip_namelist = [ |
| 164 | 'VENDOR/my_vendor_file', |
| 165 | 'ODM/my_odm_file', |
Daniel Norman | 679242b | 2022-03-18 15:46:27 -0700 | [diff] [blame] | 166 | 'IMAGES/odm.img', |
| 167 | 'IMAGES/odm.map', |
| 168 | 'IMAGES/vendor.img', |
| 169 | 'IMAGES/vendor.map', |
| 170 | 'IMAGES/my_custom_image.img', |
| 171 | 'IMAGES/my_custom_file.txt', |
| 172 | 'IMAGES/vbmeta.img', |
| 173 | 'CUSTOM_PARTITION/my_custom_file', |
| 174 | # Leftover framework pieces that shouldn't be grabbed. |
| 175 | 'IMAGES/system.img', |
| 176 | 'SYSTEM/system_file', |
Daniel Norman | 5f47677 | 2022-03-02 15:46:34 -0800 | [diff] [blame] | 177 | ] |
| 178 | |
| 179 | item_list = merge_utils.InferItemList(zip_namelist, framework=False) |
| 180 | |
| 181 | expected_vendor_item_list = [ |
Daniel Norman | 679242b | 2022-03-18 15:46:27 -0700 | [diff] [blame] | 182 | 'CUSTOM_PARTITION/*', |
| 183 | 'IMAGES/my_custom_file.txt', |
| 184 | 'IMAGES/my_custom_image.img', |
Daniel Norman | 5f47677 | 2022-03-02 15:46:34 -0800 | [diff] [blame] | 185 | 'IMAGES/odm.img', |
| 186 | 'IMAGES/odm.map', |
| 187 | 'IMAGES/vendor.img', |
| 188 | 'IMAGES/vendor.map', |
Daniel Norman | 679242b | 2022-03-18 15:46:27 -0700 | [diff] [blame] | 189 | 'META/custom_partition_filesystem_config.txt', |
Daniel Norman | 5f47677 | 2022-03-02 15:46:34 -0800 | [diff] [blame] | 190 | 'META/kernel_configs.txt', |
| 191 | 'META/kernel_version.txt', |
| 192 | 'META/odm_filesystem_config.txt', |
| 193 | 'META/otakeys.txt', |
Daniel Norman | 679242b | 2022-03-18 15:46:27 -0700 | [diff] [blame] | 194 | 'META/pack_radioimages.txt', |
Daniel Norman | 5f47677 | 2022-03-02 15:46:34 -0800 | [diff] [blame] | 195 | 'META/releasetools.py', |
| 196 | 'META/vendor_filesystem_config.txt', |
| 197 | 'ODM/*', |
Daniel Norman | 5f47677 | 2022-03-02 15:46:34 -0800 | [diff] [blame] | 198 | 'VENDOR/*', |
| 199 | ] |
| 200 | self.assertEqual(item_list, expected_vendor_item_list) |
| 201 | |
| 202 | def test_InferFrameworkMiscInfoKeys(self): |
| 203 | zip_namelist = [ |
Daniel Norman | 679242b | 2022-03-18 15:46:27 -0700 | [diff] [blame] | 204 | 'PRODUCT/', |
| 205 | 'SYSTEM/', |
| 206 | 'SYSTEM/system_ext/', |
Daniel Norman | 5f47677 | 2022-03-02 15:46:34 -0800 | [diff] [blame] | 207 | ] |
| 208 | |
| 209 | keys = merge_utils.InferFrameworkMiscInfoKeys(zip_namelist) |
| 210 | |
| 211 | expected_keys = [ |
| 212 | 'ab_update', |
Daniel Norman | 679242b | 2022-03-18 15:46:27 -0700 | [diff] [blame] | 213 | 'avb_product_add_hashtree_footer_args', |
| 214 | 'avb_product_hashtree_enable', |
Daniel Norman | 5f47677 | 2022-03-02 15:46:34 -0800 | [diff] [blame] | 215 | 'avb_system_add_hashtree_footer_args', |
| 216 | 'avb_system_ext_add_hashtree_footer_args', |
| 217 | 'avb_system_ext_hashtree_enable', |
| 218 | 'avb_system_hashtree_enable', |
| 219 | 'avb_vbmeta_system', |
| 220 | 'avb_vbmeta_system_algorithm', |
| 221 | 'avb_vbmeta_system_key_path', |
| 222 | 'avb_vbmeta_system_rollback_index_location', |
Daniel Norman | 679242b | 2022-03-18 15:46:27 -0700 | [diff] [blame] | 223 | 'building_product_image', |
Daniel Norman | 5f47677 | 2022-03-02 15:46:34 -0800 | [diff] [blame] | 224 | 'building_system_ext_image', |
| 225 | 'building_system_image', |
| 226 | 'default_system_dev_certificate', |
| 227 | 'fs_type', |
Daniel Norman | 679242b | 2022-03-18 15:46:27 -0700 | [diff] [blame] | 228 | 'product_disable_sparse', |
| 229 | 'product_fs_type', |
Daniel Norman | 5f47677 | 2022-03-02 15:46:34 -0800 | [diff] [blame] | 230 | 'system_disable_sparse', |
| 231 | 'system_ext_disable_sparse', |
| 232 | 'system_ext_fs_type', |
| 233 | ] |
| 234 | self.assertEqual(keys, expected_keys) |