1*d68f33bcSAndroid Build Coastguard Worker#!/usr/bin/env python3 2*d68f33bcSAndroid Build Coastguard Worker# Copyright 2019 The Android Open Source Project 3*d68f33bcSAndroid Build Coastguard Worker# 4*d68f33bcSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 5*d68f33bcSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 6*d68f33bcSAndroid Build Coastguard Worker# You may obtain a copy of the License at 7*d68f33bcSAndroid Build Coastguard Worker# 8*d68f33bcSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 9*d68f33bcSAndroid Build Coastguard Worker# 10*d68f33bcSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 11*d68f33bcSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 12*d68f33bcSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*d68f33bcSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 14*d68f33bcSAndroid Build Coastguard Worker# limitations under the License. 15*d68f33bcSAndroid Build Coastguard Worker 16*d68f33bcSAndroid Build Coastguard Worker"""Unittests for the utils module.""" 17*d68f33bcSAndroid Build Coastguard Worker 18*d68f33bcSAndroid Build Coastguard Workerimport datetime 19*d68f33bcSAndroid Build Coastguard Workerimport os 20*d68f33bcSAndroid Build Coastguard Workerfrom pathlib import Path 21*d68f33bcSAndroid Build Coastguard Workerimport sys 22*d68f33bcSAndroid Build Coastguard Workerimport unittest 23*d68f33bcSAndroid Build Coastguard Worker 24*d68f33bcSAndroid Build Coastguard Worker_path = os.path.realpath(__file__ + '/../..') 25*d68f33bcSAndroid Build Coastguard Workerif sys.path[0] != _path: 26*d68f33bcSAndroid Build Coastguard Worker sys.path.insert(0, _path) 27*d68f33bcSAndroid Build Coastguard Workerdel _path 28*d68f33bcSAndroid Build Coastguard Worker 29*d68f33bcSAndroid Build Coastguard Worker# We have to import our local modules after the sys.path tweak. We can't use 30*d68f33bcSAndroid Build Coastguard Worker# relative imports because this is an executable program, not a module. 31*d68f33bcSAndroid Build Coastguard Worker# pylint: disable=wrong-import-position 32*d68f33bcSAndroid Build Coastguard Workerimport rh 33*d68f33bcSAndroid Build Coastguard Workerimport rh.utils 34*d68f33bcSAndroid Build Coastguard Worker 35*d68f33bcSAndroid Build Coastguard Worker 36*d68f33bcSAndroid Build Coastguard Workerclass TimeDeltaStrTests(unittest.TestCase): 37*d68f33bcSAndroid Build Coastguard Worker """Verify behavior of timedelta_str object.""" 38*d68f33bcSAndroid Build Coastguard Worker 39*d68f33bcSAndroid Build Coastguard Worker def test_same(self): 40*d68f33bcSAndroid Build Coastguard Worker """Check timedelta of 0 seconds.""" 41*d68f33bcSAndroid Build Coastguard Worker delta = datetime.timedelta(0) 42*d68f33bcSAndroid Build Coastguard Worker self.assertEqual('0.000s', rh.utils.timedelta_str(delta)) 43*d68f33bcSAndroid Build Coastguard Worker 44*d68f33bcSAndroid Build Coastguard Worker def test_millisecondss(self): 45*d68f33bcSAndroid Build Coastguard Worker """Check timedelta of milliseconds.""" 46*d68f33bcSAndroid Build Coastguard Worker delta = datetime.timedelta(seconds=0.123456) 47*d68f33bcSAndroid Build Coastguard Worker self.assertEqual('0.123s', rh.utils.timedelta_str(delta)) 48*d68f33bcSAndroid Build Coastguard Worker 49*d68f33bcSAndroid Build Coastguard Worker def test_seconds(self): 50*d68f33bcSAndroid Build Coastguard Worker """Check timedelta of seconds.""" 51*d68f33bcSAndroid Build Coastguard Worker delta = datetime.timedelta(seconds=12.3) 52*d68f33bcSAndroid Build Coastguard Worker self.assertEqual('12.300s', rh.utils.timedelta_str(delta)) 53*d68f33bcSAndroid Build Coastguard Worker 54*d68f33bcSAndroid Build Coastguard Worker def test_minutes(self): 55*d68f33bcSAndroid Build Coastguard Worker """Check timedelta of minutes.""" 56*d68f33bcSAndroid Build Coastguard Worker delta = datetime.timedelta(seconds=72.3) 57*d68f33bcSAndroid Build Coastguard Worker self.assertEqual('1m12.300s', rh.utils.timedelta_str(delta)) 58*d68f33bcSAndroid Build Coastguard Worker 59*d68f33bcSAndroid Build Coastguard Worker def test_hours(self): 60*d68f33bcSAndroid Build Coastguard Worker """Check timedelta of hours.""" 61*d68f33bcSAndroid Build Coastguard Worker delta = datetime.timedelta(seconds=4000.3) 62*d68f33bcSAndroid Build Coastguard Worker self.assertEqual('1h6m40.300s', rh.utils.timedelta_str(delta)) 63*d68f33bcSAndroid Build Coastguard Worker 64*d68f33bcSAndroid Build Coastguard Worker 65*d68f33bcSAndroid Build Coastguard Workerclass CompletedProcessTests(unittest.TestCase): 66*d68f33bcSAndroid Build Coastguard Worker """Verify behavior of CompletedProcess object.""" 67*d68f33bcSAndroid Build Coastguard Worker 68*d68f33bcSAndroid Build Coastguard Worker def test_empty_cmdstr(self): 69*d68f33bcSAndroid Build Coastguard Worker """Check cmdstr with an empty command.""" 70*d68f33bcSAndroid Build Coastguard Worker result = rh.utils.CompletedProcess(args=[]) 71*d68f33bcSAndroid Build Coastguard Worker self.assertEqual('', result.cmdstr) 72*d68f33bcSAndroid Build Coastguard Worker 73*d68f33bcSAndroid Build Coastguard Worker def test_basic_cmdstr(self): 74*d68f33bcSAndroid Build Coastguard Worker """Check cmdstr with a basic command command.""" 75*d68f33bcSAndroid Build Coastguard Worker result = rh.utils.CompletedProcess(args=['ls', 'a b']) 76*d68f33bcSAndroid Build Coastguard Worker self.assertEqual("ls 'a b'", result.cmdstr) 77*d68f33bcSAndroid Build Coastguard Worker 78*d68f33bcSAndroid Build Coastguard Worker def test_str(self): 79*d68f33bcSAndroid Build Coastguard Worker """Check str() handling.""" 80*d68f33bcSAndroid Build Coastguard Worker # We don't enforce much, just that it doesn't crash. 81*d68f33bcSAndroid Build Coastguard Worker result = rh.utils.CompletedProcess() 82*d68f33bcSAndroid Build Coastguard Worker self.assertNotEqual('', str(result)) 83*d68f33bcSAndroid Build Coastguard Worker result = rh.utils.CompletedProcess(args=[]) 84*d68f33bcSAndroid Build Coastguard Worker self.assertNotEqual('', str(result)) 85*d68f33bcSAndroid Build Coastguard Worker 86*d68f33bcSAndroid Build Coastguard Worker def test_repr(self): 87*d68f33bcSAndroid Build Coastguard Worker """Check repr() handling.""" 88*d68f33bcSAndroid Build Coastguard Worker # We don't enforce much, just that it doesn't crash. 89*d68f33bcSAndroid Build Coastguard Worker result = rh.utils.CompletedProcess() 90*d68f33bcSAndroid Build Coastguard Worker self.assertNotEqual('', repr(result)) 91*d68f33bcSAndroid Build Coastguard Worker result = rh.utils.CompletedProcess(args=[]) 92*d68f33bcSAndroid Build Coastguard Worker self.assertNotEqual('', repr(result)) 93*d68f33bcSAndroid Build Coastguard Worker 94*d68f33bcSAndroid Build Coastguard Worker 95*d68f33bcSAndroid Build Coastguard Workerclass CalledProcessErrorTests(unittest.TestCase): 96*d68f33bcSAndroid Build Coastguard Worker """Verify behavior of CalledProcessError object.""" 97*d68f33bcSAndroid Build Coastguard Worker 98*d68f33bcSAndroid Build Coastguard Worker def test_basic(self): 99*d68f33bcSAndroid Build Coastguard Worker """Basic test we can create a normal instance.""" 100*d68f33bcSAndroid Build Coastguard Worker rh.utils.CalledProcessError(0, ['mycmd']) 101*d68f33bcSAndroid Build Coastguard Worker 102*d68f33bcSAndroid Build Coastguard Worker def test_stringify(self): 103*d68f33bcSAndroid Build Coastguard Worker """Check stringify() handling.""" 104*d68f33bcSAndroid Build Coastguard Worker # We don't assert much so we leave flexibility in changing format. 105*d68f33bcSAndroid Build Coastguard Worker err = rh.utils.CalledProcessError(0, ['mycmd']) 106*d68f33bcSAndroid Build Coastguard Worker self.assertIn('mycmd', err.stringify()) 107*d68f33bcSAndroid Build Coastguard Worker 108*d68f33bcSAndroid Build Coastguard Worker def test_str(self): 109*d68f33bcSAndroid Build Coastguard Worker """Check str() handling.""" 110*d68f33bcSAndroid Build Coastguard Worker # We don't assert much so we leave flexibility in changing format. 111*d68f33bcSAndroid Build Coastguard Worker err = rh.utils.CalledProcessError(0, ['mycmd']) 112*d68f33bcSAndroid Build Coastguard Worker self.assertIn('mycmd', str(err)) 113*d68f33bcSAndroid Build Coastguard Worker 114*d68f33bcSAndroid Build Coastguard Worker def test_repr(self): 115*d68f33bcSAndroid Build Coastguard Worker """Check repr() handling.""" 116*d68f33bcSAndroid Build Coastguard Worker # We don't assert much so we leave flexibility in changing format. 117*d68f33bcSAndroid Build Coastguard Worker err = rh.utils.CalledProcessError(0, ['mycmd']) 118*d68f33bcSAndroid Build Coastguard Worker self.assertNotEqual('', repr(err)) 119*d68f33bcSAndroid Build Coastguard Worker 120*d68f33bcSAndroid Build Coastguard Worker def test_output(self): 121*d68f33bcSAndroid Build Coastguard Worker """Make sure .output is removed and .stdout works.""" 122*d68f33bcSAndroid Build Coastguard Worker e = rh.utils.CalledProcessError( 123*d68f33bcSAndroid Build Coastguard Worker 0, ['true'], stdout='STDOUT', stderr='STDERR') 124*d68f33bcSAndroid Build Coastguard Worker with self.assertRaises(AttributeError): 125*d68f33bcSAndroid Build Coastguard Worker assert e.output is None 126*d68f33bcSAndroid Build Coastguard Worker assert e.stdout == 'STDOUT' 127*d68f33bcSAndroid Build Coastguard Worker assert e.stderr == 'STDERR' 128*d68f33bcSAndroid Build Coastguard Worker 129*d68f33bcSAndroid Build Coastguard Worker e.stdout = 'STDout' 130*d68f33bcSAndroid Build Coastguard Worker e.stderr = 'STDerr' 131*d68f33bcSAndroid Build Coastguard Worker with self.assertRaises(AttributeError): 132*d68f33bcSAndroid Build Coastguard Worker assert e.output is None 133*d68f33bcSAndroid Build Coastguard Worker assert e.stdout == 'STDout' 134*d68f33bcSAndroid Build Coastguard Worker assert e.stderr == 'STDerr' 135*d68f33bcSAndroid Build Coastguard Worker 136*d68f33bcSAndroid Build Coastguard Worker 137*d68f33bcSAndroid Build Coastguard Workerclass RunCommandTests(unittest.TestCase): 138*d68f33bcSAndroid Build Coastguard Worker """Verify behavior of run helper.""" 139*d68f33bcSAndroid Build Coastguard Worker 140*d68f33bcSAndroid Build Coastguard Worker def test_basic(self): 141*d68f33bcSAndroid Build Coastguard Worker """Simple basic test.""" 142*d68f33bcSAndroid Build Coastguard Worker ret = rh.utils.run(['true']) 143*d68f33bcSAndroid Build Coastguard Worker self.assertEqual('true', ret.cmdstr) 144*d68f33bcSAndroid Build Coastguard Worker self.assertIsNone(ret.stdout) 145*d68f33bcSAndroid Build Coastguard Worker self.assertIsNone(ret.stderr) 146*d68f33bcSAndroid Build Coastguard Worker 147*d68f33bcSAndroid Build Coastguard Worker def test_stdout_capture(self): 148*d68f33bcSAndroid Build Coastguard Worker """Verify output capturing works.""" 149*d68f33bcSAndroid Build Coastguard Worker ret = rh.utils.run(['echo', 'hi'], redirect_stdout=True) 150*d68f33bcSAndroid Build Coastguard Worker self.assertEqual('hi\n', ret.stdout) 151*d68f33bcSAndroid Build Coastguard Worker self.assertIsNone(ret.stderr) 152*d68f33bcSAndroid Build Coastguard Worker 153*d68f33bcSAndroid Build Coastguard Worker def test_stderr_capture(self): 154*d68f33bcSAndroid Build Coastguard Worker """Verify stderr capturing works.""" 155*d68f33bcSAndroid Build Coastguard Worker ret = rh.utils.run(['sh', '-c', 'echo hi >&2'], redirect_stderr=True) 156*d68f33bcSAndroid Build Coastguard Worker self.assertIsNone(ret.stdout) 157*d68f33bcSAndroid Build Coastguard Worker self.assertEqual('hi\n', ret.stderr) 158*d68f33bcSAndroid Build Coastguard Worker 159*d68f33bcSAndroid Build Coastguard Worker def test_stdout_utf8(self): 160*d68f33bcSAndroid Build Coastguard Worker """Verify reading UTF-8 data works.""" 161*d68f33bcSAndroid Build Coastguard Worker ret = rh.utils.run(['printf', r'\xc3\x9f'], redirect_stdout=True) 162*d68f33bcSAndroid Build Coastguard Worker self.assertEqual('ß', ret.stdout) 163*d68f33bcSAndroid Build Coastguard Worker self.assertIsNone(ret.stderr) 164*d68f33bcSAndroid Build Coastguard Worker 165*d68f33bcSAndroid Build Coastguard Worker def test_stdin_utf8(self): 166*d68f33bcSAndroid Build Coastguard Worker """Verify writing UTF-8 data works.""" 167*d68f33bcSAndroid Build Coastguard Worker ret = rh.utils.run(['cat'], redirect_stdout=True, input='ß') 168*d68f33bcSAndroid Build Coastguard Worker self.assertEqual('ß', ret.stdout) 169*d68f33bcSAndroid Build Coastguard Worker self.assertIsNone(ret.stderr) 170*d68f33bcSAndroid Build Coastguard Worker 171*d68f33bcSAndroid Build Coastguard Worker def test_check_false(self): 172*d68f33bcSAndroid Build Coastguard Worker """Verify handling of check=False.""" 173*d68f33bcSAndroid Build Coastguard Worker ret = rh.utils.run(['false'], check=False) 174*d68f33bcSAndroid Build Coastguard Worker self.assertNotEqual(0, ret.returncode) 175*d68f33bcSAndroid Build Coastguard Worker self.assertIn('false', str(ret)) 176*d68f33bcSAndroid Build Coastguard Worker 177*d68f33bcSAndroid Build Coastguard Worker ret = rh.utils.run(['true'], check=False) 178*d68f33bcSAndroid Build Coastguard Worker self.assertEqual(0, ret.returncode) 179*d68f33bcSAndroid Build Coastguard Worker self.assertIn('true', str(ret)) 180*d68f33bcSAndroid Build Coastguard Worker 181*d68f33bcSAndroid Build Coastguard Worker def test_check_true(self): 182*d68f33bcSAndroid Build Coastguard Worker """Verify handling of check=True.""" 183*d68f33bcSAndroid Build Coastguard Worker with self.assertRaises(rh.utils.CalledProcessError) as e: 184*d68f33bcSAndroid Build Coastguard Worker rh.utils.run(['false'], check=True) 185*d68f33bcSAndroid Build Coastguard Worker err = e.exception 186*d68f33bcSAndroid Build Coastguard Worker self.assertNotEqual(0, err.returncode) 187*d68f33bcSAndroid Build Coastguard Worker self.assertIn('false', str(err)) 188*d68f33bcSAndroid Build Coastguard Worker 189*d68f33bcSAndroid Build Coastguard Worker ret = rh.utils.run(['true'], check=True) 190*d68f33bcSAndroid Build Coastguard Worker self.assertEqual(0, ret.returncode) 191*d68f33bcSAndroid Build Coastguard Worker self.assertIn('true', str(ret)) 192*d68f33bcSAndroid Build Coastguard Worker 193*d68f33bcSAndroid Build Coastguard Worker def test_check_false_output(self): 194*d68f33bcSAndroid Build Coastguard Worker """Verify handling of output capturing w/check=False.""" 195*d68f33bcSAndroid Build Coastguard Worker with self.assertRaises(rh.utils.CalledProcessError) as e: 196*d68f33bcSAndroid Build Coastguard Worker rh.utils.run(['sh', '-c', 'echo out; echo err >&2; false'], 197*d68f33bcSAndroid Build Coastguard Worker check=True, capture_output=True) 198*d68f33bcSAndroid Build Coastguard Worker err = e.exception 199*d68f33bcSAndroid Build Coastguard Worker self.assertNotEqual(0, err.returncode) 200*d68f33bcSAndroid Build Coastguard Worker self.assertIn('false', str(err)) 201*d68f33bcSAndroid Build Coastguard Worker 202*d68f33bcSAndroid Build Coastguard Worker def test_check_true_missing_prog_output(self): 203*d68f33bcSAndroid Build Coastguard Worker """Verify handling of output capturing w/missing progs.""" 204*d68f33bcSAndroid Build Coastguard Worker with self.assertRaises(rh.utils.CalledProcessError) as e: 205*d68f33bcSAndroid Build Coastguard Worker rh.utils.run(['./!~a/b/c/d/'], check=True, capture_output=True) 206*d68f33bcSAndroid Build Coastguard Worker err = e.exception 207*d68f33bcSAndroid Build Coastguard Worker self.assertNotEqual(0, err.returncode) 208*d68f33bcSAndroid Build Coastguard Worker self.assertIn('a/b/c/d', str(err)) 209*d68f33bcSAndroid Build Coastguard Worker 210*d68f33bcSAndroid Build Coastguard Worker def test_check_false_missing_prog_output(self): 211*d68f33bcSAndroid Build Coastguard Worker """Verify handling of output capturing w/missing progs.""" 212*d68f33bcSAndroid Build Coastguard Worker ret = rh.utils.run(['./!~a/b/c/d/'], check=False, capture_output=True) 213*d68f33bcSAndroid Build Coastguard Worker self.assertNotEqual(0, ret.returncode) 214*d68f33bcSAndroid Build Coastguard Worker self.assertIn('a/b/c/d', str(ret)) 215*d68f33bcSAndroid Build Coastguard Worker 216*d68f33bcSAndroid Build Coastguard Worker def test_check_false_missing_prog_combined_output(self): 217*d68f33bcSAndroid Build Coastguard Worker """Verify handling of combined output capturing w/missing progs.""" 218*d68f33bcSAndroid Build Coastguard Worker with self.assertRaises(rh.utils.CalledProcessError) as e: 219*d68f33bcSAndroid Build Coastguard Worker rh.utils.run(['./!~a/b/c/d/'], check=True, 220*d68f33bcSAndroid Build Coastguard Worker combine_stdout_stderr=True) 221*d68f33bcSAndroid Build Coastguard Worker err = e.exception 222*d68f33bcSAndroid Build Coastguard Worker self.assertNotEqual(0, err.returncode) 223*d68f33bcSAndroid Build Coastguard Worker self.assertIn('a/b/c/d', str(err)) 224*d68f33bcSAndroid Build Coastguard Worker 225*d68f33bcSAndroid Build Coastguard Worker def test_pathlib(self): 226*d68f33bcSAndroid Build Coastguard Worker """Verify pathlib arguments work.""" 227*d68f33bcSAndroid Build Coastguard Worker result = rh.utils.run(['true', Path('/')]) 228*d68f33bcSAndroid Build Coastguard Worker # Verify stringify behavior. 229*d68f33bcSAndroid Build Coastguard Worker str(result) 230*d68f33bcSAndroid Build Coastguard Worker self.assertEqual(result.cmdstr, 'true /') 231*d68f33bcSAndroid Build Coastguard Worker 232*d68f33bcSAndroid Build Coastguard Worker 233*d68f33bcSAndroid Build Coastguard Workerif __name__ == '__main__': 234*d68f33bcSAndroid Build Coastguard Worker unittest.main() 235