1#!/usr/bin/python2
2"""Script adapter used by automation client for testing dejagnu.
3
4   This is not intended to be run on command line.
5   To kick off a single dejagnu run, use ./dejagnu/run_dejagnu.py
6"""
7
8from __future__ import print_function
9
10import argparse
11import sys
12import setup_chromeos
13
14from dejagnu import gdb_dejagnu
15from cros_utils import command_executer
16from cros_utils import email_sender
17
18
19class DejagnuAdapter(object):
20  """Dejagnu Adapter class."""
21
22  def __init__(self, board, remote, gdb_dir, chromeos_root, cleanup):
23    self._board = board
24    self._remote = remote
25    self._gdb_dir = gdb_dir
26    self._chromeos_root = chromeos_root
27    self._cleanup = cleanup
28    self._cmd_exec = command_executer.GetCommandExecuter()
29
30  def SetupChromeOS(self):
31    cmd = [setup_chromeos.__file__, '--dir=' + self._chromeos_root,
32           '--minilayout', '--jobs=8']
33    ret = setup_chromeos.Main(cmd)
34    if ret:
35      raise RuntimeError('Failed to checkout chromeos')
36    ## Do cros_sdk and setup_board, otherwise build_tc in next step will fail.
37    cmd = 'cd {0} && cros_sdk --download'.format(self._chromeos_root)
38    ret = self._cmd_exec.RunCommand(cmd, terminated_timeout=9000)
39    if ret:
40      raise RuntimeError('Failed to create chroot.')
41
42  def SetupBoard(self):
43    cmd = './setup_board --board=' + self._board
44    ret = self._cmd_exec.ChrootRunCommand(self._chromeos_root,
45                                          cmd,
46                                          terminated_timeout=4000)
47    if ret:
48      raise RuntimeError('Failed to setup board.')
49
50  def CheckGDB(self):
51    args = [gdb_dejagnu.__file__, '--board=' + self._board,
52            '--chromeos_root=' + self._chromeos_root,
53            '--mount=' + self._gdb_dir, '--remote=' + self._remote]
54    if self._cleanup:
55      args.append('--cleanup=' + self._cleanup)
56    return gdb_dejagnu.Main(args)
57
58
59# Parse the output log to determine how many failures we have.
60# Return -1 if parse output log failed.
61def GetNumNewFailures(result):
62  if not result:
63    return 0
64  return len(result)
65
66
67# Do not throw any exception in this function!
68def EmailResult(result):
69  email_to = ['yunlian@google.com']
70  if len(result) == 4:
71    subject = 'Job failed: dejagnu test didn\'t finish'
72    email_text = (
73        'Job failed prematurely, check exception below.\n' + result[3])
74  elif result[0]:
75    subject = 'Job finished: dejagnu test failed'
76    num_new_failures = GetNumNewFailures(result[1])
77    if num_new_failures >= 0:
78      summary = '{0} new fail(s), check log below.'.format(num_new_failures)
79    else:
80      summary = 'At least 1 new fail found, check log below.'
81    email_text = (summary + ('\nStdout ====\n'
82                             '{0}\n'
83                             '\nStderr ===\n'
84                             '{1}\n').format(result[1], result[2]))
85  else:
86    subject = 'Job finished: dejagnu test passed'
87    email_text = ('Cool! No new fail found.\n'
88                  '\nStdout ====\n'
89                  '{0}\n'
90                  '\nStderr ====\n'
91                  '{1}\n').format(result[1], result[2])
92
93  try:
94    email_sender.EmailSender().SendEmail(email_to, subject, email_text)
95    print('Email sent.')
96  except Exception as e:
97    # Do not propagate this email sending exception, you want to email an
98    # email exception? Just log it on console.
99    print('Sending email failed - {0}'
100          'Subject: {1}'
101          'Text: {2}').format(
102              str(e), subject, email_text)
103
104
105def ProcessArguments(argv):
106  """Processing script arguments."""
107  parser = argparse.ArgumentParser(
108      description=('This script is used by nightly client to test gdb. '
109                   'DO NOT run it unless you know what you are doing.'),
110      usage='test_gdb_dejagnu.py options')
111  parser.add_argument('-b',
112                      '--board',
113                      dest='board',
114                      help=('Required. Specify board type. For example '
115                            '\'lumpy\' and \'daisy\''))
116  parser.add_argument('-r',
117                      '--remote',
118                      dest='remote',
119                      help=('Required. Specify remote board address'))
120  parser.add_argument('-g',
121                      '--gdb_dir',
122                      dest='gdb_dir',
123                      default='',
124                      help=('Optional. Specify gdb checkout directory.'))
125  parser.add_argument('-c',
126                      '--chromeos_root',
127                      dest='chromeos_root',
128                      default='chromeos.live',
129                      help=('Optional. Specify chromeos checkout directory.'))
130  parser.add_argument('--cleanup',
131                      dest='cleanup',
132                      default=None,
133                      help=('Optional. Do cleanup after the test.'))
134
135  options = parser.parse_args(argv)
136
137  if not options.board or not options.remote:
138    raise SyntaxError('--board and --remote are mandatory options.')
139
140  return options
141
142
143def Main(argv):
144  opt = ProcessArguments(argv)
145  print(opt)
146  adapter = DejagnuAdapter(opt.board, opt.remote, opt.gdb_dir,
147                           opt.chromeos_root, opt.cleanup)
148  try:
149    adapter.SetupChromeOS()
150    adapter.SetupBoard()
151    ret = adapter.CheckGDB()
152  except Exception as e:
153    print(e)
154    ret = (1, '', '', str(e))
155  finally:
156    EmailResult(ret)
157
158  return ret
159
160
161if __name__ == '__main__':
162  retval = Main(sys.argv[1:])
163  sys.exit(retval[0])
164