diff options
Diffstat (limited to 'tests/test_pretty_print.py')
-rwxr-xr-x | tests/test_pretty_print.py | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/tests/test_pretty_print.py b/tests/test_pretty_print.py new file mode 100755 index 0000000..897f7b8 --- /dev/null +++ b/tests/test_pretty_print.py @@ -0,0 +1,321 @@ +#!/usr/bin/python +# +# This program 'pretty prints' the ctest output, namely +# files from builddir/Testing/Temporary. +# html & wiki output are produced +# wiki uploading is available by running +# +# python test_pretty_print.py --upload + +# todo +# ban opencsg<2.0 from opencsgtest +# copy all images, sysinfo.txt to bundle for html/upload (images +# can be altered by subsequent runs) +# figure out hwo to make the thing run after the test +# figure out how CTEST treats the logfiles. +# why is hash differing +# instead of having special '-info' prerun, put it as yet-another-test +# and parse the log +# provide option to replace 'expected' images on wiki +# (yes sometimes you do need to change/update them) + +import string,sys,re,os,hashlib,subprocess + +def tryread(filename): + data = None + try: + print 'reading', filename + f = open(filename) + data = f.read() + f.close() + except: + print 'couldn\'t open ',filename + return data + +def trysave(data,filename): + try: + f=open(filename,'w') + print 'writing',len(data),'bytes to',filename + f.write(data) + f.close() + except: + print 'problem writing to',filename + return None + return True + +def ezsearch(pattern,str): + x = re.search(pattern,str,re.DOTALL|re.MULTILINE) + if x and len(x.groups())>0: return x.group(1).strip() + return '' + +def read_gitinfo(): + # won't work if run from outside of branch. + data = subprocess.Popen(['git','remote','-v'],stdout=subprocess.PIPE).stdout.read() + origin = ezsearch('^origin *?(.*?)\(fetch.*?$',data) + upstream = ezsearch('^upstream *?(.*?)\(fetch.*?$',data) + data = subprocess.Popen(['git','branch'],stdout=subprocess.PIPE).stdout.read() + branch = ezsearch('^\*(.*?)$',data) + out = 'Git branch: ' + branch + ' from origin ' + origin + '\n' + out += 'Git upstream: ' + upstream + '\n' + return out + +def read_sysinfo(filename): + data = tryread(filename) + if not data: return 'sysinfo: unknown' + + machine = ezsearch('Machine:(.*?)\n',data) + machine = machine.replace(' ','-').replace('/','-') + + osinfo = ezsearch('OS info:(.*?)\n',data) + osplain = osinfo.split(' ')[0].strip().replace('/','-') + if 'windows' in osinfo.lower(): osplain = 'win' + + renderer = ezsearch('GL Renderer:(.*?)\n',data) + tmp = renderer.split(' ') + tmp = string.join(tmp[0:3],'-') + tmp = tmp.split('/')[0] + renderer = tmp + + hexhash = hashlib.md5() + hexhash.update(data) + hexhash = hexhash.hexdigest()[-4:].upper() + hash = '' + for c in hexhash: hash += chr(ord(c)+97-48) + + sysid = osplain + '_' + machine + '_' + renderer + '_' + hash + sysid = sysid.lower() + + data += read_gitinfo() + + data += 'Image comparison: PerceptualDiff by H. Yee' + return data, sysid + +class Test: + def __init__(self,fullname,time,passed,output,type,actualfile,expectedfile,scadfile,log): + self.fullname,self.time,self.passed,self.output = \ + fullname, time, passed, output + self.type, self.actualfile, self.expectedfile, self.scadfile = \ + type, actualfile, expectedfile, scadfile + self.fulltestlog = log + + def __str__(self): + x = 'fullname: ' + self.fullname + x+= '\nactualfile: ' + self.actualfile + x+= '\nexpectedfile: ' + self.expectedfile + x+= '\ntesttime: ' + self.time + x+= '\ntesttype: ' + self.type + x+= '\npassed: ' + str(self.passed) + x+= '\nscadfile: ' + self.scadfile + x+= '\noutput bytes: ' + str(len(self.output)) + x+= '\ntestlog bytes: ' + str(len(self.fulltestlog)) + x+= '\n' + return x + +def parsetest(teststring): + patterns = ["Test:(.*?)\n", # fullname + "Test time =(.*?) sec\n", + "Test time.*?Test (Passed)", + "Output:(.*?)<end of output>", + 'Command:.*?-s" "(.*?)"', # type + "actual .*?:(.*?)\n", + "expected .*?:(.*?)\n", + 'Command:.*?(testdata.*?)"' # scadfile + ] + hits = map( lambda pattern: ezsearch(pattern,teststring), patterns ) + test = Test(hits[0],hits[1],hits[2]=='Passed',hits[3],hits[4],hits[5],hits[6],hits[7],teststring) + return test + +def parselog(data): + startdate = ezsearch('Start testing: (.*?)\n',data) + enddate = ezsearch('End testing: (.*?)\n',data) + pattern = '([0-9]*/[0-9]* Testing:.*?time elapsed.*?\n)' + test_chunks = re.findall(pattern,data,re.S) + tests = map( parsetest, test_chunks ) + print 'found', len(tests),'test results' + return startdate, tests, enddate + +def wikify_filename(testname,filename,sysid): + # translate from local system to wiki style filename. + result = wiki_rootpath+'_'+testname+'_' + expected = ezsearch('(expected....$)',filename) + if expected!='': result += expected + actual = ezsearch(os.sep+'.*?-output.*?(actual.*)',filename) + if actual!='': + result += sysid+'_'+actual + return result.replace('/','_') + + +def towiki(wiki_rootpath, startdate, tests, enddate, sysinfo, sysid, testlog): + wiki_template = """ +<h3>[[WIKI_ROOTPATH]] test run report</h3> + +'''Sysid''': SYSID + +'''Result summary''': NUMPASSED / NUMTESTS tests passed ( PERCENTPASSED % ) <br> + +'''System info''': +<pre> +SYSINFO +</pre> + +start time: STARTDATE <br> +end time : ENDDATE <br> + +'''Failed image tests''' + +{| border=1 cellspacing=0 cellpadding=1 +! Testname !! expected output !! actual output +<REPEAT1> +|- +| FTESTNAME || [[File:EXPECTEDFILE|thumb|250px]] || ACTUALFILE_WIKI +</REPEAT1> +|} + +'''Failed text tests''' + +{|border=1 cellspacing=0 cellpadding=1 +! Testname +<REPEAT2> +|- +| FTESTNAME +</REPEAT2> +|} + +'''Test logs''' + +(excerpted from Testing/Temporary/LastTest.Log) + +<pre> +FAILED_TESTLOGS +</pre> + +""" + numpassed = len(filter(lambda x: x.passed, tests)) + percent = str(int(100.0*numpassed / len(tests))) + manifest = {} + s = wiki_template + repeat1 = ezsearch('(<REPEAT1>.*?</REPEAT1>)',s) + repeat2 = ezsearch('(<REPEAT2>.*?</REPEAT2>)',s) + dic = { 'STARTDATE': startdate, 'ENDDATE': enddate, 'WIKI_ROOTPATH': wiki_rootpath, + 'SYSINFO': sysinfo, 'SYSID':sysid, 'LASTTESTLOG':testlog, + 'NUMTESTS':len(tests), 'NUMPASSED':numpassed, 'PERCENTPASSED':percent } + for key in dic.keys(): + s = re.sub(key,str(dic[key]),s) + testlogs = '' + for t in tests: + # if t.passed: noop + if not t.passed: + testlogs += '\n\n'+t.fulltestlog + if t.type=='txt': + newchunk = re.sub('FTEST_OUTPUTFILE',t.fullname,repeat2) + newchunk = re.sub('FTESTNAME',t.fullname,repeat2) + s = s.replace(repeat2, newchunk+repeat2) + elif t.type=='png': + manifest[t.actualfile] = wikify_filename(t.fullname,t.actualfile,sysid) + manifest[t.expectedfile] = wikify_filename(t.fullname,t.expectedfile,sysid) + if t.actualfile: + actualfile_wiki = '[[File:'+manifest[t.actualfile]+'|thumb|250px]]' + else: + actualfile_wiki = 'No file generated.<br/>See log for details' + newchunk = re.sub('FTESTNAME',t.fullname,repeat1) + newchunk = newchunk.replace('ACTUALFILE_WIKI',actualfile_wiki) + newchunk = newchunk.replace('EXPECTEDFILE',manifest[t.expectedfile]) + s = s.replace(repeat1, newchunk+repeat1) + s = s.replace('FAILED_TESTLOGS',testlogs) + s = s.replace(repeat1,'') + s = s.replace(repeat2,'') + s = re.sub('<REPEAT.*?>\n','',s) + s = re.sub('</REPEAT.*?>','',s) + return manifest, s + + +def wikitohtml(wiki_rootpath, sysid, wikidata, manifest): + head = '<html><head><title>'+wiki_rootpath+' test run for '+sysid +'</title></head><body>' + revmanifest = dict((val,key) for key, val in manifest.iteritems()) + x=re.sub('\{\|(.*?)\n','<table \\1>\n',wikidata) + x=re.sub("'''(.*?)'''","<b>\\1</b>",x) + filestrs=re.findall('\[\[File\:(.*?)\|.*?\]\]',x) + for f in filestrs: + newfile_html='<img src="'+revmanifest[f]+'" width=250/>' + x=re.sub('\[\[File\:'+f+'\|.*?\]\]',newfile_html,x) + dic = { '|}':'</table>', '|-':'<tr>', '||':'<td>', '|':'<td>', + '!!':'<th>', '!':'<tr><th>', '\n\n':'\n<p>\n'} #order matters + for key in dic: x=x.replace(key,dic[key]) + x=re.sub("\[\[(.*?)\]\]","\\1",x) + return head + x + '</body></html>' + +def upload_dryrun(wikiurl,api_php_path,wikidata,manifest,wiki_rootpath,sysid,botname,botpass): + print 'dry run. no files to be uploaded' + print 'log in', wikiurl, api_php_path, botname, botpass + print 'save ' + '*[['+wiki_rootpath+sysid+']]' + ' to page ' + wiki_rootpath + print 'save ', len(wikidata), ' bytes to page ',wiki_rootpath+sysid + for localfile in manifest.keys(): + if localfile: + localf=open(localfile) + wikifile = manifest[localfile] + print 'upload',localfile,wikifile + +def upload(wikiurl,api_php_path,wikidata,manifest,wiki_rootpath,sysid,botname,botpass,dryrun=True): + if dryrun: + upload_dryrun(wikiurl,api_php_path,wikidata,manifest,wiki_rootpath,sysid,botname,botpass) + return None + try: + import mwclient + except: + print 'please download mwclient and unpack here:', os.cwd() + print 'open site',wikiurl + if not api_php_path == '': + site = mwclient.Site(wikiurl,api_php_path) + else: + site = mwclient.Site(wikiurl) + + print 'bot login' + site.login(botname,botpass) + + print 'edit ',wiki_rootpath + page = site.Pages[wiki_rootpath] + text = page.edit() + rootpage = wiki_rootpath + sysid + if not '[['+rootpage+']]' in text: + page.save(text +'\n*[['+rootpage+']]\n') + + print 'upload wiki data to',rootpage + page = site.Pages[rootpage] + text = page.edit() + page.save(wikidata) + + print 'upload images' + for localfile in sorted(manifest.keys()): + if localfile: + localf=open(localfile) + wikifile = manifest[localfile] + skip=False + if 'expected.png' in wikifile.lower(): + image = site.Images[wikifile] + if image.exists: + print 'skipping ',wikifile, '(expected image, already on wiki)' + skip=True + if not skip: + print wikifile,'...' + site.upload(localf,wikifile,wiki_rootpath + ' test', ignore=True) + +wikisite = 'cakebaby.referata.com' +wiki_rootpath = 'OpenSCAD' +builddir = os.getcwd() +logpath = os.path.join(builddir,'Testing','Temporary') +logfilename = os.path.join(logpath,'LastTest.log') + +def main(): + testlog = tryread(logfilename) + startdate, tests, enddate = parselog(testlog) + tests = sorted(tests, key = lambda t:t.passed) + sysinfo, sysid = read_sysinfo('sysinfo.txt') + if '--hack' in sys.argv: sysid+='_hack' + manifest, wikidata = towiki(wiki_rootpath, startdate, tests, enddate, sysinfo, sysid, testlog) + trysave(wikidata, os.path.join(logpath,sysid+'.wiki')) + htmldata = wikitohtml(wiki_rootpath, sysid, wikidata, manifest) + trysave(htmldata, os.path.join(logpath,sysid+'.html')) + if '--upload' in sys.argv: + upload(wikisite,'',wikidata,manifest,wiki_rootpath,sysid,'openscadbot','tobdacsnepo',dryrun=False) +main() + |