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