Commit 71ecc514 authored by Rafael Monnerat's avatar Rafael Monnerat

Small refactor. Now it is used a class (FunctionalTestRunner) to run the...

Small refactor. Now it is used a class (FunctionalTestRunner) to run the functional tests. This will help create custom Runners for Projects or custom products.

 * It allow not take screenshots with xwud
 * This is just a initial clean up should not change the current behaviours. 
 * More improvements and features will come soon.


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@32026 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent c27204db
...@@ -38,22 +38,6 @@ Notes: ...@@ -38,22 +38,6 @@ Notes:
./runUnitTest.py --save prepareFunctionalTest.py ./runUnitTest.py --save prepareFunctionalTest.py
""" """
host = 'localhost'
port = 8080
portal_name = 'erp5_portal'
user = 'ERP5TypeTestCase'
password = ''
send_mail = 0
stdout = 0
debug = 0
email_to_address = 'erp5-report@erp5.org'
smtp_host = ''
email_subject = 'ERP5'
run_only=''
portal_url = ''
xvfb_display = '123'
tests_framework_home = os.path.dirname(os.path.abspath(__file__)) tests_framework_home = os.path.dirname(os.path.abspath(__file__))
# handle 'system global' instance # handle 'system global' instance
if tests_framework_home.startswith('/usr/lib'): if tests_framework_home.startswith('/usr/lib'):
...@@ -63,128 +47,144 @@ else: ...@@ -63,128 +47,144 @@ else:
tests_framework_home.split(os.path.sep)[:-3]) tests_framework_home.split(os.path.sep)[:-3])
instance_home = os.path.join(real_instance_home, 'unit_test') instance_home = os.path.join(real_instance_home, 'unit_test')
profile_dir = os.path.join(instance_home, 'profile')
bt5_dir_list = ','.join([ bt5_dir_list = ','.join([
os.path.join(instance_home, 'Products/ERP5/bootstrap'), os.path.join(instance_home, 'Products/ERP5/bootstrap'),
os.path.join(instance_home, 'bt5')]) os.path.join(instance_home, 'bt5')])
class FunctionalTestRunner:
def usage(stream, msg=None): """
if msg: Used to run Functional tests
print >>stream, msg """
print >>stream def __init__(self, instance_home):
program = os.path.basename(sys.argv[0]) self.instance_home = instance_home
print >>stream, __doc__ % {"program": program} self.xvfb_fbdir = instance_home
self.send_mail = 0
def parseArgs(): self.stdout = 0
global send_mail self.debug = 0
global stdout self.email_to_address = 'erp5-report@erp5.org'
global debug self.smtp_host = ''
global email_to_address self.host = 'localhost'
global smtp_host self.port = 8080
global host self.user = 'ERP5TypeTestCase'
global port self.password = ''
global portal_name self.portal_name = 'erp5_portal'
global portal_url self.run_only = ''
global run_only self.email_subject = 'ERP5'
global email_subject self.xvfb_display = '123'
global xvfb_display self.profile_dir = os.path.join(instance_home, 'profile')
try:
opts, args = getopt.getopt(sys.argv[1:], def usage(self, stream, msg=None):
"hsd", ["help", "stdout", "debug", if msg:
"email_to_address=", "host=", "port=", print >>stream, msg
"portal_name=", "run_only=", print >>stream
"email_subject=", "smtp_host=", "xvfb_display="] ) program = os.path.basename(sys.argv[0])
except getopt.GetoptError, msg: print >>stream, __doc__ % {"program": program}
usage(sys.stderr, msg)
sys.exit(2) def parseArgs(self):
try:
for opt, arg in opts: opts, args = getopt.getopt(sys.argv[1:],
if opt in ("-s", "--stdout"): "hsd", ["help", "stdout", "debug",
stdout = 1 "email_to_address=", "host=", "port=",
elif opt in ("-d", "--debug"): "portal_name=", "run_only=", "user=",
debug = 1 "password=", "alarms=",
elif opt == '--email_to_address': "email_subject=", "smtp_host=", "xvfb_display="] )
email_to_address = arg except getopt.GetoptError, msg:
send_mail = 1 self.usage(sys.stderr, msg)
elif opt == '--smtp_host': sys.exit(2)
smtp_host = arg
elif opt in ('-h', '--help'): for opt, arg in opts:
usage(sys.stdout) if opt in ("-s", "--stdout"):
sys.exit() self.stdout = 1
elif opt == "--host": elif opt in ("-d", "--debug"):
host = arg self.debug = 1
elif opt == "--port": elif opt == '--email_to_address':
port = int(arg) self.email_to_address = arg
elif opt == "--portal_name": self.send_mail = 1
portal_name = arg elif opt == '--smtp_host':
elif opt == "--run_only": self.smtp_host = arg
run_only = arg elif opt in ('-h', '--help'):
elif opt == "--email_subject": self.usage(sys.stdout)
email_subject = arg sys.exit()
elif opt == "--xvfb_display": elif opt == "--host":
xvfb_display = arg self.host = arg
elif opt == "--port":
if not stdout: self.port = int(arg)
send_mail = 1 elif opt == "--portal_name":
self.portal_name = arg
portal_url = "http://%s:%d/%s" % (host, port, portal_name) elif opt == "--run_only":
self.run_only = arg
def openUrl(url): elif opt == "--user":
f = urllib2.urlopen(url) user = arg
file_content = f.read() elif opt == "--password":
f.close() password = arg
return file_content elif opt == "--email_subject":
self.email_subject = arg
elif opt == "--xvfb_display":
def main(): self.xvfb_display = arg
setPreference()
unsubscribeFromTimerService() if not self.stdout:
launchFuntionalTest() self.send_mail = 1
def launchFuntionalTest(): self.portal_url = "http://%s:%d/%s" % (self.host, self.port, self.portal_name)
status = getStatus()
xvfb_pid = None def openUrl(self, url):
firefox_pid = None f = urllib2.urlopen(url)
try: file_content = f.read()
if not debug: f.close()
xvfb_pid = runXvfb(xvfb_display) return file_content
firefox_pid = runFirefox(xvfb_display)
while True:
sleep(10) def main(self):
cur_status = getStatus() self.setPreference()
if status != cur_status: self.unsubscribeFromTimerService()
break self.launchFuntionalTest()
finally:
if xvfb_pid: def launchFuntionalTest(self):
os.kill(xvfb_pid, signal.SIGTERM) status = self.getStatus()
if firefox_pid: xvfb_pid = None
os.kill(firefox_pid, signal.SIGTERM) firefox_pid = None
try:
def startZope(): if not self.debug:
os.environ['erp5_save_data_fs'] = "1" xvfb_pid = self.runXvfb(self.xvfb_display)
os.system('%s/bin/zopectl start' % instance_home) firefox_pid = self.runFirefox(self.xvfb_display)
sleep(2) # ad hoc while True:
sleep(10)
def stopZope(): cur_status = self.getStatus()
os.system('%s/bin/zopectl stop' % instance_home) if status != cur_status:
break
def runXvfb(xvfb_display): finally:
pid = os.spawnlp(os.P_NOWAIT, 'Xvfb', 'Xvfb', ':%s' %xvfb_display) if xvfb_pid:
display = os.environ.get('DISPLAY') os.kill(xvfb_pid, signal.SIGTERM)
if display: if firefox_pid:
auth = Popen(['xauth', 'list', display], stdout=PIPE).communicate()[0] os.kill(firefox_pid, signal.SIGTERM)
if auth:
(displayname, protocolname, hexkey) = auth.split() def startZope(self):
Popen(['xauth', 'add', 'localhost/unix:%s' %xvfb_display, protocolname, hexkey]) os.environ['erp5_save_data_fs'] = "1"
print 'Xvfb : %d' % pid os.system('%s/bin/zopectl start' % self.instance_home)
return pid sleep(2) # ad hoc
def prepareFirefox(): def stopZope(self):
os.system("rm -rf %s" % profile_dir) os.system('%s/bin/zopectl stop' % self.instance_home)
os.mkdir(profile_dir)
prefs_js = """ def runXvfb(self, xvfb_display):
pid = os.spawnlp(os.P_NOWAIT, 'Xvfb', 'Xvfb',
'-fbdir' , '%s' % self.xvfb_fbdir ,
':%s' % xvfb_display)
display = os.environ.get('DISPLAY')
if display:
auth = Popen(['xauth', 'list', display], stdout=PIPE).communicate()[0]
if auth:
(displayname, protocolname, hexkey) = auth.split()
Popen(['xauth', 'add', 'localhost/unix:%s' %xvfb_display, protocolname, hexkey])
print 'Xvfb : %d' % pid
print 'Take screenshots using xwud -in %s/Xvfb_screen0' % self.xvfb_fbdir
return pid
def prepareFirefox(self, host, port):
os.system("rm -rf %s" % self.profile_dir)
os.mkdir(self.profile_dir)
prefs_js = """
// Don't ask if we want to switch default browsers // Don't ask if we want to switch default browsers
user_pref("browser.shell.checkDefaultBrowser", false); user_pref("browser.shell.checkDefaultBrowser", false);
...@@ -213,93 +213,89 @@ user_pref("signon.rememberSignons", false); ...@@ -213,93 +213,89 @@ user_pref("signon.rememberSignons", false);
// Make sure we do not use cache // Make sure we do not use cache
user_pref("browser.cache.check_doc_frequency", 1); user_pref("browser.cache.check_doc_frequency", 1);
user_pref("network.http.use-cache", false); user_pref("network.http.use-cache", false);
//user_pref("browser.cache.disk.capacity", 0);
//user_pref("browser.cache.disk.enable", false);
//user_pref("browser.cache.memory.enable", false);
//user_pref("browser.cache.offline.enable", false);
// this is required to upload files // this is required to upload files
user_pref("capability.principal.codebase.p1.granted", "UniversalFileRead"); user_pref("capability.principal.codebase.p1.granted", "UniversalFileRead");
user_pref("signed.applets.codebase_principal_support", true); user_pref("signed.applets.codebase_principal_support", true);
user_pref("capability.principal.codebase.p1.id", "http://%s"); user_pref("capability.principal.codebase.p1.id", "http://%s");
user_pref("capability.principal.codebase.p1.subjectName", "");""" % \ user_pref("capability.principal.codebase.p1.subjectName", "");""" % \
'%s:%s' % (host, port) '%s:%s' % (host, port)
pref_file = open(os.path.join(profile_dir, 'prefs.js'), 'w') pref_file = open(os.path.join(self.profile_dir, 'prefs.js'), 'w')
pref_file.write(prefs_js) pref_file.write(prefs_js)
pref_file.close() pref_file.close()
def runFirefox(xvfb_display): def runFirefox(self,xvfb_display):
prepareFirefox() self.prepareFirefox(self.host, self.port)
if debug: if self.debug:
try:
shutil.copy2(os.path.expanduser('~/.Xauthority'), '%s/.Xauthority' % self.profile_dir)
except IOError:
pass
else:
os.environ['DISPLAY'] = ':%s' %xvfb_display
os.environ['MOZ_NO_REMOTE'] = '1'
os.environ['HOME'] = self.profile_dir
# check if old zelenium or new zelenium
try: try:
shutil.copy2(os.path.expanduser('~/.Xauthority'), '%s/.Xauthority' % profile_dir) urllib2.urlopen("%s/portal_tests/core/scripts/selenium-version.js" % self.portal_url)
except IOError: except urllib2.HTTPError:
pass # Zelenium 0.8
else: url_string = "%s/portal_tests/?auto=true&__ac_name=%s&__ac_password=%s" % (self.portal_url, self.user, self.password)
os.environ['DISPLAY'] = ':%s' %xvfb_display
os.environ['MOZ_NO_REMOTE'] = '1'
os.environ['HOME'] = profile_dir
# check if old zelenium or new zelenium
try:
urllib2.urlopen("%s/portal_tests/core/scripts/selenium-version.js" % portal_url)
except urllib2.HTTPError:
# Zelenium 0.8
url_string = "%s/portal_tests/?auto=true&__ac_name=%s&__ac_password=%s" % (portal_url, user, password)
else:
# Zelenium 0.8+ or later
url_string = "%s/portal_tests/core/TestRunner.html?test=../test_suite_html&auto=on&resultsUrl=%s/portal_tests/postResults&__ac_name=%s&__ac_password=%s" % (portal_url, portal_url, user, password)
if run_only:
url_string = url_string.replace('/portal_tests/', '/portal_tests/%s/' % run_only, 1)
pid = os.spawnlp(os.P_NOWAIT, "firefox", "firefox", "-profile", profile_dir,
url_string)
os.environ['MOZ_NO_REMOTE'] = '0'
print 'firefox : %d' % pid
return pid
def getStatus():
try:
status = openUrl('%s/portal_tests/TestTool_getResults'
% (portal_url))
except urllib2.HTTPError, e:
if e.msg == "No Content" :
status = ""
else: else:
raise # Zelenium 0.8+ or later
return status url_string = "%s/portal_tests/core/TestRunner.html?test=../test_suite_html&auto=on&resultsUrl=%s/portal_tests/postResults&__ac_name=%s&__ac_password=%s" % (self.portal_url, self.portal_url, self.user, self.password)
def setPreference(): if self.run_only:
urllib2.urlopen('%s/BTZuite_setPreference?__ac_name=' url_string = url_string.replace('/portal_tests/', '/portal_tests/%s/' % self.run_only, 1)
'%s&__ac_password=%s&working_copy_list=%s' % pid = os.spawnlp(os.P_NOWAIT, "firefox", "firefox", "-profile", self.profile_dir,
(portal_url, user, password, bt5_dir_list)) url_string)
os.environ['MOZ_NO_REMOTE'] = '0'
def unsubscribeFromTimerService(): print 'firefox : %d' % pid
urllib2.urlopen('%s/portal_activities/?unsubscribe:method=' return pid
'&__ac_name=%s&__ac_password=%s' %
(portal_url, user, password)) def getStatus(self):
try:
def sendResult(): status = self.openUrl('%s/portal_tests/TestTool_getResults'
global email_subject % (self.portal_url))
result_uri = urllib2.urlopen('%s/portal_tests/TestTool_getResults' % portal_url).readline() except urllib2.HTTPError, e:
print result_uri if e.msg == "No Content" :
file_content = openUrl(result_uri) status = ""
passes_re = re.compile('<th[^>]*>Tests passed</th>\n\s*<td[^>]*>([^<]*)') else:
failures_re = re.compile('<th[^>]*>Tests failed</th>\n\s*<td[^>]*>([^<]*)') raise
image_re = re.compile('<img[^>]*?>') return status
error_title_re = re.compile('(?:error.gif.*?>|title status_failed"><td[^>]*>)([^>]*?)</td></tr>', re.S)
result_re = re.compile('<div style="padding-top: 10px;">\s*<p>\s*' def setPreference(self):
'<img.*?</div>\s.*?</div>\s*', re.S) urllib2.urlopen('%s/BTZuite_setPreference?__ac_name='
error_result_re = re.compile('.*(?:error.gif|title status_failed).*', re.S) '%s&__ac_password=%s&working_copy_list=%s' %
passes = passes_re.search(file_content).group(1) (self.portal_url, self.user, self.password, bt5_dir_list))
failures = failures_re.search(file_content).group(1)
error_titles = [re.compile('\s+').sub(' ', x).strip() def unsubscribeFromTimerService(self):
for x in error_title_re.findall(file_content)] urllib2.urlopen('%s/portal_activities/?unsubscribe:method='
os.chdir('%s/Products/ERP5' % instance_home) '&__ac_name=%s&__ac_password=%s' %
revision = pysvn.Client().info('.').revision.number (self.portal_url, self.user, self.password))
subject = "%s r%s: Functional Tests, %s Passes, %s Failures" \ def sendResult(self):
% (email_subject, revision, passes, failures) result_uri = urllib2.urlopen('%s/portal_tests/TestTool_getResults' % self.portal_url).readline()
summary = """ print result_uri
file_content = self.openUrl(result_uri)
passes_re = re.compile('<th[^>]*>Tests passed</th>\n\s*<td[^>]*>([^<]*)')
failures_re = re.compile('<th[^>]*>Tests failed</th>\n\s*<td[^>]*>([^<]*)')
image_re = re.compile('<img[^>]*?>')
error_title_re = re.compile('(?:error.gif.*?>|title status_failed"><td[^>]*>)([^>]*?)</td></tr>', re.S)
result_re = re.compile('<div style="padding-top: 10px;">\s*<p>\s*'
'<img.*?</div>\s.*?</div>\s*', re.S)
error_result_re = re.compile('.*(?:error.gif|title status_failed).*', re.S)
passes = passes_re.search(file_content).group(1)
failures = failures_re.search(file_content).group(1)
error_titles = [re.compile('\s+').sub(' ', x).strip()
for x in error_title_re.findall(file_content)]
# get SVN revision used
os.chdir('%s/Products/ERP5' % self.instance_home)
revision = pysvn.Client().info('.').revision.number
subject = "%s r%s: Functional Tests, %s Passes, %s Failures" \
% (self.email_subject, revision, passes, failures)
summary = """
Test Summary Test Summary
Tests passed: %4s Tests passed: %4s
...@@ -307,38 +303,39 @@ Tests failed: %4s ...@@ -307,38 +303,39 @@ Tests failed: %4s
Following tests failed: Following tests failed:
%s""" % (passes, failures, "\n".join(error_titles))
detail = '' %s""" % (passes, failures, "\n".join(error_titles))
for e in result_re.findall(file_content): detail = ''
if error_result_re.match(e): for e in result_re.findall(file_content):
detail += e if error_result_re.match(e):
detail = image_re.sub('', detail) detail += e
detail = detail.replace('<tr class="title status_failed"', '<tr class="title status_failed" style="background-color:red"') detail = image_re.sub('', detail)
detail = detail.replace('<tr class="status_failed"', '<tr class="status_failed" style="background-color:red"') detail = detail.replace('<tr class="title status_failed"', '<tr class="title status_failed" style="background-color:red"')
if detail: detail = detail.replace('<tr class="status_failed"', '<tr class="status_failed" style="background-color:red"')
detail = '<html><body>%s</body></html>' % detail if detail:
status = (not failures) detail = '<html><body>%s</body></html>' % detail
if send_mail: status = (not failures)
sendMail(subject=subject, if self.send_mail:
body=summary, sendMail(subject=subject,
status=status, body=summary,
attachments=[detail], status=status,
from_mail='nobody@svn.erp5.org', attachments=[detail],
to_mail=[email_to_address], from_mail='nobody@svn.erp5.org',
smtp_host=smtp_host) to_mail=[self.email_to_address],
if stdout: smtp_host=self.smtp_host)
print '-' * 79 if self.stdout:
print subject print '-' * 79
print '-' * 79 print subject
print summary print '-' * 79
print '-' * 79 print summary
print detail print '-' * 79
return int(failures) print detail
return int(failures)
if __name__ == "__main__": if __name__ == "__main__":
parseArgs() test_runner = FunctionalTestRunner(instance_home)
startZope() test_runner.parseArgs()
atexit.register(stopZope) test_runner.startZope()
main() atexit.register(test_runner.stopZope)
sys.exit(sendResult()) test_runner.main()
sys.exit(test_runner.sendResult())
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment