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