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