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