• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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