From a0e66a116c7078c2f89fad9be2fb669ee2f8b2f4 Mon Sep 17 00:00:00 2001 From: Kazuhiko Shiozaki <kazuhiko@nexedi.com> Date: Fri, 9 Feb 2007 13:41:11 +0000 Subject: [PATCH] * add functional automation suite * no real display needed because firefox will run on Xvfb (please install the x11-server-xvfb package) * Xvfb (and firefox on it) will be killed when functional tests finish. Usage: # prepare zope instance for functional tests $ ./runUnitTest.py --save prepareFunctionalTest.py # invoke firefox on Xvfb and send results by email. $ ./runFunctionalTest.py git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@12599 20353a03-c40f-0410-a6d1-a30d3c3de9de --- product/ERP5Type/tests/prefs.js | 24 ++++ .../ERP5Type/tests/prepareFunctionalTest.py | 71 ++++++++++ product/ERP5Type/tests/runFunctionalTest.py | 121 ++++++++++++++++++ product/ERP5Type/tests/sendMail.py | 88 +++++++++++++ 4 files changed, 304 insertions(+) create mode 100644 product/ERP5Type/tests/prefs.js create mode 100755 product/ERP5Type/tests/prepareFunctionalTest.py create mode 100755 product/ERP5Type/tests/runFunctionalTest.py create mode 100644 product/ERP5Type/tests/sendMail.py diff --git a/product/ERP5Type/tests/prefs.js b/product/ERP5Type/tests/prefs.js new file mode 100644 index 0000000000..9520ebb9e9 --- /dev/null +++ b/product/ERP5Type/tests/prefs.js @@ -0,0 +1,24 @@ +// Don't ask if we want to switch default browsers +user_pref("browser.shell.checkDefaultBrowser", false); + +// Disable pop-up blocking +user_pref("browser.allowpopups", true); +user_pref("dom.disable_open_during_load", false); + +// Configure us as the local proxy +//user_pref("network.proxy.type", 2); + +// Disable security warnings +user_pref("security.warn_submit_insecure", false); +user_pref("security.warn_submit_insecure.show_once", false); +user_pref("security.warn_entering_secure", false); +user_pref("security.warn_entering_secure.show_once", false); +user_pref("security.warn_entering_weak", false); +user_pref("security.warn_entering_weak.show_once", false); +user_pref("security.warn_leaving_secure", false); +user_pref("security.warn_leaving_secure.show_once", false); +user_pref("security.warn_viewing_mixed", false); +user_pref("security.warn_viewing_mixed.show_once", false); + +// Disable "do you want to remember this password?" +user_pref("signon.rememberSignons", false); diff --git a/product/ERP5Type/tests/prepareFunctionalTest.py b/product/ERP5Type/tests/prepareFunctionalTest.py new file mode 100755 index 0000000000..d80f0c51ad --- /dev/null +++ b/product/ERP5Type/tests/prepareFunctionalTest.py @@ -0,0 +1,71 @@ +############################################################################## +# +# Copyright (c) 2007 Nexedi SARL and Contributors. All Rights Reserved. +# Kazuhiko <kazuhiko@nexedi.com> +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsability of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# garantees and support are strongly adviced to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################## + +# +# Prepare ERP5 Zelenium Test. +# +# usage: python runUnitTest.py --save [OPTION]... prepareFunctionalTest.py +# + +import os +import sys +from time import sleep +if __name__ == '__main__': + execfile(os.path.join(sys.path[0], 'framework.py')) + +# Needed in order to have a log file inside the current folder +os.environ['EVENT_LOG_FILE'] = os.path.join(os.getcwd(), 'zLOG.log') +os.environ['EVENT_LOG_SEVERITY'] = '-300' + +from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase + +os.environ['erp5_tests_portal_id'] = 'erp5_portal' + +class TestZelenium(ERP5TypeTestCase): + def getBusinessTemplateList(self): + """ + Return the list of business templates. + """ + return ('erp5_base', 'erp5_ui_test', 'erp5_forge', + 'erp5_trade', 'erp5_pdm', 'erp5_pdf_style', + 'erp5_accounting', 'erp5_accounting_ui_test', + # 'erp5_accounting_l10n_fr', 'erp5_payroll', + # 'erp5_payroll_ui_test', + ) + + def testInformation(self): + self.assert_(False, 'This script is intended to be used with --save option.') + +if __name__ == '__main__': + framework() +else: + import unittest + def test_suite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(TestZelenium)) + return suite diff --git a/product/ERP5Type/tests/runFunctionalTest.py b/product/ERP5Type/tests/runFunctionalTest.py new file mode 100755 index 0000000000..59ad8c891c --- /dev/null +++ b/product/ERP5Type/tests/runFunctionalTest.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python + +import os +import re +import signal +from time import sleep +import urllib2 +from subprocess import Popen, PIPE +from sendMail import sendMail +import pysvn + +host = 'localhost' +port = 8080 +portal_name = 'erp5_portal' +instance_home = '/var/lib/zope/unit_test' +profile_dir = '%s/profile' % instance_home + +def main(): + setPreference() + status = getStatus() + xvfb_pid = None + firefox_pid = None + try: + xvfb_pid = runXvfb() + firefox_pid = runFirefox() + while True: + sleep(10) + cur_status = getStatus() + if status != cur_status: + break + print cur_status + finally: + if xvfb_pid: + os.kill(xvfb_pid, signal.SIGTERM) + if firefox_pid: + os.kill(firefox_pid, signal.SIGTERM) + +def startZope(): + os.environ['erp5_force_data_fs'] = "1" + os.system('%s/bin/zopectl start' % instance_home) + sleep(2) # ad hoc + +def stopZope(): + os.system('%s/bin/zopectl stop' % instance_home) + +def runXvfb(): + pid = os.spawnlp(os.P_NOWAIT, 'Xvfb', 'Xvfb', ':123') + display = os.environ['DISPLAY'] + if display: + (displayname, protocolname, hexkey) = Popen(['xauth', 'list', display], stdout=PIPE).communicate()[0].split() + Popen(['xauth', 'add', 'localhost/unix:123', protocolname, hexkey]) + print 'Xvfb : %d' % pid + return pid + +def prepareFirefox(): + os.system("rm -rf %s" % profile_dir) + os.mkdir(profile_dir) + pref = file(os.path.join(os.path.dirname(__file__), 'prefs.js')).read() + pref_file = open(os.path.join(profile_dir, 'prefs.js'), 'w') + pref_file.write(pref) + pref_file.close() + +def runFirefox(): + os.environ['MOZ_NO_REMOTE'] = '1' + os.environ['DISPLAY'] = ':123' + os.environ['HOME'] = profile_dir + prepareFirefox() + pid = os.spawnlp(os.P_NOWAIT, "firefox", "firefox", "-profile", profile_dir, "http://%s:%d/%s/portal_tests?auto=true&__ac_name=ERP5TypeTestCase&__ac_password=" % (host, port, portal_name)) + os.environ['MOZ_NO_REMOTE'] = '0' + print 'firefox : %d' % pid + return pid + +def getStatus(): + try: + status = urllib2.urlopen('http://%s:%d/%s/TestTool_getResults' % (host, port, portal_name)).read() + except urllib2.HTTPError, e: + if e.msg == "No Content" : + status = "" + else: + raise + return status + +def setPreference(): + urllib2.urlopen('http://%s:%d/%s/BTZuite_setPreference?__ac_name=ERP5TypeTestCase&__ac_password=' % (host, port, portal_name)) + +def sendResult(): + result_uri = urllib2.urlopen('http://%s:%d/%s/TestTool_getResults' % (host, port, portal_name)).readline() + file_content = urllib2.urlopen(result_uri).read() + passes_re = re.compile('<th[^>]*>Tests passed</th>\n\s*<td[^>]*>([^<]*)') + failures_re = re.compile('<th[^>]*>Tests failed</th>\n\s*<td[^>]*>([^<]*)') + check_re = re.compile('<img[^>]*?/check.gif"\s*[^>]*?>', re.M) + error_re = re.compile('<img[^>]*?/error.gif"\s*[^>]*?>', re.M) + error_title_re = re.compile('error.gif.*?>([^>]*?)</td></tr>', 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)] + os.chdir('%s/Products/ERP5' % instance_home) + revision = pysvn.Client().info('.').revision.number + + subject = "ERP5 r%s: Functional Tests, %s Passes, %s Failures" % (revision, passes, failures) + summary = """ +Test Summary + +Tests passed: %4s +Tests failed: %4s + +Following tests failed: + +%s""" % (passes, failures, "\n".join(error_titles)) + file_content = check_re.sub('<span style="color: green">PASS</span>', file_content) + file_content = error_re.sub('<span style="color: red">FAIL</span>', file_content) + status = (not failures) + sendMail(subject = subject, body = summary, status = status, + attachments = [file_content]) + +if __name__ == "__main__": + startZope() + main() + sendResult() + stopZope() diff --git a/product/ERP5Type/tests/sendMail.py b/product/ERP5Type/tests/sendMail.py new file mode 100644 index 0000000000..0165261ddb --- /dev/null +++ b/product/ERP5Type/tests/sendMail.py @@ -0,0 +1,88 @@ +############################################################################## +# +# Copyright (c) 2007 Nexedi SARL and Contributors. All Rights Reserved. +# Kazuhiko <kazuhiko@nexedi.com> +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsability of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# garantees and support are strongly adviced to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################## + +"""Send a mail with attachments. +""" + +import smtplib +import re +from datetime import date +from email.MIMEText import MIMEText +from email.MIMEBase import MIMEBase +from email.MIMEImage import MIMEImage +from email.MIMEMultipart import MIMEMultipart +from email.Message import Message + +def sendMail(subject, + body, + attachments = [], + status = False, + from_mail = 'nobody@erp5.org', + to_mail = [ 'erp5-report@erp5.org' ]): + if attachments: + msg = MIMEMultipart() + else: + msg = Message() + + msg['Subject'] = subject + msg['From'] = from_mail + msg['To'] = ', '.join(to_mail) + msg['X-ERP5-Tests'] = 'ERP5' + + if status: + msg['X-ERP5-Tests-Status'] = 'OK' + + # Guarantees the message ends in a newline + msg.preamble = subject + msg.epilogue = '' + + if attachments: + mime_text = MIMEText(body) + mime_text.add_header('Content-Disposition', 'attachment', + filename='body') + msg.attach(mime_text) + html_re = re.compile('<html>', re.I) + for item in attachments: + mime_text = MIMEText(item) + if html_re.match(item): + mime_text.set_type('text/html') + mime_text.add_header('Content-Disposition', 'attachment', + filename='attachment.html') + else: + mime_text.add_header('Content-Disposition', 'attachment', + filename='attachment.txt') + msg.attach(mime_text) + + else: + msg.set_payload(body) + + # Send the email via our own SMTP server. + s = smtplib.SMTP() + s.connect() + s.sendmail(from_mail, to_mail, msg.as_string()) + s.close() -- 2.30.9