From 8704b64840fa2d816099a102c5ff267e77480c2c Mon Sep 17 00:00:00 2001
From: Vivien Alger <algervivie@tiolive.com>
Date: Fri, 2 Sep 2011 18:55:14 +0200
Subject: [PATCH] Created report handler

---
 .../erp5functionaltestreporthandler.py        | 172 ++++++++++++++++++
 1 file changed, 172 insertions(+)
 create mode 100644 slapos/recipe/selenium/erp5functionaltestreporthandler.py

diff --git a/slapos/recipe/selenium/erp5functionaltestreporthandler.py b/slapos/recipe/selenium/erp5functionaltestreporthandler.py
new file mode 100644
index 00000000..74aa3f14
--- /dev/null
+++ b/slapos/recipe/selenium/erp5functionaltestreporthandler.py
@@ -0,0 +1,172 @@
+##############################################################################
+#
+# Copyright (c) 2010 Vifib SARL and Contributors. All Rights Reserved.
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsibility 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
+# guarantees 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 3
+# 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.
+#
+#############################################################################
+
+import re
+import urlparse
+import urllib
+import httplib
+import mimetools
+from random import randint
+import tempfile
+import os
+import stat
+import zipfile
+import mimetypes
+import datetime
+
+TB_SEP = "============================================================="\
+    "========="
+
+# REGEX FOR ZELENIUM TESTS
+TEST_PASS_RE = re.compile('<th[^>]*>Tests passed</th>\n\s*<td[^>]*>([^<]*)')
+TEST_FAILURE_RE = re.compile('<th[^>]*>Tests failed</th>\n\s*<td[^>]*>([^<]*)')
+IMAGE_RE = re.compile('<img[^>]*?>')
+TEST_ERROR_TITLE_RE = re.compile('(?:error.gif.*?>|title status_failed"><td[^>]*>)([^>]*?)</td></tr>', re.S)
+TEST_RESULT_RE = re.compile('<div style="padding-top: 10px;">\s*<p>\s*'
+                          '<img.*?</div>\s.*?</div>\s*', re.S)
+
+TEST_ERROR_RESULT_RE = re.compile('.*(?:error.gif|title status_failed).*', re.S)
+
+def get_content_type(f):
+  return mimetypes.guess_type(f.name)[0] or 'application/octet-stream'
+
+class ConnectionHelper:
+  def __init__(self, url):
+    self.conn = urlparse.urlparse(url)
+    if self.conn.scheme == 'http':
+      connection_type = httplib.HTTPConnection
+      if self.conn.port is None:
+        self.port = 80
+    else:
+      connection_type = httplib.HTTPSConnection
+      if self.conn.port is None:
+        self.port = 443
+    self.connection_type = connection_type
+
+  def _connect(self):
+    self.connection = self.connection_type(self.conn.hostname + ':' +
+        str(self.conn.port or self.port))
+
+  def POST(self, path, parameter_dict, file_list=None):
+    self._connect()
+    parameter_dict.update(__ac_name=self.conn.username,
+                          __ac_password=self.conn.password)
+    header_dict = {'Content-type': "application/x-www-form-urlencoded"}
+    if file_list is None:
+      body = urllib.urlencode(parameter_dict)
+    else:
+      boundary = mimetools.choose_boundary()
+      header_dict['Content-type'] = 'multipart/form-data; boundary=%s' % (
+          boundary,)
+      body = ''
+      for k, v in parameter_dict.iteritems():
+        body += '--%s\r\n' % boundary
+        body += 'Content-Disposition: form-data; name="%s"\r\n' % k
+        body += '\r\n'
+        body += '%s\r\n' % v
+      for name, filename in file_list:
+        f = open(filename, 'r')
+        body += '--%s\r\n' % boundary
+        body += 'Content-Disposition: form-data; name="%s"; filename="%s"\r\n'\
+                % (name, name)
+        body += 'Content-Type: %s\r\n' % get_content_type(f)
+        body += 'Content-Length: %d\r\n' % os.fstat(f.fileno())[stat.ST_SIZE]
+        body += '\r\n'
+        body += f.read()
+        f.close()
+        body += '\r\n'
+
+    self.connection.request("POST", self.conn.path + '/' + path,
+          body, header_dict)
+    self.response = self.connection.getresponse()
+
+class ERP5TestReportHandler:
+  def __init__(self, url, suite_name):
+    # random test id
+    self.test_id = "%s-%X" % (
+       ("%s" % datetime.date.today()).replace("-", ""),
+       randint(1, 10000000000000000),
+     )
+    self.connection_helper = ConnectionHelper(url)
+    self.suite_name = suite_name
+
+  def reportStart(self):
+    # report that test is running
+    print 'Starting test with id %s' % self.test_id
+    self.connection_helper.POST('TestResultModule_reportRunning', dict(
+      test_suite=self.suite_name,
+      test_report_id=self.test_id,
+      ))
+
+  def reportFinished(self, out_file):
+    # make file parsable by erp5_test_results
+    detail, success, failure, error_title_list = self.processResult(out_file)
+    log = """Title:%s
+Success: %d
+Failure: %d
+Info: %s""" % (error_title_list, success, failure, detail)
+    templog = tempfile.mkstemp()[1]
+    tl = open(templog, 'w')
+    tl.write(log)
+    tl.close()
+    # create nice zip archive
+    tempzip = tempfile.mkstemp()[1]
+    zip = zipfile.ZipFile(tempzip, 'w')
+    zip.write(templog, '%s/002/stderr' % self.suite_name)
+    zip.close()
+    os.unlink(templog)
+
+    # post it to ERP5
+    self.connection_helper.POST('TestResultModule_reportCompleted', dict(
+      test_report_id=self.test_id),
+      file_list=[('filepath', tempzip)]
+      )
+    os.unlink(tempzip)
+
+  def processResult(self, out_file):
+    file_content = out_file
+    sucess_amount = TEST_PASS_RE.search(file_content).group(1)
+    failure_amount = TEST_FAILURE_RE.search(file_content).group(1)
+    error_title_list = [re.compile('\s+').sub(' ', x).strip()
+                    for x in TEST_ERROR_TITLE_RE.findall(file_content)]
+
+    detail = ''
+    for test_result in TEST_RESULT_RE.findall(file_content):
+      if  TEST_ERROR_RESULT_RE.match(test_result):
+        detail += test_result
+
+    detail = IMAGE_RE.sub('', detail)
+    if detail:
+      detail = IMAGE_RE.sub('', detail)
+      detail = '''<html>
+<head>
+ <style type="text/css">tr.status_failed { background-color:red };</style>
+</head>
+<body>%s</body>
+</html>''' % detail
+
+    return detail, int(sucess_amount), int(failure_amount), error_title_list
-- 
2.30.9