Home | History | Annotate | Download | only in tests
      1 #!/usr/bin/env python
      2 # Copyright 2014 The Chromium Authors. All rights reserved.
      3 # Use of this source code is governed by a BSD-style license that can be
      4 # found in the LICENSE file.
      5 
      6 import os
      7 import shutil
      8 import subprocess
      9 import sys
     10 import tempfile
     11 import unittest
     12 
     13 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
     14 LIB_DIR = os.path.dirname(SCRIPT_DIR)
     15 TOOLS_DIR = os.path.dirname(LIB_DIR)
     16 SDK_DIR = os.path.dirname(TOOLS_DIR)
     17 DATA_DIR = os.path.join(SCRIPT_DIR, 'data')
     18 BUILD_TOOLS_DIR = os.path.join(SDK_DIR, 'build_tools')
     19 
     20 sys.path.append(LIB_DIR)
     21 sys.path.append(TOOLS_DIR)
     22 sys.path.append(BUILD_TOOLS_DIR)
     23 
     24 import build_paths
     25 import get_shared_deps
     26 import getos
     27 
     28 TOOLCHAIN_OUT = os.path.join(build_paths.OUT_DIR, 'sdk_tests', 'toolchain')
     29 NACL_X86_GLIBC_TOOLCHAIN = os.path.join(TOOLCHAIN_OUT,
     30                                         '%s_x86' % getos.GetPlatform(),
     31                                         'nacl_x86_glibc')
     32 
     33 
     34 def StripDependencies(deps):
     35   '''Strip the dirnames and version suffixes from
     36   a list of nexe dependencies.
     37 
     38   e.g:
     39   /path/to/libpthread.so.1a2d3fsa -> libpthread.so
     40   '''
     41   names = []
     42   for name in deps:
     43     name = os.path.basename(name)
     44     if '.so.' in name:
     45       name = name.rsplit('.', 1)[0]
     46     names.append(name)
     47   return names
     48 
     49 
     50 class TestGetNeeded(unittest.TestCase):
     51   def setUp(self):
     52     self.tempdir = None
     53     self.toolchain = NACL_X86_GLIBC_TOOLCHAIN
     54     self.objdump = os.path.join(self.toolchain, 'bin', 'i686-nacl-objdump')
     55     if os.name == 'nt':
     56       self.objdump += '.exe'
     57     self.Mktemp()
     58     self.dyn_nexe = self.createTestNexe('test_dynamic_x86_32.nexe', 'i686')
     59     self.dyn_deps = set(['libc.so', 'runnable-ld.so',
     60                          'libgcc_s.so', 'libpthread.so'])
     61 
     62   def tearDown(self):
     63     if self.tempdir:
     64       shutil.rmtree(self.tempdir)
     65 
     66   def Mktemp(self):
     67     self.tempdir = tempfile.mkdtemp()
     68 
     69   def createTestNexe(self, name, arch):
     70     '''Create an empty test .nexe file for use in create_nmf tests.
     71 
     72     This is used rather than checking in test binaries since the
     73     checked in binaries depend on .so files that only exist in the
     74     certain SDK that built them.
     75     '''
     76     compiler = os.path.join(self.toolchain, 'bin', '%s-nacl-g++' % arch)
     77     if os.name == 'nt':
     78       compiler += '.exe'
     79       os.environ['CYGWIN'] = 'nodosfilewarning'
     80     program = 'int main() { return 0; }'
     81     name = os.path.join(self.tempdir, name)
     82     cmd = [compiler, '-pthread', '-x' , 'c', '-o', name, '-']
     83     p = subprocess.Popen(cmd, stdin=subprocess.PIPE)
     84     p.communicate(input=program)
     85     self.assertEqual(p.returncode, 0)
     86     return name
     87 
     88   def testStatic(self):
     89     nexe = os.path.join(DATA_DIR, 'test_static_x86_32.nexe')
     90     # GetNeeded should not raise an error if objdump is not set, but the .nexe
     91     # is statically linked.
     92     objdump = None
     93     lib_path = []
     94     needed = get_shared_deps.GetNeeded([nexe], objdump, lib_path)
     95 
     96     # static nexe should have exactly one needed file
     97     self.assertEqual(len(needed), 1)
     98     self.assertEqual(needed.keys()[0], nexe)
     99 
    100     # arch of needed file should be x86-32
    101     arch = needed.values()[0]
    102     self.assertEqual(arch, 'x86-32')
    103 
    104   def testDynamic(self):
    105     libdir = os.path.join(self.toolchain, 'x86_64-nacl', 'lib32')
    106     needed = get_shared_deps.GetNeeded([self.dyn_nexe],
    107                                        lib_path=[libdir],
    108                                        objdump=self.objdump)
    109     names = needed.keys()
    110 
    111     # this nexe has 5 dependencies
    112     expected = set(self.dyn_deps)
    113     expected.add(os.path.basename(self.dyn_nexe))
    114 
    115     basenames = set(StripDependencies(names))
    116     self.assertEqual(expected, basenames)
    117 
    118   def testMissingArchLibrary(self):
    119     libdir = os.path.join(self.toolchain, 'x86_64-nacl', 'lib32')
    120     lib_path = [libdir]
    121     nexes = ['libgcc_s.so.1']
    122     # CreateNmfUtils uses the 32-bit library path, but not the 64-bit one
    123     # so searching for a 32-bit library should succeed while searching for
    124     # a 64-bit one should fail.
    125     get_shared_deps.GleanFromObjdump(nexes, 'x86-32', self.objdump, lib_path)
    126     self.assertRaises(get_shared_deps.Error,
    127                       get_shared_deps.GleanFromObjdump,
    128                       nexes, 'x86-64', self.objdump, lib_path)
    129 
    130   def testCorrectArch(self):
    131     lib_path = [os.path.join(self.toolchain, 'x86_64-nacl', 'lib32'),
    132                 os.path.join(self.toolchain, 'x86_64-nacl', 'lib')]
    133 
    134     needed = get_shared_deps.GetNeeded([self.dyn_nexe],
    135                                        lib_path=lib_path,
    136                                        objdump=self.objdump)
    137     for arch in needed.itervalues():
    138       self.assertEqual(arch, 'x86-32')
    139 
    140 
    141 if __name__ == '__main__':
    142   unittest.main()
    143