[Neo-report] r2444 gregory - in /trunk: neo/tests/ tools/
nobody at svn.erp5.org
nobody at svn.erp5.org
Tue Nov 9 16:58:04 CET 2010
Author: gregory
Date: Tue Nov 9 16:58:02 2010
New Revision: 2444
Log:
Factorize test runner code with BenchmarkRunner class.
Added:
trunk/neo/tests/benchmark.py
Modified:
trunk/tools/matrix
trunk/tools/perfs
trunk/tools/runner
Added: trunk/neo/tests/benchmark.py
==============================================================================
--- trunk/neo/tests/benchmark.py (added)
+++ trunk/neo/tests/benchmark.py [iso-8859-1] Tue Nov 9 16:58:02 2010
@@ -0,0 +1,116 @@
+
+import sys
+import email
+import smtplib
+import optparse
+import platform
+import datetime
+from email.MIMEMultipart import MIMEMultipart
+from email.MIMEText import MIMEText
+
+from neo.tests.functional import NEOCluster
+
+MAIL_SERVER = '127.0.0.1:25'
+
+class AttributeDict(dict):
+
+ def __getattr__(self, item):
+ return self.__getitem__(item)
+
+class BenchmarkRunner(object):
+ """
+ Base class for a command-line benchmark test runner.
+ """
+
+ def __init__(self):
+ self._successful = True
+ self._status = []
+ parser = optparse.OptionParser()
+ # register common options
+ parser.add_option('', '--title')
+ parser.add_option('-v', '--verbose', action='store_true')
+ parser.add_option('', '--mail-to', action='append')
+ parser.add_option('', '--mail-from')
+ parser.add_option('', '--mail-server')
+ self.add_options(parser)
+ # check common arguments
+ options, self._args = parser.parse_args()
+ if bool(options.mail_to) ^ bool(options.mail_from):
+ sys.exit('Need a sender and recipients to mail report')
+ mail_server = options.mail_server or MAIL_SERVER
+ # check specifics arguments
+ self._config = AttributeDict()
+ self._config.update(self.load_options(options, self._args))
+ self._config.update(dict(
+ title = options.title or self.__class__.__name__,
+ verbose = options.verbose,
+ mail_from = options.mail_from,
+ mail_to = options.mail_to,
+ mail_server = mail_server.split(':'),
+ ))
+
+ def add_status(self, key, value):
+ self._status.append((key, value))
+
+ def build_report(self, content):
+ fmt = "%-20s : %s"
+ status = "\n".join([fmt % item for item in [
+ ('Title', self._config.title),
+ ('Date', datetime.date.today().isoformat()),
+ ('Node', platform.node()),
+ ('Machine', platform.machine()),
+ ('System', platform.system()),
+ ('Python', platform.python_version()),
+ ]])
+ status += '\n\n'
+ status += "\n".join([fmt % item for item in self._status])
+ return "%s\n\n%s" % (status, content)
+
+ def send_report(self, subject, report):
+ # build report
+ # build email
+ msg = MIMEMultipart()
+ msg['Subject'] = '%s: %s' % (self._config.title, subject)
+ msg['From'] = self._config.mail_from
+ msg['To'] = ', '.join(self._config.mail_to)
+ msg['X-ERP5-Tests'] = 'NEO'
+ if self._successful:
+ msg['X-ERP5-Tests-Status'] = 'OK'
+ msg.epilogue = ''
+ msg.attach(MIMEText(report))
+
+ # send it
+ s = smtplib.SMTP()
+ s.connect(*self._config.mail_server)
+ mail = msg.as_string()
+ for recipient in self._config.mail_to:
+ try:
+ s.sendmail(self._config.mail_from, recipient, mail)
+ except smtplib.SMTPRecipientsRefused:
+ print "Mail for %s fails" % recipient
+ s.close()
+
+ def run(self):
+ subject, report = self.start()
+ report = self.build_report(report)
+ if self._config.mail_to:
+ self.send_report(subject, report)
+ print subject
+ print
+ print report
+
+ def was_successful(self):
+ return self._successful
+
+ def add_options(self, parser):
+ """ Append options to command line parser """
+ raise NotImplementedError
+
+ def load_options(self, options, args):
+ """ Check options and return a configuration dict """
+ raise NotImplementedError
+
+ def start(self):
+ """ Run the test """
+ raise NotImplementedError
+
Modified: trunk/tools/matrix
==============================================================================
--- trunk/tools/matrix [iso-8859-1] (original)
+++ trunk/tools/matrix [iso-8859-1] Tue Nov 9 16:58:02 2010
@@ -3,158 +3,128 @@
import sys
import os
import math
-import optparse
import traceback
from time import time
+from neo.tests.benchmark import BenchmarkRunner
from neo.tests.functional import NEOCluster
from ZODB.FileStorage import FileStorage
-def run(masters, storages, replicas, partitions, datafs, verbose):
- print "Import of %s with m=%s, s=%s, r=%s, p=%s" % (
- datafs, masters, storages, replicas, partitions)
- # cluster
- neo = NEOCluster(
- db_list=['test_import_%d' % i for i in xrange(storages)],
- clear_databases=True,
- partitions=partitions,
- replicas=replicas,
- master_node_count=masters,
- verbose=verbose,
- )
- # import
- neo_storage = neo.getZODBStorage()
- dfs_storage = FileStorage(file_name=datafs)
- neo.start()
- start = time()
- try:
+MIN_STORAGES = 1
+MAX_STORAGES = 2
+MIN_REPLICAS = 0
+MAX_REPLICAS = 1
+
+class MatrixImportBenchmark(BenchmarkRunner):
+
+ def add_options(self, parser):
+ parser.add_option('-d', '--datafs')
+ parser.add_option('', '--min-storages')
+ parser.add_option('', '--max-storages')
+ parser.add_option('', '--min-replicas')
+ parser.add_option('', '--max-replicas')
+
+ def load_options(self, options, args):
+ if not options.datafs or not os.path.exists(options.datafs):
+ sys.exit('Missing or wrong data.fs argument')
+ return dict(
+ datafs = options.datafs,
+ min_s = int(options.min_storages or MIN_STORAGES),
+ max_s = int(options.max_storages or MAX_STORAGES),
+ min_r = int(options.min_replicas or MIN_REPLICAS),
+ max_r = int(options.max_replicas or MAX_REPLICAS),
+ )
+
+ def start(self):
+ # build storage (logarithm) & replicas (linear) lists
+ min_s, max_s = self._config.min_s, self._config.max_s
+ min_r, max_r = self._config.min_r, self._config.max_r
+ min_s2 = int(math.log(min_s, 2))
+ max_s2 = int(math.log(max_s, 2))
+ storages = [2 ** x for x in range(min_s2, max_s2 + 1)]
+ if storages[0] < min_s:
+ storages[0] = min_s
+ if storages[-1] < max_s:
+ storages.append(max_s)
+ replicas = range(min_r, max_r + 1)
+ results = self.runMatrix(storages, replicas)
+ return self.buildReport(storages, replicas, results)
+
+ def runMatrix(self, storages, replicas):
+ stats = {}
+ size = float(os.path.getsize(self._config.datafs))
+ for s in storages:
+ for r in [r for r in replicas if r < s]:
+ stats.setdefault(s, {})
+ result = self.runImport(1, s, r, 100)
+ if result is not None:
+ result = size / result / 1024
+ stats[s][r] = result
+ return stats
+
+ def runImport(self, masters, storages, replicas, partitions):
+ print "Import of %s with m=%s, s=%s, r=%s, p=%s" % (
+ self._config.datafs, masters, storages, replicas, partitions)
+ # cluster
+ neo = NEOCluster(
+ db_list=['neot_matrix_%d' % i for i in xrange(storages)],
+ clear_databases=True,
+ partitions=partitions,
+ replicas=replicas,
+ master_node_count=masters,
+ verbose=self._config.verbose,
+ )
+ # import
+ neo_storage = neo.getZODBStorage()
+ dfs_storage = FileStorage(file_name=self._config.datafs)
+ neo.start()
+ start = time()
try:
- neo_storage.copyTransactionsFrom(dfs_storage)
- return time() - start
- except:
- traceback.print_exc()
- return None
- finally:
- neo.stop()
-
-def runMatrix(datafs, storages, replicas, verbose):
- stats = {}
- size = float(os.path.getsize(datafs))
- for s in storages:
- for r in [r for r in replicas if r < s]:
- stats.setdefault(s, {})
- result = run(1, s, r, 100, datafs, verbose)
- if result is not None:
- result = size / result / 1024
- stats[s][r] = result
- return stats
-
-def buildReport(storages, replicas, results):
- # draw an array with results
- fmt = '|' + '|'.join([' %8s '] * (len(replicas) + 1)) + '|\n'
- sep = '+' + '+'.join(['-' * 12] * (len(replicas) + 1)) + '+\n'
- report = sep
- report += fmt % tuple(['S\R'] + range(0, len(replicas)))
- report += sep
- failures = 0
- speedlist = []
- for s in storages:
- values = []
- assert s in results
- for r in replicas:
- if r in results[s]:
- if results[s][r] is None:
- values.append('FAIL')
- failures += 1
- else:
- values.append('%8.1f' % results[s][r])
- speedlist.append(results[s][r])
- else:
- values.append('N/A')
- report += fmt % (tuple([s] + values))
+ try:
+ neo_storage.copyTransactionsFrom(dfs_storage)
+ return time() - start
+ except:
+ traceback.print_exc()
+ return None
+ finally:
+ neo.stop()
+
+ def buildReport(self, storages, replicas, results):
+ config = self._config
+ self.add_status('Min storages', config.min_s)
+ self.add_status('Max storages', config.max_s)
+ self.add_status('Min replicas', config.min_r)
+ self.add_status('Max replicas', config.max_r)
+ # draw an array with results
+ fmt = '|' + '|'.join([' %8s '] * (len(replicas) + 1)) + '|\n'
+ sep = '+' + '+'.join(['-' * 12] * (len(replicas) + 1)) + '+\n'
+ report = sep
+ report += fmt % tuple(['S\R'] + range(0, len(replicas)))
report += sep
- if failures:
- info = '%d failures' % (failures, )
- else:
- info = '%.1f KB/s' % (sum(speedlist) / len(speedlist))
- summary = 'Matrix : %s ' % (info, )
- return (summary, report)
-
-def sendReport(sender, recipients, server, summary, report):
- """ Send a mail with the report summary """
- # XXX: C/C from perfs bench
- import smtplib
- from email.MIMEMultipart import MIMEMultipart
- from email.MIMEText import MIMEText
-
- # build the email
- msg = MIMEMultipart()
- msg['Subject'] = summary
- msg['From'] = sender
- msg['To'] = ', '.join(recipients)
- msg.epilogue = ''
- msg.attach(MIMEText(report))
-
- # Send via smtp server
- s = smtplib.SMTP()
- s.connect(*server)
- mail = msg.as_string()
- for recipient in recipients:
- try:
- s.sendmail(sender, recipient, mail)
- except smtplib.SMTPRecipientsRefused:
- print "Mail for %s fails" % recipient
- s.close()
+ failures = 0
+ speedlist = []
+ for s in storages:
+ values = []
+ assert s in results
+ for r in replicas:
+ if r in results[s]:
+ if results[s][r] is None:
+ values.append('FAIL')
+ failures += 1
+ else:
+ values.append('%8.1f' % results[s][r])
+ speedlist.append(results[s][r])
+ else:
+ values.append('N/A')
+ report += fmt % (tuple([s] + values))
+ report += sep
+ if failures:
+ info = '%d failures' % (failures, )
+ else:
+ info = '%.1f KB/s' % (sum(speedlist) / len(speedlist))
+ summary = 'Matrix : %s ' % (info, )
+ return (summary, report)
if __name__ == "__main__":
-
- # options
- parser = optparse.OptionParser()
- parser.add_option('-d', '--datafs')
- parser.add_option('', '--min-storages')
- parser.add_option('', '--max-storages')
- parser.add_option('', '--min-replicas')
- parser.add_option('', '--max-replicas')
- parser.add_option('', '--recipient', action='append')
- parser.add_option('', '--sender')
- parser.add_option('', '--server')
- parser.add_option('-v', '--verbose', action='store_true')
- (options, args) = parser.parse_args()
-
- # check arguments
- if not options.datafs or not os.path.exists(options.datafs):
- sys.exit('Missing or wrong data.fs argument')
- if bool(options.sender) ^ bool(options.recipient):
- sys.exit('Need a sender and recipients to mail report')
-
- # parse args
- min_s = int(options.min_storages or 1)
- max_s = int(options.max_storages or 2)
- min_r = int(options.min_replicas or 0)
- max_r = int(options.max_replicas or 1)
- datafs = options.datafs
- mail_server = options.server or '127.0.0.1:25'
- mail_server = mail_server.split(':')
- sender = options.sender
- recipient = options.recipient
- verbose = options.verbose or False
-
- # build storage (logarithm) & replicas (linear) lists
- min_s2 = int(math.log(min_s, 2))
- max_s2 = int(math.log(max_s, 2))
- storages = [2 ** x for x in range(min_s2, max_s2 + 1)]
- if storages[0] < min_s:
- storages[0] = min_s
- if storages[-1] < max_s:
- storages.append(max_s)
- replicas = range(min_r, max_r + 1)
- results = runMatrix(datafs, storages, replicas, verbose)
- summary, report = buildReport(storages, replicas, results)
-
- print summary
- print
- print report
-
- if options.sender:
- sendReport(sender, recipient, mail_server, summary, report)
+ MatrixImportBenchmark().run()
Modified: trunk/tools/perfs
==============================================================================
--- trunk/tools/perfs [iso-8859-1] (original)
+++ trunk/tools/perfs [iso-8859-1] Tue Nov 9 16:58:02 2010
@@ -2,179 +2,127 @@
import os
import sys
-import optparse
import platform
import datetime
from time import time
+from ZODB.FileStorage import FileStorage
+from neo.tests.benchmark import BenchmarkRunner
from neo.tests.functional import NEOCluster
-from neo.client.Storage import Storage
-from ZODB.FileStorage import FileStorage
from neo.profiling import PROFILING_ENABLED, profiler_decorator, \
profiler_report
-def runImport(neo, datafs):
+class ImportBenchmark(BenchmarkRunner):
+ """ Test import of a datafs """
- def counter(wrapped, d):
- @profiler_decorator
- def wrapper(*args, **kw):
- # count number of tick per second
- t = int(time())
- d.setdefault(t, 0)
- d[t] += 1
- # call original method
- wrapped(*args, **kw)
- return wrapper
-
- # open storages clients
- neo_storage = neo.getZODBStorage()
- dfs_storage = FileStorage(file_name=datafs)
- dfs_size = os.path.getsize(datafs)
-
- # monkey patch storage
- txn_dict, obj_dict = {}, {}
- neo_storage.app.tpc_begin = counter(neo_storage.app.tpc_begin, txn_dict)
- neo_storage.app.store = counter(neo_storage.app.store, obj_dict)
-
- # run import
- start = time()
- stats = neo_storage.copyTransactionsFrom(dfs_storage)
- elapsed = time() - start
-
- # return stats
- stats = {
- 'Transactions': txn_dict.values(),
- 'Objects': obj_dict.values(),
- }
- return (dfs_size, elapsed, stats)
-
-def buildReport(config, dfs_size, elapsed, stats):
- """ build a report for the given import data """
-
- pat = '%19s | %8s | %5s | %5s | %5s \n'
- sep = '%19s+%8s+%5s+%5s+%5s\n'
- sep %= ('-' * 20, '-' * 10) + ('-' * 7, ) * 3
-
- dfs_size /= 1024
- size = dfs_size / 1024
- speed = dfs_size / elapsed
-
- # system
- report = ' ' * 20 + ' NEO PERF REPORT\n\n'
- report += "\tDate : %s\n" % datetime.date.today().isoformat()
- report += "\tNode : %s\n" % platform.node()
- report += "\tProcessor : %s (%s)\n" % (platform.processor(),
- platform.architecture()[0])
- report += "\tSystem : %s (%s)\n" % (platform.system(),
- platform.release())
- report += '\n'
- # configuration
- report += "\tMasters : %s\n" % (config['masters'], )
- report += "\tStorages : %s\n" % (config['storages'], )
- report += "\tReplicas : %s\n" % (config['replicas'], )
- report += "\tPartitions : %s\n" % (config['partitions'], )
- report += '\n'
- # results
- report += '\n%19s: %6.1f MB' % ('Input size', size)
- report += '\n%19s: %6d sec' % ('Import duration', elapsed)
- report += '\n%19s: %6.1f KB/s\n' % ('Average speed', speed)
- report += '\n\n'
-
- # stats on objects and transactions
- report += pat % ('', ' num ', 'min/s', 'avg/s', 'max/s')
- for k, v in stats.items():
- report += sep
- s = sum(v)
- report += pat % (k, s, min(v), s / len(v), max(v))
- report += sep
-
- # build summary
- summary = 'Neo : %6.1f KB/s (%6.1f MB)' % (speed, size)
-
- return (summary, report)
-
-def sendReport(sender, recipients, server, summary, report):
- """ Send a mail with the report summary """
-
- import smtplib
- from email.MIMEMultipart import MIMEMultipart
- from email.MIMEText import MIMEText
-
- # build the email
- msg = MIMEMultipart()
- msg['Subject'] = summary
- msg['From'] = sender
- msg['To'] = ', '.join(recipients)
- msg.epilogue = ''
- msg.attach(MIMEText(report))
-
- # Send via smtp server
- s = smtplib.SMTP()
- s.connect(*server)
- mail = msg.as_string()
- for recipient in recipients:
- try:
- s.sendmail(sender, recipient, mail)
- except smtplib.SMTPRecipientsRefused:
- print "Mail for %s fails" % recipient
- s.close()
+ def add_options(self, parser):
+ parser.add_option('-d', '--datafs')
+ parser.add_option('-m', '--masters')
+ parser.add_option('-s', '--storages')
+ parser.add_option('-p', '--partitions')
+ parser.add_option('-r', '--replicas')
+
+ def load_options(self, options, args):
+ if not options.datafs or not os.path.exists(options.datafs):
+ sys.exit('Missing or wrong data.fs argument')
+ return dict(
+ datafs = options.datafs,
+ masters = int(options.masters or 1),
+ storages = int(options.storages or 1),
+ partitions = int(options.partitions or 10),
+ replicas = int(options.replicas or 0),
+ )
+
+ def start(self):
+ config = self._config
+ # start neo
+ neo = NEOCluster(
+ db_list=['neot_perfs_%d' % i for i in xrange(config.storages)],
+ clear_databases=True,
+ partitions=config.partitions,
+ replicas=config.replicas,
+ master_node_count=config.masters,
+ verbose=False,
+ )
-if __name__ == "__main__":
+ # import datafs
+ neo.start()
+ try:
+ return self.buildReport(*self.runImport(neo))
+ finally:
+ neo.stop()
+
+ def runImport(self, neo):
+
+ def counter(wrapped, d):
+ @profiler_decorator
+ def wrapper(*args, **kw):
+ # count number of tick per second
+ t = int(time())
+ d.setdefault(t, 0)
+ d[t] += 1
+ # call original method
+ wrapped(*args, **kw)
+ return wrapper
+
+ # open storages clients
+ datafs = self._config.datafs
+ neo_storage = neo.getZODBStorage()
+ dfs_storage = FileStorage(file_name=datafs)
+ dfs_size = os.path.getsize(datafs)
+
+ # monkey patch storage
+ txn_dict, obj_dict = {}, {}
+ neo_storage.app.tpc_begin = counter(neo_storage.app.tpc_begin, txn_dict)
+ neo_storage.app.store = counter(neo_storage.app.store, obj_dict)
+
+ # run import
+ start = time()
+ stats = neo_storage.copyTransactionsFrom(dfs_storage)
+ elapsed = time() - start
+
+ # return stats
+ stats = {
+ 'Transactions': txn_dict.values(),
+ 'Objects': obj_dict.values(),
+ }
+ return (dfs_size, elapsed, stats)
+
+ def buildReport(self, dfs_size, elapsed, stats):
+ """ build a report for the given import data """
+ config = self._config
+ dfs_size /= 1024
+ size = dfs_size / 1024
+ speed = dfs_size / elapsed
+
+ # configuration
+ self.add_status('Masters', config.masters)
+ self.add_status('Storages', config.storages)
+ self.add_status('Replicas', config.replicas)
+ self.add_status('Partitions', config.partitions)
+
+ # results
+ self.add_status('Input size', '%-.1f MB' % size)
+ self.add_status('Import duration', '%-d secs' % elapsed)
+ self.add_status('Average speed', '%-.1f KB/s' % speed)
+
+ # stats on objects and transactions
+ pat = '%19s | %8s | %5s | %5s | %5s \n'
+ sep = '%19s+%8s+%5s+%5s+%5s\n'
+ sep %= ('-' * 20, '-' * 10) + ('-' * 7, ) * 3
+ report = pat % ('', ' num ', 'min/s', 'avg/s', 'max/s')
+ for k, v in stats.items():
+ report += sep
+ s = sum(v)
+ report += pat % (k, s, min(v), s / len(v), max(v))
+ report += sep
- # handle command line options
- parser = optparse.OptionParser()
- parser.add_option('-d', '--datafs')
- parser.add_option('-m', '--master-count')
- parser.add_option('-s', '--storage-count')
- parser.add_option('-p', '--partition-count')
- parser.add_option('-r', '--replica-count')
- parser.add_option('', '--recipient', action='append')
- parser.add_option('', '--sender')
- parser.add_option('', '--server')
- (options, args) = parser.parse_args()
-
- # check arguments
- if not options.datafs or not os.path.exists(options.datafs):
- sys.exit('Missing or wrong data.fs argument')
- if bool(options.sender) ^ bool(options.recipient):
- sys.exit('Need a sender and recipients to mail report')
-
- # load options or defaults
- config = dict(
- masters = int(options.master_count or 1),
- storages = int(options.storage_count or 1),
- partitions = int(options.partition_count or 10),
- replicas = int(options.replica_count or 0),
- )
-
- datafs = options.datafs
- mail_server = options.server or '127.0.0.1:25'
- mail_server = mail_server.split(':')
- sender = options.sender
- recipient = options.recipient
-
- # start neo
- neo = NEOCluster(
- db_list=['test_import_%d' % i for i in xrange(config['storages'])],
- clear_databases=True,
- partitions=config['partitions'],
- replicas=config['replicas'],
- master_node_count=config['masters'],
- verbose=False,
- )
-
- # import datafs
- neo.start()
- summary, report = buildReport(config, *runImport(neo, datafs))
- neo.stop()
+ # build summary
+ summary = 'Perf : %.1f KB/s (%.1f MB)' % (speed, size)
+ return (summary, report)
+if __name__ == "__main__":
+ ImportBenchmark().run()
if PROFILING_ENABLED:
print profiler_report()
- # display and/or send the report
- print summary
- print report
- if options.sender:
- sendReport(sender, recipient, mail_server, summary, report)
-
-
Modified: trunk/tools/runner
==============================================================================
--- trunk/tools/runner [iso-8859-1] (original)
+++ trunk/tools/runner [iso-8859-1] Tue Nov 9 16:58:02 2010
@@ -17,7 +17,6 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import traceback
-import optparse
import unittest
import tempfile
import logging
@@ -26,6 +25,8 @@ import sys
import neo
import os
+from neo.tests.benchmark import BenchmarkRunner
+
# list of test modules
# each of them have to import its TestCase classes
UNIT_TEST_MODULES = [
@@ -153,7 +154,7 @@ class NeoTestRunner(unittest.TestResult)
def startTest(self, test):
unittest.TestResult.startTest(self, test)
- logging.info(" * TEST %s" % test)
+ logging.info(" * TEST %s", test)
stats = self._getModuleStats(test)
stats.run += 1
self.lastStart = time.time()
@@ -179,42 +180,18 @@ class NeoTestRunner(unittest.TestResult)
stats.failures += 1
self._updateTimer(stats)
- def _buildSystemInfo(self):
- import platform
- import datetime
+ def _buildSummary(self, add_status):
success = self.testsRun - len(self.errors) - len(self.failures)
- s = """
- Title : %s
- Date : %s
- Node : %s
- Machine : %s
- System : %s (%s)
- Python : %s
- Directory : %s
- Status : %7.3f%%
- """ % (
- self._title,
- datetime.date.today().isoformat(),
- platform.node(),
- platform.machine(),
- platform.system(),
- platform.release(),
- platform.python_version(),
- self.temp_directory,
- success * 100.0 / self.testsRun,
- )
- return s
-
- def _buildSummary(self):
- # visual
+ add_status('Directory', self.temp_directory)
+ add_status('Status', '%.3f%%' % (success * 100.0 / self.testsRun))
+ # visual
header = "%25s | run | success | errors | fails | time \n" % 'Test Module'
separator = "%25s-+---------+---------+---------+---------+----------\n" % ('-' * 25)
format = "%25s | %3s | %3s | %3s | %3s | %6.2fs \n"
group_f = "%25s | | | | | \n"
# header
s = ' ' * 30 + ' NEO TESTS REPORT'
- s += '\n\n'
- s += self._buildSystemInfo()
+ s += '\n'
s += '\n' + header + separator
group = None
t_success = 0
@@ -243,7 +220,7 @@ class NeoTestRunner(unittest.TestResult)
return s
def _buildErrors(self):
- s = '\n'
+ s = ''
test_formatter = lambda t: t.id()
if len(self.errors):
s += '\nERRORS:\n'
@@ -272,98 +249,53 @@ class NeoTestRunner(unittest.TestResult)
s += '\n'
return s
- def build(self):
+ def buildReport(self, add_status):
self.time = sum([s.time for s in self.modulesStats.values()])
self.subject = "%s: %s Tests, %s Errors, %s Failures" % (self._title,
self.testsRun, len(self.errors), len(self.failures))
- self._summary = self._buildSummary()
- self._errors = self._buildErrors()
- self._warnings = self._buildWarnings()
-
- def sendReport(self, smtp_server, sender, recipients):
- """ Send a mail with the report summary """
-
- import smtplib
- from email.MIMEMultipart import MIMEMultipart
- from email.MIMEText import MIMEText
-
- # build the email
- msg = MIMEMultipart()
- msg['Subject'] = self.subject
- msg['From'] = sender
- msg['To'] = ', '.join(recipients)
- #msg.preamble = self.subject
- msg.epilogue = ''
-
- # Add custom headers for client side filtering
- msg['X-ERP5-Tests'] = 'NEO'
- if self.wasSuccessful():
- msg['X-ERP5-Tests-Status'] = 'OK'
-
- # write the body
- body = MIMEText(self._summary + self._warnings + self._errors)
- msg.attach(body)
-
- # attach the log file
- if ATTACH_LOG:
- log = MIMEText(file(LOG_FILE, 'r').read())
- log.add_header('Content-Disposition', 'attachment', filename=LOG_FILE)
- msg.attach(log)
-
- # Send the email via a smtp server
- s = smtplib.SMTP()
- s.connect(*mail_server)
- mail = msg.as_string()
- for recipient in recipients:
- try:
- s.sendmail(sender, recipient, mail)
- except smtplib.SMTPRecipientsRefused, e:
- print "Mail for %s fails : %s" % (recipient, e)
- s.close()
+ summary = self._buildSummary(add_status)
+ errors = self._buildErrors()
+ warnings = self._buildWarnings()
+ report = '\n'.join([summary, errors, warnings])
+ return (self.subject, report)
+
+class TestRunner(BenchmarkRunner):
+
+ def add_options(self, parser):
+ parser.add_option('-f', '--functional', action='store_true')
+ parser.add_option('-u', '--unit', action='store_true')
+ parser.add_option('-z', '--zodb', action='store_true')
+
+ def load_options(self, options, args):
+ if not (options.unit or options.functional or options.zodb or args):
+ sys.exit('Nothing to run, please give one of -f, -u, -z')
+ return dict(
+ unit = options.unit,
+ functional = options.functional,
+ zodb = options.zodb,
+ )
-if __name__ == "__main__":
+ def start(self):
+ config = self._config
+ # run requested tests
+ runner = NeoTestRunner(title=config.title or 'Neo')
+ try:
+ if config.unit:
+ runner.run('Unit tests', UNIT_TEST_MODULES)
+ if config.functional:
+ runner.run('Functional tests', FUNC_TEST_MODULES)
+ if config.zodb:
+ runner.run('ZODB tests', ZODB_TEST_MODULES)
+ except KeyboardInterrupt:
+ config['mail_to'] = None
+ traceback.print_exc()
+ # build report
+ self._successful = runner.wasSuccessful()
+ return runner.buildReport(self.add_status)
- # handle command line options
- parser = optparse.OptionParser()
- parser.add_option('-f', '--functional', action='store_true')
- parser.add_option('-u', '--unit', action='store_true')
- parser.add_option('-z', '--zodb', action='store_true')
- parser.add_option('', '--recipient', action='append')
- parser.add_option('', '--sender')
- parser.add_option('', '--server')
- parser.add_option('', '--title')
- (options, args) = parser.parse_args()
-
- # check arguments
- if bool(options.sender) ^ bool(options.recipient):
- sys.exit('Need a sender and recipients to mail report')
- if not (options.unit or options.functional or options.zodb or args):
- sys.exit('Nothing to run, please give one of -f, -u, -z')
- mail_server = options.server or '127.0.0.1:25'
- mail_server = mail_server.split(':')
-
- # run requested tests
- runner = NeoTestRunner(title=options.title or 'Neo')
- try:
- if options.unit:
- runner.run('Unit tests', UNIT_TEST_MODULES)
- if options.functional:
- runner.run('Functional tests', FUNC_TEST_MODULES)
- if options.zodb:
- runner.run('ZODB tests', ZODB_TEST_MODULES)
- except KeyboardInterrupt:
- traceback.print_exc()
- options.sender = False
-
- # build report
- runner.build()
- print runner._errors
- print runner._warnings
- print runner._summary
-
- # send a mail
- if options.sender:
- runner.sendReport(mail_server, options.sender, options.recipient)
- if not runner.wasSuccessful():
+if __name__ == "__main__":
+ runner = TestRunner()
+ runner.run()
+ if not runner.was_successful():
sys.exit(1)
sys.exit(0)
More information about the Neo-report
mailing list