Home | History | Annotate | Download | only in test
      1 #!/usr/bin/python
      2 
      3 # Copyright 2016, The Android Open Source Project
      4 #
      5 # Permission is hereby granted, free of charge, to any person
      6 # obtaining a copy of this software and associated documentation
      7 # files (the "Software"), to deal in the Software without
      8 # restriction, including without limitation the rights to use, copy,
      9 # modify, merge, publish, distribute, sublicense, and/or sell copies
     10 # of the Software, and to permit persons to whom the Software is
     11 # furnished to do so, subject to the following conditions:
     12 #
     13 # The above copyright notice and this permission notice shall be
     14 # included in all copies or substantial portions of the Software.
     15 #
     16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     17 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     18 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     19 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
     20 # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
     21 # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     22 # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     23 # SOFTWARE.
     24 
     25 
     26 """Unit-test for ImageHandler."""
     27 
     28 
     29 import imp
     30 import os
     31 import sys
     32 import tempfile
     33 import unittest
     34 
     35 sys.dont_write_bytecode = True
     36 avbtool = imp.load_source('avbtool', './avbtool')
     37 
     38 # The file test_file.bin and test_file.bin.sparse are generated using
     39 # the following python code:
     40 #
     41 #  with open('test_file.bin', 'w+b') as f:
     42 #    f.write('Barfoo43'*128*12)
     43 #  os.system('img2simg test_file.bin test_file.bin.sparse')
     44 #  image = avbtool.ImageHandler('test_file.bin.sparse')
     45 #  image.append_dont_care(12*1024)
     46 #  image.append_fill('\x01\x02\x03\x04', 12*1024)
     47 #  image.append_raw('Foobar42'*128*12)
     48 #  image.append_dont_care(12*1024)
     49 #  del image
     50 #  os.system('rm -f test_file.bin')
     51 #  os.system('simg2img test_file.bin.sparse test_file.bin')
     52 #
     53 # and manually verified to be correct. The content of the raw and
     54 # sparse files are as follows (the line with "Fill with 0x04030201" is
     55 # a simg_dump.py bug):
     56 #
     57 # $ hexdump -C test_file.bin
     58 # 00000000  42 61 72 66 6f 6f 34 33  42 61 72 66 6f 6f 34 33  |Barfoo43Barfoo43|
     59 # *
     60 # 00003000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
     61 # *
     62 # 00006000  01 02 03 04 01 02 03 04  01 02 03 04 01 02 03 04  |................|
     63 # *
     64 # 00009000  46 6f 6f 62 61 72 34 32  46 6f 6f 62 61 72 34 32  |Foobar42Foobar42|
     65 # *
     66 # 0000c000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
     67 # *
     68 # 0000f000
     69 #
     70 # $ system/core/libsparse/simg_dump.py -v test_file.bin.sparse
     71 # test_file.bin.sparse: Total of 15 4096-byte output blocks in 5 input chunks.
     72 #             input_bytes      output_blocks
     73 # chunk    offset     number  offset  number
     74 #    1         40      12288       0       3 Raw data
     75 #    2      12340          0       3       3 Don't care
     76 #    3      12352          4       6       3 Fill with 0x04030201
     77 #    4      12368      12288       9       3 Raw data
     78 #    5      24668          0      12       3 Don't care
     79 #           24668                 15         End
     80 #
     81 
     82 
     83 class ImageHandler(unittest.TestCase):
     84 
     85   TEST_FILE_SPARSE_PATH = 'test/data/test_file.bin.sparse'
     86   TEST_FILE_PATH = 'test/data/test_file.bin'
     87   TEST_FILE_SIZE = 61440
     88   TEST_FILE_BLOCK_SIZE = 4096
     89 
     90   def _file_contents_equal(self, path1, path2, size):
     91     f1 = open(path1, 'r')
     92     f2 = open(path2, 'r')
     93     if f1.read(size) != f2.read(size):
     94       return False
     95     return True
     96 
     97   def _file_size(self, f):
     98     old_pos = f.tell()
     99     f.seek(0, os.SEEK_END)
    100     size = f.tell()
    101     f.seek(old_pos)
    102     return size
    103 
    104   def _clone_sparse_file(self):
    105     f = tempfile.NamedTemporaryFile()
    106     f.write(open(self.TEST_FILE_SPARSE_PATH).read())
    107     f.flush()
    108     return f
    109 
    110   def _unsparsify(self, path):
    111     f = tempfile.NamedTemporaryFile()
    112     os.system('simg2img {} {}'.format(path, f.name))
    113     return f
    114 
    115   def testRead(self):
    116     """Checks that reading from a sparse file works as intended."""
    117     ih = avbtool.ImageHandler(self.TEST_FILE_SPARSE_PATH)
    118 
    119     # Check that we start at offset 0.
    120     self.assertEqual(ih.tell(), 0)
    121 
    122     # Check that reading advances the cursor.
    123     self.assertEqual(ih.read(14), bytearray('Barfoo43Barfoo'))
    124     self.assertEqual(ih.tell(), 14)
    125     self.assertEqual(ih.read(2), bytearray('43'))
    126     self.assertEqual(ih.tell(), 16)
    127 
    128     # Check reading in the middle of a fill chunk gets the right data.
    129     ih.seek(0x6000 + 1)
    130     self.assertEqual(ih.read(4), bytearray('\x02\x03\x04\x01'))
    131 
    132     # Check we can cross the chunk boundary correctly.
    133     ih.seek(0x3000 - 10)
    134     self.assertEqual(ih.read(12), bytearray('43Barfoo43\x00\x00'))
    135     ih.seek(0x9000 - 3)
    136     self.assertEqual(ih.read(5), bytearray('\x02\x03\x04Fo'))
    137 
    138     # Check reading at end of file is a partial read.
    139     ih.seek(0xf000 - 2)
    140     self.assertEqual(ih.read(16), bytearray('\x00\x00'))
    141 
    142   def testTruncate(self):
    143     """Checks that we can truncate a sparse file correctly."""
    144     # Check truncation at all possible boundaries (including start and end).
    145     for size in range(0, self.TEST_FILE_SIZE + self.TEST_FILE_BLOCK_SIZE,
    146                       self.TEST_FILE_BLOCK_SIZE):
    147       sparse_file = self._clone_sparse_file()
    148       ih = avbtool.ImageHandler(sparse_file.name)
    149       ih.truncate(size)
    150       unsparse_file = self._unsparsify(sparse_file.name)
    151       self.assertEqual(self._file_size(unsparse_file), size)
    152       self.assertTrue(self._file_contents_equal(unsparse_file.name,
    153                                                 self.TEST_FILE_PATH,
    154                                                 size))
    155 
    156     # Check truncation to grow the file.
    157     grow_size = 8192
    158     sparse_file = self._clone_sparse_file()
    159     ih = avbtool.ImageHandler(sparse_file.name)
    160     ih.truncate(self.TEST_FILE_SIZE + grow_size)
    161     unsparse_file = self._unsparsify(sparse_file.name)
    162     self.assertEqual(self._file_size(unsparse_file),
    163                      self.TEST_FILE_SIZE + grow_size)
    164     self.assertTrue(self._file_contents_equal(unsparse_file.name,
    165                                               self.TEST_FILE_PATH,
    166                                               self.TEST_FILE_SIZE))
    167     unsparse_file.seek(self.TEST_FILE_SIZE)
    168     self.assertEqual(unsparse_file.read(), '\0'*grow_size)
    169 
    170   def testAppendRaw(self):
    171     """Checks that we can append raw data correctly."""
    172     sparse_file = self._clone_sparse_file()
    173     ih = avbtool.ImageHandler(sparse_file.name)
    174     data = 'SomeData'*4096
    175     ih.append_raw(data)
    176     unsparse_file = self._unsparsify(sparse_file.name)
    177     self.assertTrue(self._file_contents_equal(unsparse_file.name,
    178                                               self.TEST_FILE_PATH,
    179                                               self.TEST_FILE_SIZE))
    180     unsparse_file.seek(self.TEST_FILE_SIZE)
    181     self.assertEqual(unsparse_file.read(), data)
    182 
    183   def testAppendFill(self):
    184     """Checks that we can append fill data correctly."""
    185     sparse_file = self._clone_sparse_file()
    186     ih = avbtool.ImageHandler(sparse_file.name)
    187     data = 'ABCD'*4096
    188     ih.append_fill('ABCD', len(data))
    189     unsparse_file = self._unsparsify(sparse_file.name)
    190     self.assertTrue(self._file_contents_equal(unsparse_file.name,
    191                                               self.TEST_FILE_PATH,
    192                                               self.TEST_FILE_SIZE))
    193     unsparse_file.seek(self.TEST_FILE_SIZE)
    194     self.assertEqual(unsparse_file.read(), data)
    195 
    196   def testDontCare(self):
    197     """Checks that we can append DONT_CARE data correctly."""
    198     sparse_file = self._clone_sparse_file()
    199     ih = avbtool.ImageHandler(sparse_file.name)
    200     data = '\0'*40960
    201     ih.append_dont_care(len(data))
    202     unsparse_file = self._unsparsify(sparse_file.name)
    203     self.assertTrue(self._file_contents_equal(unsparse_file.name,
    204                                               self.TEST_FILE_PATH,
    205                                               self.TEST_FILE_SIZE))
    206     unsparse_file.seek(self.TEST_FILE_SIZE)
    207     self.assertEqual(unsparse_file.read(), data)
    208 
    209 
    210 if __name__ == '__main__':
    211   unittest.main()
    212