1#!/usr/bin/env python 2 3""" 4Run the test suite and send the result as an email message. 5 6The code for sending of the directory is copied from 7http://docs.python.org/library/email-examples.html. 8""" 9 10import os 11import sys 12import shutil 13import smtplib 14# For guessing MIME type based on file name extension 15import mimetypes 16 17from optparse import OptionParser 18 19from email import encoders 20from email.message import Message 21from email.mime.audio import MIMEAudio 22from email.mime.base import MIMEBase 23from email.mime.image import MIMEImage 24from email.mime.multipart import MIMEMultipart 25from email.mime.text import MIMEText 26 27def runTestsuite(testDir, sessDir, envs = None): 28 """Run the testsuite and return a (summary, output) tuple.""" 29 os.chdir(testDir) 30 31 for env in envs: 32 list = env.split('=') 33 var = list[0].strip() 34 val = list[1].strip() 35 print var + "=" + val 36 os.environ[var] = val 37 38 import shlex, subprocess 39 40 command_line = "./dotest.py -w -s %s" % sessDir 41 # Apply correct tokenization for subprocess.Popen(). 42 args = shlex.split(command_line) 43 44 # Use subprocess module to spawn a new process. 45 process = subprocess.Popen(args, 46 stdout=subprocess.PIPE, stderr=subprocess.PIPE) 47 # Wait for subprocess to terminate. 48 stdout, stderr = process.communicate() 49 50 # This will be used as the subject line of our email about this test. 51 cmd = "%s %s" % (' '.join(envs) if envs else "", command_line) 52 53 return (cmd, stderr) 54 55 56COMMASPACE = ', ' 57 58def main(): 59 parser = OptionParser(usage="""\ 60Run lldb test suite and send the results as a MIME message. 61 62Usage: %prog [options] 63 64Unless the -o option is given, the email is sent by forwarding to the specified 65SMTP server, which then does the normal delivery process. 66""") 67 parser.add_option('-d', '--directory', 68 type='string', action='store', 69 dest='testDir', 70 help="""The LLDB test directory directly under the top dir. 71 Otherwise use the current directory.""") 72 # 73 # This is similar to TestBase.getRunSpec(self) from lldbtest.py. 74 # 75 parser.add_option('-e', '--environment', 76 type='string', action='append', metavar='ENVIRONMENT', 77 default=[], dest='environments', 78 help="""The environment setting as prefix to the test driver. 79 Example: -e 'CC=clang' -e 'ARCH=x86_64'""") 80 parser.add_option('-m', '--mailserver', 81 type='string', action='store', metavar='MAILSERVER', 82 dest='mailserver', 83 help="""The outgoing SMTP server.""") 84 parser.add_option('-o', '--output', 85 type='string', action='store', metavar='FILE', 86 help="""Print the composed message to FILE instead of 87 sending the message to the SMTP server.""") 88 parser.add_option('-s', '--sender', 89 type='string', action='store', metavar='SENDER', 90 help='The value of the From: header (required)') 91 parser.add_option('-r', '--recipient', 92 type='string', action='append', metavar='RECIPIENT', 93 default=[], dest='recipients', 94 help='A To: header value (at least one required)') 95 opts, args = parser.parse_args() 96 if not opts.sender or not opts.recipients: 97 parser.print_help() 98 sys.exit(1) 99 testDir = opts.testDir 100 if not testDir: 101 testDir = '.' 102 103 sessDir = 'tmp-lldb-session' 104 if os.path.exists(sessDir): 105 shutil.rmtree(sessDir) 106 #print "environments:", opts.environments 107 summary, output = runTestsuite(testDir, sessDir, opts.environments) 108 109 # Create the enclosing (outer) message 110 outer = MIMEMultipart() 111 outer['Subject'] = summary 112 outer['To'] = COMMASPACE.join(opts.recipients) 113 outer['From'] = opts.sender 114 outer.preamble = 'You will not see this in a MIME-aware mail reader.\n' 115 116 # The sessDir contains all the session logs for failed/errored tests. 117 # Attach them all if it exists! 118 119 if not os.path.exists(sessDir): 120 outer.attach(MIMEText(output, 'plain')) 121 else: 122 outer.attach(MIMEText("%s\n%s\n\n" % (output, 123 "Session logs of test failures/errors:"), 124 'plain')) 125 126 for filename in (os.listdir(sessDir) if os.path.exists(sessDir) else []): 127 path = os.path.join(sessDir, filename) 128 if not os.path.isfile(path): 129 continue 130 # Guess the content type based on the file's extension. Encoding 131 # will be ignored, although we should check for simple things like 132 # gzip'd or compressed files. 133 ctype, encoding = mimetypes.guess_type(path) 134 if ctype is None or encoding is not None: 135 # No guess could be made, or the file is encoded (compressed), so 136 # use a generic bag-of-bits type. 137 ctype = 'application/octet-stream' 138 maintype, subtype = ctype.split('/', 1) 139 if maintype == 'text': 140 fp = open(path) 141 # Note: we should handle calculating the charset 142 msg = MIMEText(fp.read(), _subtype=subtype) 143 fp.close() 144 elif maintype == 'image': 145 fp = open(path, 'rb') 146 msg = MIMEImage(fp.read(), _subtype=subtype) 147 fp.close() 148 elif maintype == 'audio': 149 fp = open(path, 'rb') 150 msg = MIMEAudio(fp.read(), _subtype=subtype) 151 fp.close() 152 else: 153 fp = open(path, 'rb') 154 msg = MIMEBase(maintype, subtype) 155 msg.set_payload(fp.read()) 156 fp.close() 157 # Encode the payload using Base64 158 encoders.encode_base64(msg) 159 # Set the filename parameter 160 msg.add_header('Content-Disposition', 'attachment', filename=filename) 161 outer.attach(msg) 162 163 # Now send or store the message 164 composed = outer.as_string() 165 if opts.output: 166 fp = open(opts.output, 'w') 167 fp.write(composed) 168 fp.close() 169 else: 170 s = smtplib.SMTP(opts.mailserver) 171 s.sendmail(opts.sender, opts.recipients, composed) 172 s.quit() 173 174 175if __name__ == '__main__': 176 main() 177