1#!/usr/bin/env python2 2# 3# Copyright 2010 Google Inc. All Rights Reserved. 4"""Script adapter used by automation client for testing dejagnu. 5 6 This is not intended to be run on command line. 7 To kick off a single dejagnu run, use ./dejagnu/run_dejagnu.py 8""" 9 10from __future__ import print_function 11 12__author__ = 'shenhan@google.com (Han Shen)' 13 14import argparse 15import sys 16import setup_chromeos 17import build_tc 18 19from dejagnu import run_dejagnu 20from cros_utils import command_executer 21from cros_utils import email_sender 22 23 24class DejagnuAdapter(object): 25 """Dejagnu Adapter class""" 26 27 # TODO(shenhan): move these to constants.py. 28 _CHROMIUM_GCC_GIT = ('https://chromium.googlesource.com/' 29 'chromiumos/third_party/gcc.git') 30 _CHROMIUM_GCC_BRANCH = 'gcc.gnu.org/branches/google/gcc-4_7-mobile' 31 32 _cmd_exec = command_executer.GetCommandExecuter() 33 34 def __init__(self, board, remote, gcc_dir, chromeos_root, runtestflags, 35 cleanup): 36 self._board = board 37 self._remote = remote 38 self._gcc_dir = gcc_dir 39 self._chromeos_root = chromeos_root 40 self._runtestflags = runtestflags 41 self._cleanup = cleanup 42 43 def SetupChromeOS(self): 44 cmd = [ 45 setup_chromeos.__file__, '--dir=' + self._chromeos_root, '--minilayout', 46 '--jobs=8' 47 ] 48 ret = setup_chromeos.Main(cmd) 49 if ret: 50 raise RuntimeError('Failed to checkout chromeos') 51 ## Do cros_sdk and setup_board, otherwise build_tc in next step will fail. 52 cmd = 'cd {0} && cros_sdk --download'.format(self._chromeos_root) 53 ret = self._cmd_exec.RunCommand(cmd, terminated_timeout=9000) 54 if ret: 55 raise RuntimeError('Failed to create chroot.') 56 57 def SetupBoard(self): 58 cmd = './setup_board --board=' + self._board 59 ret = self._cmd_exec.ChrootRunCommand( 60 self._chromeos_root, cmd, terminated_timeout=4000) 61 if ret: 62 raise RuntimeError('Failed to setup board.') 63 64 def CheckoutGCC(self): 65 cmd = 'git clone {0} {1} && cd {1} && git checkout {2}'.format( 66 self._CHROMIUM_GCC_GIT, self._gcc_dir, self._CHROMIUM_GCC_BRANCH) 67 68 ret = self._cmd_exec.RunCommand(cmd, terminated_timeout=300) 69 if ret: 70 raise RuntimeError('Failed to checkout gcc.') 71 ## Handle build_tc bug. 72 cmd = ('touch {0}/gcc/config/arm/arm-tune.md ' + \ 73 '{0}/gcc/config/arm/arm-tables.opt').format(self._gcc_dir) 74 ret = self._cmd_exec.RunCommand(cmd) 75 76 def BuildGCC(self): 77 build_gcc_args = [ 78 build_tc.__file__, '--board=' + self._board, 79 '--chromeos_root=' + self._chromeos_root, '--gcc_dir=' + self._gcc_dir 80 ] 81 ret = build_tc.Main(build_gcc_args) 82 if ret: 83 raise RuntimeError('Building gcc failed.') 84 85 def CheckGCC(self): 86 args = [ 87 run_dejagnu.__file__, '--board=' + self._board, 88 '--chromeos_root=' + self._chromeos_root, '--mount=' + self._gcc_dir, 89 '--remote=' + self._remote 90 ] 91 if self._cleanup: 92 args.append('--cleanup=' + self._cleanup) 93 if self._runtestflags: 94 args.append('--flags=' + self._runtestflags) 95 return run_dejagnu.Main(args) 96 97 98# Parse the output log to determine how many failures we have. 99# Return -1 if parse output log failed. 100def GetNumNewFailures(input_str): 101 if not input_str: 102 return 0 103 start_counting = False 104 n_failures = 0 105 for l in input_str.splitlines(): 106 print(l) 107 if not start_counting and 'Build results not in the manifest' in l: 108 start_counting = True 109 elif start_counting and l and (l.find('UNRESOLVED:') == 0 or 110 l.find('FAIL:') == 0 or l.find('XFAIL:') == 0 111 or l.find('XPASS:') == 0): 112 n_failures = n_failures + 1 113 if not start_counting: 114 return -1 115 return n_failures 116 117 118# Do not throw any exception in this function! 119def EmailResult(result): 120 email_to = ['c-compiler-chrome@google.com'] 121 if len(result) == 4: 122 subject = 'Job failed: dejagnu test didn\'t finish' 123 email_text = 'Job failed prematurely, check exception below.\n' + \ 124 result[3] 125 elif result[0]: 126 subject = 'Job finished: dejagnu test failed' 127 num_new_failures = GetNumNewFailures(result[1]) 128 if num_new_failures >= 0: 129 summary = '{0} new fail(s), check log below.'.format(num_new_failures) 130 else: 131 summary = 'At least 1 new fail found, check log below.' 132 email_text = summary + \ 133 ('\nStdout ====\n' 134 '{0}\n' 135 '\nStderr ===\n' 136 '{1}\n').format(result[1], result[2]) 137 else: 138 subject = 'Job finished: dejagnu test passed' 139 email_text = ('Cool! No new fail found.\n' 140 '\nStdout ====\n' 141 '{0}\n' 142 '\nStderr ====\n' 143 '{1}\n').format(result[1], result[2]) 144 145 try: 146 email_sender.EmailSender().SendEmail(email_to, subject, email_text) 147 print('Email sent.') 148 except Exception as e: 149 # Do not propagate this email sending exception, you want to email an 150 # email exception? Just log it on console. 151 print('Sending email failed - {0}' 152 'Subject: {1}' 153 'Text: {2}').format(str(e), subject, email_text) 154 155 156def ProcessArguments(argv): 157 """Processing script arguments.""" 158 parser = argparse.ArgumentParser( 159 description=('This script is used by nightly client to test gcc. ' 160 'DO NOT run it unless you know what you are doing.'), 161 usage='test_gcc_dejagnu.py options') 162 parser.add_argument( 163 '-b', 164 '--board', 165 dest='board', 166 help=('Required. Specify board type. For example ' 167 '\'lumpy\' and \'daisy\'')) 168 parser.add_argument( 169 '-r', 170 '--remote', 171 dest='remote', 172 help=('Required. Specify remote board address')) 173 parser.add_argument( 174 '-g', 175 '--gcc_dir', 176 dest='gcc_dir', 177 default='gcc.live', 178 help=('Optional. Specify gcc checkout directory.')) 179 parser.add_argument( 180 '-c', 181 '--chromeos_root', 182 dest='chromeos_root', 183 default='chromeos.live', 184 help=('Optional. Specify chromeos checkout directory.')) 185 parser.add_argument( 186 '--cleanup', 187 dest='cleanup', 188 default=None, 189 help=('Optional. Do cleanup after the test.')) 190 parser.add_argument( 191 '--runtestflags', 192 dest='runtestflags', 193 default=None, 194 help=('Optional. Options to RUNTESTFLAGS env var ' 195 'while invoking make check. ' 196 '(Mainly used for testing purpose.)')) 197 198 options = parser.parse_args(argv[1:]) 199 200 if not options.board or not options.remote: 201 raise SyntaxError('--board and --remote are mandatory options.') 202 203 return options 204 205 206def Main(argv): 207 opt = ProcessArguments(argv) 208 adapter = DejagnuAdapter(opt.board, opt.remote, opt.gcc_dir, 209 opt.chromeos_root, opt.runtestflags, opt.cleanup) 210 try: 211 adapter.SetupChromeOS() 212 adapter.SetupBoard() 213 adapter.CheckoutGCC() 214 adapter.BuildGCC() 215 ret = adapter.CheckGCC() 216 except Exception as e: 217 print(e) 218 ret = (1, '', '', str(e)) 219 finally: 220 EmailResult(ret) 221 222 return ret 223 224 225if __name__ == '__main__': 226 retval = Main(sys.argv) 227 sys.exit(retval[0]) 228