1#!/usr/bin/env python3 2 3from __future__ import print_function 4 5import os 6import sys 7sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 8 9import tempfile 10import unittest 11 12from compat import StringIO 13from vndk_definition_tool import TaggedDict, TaggedPathDict, TaggedLibDict, \ 14 NUM_PARTITIONS, PT_SYSTEM, PT_VENDOR 15 16 17_TEST_DATA = '''Path,Tag 18/system/lib/lib_ll_ndk.so,ll-ndk 19/system/lib/lib_ll_ndk_indirect.so,ll-ndk-indirect 20/system/lib/lib_vndk_sp.so,vndk-sp 21/system/lib/lib_vndk_sp_indirect.so,vndk-sp-indirect 22/system/lib/lib_vndk_sp_indirect_private.so,vndk-sp-indirect-private 23/system/lib/lib_vndk.so,vndk 24/system/lib/lib_fwk_only.so,fwk-only 25/system/lib/lib_fwk_only_rs.so,fwk-only-rs 26/vendor/lib/lib_sp_hal.so,sp-hal 27/vendor/lib/lib_sp_hal_dep.so,sp-hal-dep 28/vendor/lib/lib_vnd_only.so,vnd-only 29/system/lib/lib_remove.so,remove 30/system/lib/lib_hl_ndk.so,hl-ndk 31/system/lib/lib_vndk_indirect.so,vndk-indirect 32/system/lib/lib_vndk_sp_both.so,vndk-sp-both 33/system/lib/lib_vndk_sp_hal.so,vndk-sp-hal 34''' 35 36_TEST_DATA_ALIAS_PATHS = { 37 '/system/lib/lib_hl_ndk.so', 38 '/system/lib/lib_vndk_sp_both.so', 39 '/system/lib/lib_vndk_sp_hal.so', 40 '/system/lib/lib_vndk_indirect.so' 41} 42 43 44class TaggedDictTest(unittest.TestCase): 45 def test_normalize_tag(self): 46 self.assertEqual('ll_ndk', TaggedDict._normalize_tag('ll-ndk')) 47 self.assertEqual('ll_ndk', TaggedDict._normalize_tag('LL-NDK')) 48 self.assertEqual('ll_ndk', TaggedDict._normalize_tag('LL_NDK')) 49 with self.assertRaises(ValueError): 50 TaggedDict._normalize_tag('unknown-lib-tag') 51 52 53 def _check_tag_visibility(self, d, from_tag, visible_tags): 54 for to_tag in TaggedDict.TAGS: 55 self.assertEqual(d.is_tag_visible(from_tag, to_tag), 56 to_tag in visible_tags) 57 58 59 def test_is_tag_visible(self): 60 d = TaggedDict() 61 62 # LL-NDK 63 visible_tags = {'ll_ndk', 'll_ndk_indirect'} 64 self._check_tag_visibility(d, 'll_ndk', visible_tags) 65 self._check_tag_visibility(d, 'll_ndk_indirect', visible_tags) 66 67 # VNDK-SP 68 visible_tags = {'ll_ndk', 'vndk_sp', 'vndk_sp_indirect', 69 'vndk_sp_indirect_private', 'fwk_only_rs'} 70 self._check_tag_visibility(d, 'vndk_sp', visible_tags) 71 self._check_tag_visibility(d, 'vndk_sp_indirect', visible_tags) 72 self._check_tag_visibility(d, 'vndk_sp_indirect_private', visible_tags) 73 74 # VNDK 75 visible_tags = {'ll_ndk', 'vndk_sp', 'vndk_sp_indirect', 76 'vndk'} 77 self._check_tag_visibility(d, 'vndk', visible_tags) 78 79 # FWK-ONLY 80 visible_tags = {'ll_ndk', 'll_ndk_indirect', 81 'vndk_sp', 'vndk_sp_indirect', 82 'vndk_sp_indirect_private', 'vndk', 'fwk_only', 83 'fwk_only_rs', 'sp_hal'} 84 self._check_tag_visibility(d, 'fwk_only', visible_tags) 85 self._check_tag_visibility(d, 'fwk_only_rs', visible_tags) 86 87 # SP-HAL 88 visible_tags = {'ll_ndk', 'vndk_sp', 'sp_hal', 'sp_hal_dep'} 89 self._check_tag_visibility(d, 'sp_hal', visible_tags) 90 self._check_tag_visibility(d, 'sp_hal_dep', visible_tags) 91 92 # VND-ONLY 93 visible_tags = {'ll_ndk', 'vndk_sp', 'vndk_sp_indirect', 94 'vndk', 'sp_hal', 'sp_hal_dep', 'vnd_only'} 95 self._check_tag_visibility(d, 'vnd_only', visible_tags) 96 97 # Remove 98 self._check_tag_visibility(d, 'remove', set()) 99 100 101class TaggedPathDictTest(unittest.TestCase): 102 def test_enumerate_paths(self): 103 tagged_paths = TaggedPathDict() 104 105 self.assertEqual( 106 ['/system/lib/libc.so'], 107 list(tagged_paths._enumerate_paths('/system/lib/libc.so'))) 108 109 self.assertEqual( 110 ['/system/lib/libc.so', '/system/lib64/libc.so'], 111 list(tagged_paths._enumerate_paths('/system/${LIB}/libc.so'))) 112 113 self.assertEqual( 114 ['/system/lib/vndk/libutils.so', 115 '/system/lib64/vndk/libutils.so'], 116 list(tagged_paths._enumerate_paths( 117 '/system/${LIB}/vndk${VNDK_VER}/libutils.so'))) 118 119 tagged_paths = TaggedPathDict(['current', '27', '28']) 120 121 self.assertEqual( 122 ['/system/lib/vndk/libutils.so', 123 '/system/lib64/vndk/libutils.so', 124 '/system/lib/vndk-27/libutils.so', 125 '/system/lib64/vndk-27/libutils.so', 126 '/system/lib/vndk-28/libutils.so', 127 '/system/lib64/vndk-28/libutils.so'], 128 list(tagged_paths._enumerate_paths( 129 '/system/${LIB}/vndk${VNDK_VER}/libutils.so'))) 130 131 self.assertEqual( 132 ['/system/lib/vndk/libutils.so', 133 '/system/lib/vndk-27/libutils.so', 134 '/system/lib/vndk-28/libutils.so'], 135 list(tagged_paths._enumerate_paths( 136 '/system/lib/vndk${VNDK_VER}/libutils.so'))) 137 138 def test_load_from_csv_empty(self): 139 try: 140 TaggedPathDict().load_from_csv(StringIO('')) 141 except StopIteration: 142 self.fail('empty file should be considered as a valid input') 143 144 145 def test_load_from_csv_with_header(self): 146 fp = StringIO('Path,Tag\nliba.so,fwk-only\n') 147 d = TaggedPathDict() 148 d.load_from_csv(fp) 149 self.assertIn('liba.so', d.fwk_only) 150 151 fp = StringIO('Tag,Path\nfwk-only,liba.so\n') 152 d = TaggedPathDict() 153 d.load_from_csv(fp) 154 self.assertIn('liba.so', d.fwk_only) 155 156 157 def test_load_from_csv_without_header(self): 158 fp = StringIO('liba.so,fwk-only\n') 159 d = TaggedPathDict() 160 d.load_from_csv(fp) 161 self.assertIn('liba.so', d.fwk_only) 162 163 164 def _check_test_data_loaded(self, d): 165 # Paths 166 self.assertIn('/system/lib/lib_ll_ndk.so', d.ll_ndk) 167 self.assertIn('/system/lib/lib_ll_ndk_indirect.so', d.ll_ndk_indirect) 168 self.assertIn('/system/lib/lib_vndk_sp.so', d.vndk_sp) 169 self.assertIn('/system/lib/lib_vndk_sp_indirect.so', d.vndk_sp_indirect) 170 self.assertIn('/system/lib/lib_vndk_sp_indirect_private.so', 171 d.vndk_sp_indirect_private) 172 self.assertIn('/system/lib/lib_vndk.so', d.vndk) 173 self.assertIn('/system/lib/lib_fwk_only.so', d.fwk_only) 174 self.assertIn('/system/lib/lib_fwk_only_rs.so', d.fwk_only_rs) 175 self.assertIn('/vendor/lib/lib_sp_hal.so', d.sp_hal) 176 self.assertIn('/vendor/lib/lib_sp_hal_dep.so', d.sp_hal_dep) 177 self.assertIn('/vendor/lib/lib_vnd_only.so', d.vnd_only) 178 self.assertIn('/system/lib/lib_remove.so', d.remove) 179 180 # Aliases 181 self.assertIn('/system/lib/lib_hl_ndk.so', d.fwk_only) 182 self.assertIn('/system/lib/lib_vndk_sp_both.so', d.vndk_sp) 183 self.assertIn('/system/lib/lib_vndk_sp_hal.so', d.vndk_sp) 184 self.assertIn('/system/lib/lib_vndk_indirect.so', d.vndk) 185 186 187 def test_load_from_csv_tags(self): 188 fp = StringIO(_TEST_DATA) 189 d = TaggedPathDict() 190 d.load_from_csv(fp) 191 self._check_test_data_loaded(d) 192 193 194 def test_create_from_csv(self): 195 d = TaggedPathDict.create_from_csv(StringIO(_TEST_DATA)) 196 self._check_test_data_loaded(d) 197 198 199 def test_create_from_csv_path(self): 200 with tempfile.NamedTemporaryFile('w+') as f: 201 f.write(_TEST_DATA) 202 f.flush() 203 204 d = TaggedPathDict.create_from_csv_path(f.name) 205 self._check_test_data_loaded(d) 206 207 208 def test_get_path_tag(self): 209 fp = StringIO(_TEST_DATA) 210 d = TaggedPathDict() 211 d.load_from_csv(fp) 212 213 self.assertEqual('ll_ndk', d.get_path_tag('/system/lib/lib_ll_ndk.so')) 214 self.assertEqual('ll_ndk_indirect', 215 d.get_path_tag('/system/lib/lib_ll_ndk_indirect.so')) 216 self.assertEqual('vndk_sp', 217 d.get_path_tag('/system/lib/lib_vndk_sp.so')) 218 self.assertEqual('vndk_sp_indirect', 219 d.get_path_tag('/system/lib/lib_vndk_sp_indirect.so')) 220 self.assertEqual( 221 'vndk_sp_indirect_private', 222 d.get_path_tag('/system/lib/lib_vndk_sp_indirect_private.so')) 223 self.assertEqual('vndk', d.get_path_tag('/system/lib/lib_vndk.so')) 224 self.assertEqual('fwk_only', 225 d.get_path_tag('/system/lib/lib_fwk_only.so')) 226 self.assertEqual('fwk_only_rs', 227 d.get_path_tag('/system/lib/lib_fwk_only_rs.so')) 228 self.assertEqual('sp_hal', 229 d.get_path_tag('/vendor/lib/lib_sp_hal.so')) 230 self.assertEqual('sp_hal_dep', 231 d.get_path_tag('/vendor/lib/lib_sp_hal_dep.so')) 232 self.assertEqual('vnd_only', 233 d.get_path_tag('/vendor/lib/lib_vnd_only.so')) 234 self.assertEqual('remove', 235 d.get_path_tag('/system/lib/lib_remove.so')) 236 237 # Aliases 238 self.assertEqual('fwk_only', 239 d.get_path_tag('/system/lib/lib_hl_ndk.so')) 240 self.assertEqual('vndk_sp', 241 d.get_path_tag('/system/lib/lib_vndk_sp_hal.so')) 242 self.assertEqual('vndk_sp', 243 d.get_path_tag('/system/lib/lib_vndk_sp_both.so')) 244 self.assertEqual('vndk', 245 d.get_path_tag('/system/lib/lib_vndk_indirect.so')) 246 247 # Unmatched paths 248 self.assertEqual('fwk_only', d.get_path_tag('/system/lib/unknown.so')) 249 self.assertEqual('fwk_only', d.get_path_tag('/data/lib/unknown.so')) 250 self.assertEqual('vnd_only', d.get_path_tag('/vendor/lib/unknown.so')) 251 252 253 def _check_path_visibility(self, d, all_paths, from_paths, visible_paths): 254 for from_path in from_paths: 255 for to_path in all_paths: 256 self.assertEqual(d.is_path_visible(from_path, to_path), 257 to_path in visible_paths) 258 259 260 def test_is_path_visible(self): 261 fp = StringIO(_TEST_DATA) 262 d = TaggedPathDict() 263 d.load_from_csv(fp) 264 265 # Collect path universe set. 266 all_paths = set() 267 for tag in TaggedPathDict.TAGS: 268 all_paths |= getattr(d, tag) 269 all_paths -= _TEST_DATA_ALIAS_PATHS 270 271 # LL-NDK 272 from_paths = { 273 '/system/lib/lib_ll_ndk.so', 274 '/system/lib/lib_ll_ndk_indirect.so', 275 } 276 visible_paths = { 277 '/system/lib/lib_ll_ndk.so', 278 '/system/lib/lib_ll_ndk_indirect.so', 279 } 280 self._check_path_visibility(d, all_paths, from_paths, visible_paths) 281 282 # VNDK-SP 283 from_paths = { 284 '/system/lib/lib_vndk_sp.so', 285 '/system/lib/lib_vndk_sp_indirect.so', 286 '/system/lib/lib_vndk_sp_indirect_private.so', 287 } 288 visible_paths = { 289 '/system/lib/lib_ll_ndk.so', 290 '/system/lib/lib_vndk_sp.so', 291 '/system/lib/lib_vndk_sp_indirect.so', 292 '/system/lib/lib_vndk_sp_indirect_private.so', 293 '/system/lib/lib_fwk_only_rs.so', 294 } 295 self._check_path_visibility(d, all_paths, from_paths, visible_paths) 296 297 # VNDK 298 from_paths = { 299 '/system/lib/lib_vndk.so', 300 } 301 visible_paths = { 302 '/system/lib/lib_ll_ndk.so', 303 '/system/lib/lib_vndk_sp.so', 304 '/system/lib/lib_vndk_sp_indirect.so', 305 '/system/lib/lib_vndk.so', 306 } 307 self._check_path_visibility(d, all_paths, from_paths, visible_paths) 308 309 # FWK-ONLY 310 from_paths = { 311 '/system/lib/lib_fwk_only.so', 312 '/system/lib/lib_fwk_only_rs.so', 313 } 314 visible_paths = { 315 '/system/lib/lib_ll_ndk.so', 316 '/system/lib/lib_ll_ndk_indirect.so', 317 '/system/lib/lib_vndk_sp.so', 318 '/system/lib/lib_vndk_sp_indirect.so', 319 '/system/lib/lib_vndk_sp_indirect_private.so', 320 '/system/lib/lib_vndk.so', 321 '/system/lib/lib_fwk_only.so', 322 '/system/lib/lib_fwk_only_rs.so', 323 '/vendor/lib/lib_sp_hal.so', 324 } 325 self._check_path_visibility(d, all_paths, from_paths, visible_paths) 326 327 # SP-HAL 328 from_paths = { 329 '/vendor/lib/lib_sp_hal.so', 330 '/vendor/lib/lib_sp_hal_dep.so', 331 } 332 visible_paths = { 333 '/system/lib/lib_ll_ndk.so', 334 '/system/lib/lib_vndk_sp.so', 335 '/vendor/lib/lib_sp_hal.so', 336 '/vendor/lib/lib_sp_hal_dep.so', 337 } 338 self._check_path_visibility(d, all_paths, from_paths, visible_paths) 339 340 # VND-ONLY 341 from_paths = { 342 '/vendor/lib/lib_vnd_only.so', 343 } 344 visible_paths = { 345 '/system/lib/lib_ll_ndk.so', 346 '/system/lib/lib_vndk_sp.so', 347 '/system/lib/lib_vndk_sp_indirect.so', 348 '/system/lib/lib_vndk.so', 349 '/vendor/lib/lib_sp_hal.so', 350 '/vendor/lib/lib_sp_hal_dep.so', 351 '/vendor/lib/lib_vnd_only.so', 352 } 353 self._check_path_visibility(d, all_paths, from_paths, visible_paths) 354 355 356class MockSPLibResult(object): 357 def __init__(self, sp_hal, sp_hal_dep): 358 self.sp_hal = sp_hal 359 self.sp_hal_dep = sp_hal_dep 360 361 362class MockELFLinkData(object): 363 def __init__(self, path): 364 self.path = path 365 366 367class MockELFGraph(object): 368 def __init__(self): 369 self.lib_pt = [dict() for i in range(NUM_PARTITIONS)] 370 371 def add(self, path): 372 partition = PT_VENDOR if path.startswith('/vendor') else PT_SYSTEM 373 lib = MockELFLinkData(path) 374 self.lib_pt[partition][path] = lib 375 return lib 376 377 def compute_sp_lib(self, generic_refs=None): 378 vendor_libs = self.lib_pt[PT_VENDOR].values() 379 return MockSPLibResult( 380 set(v for v in vendor_libs if 'lib_sp_hal.so' in v.path), 381 set(v for v in vendor_libs if 'lib_sp_hal_dep.so' in v.path)) 382 383 384class TaggedLibDictTest(unittest.TestCase): 385 def setUp(self): 386 self.tagged_paths = TaggedPathDict.create_from_csv(StringIO(_TEST_DATA)) 387 388 self.graph = MockELFGraph() 389 390 self.lib_ll_ndk = self.graph.add('/system/lib/lib_ll_ndk.so') 391 self.lib_ll_ndk_indirect = \ 392 self.graph.add('/system/lib/lib_ll_ndk_indirect.so') 393 394 self.lib_vndk_sp = self.graph.add('/system/lib/lib_vndk_sp.so') 395 self.lib_vndk_sp_indirect = \ 396 self.graph.add('/system/lib/lib_vndk_sp_indirect.so') 397 self.lib_vndk_sp_indirect_private = \ 398 self.graph.add('/system/lib/lib_vndk_sp_indirect_private.so') 399 400 self.lib_vndk = self.graph.add('/system/lib/lib_vndk.so') 401 402 self.lib_fwk_only = self.graph.add('/system/lib/lib_fwk_only.so') 403 self.lib_fwk_only_rs = self.graph.add('/system/lib/lib_fwk_only_rs.so') 404 405 self.lib_sp_hal = self.graph.add('/vendor/lib/lib_sp_hal.so') 406 self.lib_sp_hal_dep = self.graph.add('/vendor/lib/lib_sp_hal_dep.so') 407 408 self.lib_vnd_only = self.graph.add('/vendor/lib/lib_vnd_only.so') 409 410 self.tagged_libs = TaggedLibDict.create_from_graph( 411 self.graph, self.tagged_paths) 412 413 414 def test_create_from_graph(self): 415 self.assertIn(self.lib_ll_ndk, self.tagged_libs.ll_ndk) 416 self.assertIn(self.lib_ll_ndk_indirect, 417 self.tagged_libs.ll_ndk_indirect) 418 self.assertIn(self.lib_vndk_sp, self.tagged_libs.vndk_sp) 419 self.assertIn(self.lib_vndk_sp_indirect, 420 self.tagged_libs.vndk_sp_indirect) 421 self.assertIn(self.lib_vndk_sp_indirect_private, 422 self.tagged_libs.vndk_sp_indirect_private) 423 424 self.assertIn(self.lib_vndk, self.tagged_libs.vndk) 425 426 self.assertIn(self.lib_fwk_only, self.tagged_libs.fwk_only) 427 self.assertIn(self.lib_fwk_only_rs, self.tagged_libs.fwk_only_rs) 428 429 self.assertIn(self.lib_sp_hal, self.tagged_libs.sp_hal) 430 self.assertIn(self.lib_sp_hal_dep, self.tagged_libs.sp_hal_dep) 431 self.assertIn(self.lib_vnd_only, self.tagged_libs.vnd_only) 432 433 434 def test_get_path_tag(self): 435 d = self.tagged_libs 436 437 self.assertEqual('ll_ndk', d.get_path_tag(self.lib_ll_ndk)) 438 self.assertEqual('ll_ndk_indirect', 439 d.get_path_tag(self.lib_ll_ndk_indirect)) 440 self.assertEqual('vndk_sp', d.get_path_tag(self.lib_vndk_sp)) 441 self.assertEqual('vndk_sp_indirect', 442 d.get_path_tag(self.lib_vndk_sp_indirect)) 443 self.assertEqual('vndk_sp_indirect_private', 444 d.get_path_tag(self.lib_vndk_sp_indirect_private)) 445 self.assertEqual('vndk', d.get_path_tag(self.lib_vndk)) 446 self.assertEqual('fwk_only', d.get_path_tag(self.lib_fwk_only)) 447 self.assertEqual('fwk_only_rs', d.get_path_tag(self.lib_fwk_only_rs)) 448 self.assertEqual('sp_hal', d.get_path_tag(self.lib_sp_hal)) 449 self.assertEqual('sp_hal_dep', d.get_path_tag(self.lib_sp_hal_dep)) 450 self.assertEqual('vnd_only', d.get_path_tag(self.lib_vnd_only)) 451 452 # Unmatched paths 453 tag = d.get_path_tag(MockELFLinkData('/system/lib/unknown.so')) 454 self.assertEqual('fwk_only', tag) 455 tag = d.get_path_tag(MockELFLinkData('/data/lib/unknown.so')) 456 self.assertEqual('fwk_only', tag) 457 tag = d.get_path_tag(MockELFLinkData('/vendor/lib/unknown.so')) 458 self.assertEqual('vnd_only', tag) 459 460 461if __name__ == '__main__': 462 unittest.main() 463