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_indirect.so,ll-ndk-indirect 17/system/lib/lib_vndk_sp.so,vndk-sp 18/system/lib/lib_vndk_sp_indirect.so,vndk-sp-indirect 19/system/lib/lib_vndk_sp_indirect_private.so,vndk-sp-indirect-private 20/system/lib/lib_vndk.so,vndk 21/system/lib/lib_fwk_only.so,fwk-only 22/system/lib/lib_fwk_only_rs.so,fwk-only-rs 23/vendor/lib/lib_sp_hal.so,sp-hal 24/vendor/lib/lib_sp_hal_dep.so,sp-hal-dep 25/vendor/lib/lib_vnd_only.so,vnd-only 26/system/lib/lib_remove.so,remove 27/system/lib/lib_hl_ndk.so,hl-ndk 28/system/lib/lib_vndk_indirect.so,vndk-indirect 29/system/lib/lib_vndk_sp_both.so,vndk-sp-both 30/system/lib/lib_vndk_sp_hal.so,vndk-sp-hal 31''' 32 33_TEST_DATA_ALIAS_PATHS = { 34 '/system/lib/lib_hl_ndk.so', 35 '/system/lib/lib_vndk_sp_both.so', 36 '/system/lib/lib_vndk_sp_hal.so', 37 '/system/lib/lib_vndk_indirect.so' 38} 39 40 41class TaggedDictTest(unittest.TestCase): 42 def test_normalize_tag(self): 43 self.assertEqual('ll_ndk', TaggedDict._normalize_tag('ll-ndk')) 44 self.assertEqual('ll_ndk', TaggedDict._normalize_tag('LL-NDK')) 45 self.assertEqual('ll_ndk', TaggedDict._normalize_tag('LL_NDK')) 46 with self.assertRaises(ValueError): 47 TaggedDict._normalize_tag('unknown-lib-tag') 48 49 50 def _check_tag_visibility(self, d, from_tag, visible_tags): 51 for to_tag in TaggedDict.TAGS: 52 self.assertEqual(d.is_tag_visible(from_tag, to_tag), 53 to_tag in visible_tags) 54 55 56 def test_is_tag_visible(self): 57 d = TaggedDict() 58 59 # LL-NDK 60 visible_tags = {'ll_ndk', 'll_ndk_indirect'} 61 self._check_tag_visibility(d, 'll_ndk', visible_tags) 62 self._check_tag_visibility(d, 'll_ndk_indirect', visible_tags) 63 64 # VNDK-SP 65 visible_tags = {'ll_ndk', 'vndk_sp', 'vndk_sp_indirect', 66 'vndk_sp_indirect_private', 'fwk_only_rs'} 67 self._check_tag_visibility(d, 'vndk_sp', visible_tags) 68 self._check_tag_visibility(d, 'vndk_sp_indirect', visible_tags) 69 self._check_tag_visibility(d, 'vndk_sp_indirect_private', visible_tags) 70 71 # VNDK 72 visible_tags = {'ll_ndk', 'vndk_sp', 'vndk_sp_indirect', 73 'vndk'} 74 self._check_tag_visibility(d, 'vndk', visible_tags) 75 76 # FWK-ONLY 77 visible_tags = {'ll_ndk', 'll_ndk_indirect', 78 'vndk_sp', 'vndk_sp_indirect', 79 'vndk_sp_indirect_private', 'vndk', 'fwk_only', 80 'fwk_only_rs', 'sp_hal'} 81 self._check_tag_visibility(d, 'fwk_only', visible_tags) 82 self._check_tag_visibility(d, 'fwk_only_rs', visible_tags) 83 84 # SP-HAL 85 visible_tags = {'ll_ndk', 'vndk_sp', 'sp_hal', 'sp_hal_dep'} 86 self._check_tag_visibility(d, 'sp_hal', visible_tags) 87 self._check_tag_visibility(d, 'sp_hal_dep', visible_tags) 88 89 # VND-ONLY 90 visible_tags = {'ll_ndk', 'vndk_sp', 'vndk_sp_indirect', 91 'vndk', 'sp_hal', 'sp_hal_dep', 'vnd_only'} 92 self._check_tag_visibility(d, 'vnd_only', visible_tags) 93 94 # Remove 95 self._check_tag_visibility(d, 'remove', set()) 96 97 98class TaggedPathDictTest(unittest.TestCase): 99 def test_enumerate_paths(self): 100 tagged_paths = TaggedPathDict() 101 102 self.assertEqual( 103 ['/system/lib/libc.so'], 104 list(tagged_paths._enumerate_paths('/system/lib/libc.so'))) 105 106 self.assertEqual( 107 ['/system/lib/libc.so', '/system/lib64/libc.so'], 108 list(tagged_paths._enumerate_paths('/system/${LIB}/libc.so'))) 109 110 self.assertEqual( 111 ['/system/lib/vndk/libutils.so', 112 '/system/lib64/vndk/libutils.so'], 113 list(tagged_paths._enumerate_paths( 114 '/system/${LIB}/vndk${VNDK_VER}/libutils.so'))) 115 116 tagged_paths = TaggedPathDict(['current', '27', '28']) 117 118 self.assertEqual( 119 ['/system/lib/vndk/libutils.so', 120 '/system/lib64/vndk/libutils.so', 121 '/system/lib/vndk-27/libutils.so', 122 '/system/lib64/vndk-27/libutils.so', 123 '/system/lib/vndk-28/libutils.so', 124 '/system/lib64/vndk-28/libutils.so'], 125 list(tagged_paths._enumerate_paths( 126 '/system/${LIB}/vndk${VNDK_VER}/libutils.so'))) 127 128 self.assertEqual( 129 ['/system/lib/vndk/libutils.so', 130 '/system/lib/vndk-27/libutils.so', 131 '/system/lib/vndk-28/libutils.so'], 132 list(tagged_paths._enumerate_paths( 133 '/system/lib/vndk${VNDK_VER}/libutils.so'))) 134 135 136 def test_load_from_csv_empty(self): 137 try: 138 TaggedPathDict().load_from_csv(StringIO('')) 139 except StopIteration: 140 self.fail('empty file should be considered as a valid input') 141 142 143 def test_load_from_csv_with_header(self): 144 fp = StringIO('Path,Tag\nliba.so,fwk-only\n') 145 d = TaggedPathDict() 146 d.load_from_csv(fp) 147 self.assertIn('liba.so', d.fwk_only) 148 149 fp = StringIO('Tag,Path\nfwk-only,liba.so\n') 150 d = TaggedPathDict() 151 d.load_from_csv(fp) 152 self.assertIn('liba.so', d.fwk_only) 153 154 155 def test_load_from_csv_without_header(self): 156 fp = StringIO('liba.so,fwk-only\n') 157 d = TaggedPathDict() 158 d.load_from_csv(fp) 159 self.assertIn('liba.so', d.fwk_only) 160 161 162 def _check_test_data_loaded(self, d): 163 # Paths 164 self.assertIn('/system/lib/lib_ll_ndk.so', d.ll_ndk) 165 self.assertIn('/system/lib/lib_ll_ndk_indirect.so', d.ll_ndk_indirect) 166 self.assertIn('/system/lib/lib_vndk_sp.so', d.vndk_sp) 167 self.assertIn('/system/lib/lib_vndk_sp_indirect.so', d.vndk_sp_indirect) 168 self.assertIn('/system/lib/lib_vndk_sp_indirect_private.so', 169 d.vndk_sp_indirect_private) 170 self.assertIn('/system/lib/lib_vndk.so', d.vndk) 171 self.assertIn('/system/lib/lib_fwk_only.so', d.fwk_only) 172 self.assertIn('/system/lib/lib_fwk_only_rs.so', d.fwk_only_rs) 173 self.assertIn('/vendor/lib/lib_sp_hal.so', d.sp_hal) 174 self.assertIn('/vendor/lib/lib_sp_hal_dep.so', d.sp_hal_dep) 175 self.assertIn('/vendor/lib/lib_vnd_only.so', d.vnd_only) 176 self.assertIn('/system/lib/lib_remove.so', d.remove) 177 178 # Aliases 179 self.assertIn('/system/lib/lib_hl_ndk.so', d.fwk_only) 180 self.assertIn('/system/lib/lib_vndk_sp_both.so', d.vndk_sp) 181 self.assertIn('/system/lib/lib_vndk_sp_hal.so', d.vndk_sp) 182 self.assertIn('/system/lib/lib_vndk_indirect.so', d.vndk) 183 184 185 def test_load_from_csv_tags(self): 186 fp = StringIO(_TEST_DATA) 187 d = TaggedPathDict() 188 d.load_from_csv(fp) 189 self._check_test_data_loaded(d) 190 191 192 def test_create_from_csv(self): 193 d = TaggedPathDict.create_from_csv(StringIO(_TEST_DATA)) 194 self._check_test_data_loaded(d) 195 196 197 def test_create_from_csv_path(self): 198 with tempfile.NamedTemporaryFile('w+') as f: 199 f.write(_TEST_DATA) 200 f.flush() 201 202 d = TaggedPathDict.create_from_csv_path(f.name) 203 self._check_test_data_loaded(d) 204 205 206 def test_get_path_tag(self): 207 fp = StringIO(_TEST_DATA) 208 d = TaggedPathDict() 209 d.load_from_csv(fp) 210 211 self.assertEqual('ll_ndk', d.get_path_tag('/system/lib/lib_ll_ndk.so')) 212 self.assertEqual('ll_ndk_indirect', 213 d.get_path_tag('/system/lib/lib_ll_ndk_indirect.so')) 214 self.assertEqual('vndk_sp', 215 d.get_path_tag('/system/lib/lib_vndk_sp.so')) 216 self.assertEqual('vndk_sp_indirect', 217 d.get_path_tag('/system/lib/lib_vndk_sp_indirect.so')) 218 self.assertEqual( 219 'vndk_sp_indirect_private', 220 d.get_path_tag('/system/lib/lib_vndk_sp_indirect_private.so')) 221 self.assertEqual('vndk', d.get_path_tag('/system/lib/lib_vndk.so')) 222 self.assertEqual('fwk_only', 223 d.get_path_tag('/system/lib/lib_fwk_only.so')) 224 self.assertEqual('fwk_only_rs', 225 d.get_path_tag('/system/lib/lib_fwk_only_rs.so')) 226 self.assertEqual('sp_hal', 227 d.get_path_tag('/vendor/lib/lib_sp_hal.so')) 228 self.assertEqual('sp_hal_dep', 229 d.get_path_tag('/vendor/lib/lib_sp_hal_dep.so')) 230 self.assertEqual('vnd_only', 231 d.get_path_tag('/vendor/lib/lib_vnd_only.so')) 232 self.assertEqual('remove', 233 d.get_path_tag('/system/lib/lib_remove.so')) 234 235 # Aliases 236 self.assertEqual('fwk_only', 237 d.get_path_tag('/system/lib/lib_hl_ndk.so')) 238 self.assertEqual('vndk_sp', 239 d.get_path_tag('/system/lib/lib_vndk_sp_hal.so')) 240 self.assertEqual('vndk_sp', 241 d.get_path_tag('/system/lib/lib_vndk_sp_both.so')) 242 self.assertEqual('vndk', 243 d.get_path_tag('/system/lib/lib_vndk_indirect.so')) 244 245 # Unmatched paths 246 self.assertEqual('fwk_only', d.get_path_tag('/system/lib/unknown.so')) 247 self.assertEqual('fwk_only', d.get_path_tag('/data/lib/unknown.so')) 248 self.assertEqual('vnd_only', d.get_path_tag('/vendor/lib/unknown.so')) 249 250 251 def _check_path_visibility(self, d, all_paths, from_paths, visible_paths): 252 for from_path in from_paths: 253 for to_path in all_paths: 254 self.assertEqual(d.is_path_visible(from_path, to_path), 255 to_path in visible_paths) 256 257 258 def test_is_path_visible(self): 259 fp = StringIO(_TEST_DATA) 260 d = TaggedPathDict() 261 d.load_from_csv(fp) 262 263 # Collect path universe set. 264 all_paths = set() 265 for tag in TaggedPathDict.TAGS: 266 all_paths |= getattr(d, tag) 267 all_paths -= _TEST_DATA_ALIAS_PATHS 268 269 # LL-NDK 270 from_paths = { 271 '/system/lib/lib_ll_ndk.so', 272 '/system/lib/lib_ll_ndk_indirect.so', 273 } 274 visible_paths = { 275 '/system/lib/lib_ll_ndk.so', 276 '/system/lib/lib_ll_ndk_indirect.so', 277 } 278 self._check_path_visibility(d, all_paths, from_paths, visible_paths) 279 280 # VNDK-SP 281 from_paths = { 282 '/system/lib/lib_vndk_sp.so', 283 '/system/lib/lib_vndk_sp_indirect.so', 284 '/system/lib/lib_vndk_sp_indirect_private.so', 285 } 286 visible_paths = { 287 '/system/lib/lib_ll_ndk.so', 288 '/system/lib/lib_vndk_sp.so', 289 '/system/lib/lib_vndk_sp_indirect.so', 290 '/system/lib/lib_vndk_sp_indirect_private.so', 291 '/system/lib/lib_fwk_only_rs.so', 292 } 293 self._check_path_visibility(d, all_paths, from_paths, visible_paths) 294 295 # VNDK 296 from_paths = { 297 '/system/lib/lib_vndk.so', 298 } 299 visible_paths = { 300 '/system/lib/lib_ll_ndk.so', 301 '/system/lib/lib_vndk_sp.so', 302 '/system/lib/lib_vndk_sp_indirect.so', 303 '/system/lib/lib_vndk.so', 304 } 305 self._check_path_visibility(d, all_paths, from_paths, visible_paths) 306 307 # FWK-ONLY 308 from_paths = { 309 '/system/lib/lib_fwk_only.so', 310 '/system/lib/lib_fwk_only_rs.so', 311 } 312 visible_paths = { 313 '/system/lib/lib_ll_ndk.so', 314 '/system/lib/lib_ll_ndk_indirect.so', 315 '/system/lib/lib_vndk_sp.so', 316 '/system/lib/lib_vndk_sp_indirect.so', 317 '/system/lib/lib_vndk_sp_indirect_private.so', 318 '/system/lib/lib_vndk.so', 319 '/system/lib/lib_fwk_only.so', 320 '/system/lib/lib_fwk_only_rs.so', 321 '/vendor/lib/lib_sp_hal.so', 322 } 323 self._check_path_visibility(d, all_paths, from_paths, visible_paths) 324 325 # SP-HAL 326 from_paths = { 327 '/vendor/lib/lib_sp_hal.so', 328 '/vendor/lib/lib_sp_hal_dep.so', 329 } 330 visible_paths = { 331 '/system/lib/lib_ll_ndk.so', 332 '/system/lib/lib_vndk_sp.so', 333 '/vendor/lib/lib_sp_hal.so', 334 '/vendor/lib/lib_sp_hal_dep.so', 335 } 336 self._check_path_visibility(d, all_paths, from_paths, visible_paths) 337 338 # VND-ONLY 339 from_paths = { 340 '/vendor/lib/lib_vnd_only.so', 341 } 342 visible_paths = { 343 '/system/lib/lib_ll_ndk.so', 344 '/system/lib/lib_vndk_sp.so', 345 '/system/lib/lib_vndk_sp_indirect.so', 346 '/system/lib/lib_vndk.so', 347 '/vendor/lib/lib_sp_hal.so', 348 '/vendor/lib/lib_sp_hal_dep.so', 349 '/vendor/lib/lib_vnd_only.so', 350 } 351 self._check_path_visibility(d, all_paths, from_paths, visible_paths) 352 353 354class MockSPLibResult(object): 355 def __init__(self, sp_hal, sp_hal_dep): 356 self.sp_hal = sp_hal 357 self.sp_hal_dep = sp_hal_dep 358 359 360class MockELFLinkData(object): 361 def __init__(self, path): 362 self.path = path 363 364 365class MockELFGraph(object): 366 def __init__(self): 367 self.lib_pt = [dict() for i in range(NUM_PARTITIONS)] 368 369 370 def add(self, path): 371 partition = PT_VENDOR if path.startswith('/vendor') else PT_SYSTEM 372 lib = MockELFLinkData(path) 373 self.lib_pt[partition][path] = lib 374 return lib 375 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