source: branches/testScripts/nightlyBuild.py @ 613

Last change on this file since 613 was 613, checked in by jpfasano, 14 years ago

Removed Cbc from ALL_TESTS_COMPLETED_SUCCESSFULLY_CMDS data structure so code will not look for the "All Tests Completed Successfully" message after running Cbc.

File size: 17.7 KB
Line 
1#! /usr/bin/env python
2
3import os
4import sys
5import commands
6import smtplib
7import re 
8import time
9
10# TODO:
11#   -After "svn co" then get all 3rd party packages.
12#   -Get some information about the platform and put this in email failure message.
13#   -Implement Kipp's vpath (delete vpath instead of 'make distclean').
14#   Break this file up into multiple files so it is manageable.
15#   Don't do build if 'svn update' doesn't change anything and prior test was OK.
16#     (no need to re-run if nothing has changed since prior run)
17#   Build both trunk and latest stable
18#   Build both optimized and debug (or have a set of config-site scripts to test?)
19#   Check the testing of the success criteria of each projects "make test"
20#   Implement "cbc -miplib" test for successful run.  JohnF sent JP the criteria
21#     to test on in an email dated 10/12/2007 12:01pm
22
23#----------------------------------------------------------------------
24# NIGHTLY_BUILD_ROOT_DIR:
25#   directory where code will be checked out and builds
26#   done. If the directory does not exist, it will be created.
27#----------------------------------------------------------------------
28NIGHTLY_BUILD_ROOT_DIR = '/home/jp/COIN'
29
30#----------------------------------------------------------------------
31# Values for sending mail:
32#  SMTP_SERVER_NAME: name of smtp server. For gmail server
33#                 this is smtp.gmail.com
34#  SMTP_SERVER_PORT: port number of the smtp server. This is typically 25,
35#                 but for gmail server it is 587.
36#  SMTP_SSL_SERVER: 0 or 1. If 1 then SMTP uses SSL (sometimes called startltls).
37#                 For gmail this is 1.
38#  SMTP_USER_NAME: name of authorized user on server. If using gmail server
39#                 this is gmail_userid@gmail.com which is coded as
40#                 'gmail_userid _AT_ gmail _DOT_ com. 
41#  SMTP_PASSWORD_FILENAME: name of file containing smtp user's password
42#  SENDER_EMAIL_ADDR: email sent by this script will be from this address
43#  MY_EMAIL_ADDR: All problems detected by the script will be sent to
44#                 this email address. The intention is for this to be
45#                 the email address of the person running this script
46#  SEND_MAIL_TO_PROJECT_MANAGER: 0 or 1. If 1 then any problems
47#                 detected are sent to MY_EMAIL_ADDRESS and the
48#                 project manager.
49#----------------------------------------------------------------------
50#SMTP_SERVER_NAME = 'outgoing.verizon.net'
51#SMTP_SERVER_PORT = 25
52#SMTP_SSL_SERVER = 0
53#SMTP_USER_NAME = 'jpfasano'
54
55SMTP_SERVER_NAME = 'smtp.gmail.com'
56SMTP_SERVER_PORT = 587
57SMTP_SSL_SERVER = 1
58SMTP_USER_NAME = 'jpfasano _AT_ gmail _DOT_ com'
59SMTP_PASSWORD_FILENAME = '/home/jp/bin/smtpPwFile'
60
61SENDER_EMAIL_ADDR='jpfasano _AT_ verizon _DOT_ net'
62MY_EMAIL_ADDR='jpfasano _AT_ us _DOT_ ibm _DOT_ com'
63SEND_MAIL_TO_PROJECT_MANAGER=0
64#SMTP_SERVER_NAME = 'gsbims.chicagogsb.edu'
65
66
67#----------------------------------------------------------------------
68# List of Projects to be processed by script
69#----------------------------------------------------------------------
70PROJECTS = ['CoinUtils','DyLP','Clp','SYMPHONY','Vol','Osi','Cgl','Cbc','Ipopt','OS','CppAD']
71#PROJECTS = ['CppAD']
72
73#----------------------------------------------------------------------
74PROJECT_EMAIL_ADDRS = {}
75UNITTEST_DIR = {}
76UNITTEST_CMD = {}
77ALL_TESTS_COMPLETED_SUCCESSFULLY_CMDS = {} 
78
79#----------------------------------------------------------------------
80PROJECT_EMAIL_ADDRS['CoinUtils'] = 'ladanyi _AT_ us _DOT_ ibm _DOT_ com'
81ALL_TESTS_COMPLETED_SUCCESSFULLY_CMDS['CoinUtils'] = ['make test']
82
83#----------------------------------------------------------------------
84PROJECT_EMAIL_ADDRS['DyLP'] = 'lou _AT_ cs _DOT_ sfu _DOT_ ca'
85UNITTEST_DIR['DyLP'] = os.path.join('Osi','test')
86UNITTEST_CMD['DyLP'] = './unitTest -testOsiSolverInterface -netlibDir=_NETLIBDIR_ -cerr2cout' 
87ALL_TESTS_COMPLETED_SUCCESSFULLY_CMDS['DyLP'] = ['make test']
88
89#----------------------------------------------------------------------
90PROJECT_EMAIL_ADDRS['Clp'] = 'jjforre _AT_ us _DOT_ ibm _DOT_ com'
91UNITTEST_DIR['Clp'] = os.path.join('Clp','src')
92UNITTEST_CMD['Clp'] = './clp -unitTest -netlib dirNetlib=_NETLIBDIR_' 
93ALL_TESTS_COMPLETED_SUCCESSFULLY_CMDS['Clp'] = ['make test',UNITTEST_CMD['Clp']]
94
95#----------------------------------------------------------------------
96PROJECT_EMAIL_ADDRS['SYMPHONY'] = 'tkr2 _AT_ lehigh _DOT_ edu'
97ALL_TESTS_COMPLETED_SUCCESSFULLY_CMDS['SYMPHONY'] = ['make test']
98
99#----------------------------------------------------------------------
100PROJECT_EMAIL_ADDRS['Vol'] = 'barahon _AT_ us _DOT_ ibm _DOT_ com'
101
102#----------------------------------------------------------------------
103PROJECT_EMAIL_ADDRS['Osi'] = 'mjs _AT_ ces _DOT_ clemson _DOT_ edu'
104UNITTEST_DIR['Osi'] = os.path.join('Osi','test')
105UNITTEST_CMD['Osi'] = './unitTest -testOsiSolverInterface' 
106UNITTEST_CMD['Osi'] = './unitTest -testOsiSolverInterface -netlibDir=_NETLIBDIR_ -cerr2cout' 
107ALL_TESTS_COMPLETED_SUCCESSFULLY_CMDS['Osi'] = ['make test',UNITTEST_CMD['Osi']]
108
109#----------------------------------------------------------------------
110PROJECT_EMAIL_ADDRS['Cgl'] = 'robinlh _AT_ us _DOT_ ibm _DOT_ com'
111ALL_TESTS_COMPLETED_SUCCESSFULLY_CMDS['Cgl'] = ['make test']
112
113#----------------------------------------------------------------------
114PROJECT_EMAIL_ADDRS['Cbc'] = 'jjforre _AT_ us _DOT_ ibm _DOT_ com'
115
116#----------------------------------------------------------------------
117PROJECT_EMAIL_ADDRS['Ipopt'] = 'andreasw _AT_ us _DOT_ ibm _DOT_ com'
118
119#----------------------------------------------------------------------
120PROJECT_EMAIL_ADDRS['OS'] = 'kipp _DOT_ martin _AT_ chicagogsb _DOT_ edu'
121
122#----------------------------------------------------------------------
123PROJECT_EMAIL_ADDRS['CppAD'] = 'bradbell _AT_ washington _DOT_ edu'
124
125#------------------------------------------------------------------------
126# Send email typically about an error.
127#  project: coin project name
128#  cmd: command being exucuted. perhaps: "svn update", "./configure",
129#       "make".
130#  cmdMsgs: the messages generated by cmd.  This will typically contain
131#       errors issued by cmd.
132#------------------------------------------------------------------------
133def sendEmailCmdMsgs(project,cmdMsgs,cmd):
134  curDir = os.getcwd()
135 
136  toAddrs = [unscrambleEmailAddress(MY_EMAIL_ADDR)]
137  if PROJECT_EMAIL_ADDRS.has_key(project) and SEND_MAIL_TO_PROJECT_MANAGER:
138    toAddrs.append(unscrambleEmailAddress(PROJECT_EMAIL_ADDRS[project]))
139
140  subject = project + " build problem when running '" + cmd +"'"
141
142  emailMsg  = "'" + cmd + "' from directory " + curDir + " failed.\n\n"
143  emailMsg += "Operating System: "+os.name
144  emailMsg += "'" + cmd + "' messages are:\n" 
145  emailMsg += cmdMsgs
146  sendEmail(toAddrs,subject,emailMsg)
147  writeLogMessage( "  email sent regarding "+project+" running '"+cmd+"'" )
148
149#------------------------------------------------------------------------
150# Send email
151#------------------------------------------------------------------------
152def sendEmail(toAddrs,subject,message):
153
154  sender = unscrambleEmailAddress(SENDER_EMAIL_ADDR) 
155  msgWHeader = ("From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n"
156       % (sender, ", ".join(toAddrs), subject))
157  msgWHeader += message
158 
159  # Get smpt server password
160  if os.path.isfile(SMTP_PASSWORD_FILENAME) :
161    pwFilePtr = open(SMTP_PASSWORD_FILENAME,'r')
162    smtppass  = pwFilePtr.read().strip()
163    pwFilePtr.close()
164  else :
165    writeLogMessage( "Failure reading pwFileName=" + SMTP_PASSWORD_FILENAME )
166    sys.exit(1)
167   
168  session = smtplib.SMTP(SMTP_SERVER_NAME,SMTP_SERVER_PORT)
169  #session.set_debuglevel(1)
170  if SMTP_SSL_SERVER==1 :
171    session.ehlo('x')
172    session.starttls()
173    session.ehlo('x') 
174  session.login(unscrambleEmailAddress(SMTP_USER_NAME),smtppass)
175
176  rc = session.sendmail(sender,toAddrs,msgWHeader)
177  if rc!={} :
178    writeLogMessage( 'session.sendmail rc='  )
179    writeLogMessage( rc )
180  session.quit()
181
182#------------------------------------------------------------------------
183# Decrypt email address
184#------------------------------------------------------------------------
185def unscrambleEmailAddress( scrambledEmailAddress ) :
186  retVal = scrambledEmailAddress
187  retVal = retVal.replace(' _AT_ ','@')
188  retVal = retVal.replace(' _DOT_ ','.')
189  return retVal
190
191#------------------------------------------------------------------------
192# Function to Check Return Code from unitTest
193#------------------------------------------------------------------------
194def didTestFail( rc, project, buildStep ) :
195  retVal = 0
196
197  # If the return code is not 0, then failure
198  if rc[0] != 0 :
199    retVal = 1
200
201  # Many tests write a "Success" message.
202  # For test that do this, check for the success message
203  if ALL_TESTS_COMPLETED_SUCCESSFULLY_CMDS.has_key(project) : 
204    if buildStep in ALL_TESTS_COMPLETED_SUCCESSFULLY_CMDS[project] :
205      # Is the success message contained in the output?
206      if rc[1].rfind("All tests completed successfully") == -1 :
207        # Success message not found, assume test failed
208        retVal = 1
209
210  #---------------------------------------------------------------------
211  # Some (project,buildStep) pairs require further checking
212  # to determine if they were successful
213  #---------------------------------------------------------------------
214  # Clp's "./clp -unitTest -netlib dirNetlib=_NETLIBDIR_"
215  if project=='Clp' and buildStep==UNITTEST_CMD['Clp'] :
216    # Check that last netlib test case ran by looking for message of form
217    # '../../Data/Netlib/woodw took 0.47 seconds using algorithm either'
218    reexp = r"(.|\n)*\.\.(\\|/)\.\.(\\|/)Data(\\|/)Netlib(\\|/)woodw took (\d*\.\d*) seconds using algorithm either(.|\n)*"
219    msgTail = rc[1][-200:]
220    if not re.compile(reexp).match(msgTail,1) :
221      # message not found, assume test failed
222      retVal = 1
223  elif project=='Cbc' and buildStep=='make test' :
224    # Check that last the last few lines are of the form
225    # 'cbc_clp solved 2 out of 2 and took XX.XX seconds.'
226    reexp=r"(.|\n)*cbc_clp solved 2 out of 2 and took (\d*\.\d*) seconds."
227    msgTail = rc[1][-300:]
228    if not re.compile(reexp).match(msgTail,1) :
229      # message not found, assume test failed
230      retVal = 1
231
232  return retVal
233
234#------------------------------------------------------------------------
235# Function for executing svn commands
236#------------------------------------------------------------------------
237def issueSvnCmd(svnCmd,dir,project) :
238  retVal='OK'
239  os.chdir(dir)
240  writeLogMessage('  '+svnCmd)
241  rc=commands.getstatusoutput(svnCmd)
242  if rc[0] != 0 :
243    sendEmailCmdMsgs(project,rc[1],svnCmd)
244    retVal='Error'
245  return retVal
246
247#------------------------------------------------------------------------
248# Function to write log messages
249#------------------------------------------------------------------------
250def writeLogMessage( msg ) :
251  logMsg = time.ctime(time.time())+': '
252  logMsg += msg
253  print logMsg
254
255#------------------------------------------------------------------------
256#  Main Program Starts Here 
257#------------------------------------------------------------------------
258
259#------------------------------------------------------------------------
260#  If needed create the top level directory
261#------------------------------------------------------------------------
262# rc=commands.getstatusoutput(NIGHTLY_BUILD_ROOT_DIR)
263if not os.path.isdir(NIGHTLY_BUILD_ROOT_DIR) :
264  os.makedirs(NIGHTLY_BUILD_ROOT_DIR)
265os.chdir(NIGHTLY_BUILD_ROOT_DIR)
266
267#------------------------------------------------------------------------
268#  Get the data directories if they don't already exist
269#------------------------------------------------------------------------
270dataBaseDir=os.path.join(NIGHTLY_BUILD_ROOT_DIR,'Data')
271if not os.path.isdir(dataBaseDir) :
272  os.makedirs(dataBaseDir)
273dataDirs=['Netlib','miplib3']
274for d in dataDirs :
275  dataDir=os.path.join(dataBaseDir,d)
276  if not os.path.isdir(dataDir) :
277    svnCmd='svn checkout https://projects.coin-or.org/svn/Data/releases/1.0.0/'+d+' '+d
278    if issueSvnCmd(svnCmd,dataBaseDir,'Data')!='OK' :
279      sys.exit(1)
280    rc=commands.getstatusoutput('find '+d+' -name \*.gz -print | xargs gzip -d')
281netlibDir=os.path.join(dataBaseDir,'Netlib')
282miplib3Dir=os.path.join(dataBaseDir,'miplib3')
283
284#------------------------------------------------------------------------
285# Loop once for each project
286#------------------------------------------------------------------------
287for p in PROJECTS:
288  writeLogMessage( p )
289  rc = [0]
290
291  #---------------------------------------------------------------------
292  # svn checkout or update the project
293  #---------------------------------------------------------------------
294  projectBaseDir=os.path.join(NIGHTLY_BUILD_ROOT_DIR,p)
295  projectCheckOutDir=os.path.join(projectBaseDir,'trunk')
296  if not os.path.isdir(projectBaseDir) :
297    os.makedirs(projectBaseDir)
298  if not os.path.isdir(projectCheckOutDir) :
299    svnCmd='svn checkout https://projects.coin-or.org/svn/'+p+'/trunk trunk'
300    if issueSvnCmd(svnCmd,projectBaseDir,p)!='OK' :
301      continue
302  else :
303    svnCmd='svn update'
304    if issueSvnCmd(svnCmd,projectCheckOutDir,p)!='OK' :
305      continue
306
307  #---------------------------------------------------------------------
308  # Should probably run make 'distclean' to do a build from scrath
309  # or delete the VPATH directory when there is one
310  #---------------------------------------------------------------------
311
312
313  #---------------------------------------------------------------------
314  # Run configure part of buid
315  #---------------------------------------------------------------------
316  os.chdir(projectCheckOutDir)
317  configCmd = os.path.join('.','configure -C')
318  writeLogMessage('  '+configCmd)
319  rc=commands.getstatusoutput(configCmd)
320 
321  # Check if configure worked
322  if rc[0] != 0 :
323    error_msg = rc[1] + '\n\n'
324    # Add contents of log file to message
325    logFileName = 'config.log'
326    if os.path.isfile(logFileName) :
327      logFilePtr = open(logFileName,'r')
328      error_msg += "config.log contains: \n" 
329      error_msg += logFilePtr.read()
330      logFilePtr.close()
331    sendEmailCmdMsgs(p,error_msg,configCmd)
332    continue
333
334  #---------------------------------------------------------------------
335  # Run make part of buid
336  #---------------------------------------------------------------------
337  writeLogMessage( '  make' )
338  rc=commands.getstatusoutput('make')
339 
340  # Check if make worked
341  if rc[0] != 0 :
342    sendEmailCmdMsgs(p,rc[1],'make')
343    continue
344
345  #---------------------------------------------------------------------
346  # Run 'make test' part of buid
347  #---------------------------------------------------------------------
348  writeLogMessage( '  make test' )
349  rc=commands.getstatusoutput('make test')
350 
351  # Check if 'make test' worked
352  if didTestFail(rc,p,"make test") :
353    sendEmailCmdMsgs(p,rc[1],"make test")
354    continue
355
356  #---------------------------------------------------------------------
357  # Run unitTest if available and different from 'make test'
358  #---------------------------------------------------------------------
359  if UNITTEST_CMD.has_key(p) :
360    unitTestPath = os.path.join(projectCheckOutDir,UNITTEST_DIR[p])
361    os.chdir(unitTestPath)
362
363    unitTestCmd=UNITTEST_CMD[p]
364    unitTestCmd=unitTestCmd.replace('_NETLIBDIR_',netlibDir)
365    unitTestCmd=unitTestCmd.replace('_MIPLIB3DIR_',miplib3Dir)
366
367    writeLogMessage( '  '+unitTestCmd )
368    rc=commands.getstatusoutput(unitTestCmd)
369 
370    if didTestFail(rc,p,unitTestCmd) :
371      sendEmailCmdMsgs(p,rc[1],unitTestCmd)
372      continue
373
374  # For testing purposes only do first successful project
375  #break
376
377
378writeLogMessage( "nightlyBuild.py Finished" )
379
380sys.exit(0)
381
382
383# START KIPP
384#----------------------------------------------------------------------
385# CONFIG FILE PATH:
386#   path to the config file for the build
387#   done. If the directory does not exist, it will be created.
388#   this should have all of the user specific data
389#   it should have values for
390#   NIGHTLY_BUILD_ROOT
391#   SMTP_SERVER_NAME
392#   SMTP_SERVER_PORT
393#   SMTP_SSL_SERVER
394#   SMTP_USER_NAME
395#   SMTP_PASSWORD_FILENAME = '/home/jp/bin/smtpPwFile'
396#   SENDER_EMAIL_ADDR='jpfasano _AT_ verizon _DOT_ net'
397#   MY_EMAIL_ADDR='jpfasano _AT_ us _DOT_ ibm _DOT_ com'
398#   
399#----------------------------------------------------------------------
400
401CONFIG_FILE_PATH = '/Users/kmartin/Documents/files/configDir/'
402CONFIG_FILENAME = 'config.txt'
403
404
405# Get configFile data
406
407configFile = os.path.join(os.path.dirname( CONFIG_FILE_PATH),
408                                 os.path.basename(CONFIG_FILENAME ))
409if os.path.isfile(  configFile) :
410  pwFilePtr = open(configFile ,'r')
411  d = pwFilePtr.readlines()
412  # do pwFilePtr.read() to get a string object
413  # we have a list object
414  print d[0]
415  print d[1]
416  # make a dictionary
417  config_dic = {}
418
419  #smtppass  = pwFilePtr.read().strip()
420  pwFilePtr.close()
421else :
422  #writeLogMessage( "Failure reading pwFileName=" + CONFIG_FILENAME )
423  #print cmdMsgs
424  sys.exit( 1)
425sys.exit( 0)
426
427
428
429# START KIPP
430#----------------------------------------------------------------------
431#   path to the config file for the build
432#   get the user dependent variables
433# CONFIG FILE PATH:
434#   it should have values for
435#   NIGHTLY_BUILD_ROOT
436#   SMTP_SERVER_NAME
437#   SMTP_SERVER_PORT
438#   SMTP_SSL_SERVER
439#   SMTP_USER_NAME
440#   SMTP_PASSWORD_FILENAME
441#   SENDER_EMAIL_ADDR
442#   MY_EMAIL_ADDR
443#   
444#----------------------------------------------------------------------
445
446CONFIG_FILE_PATH = '/Users/kmartin/Documents/files/configDir/'
447CONFIG_FILENAME = 'config.txt'
448
449
450# Get configFile data
451
452configFile = os.path.join(os.path.dirname( CONFIG_FILE_PATH),
453                                 os.path.basename(CONFIG_FILENAME ))
454if os.path.isfile(  configFile) :
455  pwFilePtr = open(configFile ,'r')
456  d = pwFilePtr.readlines()
457  # do pwFilePtr.read() to get a string object
458  # we have a list object
459  print d[0]
460  print d[1]
461  # make a dictionary
462  config_dic = {}
463
464  #smtppass  = pwFilePtr.read().strip()
465  pwFilePtr.close()
466else :
467  #writeLogMessage( "Failure reading pwFileName=" + CONFIG_FILENAME )
468  #print cmdMsgs
469  sys.exit( 1)
470sys.exit( 0)
471
472# END KIPP
Note: See TracBrowser for help on using the repository browser.