1*8975f5c5SAndroid Build Coastguard Worker#!/usr/bin/env vpython3 2*8975f5c5SAndroid Build Coastguard Worker# Copyright 2022 The Chromium Authors 3*8975f5c5SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 4*8975f5c5SAndroid Build Coastguard Worker# found in the LICENSE file. 5*8975f5c5SAndroid Build Coastguard Worker 6*8975f5c5SAndroid Build Coastguard Workerimport os 7*8975f5c5SAndroid Build Coastguard Workerimport subprocess 8*8975f5c5SAndroid Build Coastguard Workerimport tarfile 9*8975f5c5SAndroid Build Coastguard Workerimport unittest 10*8975f5c5SAndroid Build Coastguard Workerfrom unittest import mock 11*8975f5c5SAndroid Build Coastguard Worker 12*8975f5c5SAndroid Build Coastguard Workerfrom gcs_download import DownloadAndUnpackFromCloudStorage 13*8975f5c5SAndroid Build Coastguard Worker 14*8975f5c5SAndroid Build Coastguard Worker 15*8975f5c5SAndroid Build Coastguard Workerdef _mock_task(status_code: int = 0, stderr: str = '') -> mock.Mock: 16*8975f5c5SAndroid Build Coastguard Worker task_mock = mock.Mock() 17*8975f5c5SAndroid Build Coastguard Worker attrs = { 18*8975f5c5SAndroid Build Coastguard Worker 'returncode': status_code, 19*8975f5c5SAndroid Build Coastguard Worker 'wait.return_value': status_code, 20*8975f5c5SAndroid Build Coastguard Worker 'communicate.return_value': (None, stderr.encode()), 21*8975f5c5SAndroid Build Coastguard Worker } 22*8975f5c5SAndroid Build Coastguard Worker task_mock.configure_mock(**attrs) 23*8975f5c5SAndroid Build Coastguard Worker 24*8975f5c5SAndroid Build Coastguard Worker return task_mock 25*8975f5c5SAndroid Build Coastguard Worker 26*8975f5c5SAndroid Build Coastguard Worker 27*8975f5c5SAndroid Build Coastguard Worker@mock.patch('tempfile.TemporaryDirectory') 28*8975f5c5SAndroid Build Coastguard Worker@mock.patch('gs_util_wrapper.subprocess.run') 29*8975f5c5SAndroid Build Coastguard Worker@mock.patch('tarfile.open') 30*8975f5c5SAndroid Build Coastguard Worker@unittest.skipIf(os.name == 'nt', 'Fuchsia tests not supported on Windows') 31*8975f5c5SAndroid Build Coastguard Workerclass TestDownloadAndUnpackFromCloudStorage(unittest.TestCase): 32*8975f5c5SAndroid Build Coastguard Worker def testHappyPath(self, mock_tarfile, mock_run, mock_tmp_dir): 33*8975f5c5SAndroid Build Coastguard Worker mock_run.return_value = _mock_task() 34*8975f5c5SAndroid Build Coastguard Worker 35*8975f5c5SAndroid Build Coastguard Worker tmp_dir = os.path.join('some', 'tmp', 'dir') 36*8975f5c5SAndroid Build Coastguard Worker mock_tmp_dir.return_value.__enter__.return_value = tmp_dir 37*8975f5c5SAndroid Build Coastguard Worker 38*8975f5c5SAndroid Build Coastguard Worker mock_seq = mock.Mock() 39*8975f5c5SAndroid Build Coastguard Worker mock_seq.attach_mock(mock_run, 'Run') 40*8975f5c5SAndroid Build Coastguard Worker mock_seq.attach_mock(mock_tarfile, 'Untar') 41*8975f5c5SAndroid Build Coastguard Worker mock_seq.attach_mock(mock_tmp_dir, 'MkTmpD') 42*8975f5c5SAndroid Build Coastguard Worker 43*8975f5c5SAndroid Build Coastguard Worker output_dir = os.path.join('output', 'dir') 44*8975f5c5SAndroid Build Coastguard Worker DownloadAndUnpackFromCloudStorage('gs://some/url', output_dir) 45*8975f5c5SAndroid Build Coastguard Worker 46*8975f5c5SAndroid Build Coastguard Worker image_tgz_path = os.path.join(tmp_dir, 'image.tgz') 47*8975f5c5SAndroid Build Coastguard Worker mock_seq.assert_has_calls([ 48*8975f5c5SAndroid Build Coastguard Worker mock.call.MkTmpD(), 49*8975f5c5SAndroid Build Coastguard Worker mock.call.MkTmpD().__enter__(), 50*8975f5c5SAndroid Build Coastguard Worker mock.call.Run(mock.ANY, check=True), 51*8975f5c5SAndroid Build Coastguard Worker mock.call.Untar(name=image_tgz_path, mode='r|gz'), 52*8975f5c5SAndroid Build Coastguard Worker mock.call.Untar().extractall(path=output_dir), 53*8975f5c5SAndroid Build Coastguard Worker mock.call.MkTmpD().__exit__(None, None, None) 54*8975f5c5SAndroid Build Coastguard Worker ], 55*8975f5c5SAndroid Build Coastguard Worker any_order=False) 56*8975f5c5SAndroid Build Coastguard Worker 57*8975f5c5SAndroid Build Coastguard Worker # Verify cmd. 58*8975f5c5SAndroid Build Coastguard Worker cmd = ' '.join(mock_run.call_args[0][0]) 59*8975f5c5SAndroid Build Coastguard Worker self.assertRegex( 60*8975f5c5SAndroid Build Coastguard Worker cmd, 61*8975f5c5SAndroid Build Coastguard Worker r'.*python3?\s.*gsutil.py\s+cp\s+gs://some/url\s+' + image_tgz_path) 62*8975f5c5SAndroid Build Coastguard Worker 63*8975f5c5SAndroid Build Coastguard Worker def testFailedTarOpen(self, mock_tarfile, mock_run, mock_tmp_dir): 64*8975f5c5SAndroid Build Coastguard Worker mock_run.return_value = _mock_task(stderr='some error') 65*8975f5c5SAndroid Build Coastguard Worker mock_tarfile.side_effect = tarfile.ReadError() 66*8975f5c5SAndroid Build Coastguard Worker 67*8975f5c5SAndroid Build Coastguard Worker with self.assertRaises(tarfile.ReadError): 68*8975f5c5SAndroid Build Coastguard Worker DownloadAndUnpackFromCloudStorage('', '') 69*8975f5c5SAndroid Build Coastguard Worker mock_tmp_dir.assert_called_once() 70*8975f5c5SAndroid Build Coastguard Worker mock_run.assert_called_once() 71*8975f5c5SAndroid Build Coastguard Worker mock_tarfile.assert_called_once() 72*8975f5c5SAndroid Build Coastguard Worker 73*8975f5c5SAndroid Build Coastguard Worker def testBadTaskStatusCode(self, mock_tarfile, mock_run, mock_tmp_dir): 74*8975f5c5SAndroid Build Coastguard Worker mock_run.side_effect = subprocess.CalledProcessError(cmd='some/command', 75*8975f5c5SAndroid Build Coastguard Worker returncode=1) 76*8975f5c5SAndroid Build Coastguard Worker 77*8975f5c5SAndroid Build Coastguard Worker with self.assertRaises(subprocess.CalledProcessError): 78*8975f5c5SAndroid Build Coastguard Worker DownloadAndUnpackFromCloudStorage('', '') 79*8975f5c5SAndroid Build Coastguard Worker mock_run.assert_called_once() 80*8975f5c5SAndroid Build Coastguard Worker mock_tarfile.assert_not_called() 81*8975f5c5SAndroid Build Coastguard Worker mock_tmp_dir.assert_called_once() 82*8975f5c5SAndroid Build Coastguard Worker 83*8975f5c5SAndroid Build Coastguard Worker 84*8975f5c5SAndroid Build Coastguard Workerif __name__ == '__main__': 85*8975f5c5SAndroid Build Coastguard Worker unittest.main() 86