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 6import os 7import unittest 8 9from devil import devil_env 10from devil.android import device_errors 11from devil.android import md5sum 12 13with devil_env.SysPath(devil_env.PYMOCK_PATH): 14 import mock # pylint: disable=import-error 15 16TEST_OUT_DIR = os.path.join('test', 'out', 'directory') 17HOST_MD5_EXECUTABLE = os.path.join(TEST_OUT_DIR, 'md5sum_bin_host') 18MD5_DIST = os.path.join(TEST_OUT_DIR, 'md5sum_dist') 19 20 21class Md5SumTest(unittest.TestCase): 22 def setUp(self): 23 mocked_attrs = { 24 'md5sum_host': HOST_MD5_EXECUTABLE, 25 'md5sum_device': MD5_DIST, 26 } 27 self._patchers = [ 28 mock.patch( 29 'devil.devil_env._Environment.FetchPath', 30 mock.Mock(side_effect=lambda a, device=None: mocked_attrs[a])), 31 mock.patch('os.path.exists', new=mock.Mock(return_value=True)), 32 ] 33 for p in self._patchers: 34 p.start() 35 36 def tearDown(self): 37 for p in self._patchers: 38 p.stop() 39 40 def testCalculateHostMd5Sums_singlePath(self): 41 test_path = '/test/host/file.dat' 42 mock_get_cmd_output = mock.Mock( 43 return_value='0123456789abcdef') 44 with mock.patch( 45 'devil.utils.cmd_helper.GetCmdOutput', new=mock_get_cmd_output): 46 out = md5sum.CalculateHostMd5Sums(test_path) 47 self.assertEquals(1, len(out)) 48 self.assertTrue('/test/host/file.dat' in out) 49 self.assertEquals('0123456789abcdef', out['/test/host/file.dat']) 50 mock_get_cmd_output.assert_called_once_with( 51 [HOST_MD5_EXECUTABLE, "-gz", mock.ANY]) 52 53 def testCalculateHostMd5Sums_list(self): 54 test_paths = ['/test/host/file0.dat', '/test/host/file1.dat'] 55 mock_get_cmd_output = mock.Mock( 56 return_value='0123456789abcdef\n123456789abcdef0\n') 57 with mock.patch( 58 'devil.utils.cmd_helper.GetCmdOutput', new=mock_get_cmd_output): 59 out = md5sum.CalculateHostMd5Sums(test_paths) 60 self.assertEquals(2, len(out)) 61 self.assertTrue('/test/host/file0.dat' in out) 62 self.assertEquals('0123456789abcdef', out['/test/host/file0.dat']) 63 self.assertTrue('/test/host/file1.dat' in out) 64 self.assertEquals('123456789abcdef0', out['/test/host/file1.dat']) 65 mock_get_cmd_output.assert_called_once_with( 66 [HOST_MD5_EXECUTABLE, "-gz", mock.ANY]) 67 68 def testCalculateDeviceMd5Sums_noPaths(self): 69 device = mock.NonCallableMock() 70 device.RunShellCommand = mock.Mock(side_effect=Exception()) 71 72 out = md5sum.CalculateDeviceMd5Sums([], device) 73 self.assertEquals(0, len(out)) 74 75 def testCalculateDeviceMd5Sums_singlePath(self): 76 test_path = '/storage/emulated/legacy/test/file.dat' 77 78 device = mock.NonCallableMock() 79 device_md5sum_output = ['0123456789abcdef',] 80 device.RunShellCommand = mock.Mock(return_value=device_md5sum_output) 81 82 with mock.patch('os.path.getsize', return_value=1337): 83 out = md5sum.CalculateDeviceMd5Sums(test_path, device) 84 self.assertEquals(1, len(out)) 85 self.assertTrue('/storage/emulated/legacy/test/file.dat' in out) 86 self.assertEquals('0123456789abcdef', 87 out['/storage/emulated/legacy/test/file.dat']) 88 self.assertEquals(1, len(device.RunShellCommand.call_args_list)) 89 90 def testCalculateDeviceMd5Sums_list(self): 91 test_path = [ 92 '/storage/emulated/legacy/test/file0.dat', 93 '/storage/emulated/legacy/test/file1.dat' 94 ] 95 device = mock.NonCallableMock() 96 device_md5sum_output = [ 97 '0123456789abcdef', 98 '123456789abcdef0', 99 ] 100 device.RunShellCommand = mock.Mock(return_value=device_md5sum_output) 101 102 with mock.patch('os.path.getsize', return_value=1337): 103 out = md5sum.CalculateDeviceMd5Sums(test_path, device) 104 self.assertEquals(2, len(out)) 105 self.assertTrue('/storage/emulated/legacy/test/file0.dat' in out) 106 self.assertEquals('0123456789abcdef', 107 out['/storage/emulated/legacy/test/file0.dat']) 108 self.assertTrue('/storage/emulated/legacy/test/file1.dat' in out) 109 self.assertEquals('123456789abcdef0', 110 out['/storage/emulated/legacy/test/file1.dat']) 111 self.assertEquals(1, len(device.RunShellCommand.call_args_list)) 112 113 def testCalculateDeviceMd5Sums_generator(self): 114 test_path = ('/storage/emulated/legacy/test/file%d.dat' % n 115 for n in range(0, 2)) 116 117 device = mock.NonCallableMock() 118 device_md5sum_output = [ 119 '0123456789abcdef', 120 '123456789abcdef0', 121 ] 122 device.RunShellCommand = mock.Mock(return_value=device_md5sum_output) 123 124 with mock.patch('os.path.getsize', return_value=1337): 125 out = md5sum.CalculateDeviceMd5Sums(test_path, device) 126 self.assertEquals(2, len(out)) 127 self.assertTrue('/storage/emulated/legacy/test/file0.dat' in out) 128 self.assertEquals('0123456789abcdef', 129 out['/storage/emulated/legacy/test/file0.dat']) 130 self.assertTrue('/storage/emulated/legacy/test/file1.dat' in out) 131 self.assertEquals('123456789abcdef0', 132 out['/storage/emulated/legacy/test/file1.dat']) 133 self.assertEquals(1, len(device.RunShellCommand.call_args_list)) 134 135 def testCalculateDeviceMd5Sums_singlePath_linkerWarning(self): 136 # See crbug/479966 137 test_path = '/storage/emulated/legacy/test/file.dat' 138 139 device = mock.NonCallableMock() 140 device_md5sum_output = [ 141 'WARNING: linker: /data/local/tmp/md5sum/md5sum_bin: ' 142 'unused DT entry: type 0x1d arg 0x15db', 143 'THIS_IS_NOT_A_VALID_CHECKSUM_ZZZ some random text', 144 '0123456789abcdef', 145 ] 146 device.RunShellCommand = mock.Mock(return_value=device_md5sum_output) 147 148 with mock.patch('os.path.getsize', return_value=1337): 149 out = md5sum.CalculateDeviceMd5Sums(test_path, device) 150 self.assertEquals(1, len(out)) 151 self.assertTrue('/storage/emulated/legacy/test/file.dat' in out) 152 self.assertEquals('0123456789abcdef', 153 out['/storage/emulated/legacy/test/file.dat']) 154 self.assertEquals(1, len(device.RunShellCommand.call_args_list)) 155 156 def testCalculateDeviceMd5Sums_list_fileMissing(self): 157 test_path = [ 158 '/storage/emulated/legacy/test/file0.dat', 159 '/storage/emulated/legacy/test/file1.dat' 160 ] 161 device = mock.NonCallableMock() 162 device_md5sum_output = [ 163 '0123456789abcdef', 164 '[0819/203513:ERROR:md5sum.cc(25)] Could not open file asdf', 165 '', 166 ] 167 device.RunShellCommand = mock.Mock(return_value=device_md5sum_output) 168 169 with mock.patch('os.path.getsize', return_value=1337): 170 out = md5sum.CalculateDeviceMd5Sums(test_path, device) 171 self.assertEquals(1, len(out)) 172 self.assertTrue('/storage/emulated/legacy/test/file0.dat' in out) 173 self.assertEquals('0123456789abcdef', 174 out['/storage/emulated/legacy/test/file0.dat']) 175 self.assertEquals(1, len(device.RunShellCommand.call_args_list)) 176 177 def testCalculateDeviceMd5Sums_requiresBinary(self): 178 test_path = '/storage/emulated/legacy/test/file.dat' 179 180 device = mock.NonCallableMock() 181 device.adb = mock.NonCallableMock() 182 device.adb.Push = mock.Mock() 183 device_md5sum_output = [ 184 'WARNING: linker: /data/local/tmp/md5sum/md5sum_bin: ' 185 'unused DT entry: type 0x1d arg 0x15db', 186 'THIS_IS_NOT_A_VALID_CHECKSUM_ZZZ some random text', 187 '0123456789abcdef', 188 ] 189 error = device_errors.AdbShellCommandFailedError('cmd', 'out', 2) 190 device.RunShellCommand = mock.Mock( 191 side_effect=(error, '', device_md5sum_output)) 192 193 with mock.patch( 194 'os.path.isdir', return_value=True), (mock.patch( 195 'os.path.getsize', return_value=1337)): 196 out = md5sum.CalculateDeviceMd5Sums(test_path, device) 197 self.assertEquals(1, len(out)) 198 self.assertTrue('/storage/emulated/legacy/test/file.dat' in out) 199 self.assertEquals('0123456789abcdef', 200 out['/storage/emulated/legacy/test/file.dat']) 201 self.assertEquals(3, len(device.RunShellCommand.call_args_list)) 202 device.adb.Push.assert_called_once_with('test/out/directory/md5sum_dist', 203 '/data/local/tmp/md5sum') 204 205 206if __name__ == '__main__': 207 unittest.main(verbosity=2) 208