PKT;4 funkload/FunkLoadDocTest.py# (C) Copyright 2006 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """FunkLoad doc test $Id: FunkLoadDocTest.py 32254 2006-01-26 10:58:02Z bdelbosc $ """ import os from tempfile import gettempdir from FunkLoadTestCase import FunkLoadTestCase import PatchWebunit class FunkLoadDocTest(FunkLoadTestCase): """Class to use in doctest. >>> from FunkLoadDocTest import FunkLoadDocTest >>> fl = FunkLoadDocTest() >>> ret = fl.get('http://localhost') >>> ret.code 200 >>> 'HTML' in ret.body True """ def __init__(self, debug=False, debug_level=1): """Initialise the test case.""" class Dummy: pass option = Dummy() option.ftest_sleep_time_max = .001 option.ftest_sleep_time_min = .001 if debug: option.ftest_log_to = 'console file' if debug_level: option.debug_level = debug_level else: option.ftest_log_to = 'file' tmp_path = gettempdir() option.ftest_log_path = os.path.join(tmp_path, 'fl-doc-test.log') option.ftest_result_path = os.path.join(tmp_path, 'fl-doc-test.xml') FunkLoadTestCase.__init__(self, 'runTest', option) def runTest(self): """FL doctest""" return def _test(): import doctest, FunkLoadDocTest return doctest.testmod(FunkLoadDocTest) if __name__ == "__main__": _test() PKv]i6dzF,F,funkload/ReportStats.py# (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """Classes that collect statistics submitted by the result parser. $Id: ReportStats.py 24737 2005-08-31 09:00:16Z bdelbosc $ """ class MonitorStat: """Collect system monitor info.""" def __init__(self, attrs): for key, value in attrs.items(): setattr(self, key, value) class ErrorStat: """Collect Error or Failure stats.""" def __init__(self, cycle, step, number, code, header, body, traceback): self.cycle = cycle self.step = step self.number = number self.code = code self.header = header and header.copy() or {} self.body = body or None self.traceback = traceback class Percentiles: """ Calculate Percentiles with the given stepsize. """ def __init__(self, stepsize=10, name ="UNKNOWN", results=None): self.stepsize = stepsize self.name = name if results is None: self.results = [] else: self.results = results def addResult(self, newresult): """Add a new result.""" self.results.append(newresult) def calcPercentiles(self): """Compute percentiles.""" results = self.results results.sort() len_results = len(results) old_value = -1 for perc in range(0, 100, self.stepsize): index = int(perc / 100.0 * len_results) try: value = results[index] except IndexError: value = -1.0 setattr(self, "perc%02d" % perc, float(value)) old_value = value def __str__(self): self.calcPercentiles() fmt_string = ["Percentiles: %s" % self.name] for perc in range(0, 100, self.stepsize): name = "perc%02d" % perc fmt_string.append("%s=%s" % (name, getattr(self, name))) return ", ".join(fmt_string) def __repr__(self): return "Percentiles(stepsize=%r, name=%r, results=%r)" % ( self.stepsize, self.name, self.results) class AllResponseStat: """Collect stat for all response in a cycle.""" def __init__(self, cycle, cycle_duration, cvus): self.cycle = cycle self.cycle_duration = cycle_duration self.cvus = int(cvus) self.per_second = {} self.max = 0 self.min = 999999999 self.avg = 0 self.total = 0 self.count = 0 self.success = 0 self.error = 0 self.error_percent = 0 self.rps = 0 self.rps_min = 0 self.rps_max = 0 self.finalized = False self.percentiles = Percentiles(stepsize = 5, name = cycle) def add(self, date, result, duration): """Add a new response to stat.""" date_s = int(float(date)) self.per_second [date_s] = self.per_second.setdefault( int(date_s), 0) + 1 self.count += 1 if result == 'Successful': self.success += 1 else: self.error += 1 self.max = max(self.max, float(duration)) self.min = min(self.min, float(duration)) self.total += float(duration) self.finalized = False self.percentiles.addResult(float(duration)) def finalize(self): """Compute avg times.""" if self.finalized: return if self.count: self.avg = self.total / float(self.count) self.min = min(self.max, self.min) if self.error: self.error_percent = 100.0 * self.error / float(self.count) rps_min = rps_max = 0 for date in self.per_second.keys(): rps_max = max(rps_max, self.per_second[date]) rps_min = min(rps_min, self.per_second[date]) if self.cycle_duration: rps = self.count / float(self.cycle_duration) if rps < 1: # average is lower than 1 this means that sometime there was # no request during one second rps_min = 0 self.rps = rps self.rps_max = rps_max self.rps_min = rps_min self.percentiles.calcPercentiles() self.finalized = True class SinglePageStat: """Collect stat for a single page.""" def __init__(self, step): self.step = step self.count = 0 self.date_s = None self.duration = 0.0 self.result = 'Successful' self.percentiles = Percentiles(stepsize=5, name=step) def addResponse(self, date, result, duration): """Add a response to a page.""" self.count += 1 if self.date_s is None: self.date_s = int(float(date)) self.duration += float(duration) self.percentiles.addResult(float(duration)) if result != 'Successful': self.result = result def __repr__(self): """Representation.""" return 'page %s %s %ss' % (self.step, self.result, self.duration) class PageStat(AllResponseStat): """Collect stat for asked pages in a cycle.""" def __init__(self, cycle, cycle_duration, cvus): AllResponseStat.__init__(self, cycle, cycle_duration, cvus) self.threads = {} def add(self, thread, step, date, result, duration, rtype): """Add a new response to stat.""" thread = self.threads.setdefault(thread, {'count': 0, 'pages': {}}) if str(rtype) in ('post', 'get', 'xmlrpc'): new_page = True else: new_page = False if new_page: thread['count'] += 1 self.count += 1 if not thread['count']: # don't take into account request that belongs to a staging up page return stat = thread['pages'].setdefault(thread['count'], SinglePageStat(step)) stat.addResponse(date, result, duration) self.percentiles.addResult(float(duration)) self.finalized = False def finalize(self): """Compute avg times.""" if self.finalized: return for thread in self.threads.keys(): for page in self.threads[thread]['pages'].values(): if str(page.result) == 'Successful': if page.date_s: count = self.per_second.setdefault(page.date_s, 0) + 1 self.per_second[page.date_s] = count self.success += 1 self.total += page.duration else: self.error += 1 continue duration = page.duration self.max = max(self.max, duration) self.min = min(self.min, duration) AllResponseStat.finalize(self) if self.cycle_duration: # override rps to srps self.rps = self.success / float(self.cycle_duration) self.percentiles.calcPercentiles() self.finalized = True class ResponseStat: """Collect stat a specific response in a cycle.""" def __init__(self, step, number, cvus): self.step = step self.number = number self.cvus = int(cvus) self.max = 0 self.min = 999999999 self.avg = 0 self.total = 0 self.count = 0 self.success = 0 self.error = 0 self.error_percent = 0 self.url = '?' self.description = '' self.type = '?' self.finalized = False self.percentiles = Percentiles(stepsize=5, name=step) def add(self, rtype, result, url, duration, description=None): """Add a new response to stat.""" self.count += 1 if result == 'Successful': self.success += 1 else: self.error += 1 self.max = max(self.max, float(duration)) self.min = min(self.min, float(duration)) self.total += float(duration) self.percentiles.addResult(float(duration)) self.url = url self.type = rtype if description is not None: self.description = description self.finalized = False def finalize(self): """Compute avg times.""" if self.finalized: return if self.total: self.avg = self.total / float(self.count) self.min = min(self.max, self.min) if self.error: self.error_percent = 100.0 * self.error / float(self.count) self.percentiles.calcPercentiles() self.finalized = True class TestStat: """Collect test stat for a cycle. Stat on successful test case. """ def __init__(self, cycle, cycle_duration, cvus): self.cycle = cycle self.cycle_duration = float(cycle_duration) self.cvus = int(cvus) self.max = 0 self.min = 999999999 self.avg = 0 self.total = 0 self.count = 0 self.success = 0 self.error = 0 self.error_percent = 0 self.traceback = [] self.pages = self.images = self.redirects = self.links = 0 self.xmlrpc = 0 self.tps = 0 self.finalized = False self.percentiles = Percentiles(stepsize=5, name=cycle) def add(self, result, pages, xmlrpc, redirects, images, links, duration, traceback=None): """Add a new response to stat.""" self.finalized = False self.count += 1 if traceback is not None: self.traceback.append(traceback) if result == 'Successful': self.success += 1 else: self.error += 1 return self.max = max(self.max, float(duration)) self.min = min(self.min, float(duration)) self.total += float(duration) self.pages = max(self.pages, int(pages)) self.xmlrpc = max(self.xmlrpc, int(xmlrpc)) self.redirects = max(self.redirects, int(redirects)) self.images = max(self.images, int(images)) self.links = max(self.links, int(links)) self.percentiles.addResult(float(duration)) def finalize(self): """Compute avg times.""" if self.finalized: return if self.success: self.avg = self.total / float(self.success) self.min = min(self.max, self.min) if self.error: self.error_percent = 100.0 * self.error / float(self.count) if self.cycle_duration: self.tps = self.success / float(self.cycle_duration) self.percentiles.calcPercentiles() self.finalized = True PKLb6HY8Y8funkload/PatchWebunit.py# (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """Patching Richard Jones' webunit for FunkLoad. * Add cache for links (css, js) * store a browser history * add headers * log response * remove webunit log * fix HTTPResponse __repr__ * patching webunit mimeEncode to be rfc 1945 3.6.2 compliant using CRLF * patching to remove cookie with a 'deleted' value * patching to have application/x-www-form-urlencoded by default and only multipart when a file is posted * patch fetch postdata must be [(key, value) ...] no more dict or list value $Id: PatchWebunit.py 24649 2005-08-29 14:20:19Z bdelbosc $ """ import os import sys import time import urlparse from urllib import urlencode import httplib import cStringIO from mimetypes import guess_type from webunit import cookie from webunit.IMGSucker import IMGSucker from webunit.webunittest import WebTestCase, WebFetcher from webunit.webunittest import HTTPResponse, HTTPError, VERBOSE from webunit.utility import Upload from utils import thread_sleep BOUNDARY = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' SEP_BOUNDARY = '--' + BOUNDARY END_BOUNDARY = SEP_BOUNDARY + '--' def mimeEncode(data, sep_boundary=SEP_BOUNDARY, end_boundary=END_BOUNDARY): '''Take the mapping of data and construct the body of a multipart/form-data message with it using the indicated boundaries. ''' ret = cStringIO.StringIO() first_part = True for key, value in data: if not key: continue # Don't add newline before first part if first_part: first_part = False else: ret.write('\r\n') ret.write(sep_boundary) if isinstance(value, Upload): ret.write('\r\nContent-Disposition: form-data; name="%s"'%key) ret.write('; filename="%s"\r\n' % value.filename) if value.filename: mimetype = guess_type(value.filename)[0] if mimetype is not None: ret.write('Content-Type: %s\r\n' % mimetype) value = open(os.path.join(value.filename), "rb").read() else: value = '' ret.write('\r\n') else: ret.write('\r\nContent-Disposition: form-data; name="%s"'%key) ret.write("\r\n\r\n") ret.write(str(value)) if value and value[-1] == '\r': ret.write('\r\n') # write an extra newline ret.write('\r\n') ret.write(end_boundary) return ret.getvalue() class FKLIMGSucker(IMGSucker): """Image and links loader, patched to log response stats.""" def __init__(self, url, session, ftestcase=None): IMGSucker.__init__(self, url, session) self.ftestcase = ftestcase def do_img(self, attributes): """Process img tag.""" newattributes = [] for name, value in attributes: if name == 'src': url = urlparse.urljoin(self.base, value) # TODO: figure the re-write path # newattributes.append((name, path)) if not self.session.images.has_key(url): self.ftestcase.logdd(' img: %s ...' % url) t_start = time.time() self.session.images[url] = self.session.fetch(url) t_stop = time.time() self.ftestcase.logdd(' Done in %.3fs' % (t_stop - t_start)) self.session.history.append(('image', url)) self.ftestcase.total_time += (t_stop - t_start) self.ftestcase.total_images += 1 self.ftestcase._log_response(self.session.images[url], 'image', None, t_start, t_stop) thread_sleep() # give a chance to other threads else: newattributes.append((name, value)) # Write the img tag to file (with revised paths) self.unknown_starttag('img', newattributes) def do_link(self, attributes): """Process link tag.""" newattributes = [('rel', 'stylesheet'), ('type', 'text/css')] for name, value in attributes: if name == 'href': url = urlparse.urljoin(self.base, value) # TODO: figure the re-write path # newattributes.append((name, path)) if not self.session.css.has_key(url): self.ftestcase.logdd(' link: %s ...' % url) t_start = time.time() self.session.css[url] = self.session.fetch(url) t_stop = time.time() self.ftestcase.logdd(' Done in %.3fs' % (t_stop - t_start)) self.session.history.append(('link', url)) self.ftestcase.total_time += (t_stop - t_start) self.ftestcase.total_links += 1 self.ftestcase._log_response(self.session.css[url], 'link', None, t_start, t_stop) thread_sleep() # give a chance to other threads else: newattributes.append((name, value)) # Write the link tag to file (with revised paths) self.unknown_starttag('link', newattributes) # remove webunit logging def WTC_log(self, message, content): """Remove webunit logging.""" pass WebTestCase.log = WTC_log # use fl img sucker def WTC_pageImages(self, url, page, testcase=None): '''Given the HTML page that was loaded from url, grab all the images. ''' sucker = FKLIMGSucker(url, self, testcase) sucker.feed(page) sucker.close() WebTestCase.pageImages = WTC_pageImages # WebFetcher fetch def WF_fetch(self, url, postdata=None, server=None, port=None, protocol=None, ok_codes=None): '''Run a single test request to the indicated url. Use the POST data if supplied. Raises failureException if the returned data contains any of the strings indicated to be Error Content. Returns a HTTPReponse object wrapping the response from the server. ''' # see if the url is fully-qualified (not just a path) t_protocol, t_server, t_url, x, t_args, x = urlparse.urlparse(url) if t_server: protocol = t_protocol if ':' in t_server: server, port = t_server.split(':') else: server = t_server if protocol == 'http': port = '80' else: port = '443' url = t_url if t_args: url = url + '?' + t_args # ignore the machine name if the URL is for localhost if t_server == 'localhost': server = None elif not server: # no server was specified with this fetch, or in the URL, so # see if there's a base URL to use. base = self.get_base_url() if base: t_protocol, t_server, t_url, x, x, x = urlparse.urlparse(base) if t_protocol: protocol = t_protocol if t_server: server = t_server if t_url: url = urlparse.urljoin(t_url, url) # TODO: allow override of the server and port from the URL! if server is None: server = self.server if port is None: port = self.port if protocol is None: protocol = self.protocol if ok_codes is None: ok_codes = self.expect_codes webproxy = {} if protocol == 'http': try: proxystring = os.environ["http_proxy"].replace("http://", "") webproxy['host'] = proxystring.split(":")[0] webproxy['port'] = int(proxystring.split(":")[1]) except (KeyError, IndexError, ValueError): webproxy = False if webproxy: h = httplib.HTTPConnection(webproxy['host'], webproxy['port']) else: h = httplib.HTTP(server, int(port)) if int(port) == 80: host_header = server else: host_header = '%s:%s' % (server, port) elif protocol == 'https': #if httpslib is None: #raise ValueError, "Can't fetch HTTPS: M2Crypto not installed" h = httplib.HTTPS(server, int(port)) if int(port) == 443: host_header = server else: host_header = '%s:%s' % (server, port) else: raise ValueError, protocol params = None if postdata: if webproxy: h.putrequest('POST', "http://%s%s" % (host_header, url)) else: # Normal post h.putrequest('POST', url) is_multipart = False for field, value in postdata: if isinstance(value, Upload): # Post with a data file requires multipart mimeencode is_multipart = True if is_multipart: params = mimeEncode(postdata) h.putheader('Content-type', 'multipart/form-data; boundary=%s'% BOUNDARY) else: params = urlencode(postdata) h.putheader('Content-type', 'application/x-www-form-urlencoded') h.putheader('Content-length', str(len(params))) else: if webproxy: h.putrequest('GET', "http://%s%s" % (host_header, url)) else: # Normal GET h.putrequest('GET', url) # Other Full Request headers if self.authinfo: h.putheader('Authorization', "Basic %s"%self.authinfo) if not webproxy: # HTTPConnection seems to add a host header itself. # So we only need to do this if we are not using a proxy. h.putheader('Host', host_header) # FL Patch ------------------------- for key, value in self.extra_headers: h.putheader(key, value) # FL Patch end --------------------- # Send cookies # - check the domain, max-age (seconds), path and secure # (http://www.ietf.org/rfc/rfc2109.txt) cookies_used = [] cookie_list = [] for domain, cookies in self.cookies.items(): # check cookie domain if not server.endswith(domain): continue for path, cookies in cookies.items(): # check that the path matches urlpath = urlparse.urlparse(url)[2] if not urlpath.startswith(path) and not (path == '/' and urlpath == ''): continue for sendcookie in cookies.values(): # and that the cookie is or isn't secure if sendcookie['secure'] and protocol != 'https': continue if sendcookie.coded_value == '"deleted"': continue # TODO: check max-age cookie_list.append("%s=%s;"%(sendcookie.key, sendcookie.coded_value)) cookies_used.append(sendcookie.key) if cookie_list: h.putheader('Cookie', ' '.join(cookie_list)) # check that we sent the cookies we expected to if self.expect_cookies is not None: assert cookies_used == self.expect_cookies, \ "Didn't use all cookies (%s expected, %s used)"%( self.expect_cookies, cookies_used) # finish the headers h.endheaders() if params is not None: h.send(params) # handle the reply if webproxy: r = h.getresponse() errcode = r.status errmsg = r.reason headers = r.msg data = r.read() response = HTTPResponse(self.cookies, protocol, server, port, url, errcode, errmsg, headers, data, self.error_content) else: # get the body and save it errcode, errmsg, headers = h.getreply() f = h.getfile() g = cStringIO.StringIO() d = f.read() while d: g.write(d) d = f.read() response = HTTPResponse(self.cookies, protocol, server, port, url, errcode, errmsg, headers, g.getvalue(), self.error_content) f.close() if errcode not in ok_codes: if VERBOSE: sys.stdout.write('e') sys.stdout.flush() raise HTTPError(response) # decode the cookies if self.accept_cookies: try: # decode the cookies and update the cookies store cookie.decodeCookies(url, server, headers, self.cookies) except: if VERBOSE: sys.stdout.write('c') sys.stdout.flush() raise # Check errors if self.error_content: data = response.body for content in self.error_content: if data.find(content) != -1: msg = "Matched error: %s" % content if hasattr(self, 'results') and self.results: self.writeError(url, msg) self.log('Matched error'+`(url, content)`, data) if VERBOSE: sys.stdout.write('c') sys.stdout.flush() raise self.failureException, msg if VERBOSE: sys.stdout.write('_') sys.stdout.flush() return response WebFetcher.fetch = WF_fetch def HR___repr__(self): """fix HTTPResponse rendering.""" return """""" % ( self.protocol, self.server, self.port, self.url, self.code, self.message) HTTPResponse.__repr__ = HR___repr__ PKLb6MHfunkload/FunkLoadTestCase.py# (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """FunkLoad test case using Richard Jones' webunit. $Id: FunkLoadTestCase.py 24757 2005-08-31 12:22:19Z bdelbosc $ """ import os import sys import time import re from warnings import warn from socket import error as SocketError from types import DictType, ListType, TupleType from datetime import datetime import unittest import traceback from random import random from urllib import urlencode from tempfile import mkdtemp from xml.sax.saxutils import quoteattr from urlparse import urljoin from ConfigParser import ConfigParser, NoSectionError, NoOptionError from webunit.webunittest import WebTestCase, HTTPError import PatchWebunit from utils import get_default_logger, mmn_is_bench, mmn_decode from utils import recording, thread_sleep, is_html, get_version, trace from xmlrpclib import ServerProxy _marker = [] # ------------------------------------------------------------ # Classes # class FunkLoadTestCase(unittest.TestCase): """Unit test with browser and configuration capabilties.""" # ------------------------------------------------------------ # Initialisation # def __init__(self, methodName='runTest', options=None): """Initialise the test case. Note that methodName is encoded in bench mode to provide additional information like thread_id, concurrent virtual users...""" if mmn_is_bench(methodName): self.in_bench_mode = True else: self.in_bench_mode = False self.test_name, self.cycle, self.cvus, self.thread_id = mmn_decode( methodName) self.meta_method_name = methodName self.suite_name = self.__class__.__name__ unittest.TestCase.__init__(self, methodName=self.test_name) self._response = None self.options = options self.debug_level = getattr(options, 'debug_level', 0) self._funkload_init() self._dump_dir = getattr(options, 'dump_dir', None) self._dumping = self._dump_dir and True or False self._viewing = getattr(options, 'firefox_view', False) self._accept_invalid_links = getattr(options, 'accept_invalid_links', False) self._simple_fetch = getattr(options, 'simple_fetch', False) self._stop_on_fail = getattr(options, 'stop_on_fail', False) if self._viewing and not self._dumping: # viewing requires dumping contents self._dumping = True self._dump_dir = mkdtemp('_funkload') self._loop_mode = getattr(options, 'loop_steps', False) if self._loop_mode: if options.loop_steps.count(':'): steps = options.loop_steps.split(':') self._loop_steps = range(int(steps[0]), int(steps[1])) else: self._loop_steps = [int(options.loop_steps)] self._loop_number = options.loop_number self._loop_recording = False self._loop_records = [] def _funkload_init(self): """Initialize a funkload test case using a configuration file.""" # look into configuration file config_directory = os.getenv('FL_CONF_PATH', '.') config_path = os.path.join(config_directory, self.__class__.__name__ + '.conf') config_path = os.path.abspath(config_path) if not os.path.exists(config_path): config_path = "Missing: "+ config_path config = ConfigParser() config.read(config_path) self._config = config self._config_path = config_path self.default_user_agent = self.conf_get('main', 'user_agent', 'FunkLoad/%s' % get_version(), quiet=True) if self.in_bench_mode: section = 'bench' else: section = 'ftest' ok_codes = self.conf_getList(section, 'ok_codes', [200, 301, 302], quiet=True) self.ok_codes = map(int, ok_codes) self.sleep_time_min = self.conf_getFloat(section, 'sleep_time_min', 0) self.sleep_time_max = self.conf_getFloat(section, 'sleep_time_max', 0) self.log_to = self.conf_get(section, 'log_to', 'console file') self.log_path = self.conf_get(section, 'log_path', 'funkload.log') self.result_path = os.path.abspath( self.conf_get(section, 'result_path', 'funkload.xml')) # init loggers self.logger = get_default_logger(self.log_to, self.log_path) self.logger_result = get_default_logger(log_to="xml", log_path=self.result_path, name="FunkLoadResult") #self.logd('_funkload_init config [%s], log_to [%s],' # ' log_path [%s], result [%s].' % ( # self._config_path, self.log_to, self.log_path, self.result_path)) # init webunit browser (passing a fake methodName) self._browser = WebTestCase(methodName='log') self.clearContext() #self.logd('# FunkLoadTestCase._funkload_init done') def clearContext(self): """Resset the testcase.""" self._browser.clearContext() self._browser.css = {} self._browser.history = [] self._browser.extra_headers = [] self.step_success = True self.test_status = 'Successful' self.steps = 0 self.page_responses = 0 self.total_responses = 0 self.total_time = 0.0 self.total_pages = self.total_images = 0 self.total_links = self.total_redirects = 0 self.total_xmlrpc = 0 self.clearBasicAuth() self.clearHeaders() self.setUserAgent(self.default_user_agent) self.logdd('FunkLoadTestCase.clearContext done') #------------------------------------------------------------ # browser simulation # def _connect(self, url, params, ok_codes, rtype, description): """Handle fetching, logging, errors and history.""" t_start = time.time() try: response = self._browser.fetch(url, params, ok_codes=ok_codes) except: etype, value, tback = sys.exc_info() t_stop = time.time() t_delta = t_stop - t_start self.total_time += t_delta self.step_success = False self.test_status = 'Failure' self.logd(' Failed in %.3fs' % t_delta) if etype is HTTPError: self._log_response(value.response, rtype, description, t_start, t_stop, log_body=True) if self._dumping: self._dump_content(value.response) raise self.failureException, str(value.response) else: self._log_response_error(url, rtype, description, t_start, t_stop) if etype is SocketError: raise SocketError("Can't load %s." % url) raise t_stop = time.time() # Log response t_delta = t_stop - t_start self.total_time += t_delta if rtype in ('post', 'get'): self.total_pages += 1 elif rtype == 'redirect': self.total_redirects += 1 elif rtype == 'link': self.total_links += 1 if rtype in ('post', 'get', 'redirect'): # this is a valid referer for the next request self.setHeader('Referer', url) self._browser.history.append((rtype, url)) self.logd(' Done in %.3fs' % t_delta) self._log_response(response, rtype, description, t_start, t_stop) if self._dumping: self._dump_content(response) return response def _browse(self, url_in, params_in=None, description=None, ok_codes=None, method='post', follow_redirect=True, load_auto_links=True, sleep=True): """Simulate a browser handle redirects, load/cache css and images.""" self._response = None # Loop mode if self._loop_mode: if self.steps == self._loop_steps[0]: self._loop_recording = True self.logi('Loop mode start recording') if self._loop_recording: self._loop_records.append((url_in, params_in, description, ok_codes, method, follow_redirect, load_auto_links, False)) # ok codes if ok_codes is None: ok_codes = self.ok_codes if type(params_in) is DictType: params_in = params_in.items() params = [] if params_in: for key, value in params_in: if type(value) is DictType: for val, selected in value.items(): if selected: params.append((key, val)) elif type(value) in (ListType, TupleType): for val in value: params.append((key, val)) else: params.append((key, value)) if method == 'get' and params: url = url_in + '?' + urlencode(params) params = None else: url = url_in if method == 'get': self.logd('GET: %s\n\tPage %i: %s ...' % (url, self.steps, description or '')) else: url = url_in self.logd('POST: %s %s\n\tPage %i: %s ...' % (url, str(params), self.steps, description or '')) # Fetching response = self._connect(url, params, ok_codes, method, description) # Check redirection if follow_redirect and response.code in (301, 302): max_redirect_count = 10 thread_sleep() # give a chance to other threads while response.code in (301, 302) and max_redirect_count: # Figure the location - which may be relative newurl = response.headers['Location'] url = urljoin(url_in, newurl) self.logd(' Load redirect link: %s' % url) response = self._connect(url, None, ok_codes, 'redirect', None) max_redirect_count -= 1 if not max_redirect_count: self.logd(' WARNING Too many redirects give up.') # Load auto links (css and images) response.is_html = is_html(response.body) if load_auto_links and response.is_html and not self._simple_fetch: self.logd(' Load css and images...') page = response.body t_start = time.time() c_start = self.total_time try: # pageImages is patched to call _log_response on all links self._browser.pageImages(url, page, self) except HTTPError, error: if self._accept_invalid_links: self.logd(' ' + str(error)) else: t_stop = time.time() t_delta = t_stop - t_start self.step_success = False self.test_status = 'Failure' self.logd(' Failed in ~ %.2fs' % t_delta) # XXX The duration logged for this response is wrong self._log_response(error.response, 'link', None, t_start, t_stop, log_body=True) raise self.failureException, str(error) c_stop = self.total_time self.logd(' Done in %.3fs' % (c_stop - c_start)) if sleep: self.sleep() self._response = response # Loop mode if self._loop_mode and self.steps == self._loop_steps[-1]: self._loop_recording = False self.logi('Loop mode end recording.') t_start = self.total_time count = 0 for i in range(self._loop_number): self.logi('Loop mode replay %i' % i) for record in self._loop_records: count += 1 self.steps += 1 self._browse(*record) t_delta = self.total_time - t_start text = ('End of loop: %d pages rendered in %.3fs, ' 'avg of %.3fs per page, ' '%.3f SPPS without concurrency.' % (count, t_delta, t_delta/count, count/t_delta)) self.logi(text) trace(text + '\n') return response def post(self, url, params=None, description=None, ok_codes=None): """POST method on url with params.""" self.steps += 1 self.page_responses = 0 response = self._browse(url, params, description, ok_codes, method="post") return response def get(self, url, params=None, description=None, ok_codes=None): """GET method on url adding params.""" self.steps += 1 self.page_responses = 0 response = self._browse(url, params, description, ok_codes, method="get") return response def exists(self, url, params=None, description="Checking existence"): """Try a GET on URL return True if the page exists or False.""" resp = self.get(url, params, description=description, ok_codes=[200, 301, 302, 404, 503]) if resp.code not in [200, 301, 302]: self.logd('Page %s not found.' % url) return False self.logd('Page %s exists.' % url) return True def xmlrpc(self, url_in, method_name, params=None, description=None): """Call an xml rpc method_name on url with params.""" self.steps += 1 self.page_responses = 0 self.logd('XMLRPC: %s::%s\n\tCall %i: %s ...' % (url_in, method_name, self.steps, description or '')) response = None t_start = time.time() if self._authinfo is not None: url = url_in.replace('//', '//'+self._authinfo) else: url = url_in try: server = ServerProxy(url) method = getattr(server, method_name) if params is not None: response = method(*params) else: response = method() except: etype, value, tback = sys.exc_info() t_stop = time.time() t_delta = t_stop - t_start self.total_time += t_delta self.step_success = False self.test_status = 'Error' self.logd(' Failed in %.3fs' % t_delta) self._log_xmlrpc_response(url_in, method_name, description, response, t_start, t_stop, -1) if etype is SocketError: raise SocketError("Can't access %s." % url) raise t_stop = time.time() t_delta = t_stop - t_start self.total_time += t_delta self.total_xmlrpc += 1 self.logd(' Done in %.3fs' % t_delta) self._log_xmlrpc_response(url_in, method_name, description, response, t_start, t_stop, 200) self.sleep() return response def xmlrpc_call(self, url_in, method_name, params=None, description=None): """BBB of xmlrpc, this method will be removed for 1.6.0.""" warn('Since 1.4.0 the method "xmlrpc_call" is renamed into "xmlrpc".', DeprecationWarning, stacklevel=2) return self.xmlrpc(url_in, method_name, params, description) def waitUntilAvailable(self, url, time_out=20, sleep_time=2): """Wait until url is available. Try a get on url every sleep_time until server is reached or time is out.""" time_start = time.time() while(True): try: self._browser.fetch(url, None, ok_codes=[200, 301, 302]) except SocketError: if time.time() - time_start > time_out: self.fail('Time out service %s not available after %ss' % (url, time_out)) else: return time.sleep(sleep_time) def setBasicAuth(self, login, password): """Set http basic authentication.""" self._browser.setBasicAuth(login, password) self._authinfo = '%s:%s@' % (login, password) def clearBasicAuth(self): """Remove basic authentication.""" self._browser.clearBasicAuth() self._authinfo = None def addHeader(self, key, value): """Add an http header.""" self._browser.extra_headers.append((key, value)) def setHeader(self, key, value): """Add or override an http header. If value is None, the key is removed.""" headers = self._browser.extra_headers for i, (k, v) in enumerate(headers): if k == key: if value is not None: headers[i] = (key, value) else: del headers[i] break else: if value is not None: headers.append((key, value)) def delHeader(self, key): """Remove an http header key.""" self.setHeader(key, None) def clearHeaders(self): """Remove all http headers set by addHeader or setUserAgent. Note that the Referer is also removed.""" self._browser.extra_headers = [] def setUserAgent(self, agent): """Set User-Agent http header for the next requests. If agent is None, the user agent header is removed.""" self.setHeader('User-Agent', agent) def sleep(self): """Sleeps a random amount of time. Between the predefined sleep_time_min and sleep_time_max values. """ s_min = self.sleep_time_min s_max = self.sleep_time_max if s_max != s_min: s_val = s_min + abs(s_max - s_min) * random() else: s_val = s_min # we should always sleep something thread_sleep(s_val) #------------------------------------------------------------ # Assertion helpers # def getLastUrl(self): """Return the last accessed url taking into account redirection.""" response = self._response if response is not None: return response.url return '' def getBody(self): """Return the last response content.""" response = self._response if response is not None: return response.body return '' def listHref(self, pattern=None): """Return a list of href anchor url present in the last html response. Filtering href using the pattern regex if present.""" response = self._response ret = [] if response is not None: a_links = response.getDOM().getByName('a') if a_links: ret = [getattr(x, 'href', '') for x in a_links] if pattern is not None: pat = re.compile(pattern) ret = [href for href in ret if pat.search(href) is not None] return ret def getLastBaseUrl(self): """Return the base href url.""" response = self._response if response is not None: base = response.getDOM().getByName('base') if base: return base[0].href return '' #------------------------------------------------------------ # configuration file utils # def conf_get(self, section, key, default=_marker, quiet=False): """Return an entry from the options or configuration file.""" # check for a command line options opt_key = '%s_%s' % (section, key) opt_val = getattr(self.options, opt_key, None) if opt_val: #print('[%s] %s = %s from options.' % (section, key, opt_val)) return opt_val # check for the configuration file if opt val is None # or nul try: val = self._config.get(section, key) except (NoSectionError, NoOptionError): if not quiet: self.logi('[%s] %s not found' % (section, key)) if default is _marker: raise val = default #print('[%s] %s = %s from config.' % (section, key, val)) return val def conf_getInt(self, section, key, default=_marker, quiet=False): """Return an integer from the configuration file.""" return int(self.conf_get(section, key, default, quiet)) def conf_getFloat(self, section, key, default=_marker, quiet=False): """Return a float from the configuration file.""" return float(self.conf_get(section, key, default, quiet)) def conf_getList(self, section, key, default=_marker, quiet=False, separator=None): """Return a list from the configuration file.""" value = self.conf_get(section, key, default, quiet) if value is default: return value if separator is None: separator = ':' if value.count(separator): return value.split(separator) return [value] #------------------------------------------------------------ # Extend unittest.TestCase to provide bench cycle hook # def setUpCycle(self): """Called on bench mode before a cycle start.""" pass def tearDownCycle(self): """Called after a cycle in bench mode.""" pass #------------------------------------------------------------ # logging # def logd(self, message): """Debug log.""" self.logger.debug(self.meta_method_name +': ' +message) def logdd(self, message): """Verbose Debug log.""" if self.debug_level >= 2: self.logger.debug(self.meta_method_name +': ' +message) def logi(self, message): """Info log.""" if hasattr(self, 'logger'): self.logger.info(self.meta_method_name+': '+message) else: print self.meta_method_name+': '+message def _logr(self, message, force=False): """Log a result.""" if force or not self.in_bench_mode or recording(): self.logger_result.info(message) def _open_result_log(self, **kw): """Open the result log.""" xml = ['' % ( get_version(), datetime.now().isoformat())] for key, value in kw.items(): xml.append('' % ( key, quoteattr(str(value)))) self._logr('\n'.join(xml), force=True) def _close_result_log(self): """Close the result log.""" self._logr('', force=True) def _log_response_error(self, url, rtype, description, time_start, time_stop): """Log a response that raise an unexpected exception.""" self.total_responses += 1 self.page_responses += 1 info = {} info['cycle'] = self.cycle info['cvus'] = self.cvus info['thread_id'] = self.thread_id info['suite_name'] = self.suite_name info['test_name'] = self.test_name info['step'] = self.steps info['number'] = self.page_responses info['type'] = rtype info['url'] = quoteattr(url) info['code'] = -1 info['description'] = description and quoteattr(description) or '""' info['time_start'] = time_start info['duration'] = time_stop - time_start info['result'] = 'Error' info['traceback'] = quoteattr(' '.join( traceback.format_exception(*sys.exc_info()))) message = '''''' % info self._logr(message) def _log_response(self, response, rtype, description, time_start, time_stop, log_body=False): """Log a response.""" self.total_responses += 1 self.page_responses += 1 info = {} info['cycle'] = self.cycle info['cvus'] = self.cvus info['thread_id'] = self.thread_id info['suite_name'] = self.suite_name info['test_name'] = self.test_name info['step'] = self.steps info['number'] = self.page_responses info['type'] = rtype info['url'] = quoteattr(response.url) info['code'] = response.code info['description'] = description and quoteattr(description) or '""' info['time_start'] = time_start info['duration'] = time_stop - time_start info['result'] = self.step_success and 'Successful' or 'Failure' response_start = '''' else: response_start = response_start + '>\n ' header_xml = [] for key, value in response.headers.items(): header_xml.append('
' % ( key, quoteattr(value))) headers = '\n'.join(header_xml) + '\n ' message = '\n'.join([ response_start, headers, ' \n ' % response.body, '']) self._logr(message) def _log_xmlrpc_response(self, url, method, description, response, time_start, time_stop, code): """Log a response.""" self.total_responses += 1 self.page_responses += 1 info = {} info['cycle'] = self.cycle info['cvus'] = self.cvus info['thread_id'] = self.thread_id info['suite_name'] = self.suite_name info['test_name'] = self.test_name info['step'] = self.steps info['number'] = self.page_responses info['type'] = 'xmlrpc' info['url'] = quoteattr(url + '#' + method) info['code'] = code info['description'] = description and quoteattr(description) or '""' info['time_start'] = time_start info['duration'] = time_stop - time_start info['result'] = self.step_success and 'Successful' or 'Failure' message = '''"''' % info self._logr(message) def _log_result(self, time_start, time_stop): """Log the test result.""" info = {} info['cycle'] = self.cycle info['cvus'] = self.cvus info['thread_id'] = self.thread_id info['suite_name'] = self.suite_name info['test_name'] = self.test_name info['steps'] = self.steps info['time_start'] = time_start info['duration'] = time_stop - time_start info['connection_duration'] = self.total_time info['requests'] = self.total_responses info['pages'] = self.total_pages info['xmlrpc'] = self.total_xmlrpc info['redirects'] = self.total_redirects info['images'] = self.total_images info['links'] = self.total_links info['result'] = self.test_status if self.test_status != 'Successful': info['traceback'] = 'traceback=' + quoteattr(' '.join( traceback.format_exception(*sys.exc_info()))) + ' ' else: info['traceback'] = '' text = '''''' % info self._logr(text) def _dump_content(self, response): """Dump the html content in a file. Use firefox to render the content if we are in rt viewing mode.""" dump_dir = self._dump_dir if dump_dir is None: return if getattr(response, 'code', 301) in [301, 302]: return if not response.body: return if not os.access(dump_dir, os.W_OK): os.mkdir(dump_dir, 0775) content_type = response.headers.get('content-type') if content_type == 'text/xml': ext = '.xml' else: ext = os.path.splitext(response.url)[1] if not ext.startswith('.') or len(ext) > 4: ext = '.html' file_path = os.path.abspath( os.path.join(dump_dir, '%3.3i%s' % (self.steps, ext))) f = open(file_path, 'w') f.write(response.body) f.close() if self._viewing: cmd = 'firefox -remote "openfile(file://%s,new-tab)"' % file_path ret = os.system(cmd) if ret != 0: self.logi('Failed to remote control firefox: %s' % cmd) self._viewing = False #------------------------------------------------------------ # Overriding unittest.TestCase # def __call__(self, result=None): """Run the test method. Override to log test result.""" t_start = time.time() if result is None: result = self.defaultTestResult() result.startTest(self) if sys.version_info >= (2, 5): testMethod = getattr(self, self._testMethodName) else: testMethod = getattr(self, self._TestCase__testMethodName) try: ok = False try: self.logd('Starting -----------------------------------\n\t%s' % self.conf_get(self.meta_method_name, 'description', '')) self.setUp() except KeyboardInterrupt: raise except: result.addError(self, self._TestCase__exc_info()) self.test_status = 'Error' self._log_result(t_start, time.time()) return try: testMethod() ok = True except self.failureException: if sys.version_info >= (2, 5): result.addFailure(self, self._exc_info()) else: result.addFailure(self, self._TestCase__exc_info()) self.test_status = 'Failure' except KeyboardInterrupt: raise except: if sys.version_info >= (2, 5): result.addFailure(self, self._exc_info()) else: result.addError(self, self._TestCase__exc_info()) self.test_status = 'Error' try: self.tearDown() except KeyboardInterrupt: raise except: if sys.version_info >= (2, 5): result.addFailure(self, self._exc_info()) else: result.addError(self, self._TestCase__exc_info()) self.test_status = 'Error' ok = False if ok: result.addSuccess(self) finally: self._log_result(t_start, time.time()) if not ok and self._stop_on_fail: result.stop() result.stopTest(self) # ------------------------------------------------------------ # testing # class DummyTestCase(FunkLoadTestCase): """Testing Funkload TestCase.""" def test_apache(self): """Simple apache test.""" self.logd('start apache test') for i in range(2): self.get('http://localhost/') self.logd('base_url: ' + self.getLastBaseUrl()) self.logd('url: ' + self.getLastUrl()) self.logd('hrefs: ' + str(self.listHref())) self.logd("Total connection time = %s" % self.total_time) if __name__ == '__main__': unittest.main() PKT;4* X**funkload/__init__.py# (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # # """Funkload package init. $Id: __init__.py 24649 2005-08-29 14:20:19Z bdelbosc $ """ PKT;4QL1'1'funkload/XmlRpcBase.py# (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """Base class to build XML RPC daemon server. $Id: XmlRpcBase.py 30282 2005-12-05 12:52:30Z bdelbosc $ """ import sys, os from socket import error as SocketError from time import sleep from ConfigParser import ConfigParser, NoOptionError from SimpleXMLRPCServer import SimpleXMLRPCServer from xmlrpclib import ServerProxy import logging from optparse import OptionParser, TitledHelpFormatter from utils import create_daemon, get_default_logger, close_logger from utils import trace, get_version def is_server_running(host, port): """Check if the XML/RPC server is running checking getStatus RPC.""" server = ServerProxy("http://%s:%s" % (host, port)) try: server.getStatus() except SocketError: return False return True # ------------------------------------------------------------ # rpc to manage the server # class MySimpleXMLRPCServer(SimpleXMLRPCServer): """SimpleXMLRPCServer with allow_reuse_address.""" # this property set SO_REUSEADDR which tells the operating system to allow # code to connect to a socket even if it's waiting for other potential # packets allow_reuse_address = True # ------------------------------------------------------------ # Server # class XmlRpcBaseServer: """The base class for xml rpc server.""" usage = """%prog [options] config_file Start %prog XML/RPC daemon. """ server_name = None # list RPC Methods method_names = ['stopServer', 'getStatus'] def __init__(self, argv=None): if self.server_name is None: self.server_name = self.__class__.__name__ if argv is None: argv = sys.argv conf_path, options = self.parseArgs(argv) self.default_log_path = self.server_name + '.log' self.default_pid_path = self.server_name + '.pid' self.server = None self.quit = False # read conf conf = ConfigParser() conf.read(conf_path) self.conf_path = conf_path self.host = conf.get('server', 'host') self.port = conf.getint('server', 'port') try: self.pid_path = conf.get('server', 'pid_path') except NoOptionError: self.pid_path = self.default_pid_path try: log_path = conf.get('server', 'log_path') except NoOptionError: log_path = self.default_log_path if is_server_running(self.host, self.port): trace("Server already running on %s:%s." % (self.host, self.port)) sys.exit(0) trace('Starting %s server at http://%s:%s/' % (self.server_name, self.host, self.port)) # init logger if options.verbose: level = logging.DEBUG else: level = logging.INFO if options.debug: log_to = 'file console' else: log_to = 'file' self.logger = get_default_logger(log_to, log_path, level=level, name=self.server_name) # subclass init self._init_cb(conf, options) # daemon mode if not options.debug: trace(' as daemon.\n') close_logger(self.server_name) create_daemon() # re init the logger self.logger = get_default_logger(log_to, log_path, level=level, name=self.server_name) else: trace(' in debug mode.\n') # init rpc self.initServer() def _init_cb(self, conf, options): """init procedure intend to be implemented by subclasses. This method is called before to switch in daemon mode. conf is a ConfigParser object.""" pass def logd(self, message): """Debug log.""" self.logger.debug(message) def log(self, message): """Log information.""" self.logger.info(message) def parseArgs(self, argv): """Parse programs args.""" parser = OptionParser(self.usage, formatter=TitledHelpFormatter(), version="FunkLoad %s" % get_version()) parser.add_option("-v", "--verbose", action="store_true", help="Verbose output") parser.add_option("-d", "--debug", action="store_true", help="debug mode, server is run in forground") options, args = parser.parse_args(argv) if len(args) != 2: parser.error("Missing configuration file argument") return args[1], options def initServer(self): """init the XMLR/PC Server.""" self.log("Init XML/RPC server %s:%s." % (self.host, self.port)) server = MySimpleXMLRPCServer((self.host, self.port)) for method_name in self.method_names: self.logd('register %s' % method_name) server.register_function(getattr(self, method_name)) self.server = server def run(self): """main server loop.""" server = self.server pid = os.getpid() open(self.pid_path, "w").write(str(pid)) self.log("XML/RPC server pid=%i running." % pid) while not self.quit: server.handle_request() sleep(.5) server.server_close() self.log("XML/RPC server pid=%i stopped." % pid) os.remove(self.pid_path) __call__ = run # RPC # def stopServer(self): """Stop the server.""" self.log("stopServer request.") self.quit = True return 1 def getStatus(self): """Return a status.""" self.logd("getStatus request.") return "%s running pid = %s" % (self.server_name, os.getpid()) # ------------------------------------------------------------ # Controller # class XmlRpcBaseController: """An XML/RPC controller.""" usage = """%prog config_file action action can be: start|startd|stop|restart|status|test Execute action on the XML/RPC server. """ # the server class server_class = XmlRpcBaseServer def __init__(self, argv=None): if argv is None: argv = sys.argv conf_path, self.action, options = self.parseArgs(argv) # read conf conf = ConfigParser() conf.read(conf_path) self.host = conf.get('server', 'host') self.conf_path = conf_path self.port = conf.getint('server', 'port') self.url = 'http://%s:%s/' % (self.host, self.port) self.verbose = not options.quiet self.server = ServerProxy(self.url) def parseArgs(self, argv): """Parse programs args.""" parser = OptionParser(self.usage, formatter=TitledHelpFormatter(), version="FunkLoad %s" % get_version()) parser.add_option("-q", "--quiet", action="store_true", help="Verbose output") options, args = parser.parse_args(argv) if len(args) != 3: parser.error("Missing argument") return args[1], args[2], options def log(self, message, force=False): """Log a message.""" if force or self.verbose: trace(str(message)) def startServer(self, debug=False): """Start an XML/RPC server.""" argv = ['cmd', self.conf_path] if debug: argv.append('-dv') daemon = self.server_class(argv) daemon.run() def __call__(self, action=None): """Call the xml rpc action""" server = self.server if action is None: action = self.action is_running = is_server_running(self.host, self.port) if action == 'status': if is_running: ret = server.getStatus() self.log('%s %s.\n' % (self.url, ret)) else: self.log('No server reachable at %s.\n' % self.url) return 0 elif action in ('stop', 'restart'): if is_running: ret = server.stopServer() self.log('Server %s is stopped.\n' % self.url) is_running = False elif action == 'stop': self.log('No server reachable at %s.\n' % self.url) if action == 'restart': self('start') elif 'start' in action: if is_running: self.log('Server %s is already running.\n' % self.url) else: return self.startServer(action=='startd') elif not is_running: self.log('No server reachable at %s.\n' % self.url) return -1 elif action == 'reload': ret = server.reloadConf() self.log('done\n') elif action == 'test': return self.test() else: raise NotImplementedError('Unknow action %s' % action) return 0 # this method is done to be overriden in sub classes def test(self): """Testing the XML/RPC. Must return an exit code, 0 for success. """ ret = self.server.getStatus() self.log('Testing getStatus: %s\n' % ret) return 0 def main(): """Main""" ctl = XmlRpcBaseController() ret = ctl() sys.exit(ret) if __name__ == '__main__': main() PKH\b4@U!U!funkload/utils.py# (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """FunkLoad common utils. $Id: utils.py 24649 2005-08-29 14:20:19Z bdelbosc $ """ import os import sys import time import logging from time import sleep from socket import error as SocketError from xmlrpclib import ServerProxy MIN_SLEEPTIME = 0.005 # minimum sleep time to let # python threads working properly def thread_sleep(seconds=0): """Sleep seconds. Insure that seconds is at least MIN_SLEEPTIME to let threads working properly.""" #if seconds: # trace('sleep %s' % seconds) sleep(max(abs(seconds), MIN_SLEEPTIME)) # ------------------------------------------------------------ # semaphores # g_recording = False g_running = False def recording(): """A semaphore to tell the running threads when to begin recording.""" global g_recording return g_recording def set_recording_flag(value): """Enable recording.""" global g_recording g_recording = value def running(): """A semaphore to tell the running threads that it should continue running ftest.""" global g_running return g_running def set_running_flag(value): """Set running mode on.""" global g_running g_running = value # ------------------------------------------------------------ # daemon # # See the Chad J. Schroeder example for a full explanation # this version does not chdir to '/' to keep relative path def create_daemon(): """Detach a process from the controlling terminal and run it in the background as a daemon. """ try: pid = os.fork() except OSError, msg: raise Exception, "%s [%d]" % (msg.strerror, msg.errno) if (pid == 0): os.setsid() try: pid = os.fork() except OSError, msg: raise Exception, "%s [%d]" % (msg.strerror, msg.errno) if (pid == 0): os.umask(0) else: os._exit(0) else: sleep(.5) os._exit(0) import resource maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1] if (maxfd == resource.RLIM_INFINITY): maxfd = 1024 for fd in range(0, maxfd): try: os.close(fd) except OSError: pass os.open('/dev/null', os.O_RDWR) os.dup2(0, 1) os.dup2(0, 2) return(0) # ------------------------------------------------------------ # meta method name encodage # MMN_SEP = ':' # meta method name separator def mmn_is_bench(meta_method_name): """Is it a meta method name ?.""" return meta_method_name.count(MMN_SEP) and True or False def mmn_encode(method_name, cycle, cvus, thread_id): """Encode a extra information into a method_name.""" return MMN_SEP.join((method_name, str(cycle), str(cvus), str(thread_id))) def mmn_decode(meta_method_name): """Decode a meta method name.""" if mmn_is_bench(meta_method_name): method_name, cycle, cvus, thread_id = meta_method_name.split(MMN_SEP) return (method_name, int(cycle), int(cvus), int(thread_id)) else: return (meta_method_name, 1, 0, 1) # ------------------------------------------------------------ # logging # def get_default_logger(log_to, log_path=None, level=logging.DEBUG, name='FunkLoad'): """Get a logger.""" logger = logging.getLogger(name) if logger.handlers: # already setup return logger if log_to.count("console"): hdlr = logging.StreamHandler() logger.addHandler(hdlr) if log_to.count("file") and log_path: formatter = logging.Formatter( '%(asctime)s %(levelname)s %(message)s') hdlr = logging.FileHandler(log_path) hdlr.setFormatter(formatter) logger.addHandler(hdlr) if log_to.count("xml") and log_path: if os.access(log_path, os.F_OK): os.rename(log_path, log_path + '.bak-' + str(int(time.time()))) hdlr = logging.FileHandler(log_path) logger.addHandler(hdlr) logger.setLevel(level) return logger def close_logger(name): """Close the logger.""" logger = logging.getLogger(name) for hdlr in logger.handlers: logger.removeHandler(hdlr) def trace(message): """Simple print to stdout Not thread safe.""" sys.stdout.write(message) sys.stdout.flush() # ------------------------------------------------------------ # xmlrpc # def xmlrpc_get_credential(host, port, group=None): """Get credential thru xmlrpc credential_server.""" url = "http://%s:%s" % (host, port) server = ServerProxy(url) try: return server.getCredential(group) except SocketError: raise SocketError( 'No Credential server reachable at %s, use fl-credential-ctl ' 'to start the credential server.' % url) def xmlrpc_list_groups(host, port): """Get list of groups thru xmlrpc credential_server.""" url = "http://%s:%s" % (host, port) server = ServerProxy(url) try: return server.listGroups() except SocketError: raise SocketError( 'No Credential server reachable at %s, use fl-credential-ctl ' 'to start the credential server.' % url) def xmlrpc_list_credentials(host, port, group=None): """Get list of users thru xmlrpc credential_server.""" url = "http://%s:%s" % (host, port) server = ServerProxy(url) try: return server.listCredentials(group) except SocketError: raise SocketError( 'No Credential server reachable at %s, use fl-credential-ctl ' 'to start the credential server.' % url) # ------------------------------------------------------------ # misc # def get_version(): """Retrun the FunkLoad package version.""" from pkg_resources import get_distribution return get_distribution('funkload').version _COLOR = {'green': "\x1b[32;01m", 'red': "\x1b[31;01m", 'reset': "\x1b[0m" } def red_str(text): """Return red text.""" global _COLOR return _COLOR['red'] + text + _COLOR['reset'] def green_str(text): """Return green text.""" global _COLOR return _COLOR['green'] + text + _COLOR['reset'] def is_html(text): """Simple check that return True if the text is an html page.""" if ' self.length: mid_size = (self.length - 3) / 2 other = other[:mid_size] + self.extra + other[-mid_size:] return other def is_valid_html(html=None, file_path=None, accept_warning=False): """Ask tidy if the html is valid. Return a tuple (status, errors) """ if not file_path: fd, file_path = mkstemp(prefix='fl-tidy', suffix='.html') os.write(fd, html) os.close(fd) tidy_cmd = 'tidy -errors %s' % file_path ret, output = getstatusoutput(tidy_cmd) status = False if ret == 0: status = True elif ret == 256: # got warnings if accept_warning: status = True elif ret > 512: if 'command not found' in output: raise RuntimeError('tidy command not found, please install tidy.') raise RuntimeError('Executing [%s] return: %s ouput: %s' % (tidy_cmd, ret, output)) return status, output PK$M[6BLo>>funkload/ReportRenderer.py# (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """Classes that render statistics. $Id: ReportRenderer.py 24736 2005-08-31 08:59:54Z bdelbosc $ """ import os try: import gdchart g_has_gdchart = 1 except ImportError: g_has_gdchart = 0 from shutil import copyfile # ------------------------------------------------------------ # ReST rendering # def rst_title(title, level=1): """Return a rst title.""" rst_level = ['=', '=', '-', '~'] if level == 0: rst = [rst_level[level] * len(title)] else: rst = [''] rst.append(title) rst.append(rst_level[level] * len(title)) rst.append('') return '\n'.join(rst) class BaseRst: """Base class for ReST renderer.""" fmt_int = "%7d" fmt_float = "%7.3f" fmt_percent = "%6.2f%%" fmt_deco = "=======" headers = [] indent = 0 image_names = [] with_percentiles = False def __init__(self, stats): self.stats = stats def __repr__(self): """Render stats.""" ret = [''] ret.append(self.render_header()) ret.append(self.render_stat()) ret.append(self.render_footer()) return '\n'.join(ret) def render_images(self): """Render images link.""" indent = ' ' * self.indent rst = [] for image_name in self.image_names: rst.append(indent + " .. image:: %s.png" % image_name) rst.append('') return '\n'.join(rst) def render_header(self, with_chart=False): """Render rst header.""" headers = self.headers[:] if self.with_percentiles: self._attach_percentiles_header(headers) deco = ' ' + " ".join([self.fmt_deco] * len(headers)) header = " " + " ".join([ "%7s" % h for h in headers ]) indent = ' ' * self.indent ret = [] if with_chart: ret.append(self.render_images()) ret.append(indent + deco) ret.append(indent + header) ret.append(indent + deco) return '\n'.join(ret) def _attach_percentiles_header(self, headers): """ Attach percentile headers. """ headers.extend( ["P10", "MED", "P90", "P95"]) def _attach_percentiles(self, ret): """ Attach percentiles, if this is wanted. """ percentiles = self.stats.percentiles fmt = self.fmt_float ret.extend([ fmt % percentiles.perc10, fmt % percentiles.perc50, fmt % percentiles.perc90, fmt % percentiles.perc95 ]) def render_footer(self): """Render rst footer.""" headers = self.headers[:] if self.with_percentiles: self._attach_percentiles_header(headers) deco = " ".join([self.fmt_deco] * len(headers)) return ' ' * (self.indent + 1) + deco def render_stat(self): """Render rst stat.""" raise NotImplemented class AllResponseRst(BaseRst): """AllResponseStat rendering.""" headers = [ "CUs", "RPS", "maxRPS", "TOTAL", "SUCCESS","ERROR", "MIN", "AVG", "MAX" ] image_names = ['requests_rps', 'requests'] def render_stat(self): """Render rst stat.""" ret = [' ' * self.indent] stats = self.stats stats.finalize() ret.append(self.fmt_int % stats.cvus) ret.append(self.fmt_float % stats.rps) ret.append(self.fmt_float % stats.rps_max) ret.append(self.fmt_int % stats.count) ret.append(self.fmt_int % stats.success) ret.append(self.fmt_percent % stats.error_percent) ret.append(self.fmt_float % stats.min) ret.append(self.fmt_float % stats.avg) ret.append(self.fmt_float % stats.max) if self.with_percentiles: self._attach_percentiles(ret) ret = ' '.join(ret) return ret class PageRst(AllResponseRst): """Page rendering.""" headers = ["CUs", "SPPS", "maxSPPS", "TOTAL", "SUCCESS", "ERROR", "MIN", "AVG", "MAX"] image_names = ['pages_spps', 'pages'] class ResponseRst(BaseRst): """Response rendering.""" headers = ["CUs", "TOTAL", "SUCCESS", "ERROR", "MIN", "AVG", "MAX"] indent = 4 image_names = ['request_'] def __init__(self, stats): BaseRst.__init__(self, stats) # XXX quick fix for #1017 self.image_names = [name + str(stats.step) + '.' + str(stats.number) for name in self.image_names] def render_stat(self): """Render rst stat.""" stats = self.stats stats.finalize() ret = [' ' * self.indent] ret.append(self.fmt_int % stats.cvus) ret.append(self.fmt_int % stats.count) ret.append(self.fmt_int % stats.success) ret.append(self.fmt_percent % stats.error_percent) ret.append(self.fmt_float % stats.min) ret.append(self.fmt_float % stats.avg) ret.append(self.fmt_float % stats.max) if self.with_percentiles: self._attach_percentiles(ret) ret = ' '.join(ret) return ret class TestRst(BaseRst): """Test Rendering.""" headers = ["CUs", "STPS", "TOTAL", "SUCCESS", "ERROR"] image_names = ['tests'] with_percentiles = False def render_stat(self): """Render rst stat.""" stats = self.stats stats.finalize() ret = [' ' * self.indent] ret.append(self.fmt_int % stats.cvus) ret.append(self.fmt_float % stats.tps) ret.append(self.fmt_int % stats.count) ret.append(self.fmt_int % stats.success) ret.append(self.fmt_percent % stats.error_percent) ret = ' '.join(ret) return ret class RenderRst: """Render stats in ReST format.""" # number of slowest requests to display slowest_items = 5 def __init__(self, config, stats, error, monitor, options): self.config = config self.stats = stats self.error = error self.monitor = monitor self.options = options self.rst = [] cycles = stats.keys() cycles.sort() self.cycles = cycles if options.with_percentiles: BaseRst.with_percentiles = True if options.html: self.with_chart = True else: self.with_chart = False def getRepresentativeCycleStat(self): """Return the cycle stat with the maximum number of steps.""" stats = self.stats max_steps = 0 cycle_r = None for cycle in self.cycles: steps = stats[cycle]['response_step'].keys() if cycle_r is None: cycle_r = stats[cycle] if len(steps) > max_steps: max_steps = steps cycle_r = stats[cycle] return cycle_r def getBestStpsCycle(self): """Return the cycle with the maximum STPS.""" stats = self.stats max_stps = -1 cycle_r = None for cycle in self.cycles: if not stats[cycle].has_key('test'): continue stps = stats[cycle]['test'].tps if stps > max_stps: max_stps = stps cycle_r = cycle if cycle_r is None and len(self.cycles): # no test ends during a cycle return the first one cycle_r = self.cycles[0] return cycle_r def append(self, text): """Append text to rst output.""" self.rst.append(text) def renderConfig(self): """Render bench configuration.""" config = self.config self.append(rst_title("FunkLoad_ bench report", 0)) self.append('') date = config['time'][:19].replace('T', ' ') self.append(':date: ' + date) description = [config['class_description']] description += ["Bench result of ``%s.%s``: " % (config['class'], config['method'])] description += [config['description']] indent = "\n " self.append(':abstract: ' + indent.join(description)) self.append('') self.append(".. _FunkLoad: http://funkload.nuxeo.org/") self.append(".. sectnum:: :depth: 2") self.append(".. contents:: Table of contents") self.append(rst_title("Bench configuration", 2)) self.append("* Launched: %s" % date) self.append("* Test: ``%s.py %s.%s``" % (config['module'], config['class'], config['method'])) self.append("* Server: %s" % config['server_url']) self.append("* Cycles of concurrent users: %s" % config['cycles']) self.append("* Cycle duration: %ss" % config['duration']) self.append("* Sleeptime between request: from %ss to %ss" % ( config['sleep_time_min'], config['sleep_time_max'])) self.append("* Sleeptime between test case: %ss" % config['sleep_time']) self.append("* Startup delay between thread: %ss" % config['startup_delay']) self.append("* FunkLoad_ version: %s" % config['version']) self.append("") def renderTestContent(self, test): """Render global information about test content.""" self.append(rst_title("Bench content", 2)) config = self.config self.append('The test ``%s.%s`` contains: ' % (config['class'], config['method'])) self.append('') self.append("* %s page(s)" % test.pages) self.append("* %s redirect(s)" % test.redirects) self.append("* %s link(s)" % test.links) self.append("* %s image(s)" % test.images) self.append("* %s XML RPC call(s)" % test.xmlrpc) self.append('') self.append('The bench contains:') total_tests = 0 total_tests_error = 0 total_pages = 0 total_pages_error = 0 total_responses = 0 total_responses_error = 0 stats = self.stats for cycle in self.cycles: if stats[cycle].has_key('test'): total_tests += stats[cycle]['test'].count total_tests_error += stats[cycle]['test'].error if stats[cycle].has_key('page'): stat = stats[cycle]['page'] stat.finalize() total_pages += stat.count total_pages_error += stat.error if stats[cycle].has_key('response'): total_responses += stats[cycle]['response'].count total_responses_error += stats[cycle]['response'].error self.append('') self.append("* %s tests" % total_tests + ( total_tests_error and ", %s error(s)" % total_tests_error or '')) self.append("* %s pages" % total_pages + ( total_pages_error and ", %s error(s)" % total_pages_error or '')) self.append("* %s requests" % total_responses + ( total_responses_error and ", %s error(s)" % total_responses_error or '')) self.append('') def renderCyclesStat(self, key, title, description=''): """Render a type of stats for all cycles.""" stats = self.stats first = True if key == 'test': klass = TestRst elif key == 'page': klass = PageRst elif key == 'response': klass = AllResponseRst self.append(rst_title(title, 2)) if description: self.append(description) self.append('') renderer = None for cycle in self.cycles: if not stats[cycle].has_key(key): continue renderer = klass(stats[cycle][key]) if first: self.append(renderer.render_header(self.with_chart)) first = False self.append(renderer.render_stat()) if renderer is not None: self.append(renderer.render_footer()) else: self.append('Sorry no %s have finished during a cycle, ' 'the cycle duration is too short.\n' % key) def renderCyclesStepStat(self, step): """Render a step stats for all cycle.""" stats = self.stats first = True renderer = None for cycle in self.cycles: stat = stats[cycle]['response_step'].get(step) if stat is None: continue renderer = ResponseRst(stat) if first: self.append(renderer.render_header(self.with_chart)) first = False self.append(renderer.render_stat()) if renderer is not None: self.append(renderer.render_footer()) def renderPageDetail(self, cycle_r): """Render a page detail.""" self.append(rst_title("Page detail stats", 2)) cycle_r_steps = cycle_r['response_step'] steps = cycle_r['response_step'].keys() steps.sort() self.steps = steps current_step = -1 for step_name in steps: a_step = cycle_r_steps[step_name] if a_step.step != current_step: current_step = a_step.step self.append(rst_title("PAGE %s: %s" % ( a_step.step, a_step.description or a_step.url), 3)) self.append('* Req: %s, %s, url %s' % (a_step.number, a_step.type, a_step.url)) self.append('') self.renderCyclesStepStat(step_name) def renderMonitors(self): """Render all monitored hosts.""" if not self.monitor or not self.with_chart: return self.append(rst_title("Monitored hosts", 2)) for host in self.monitor.keys(): self.renderMonitor(host) def renderMonitor(self, host): """Render a monitored host.""" description = self.config.get(host, '') self.append(rst_title("%s: %s" % (host, description), 3)) self.append("**Load average**\n\n.. image:: %s_load.png\n" % host) self.append("**Memory usage**\n\n.. image:: %s_mem.png\n" % host) self.append("**Network traffic**\n\n.. image:: %s_net.png\n" % host) def renderSlowestRequests(self, number): """Render the n slowest requests of the best cycle.""" stats = self.stats self.append(rst_title("%i Slowest requests"% number, 2)) cycle = self.getBestStpsCycle() cycle_name = None if not (cycle and stats[cycle].has_key('response_step')): return steps = stats[cycle]['response_step'].keys() items = [] for step_name in steps: stat = stats[cycle]['response_step'][step_name] stat.finalize() items.append((stat.avg, stat.step, stat.type, stat.url, stat.description)) if not cycle_name: cycle_name = stat.cvus items.sort() items.reverse() self.append('Slowest average response time during the best cycle ' 'with **%s** CUs:\n' % cycle_name) for item in items[:number]: self.append('* In page %s %s: %s took **%.3fs**\n' ' `%s`' % ( item[1], item[2], item[3], item[0], item[4])) def renderErrors(self): """Render error list.""" if not len(self.error): return self.append(rst_title("Failures and Errors", 2)) for status in ('Failure', 'Error'): if not self.error.has_key(status): continue stats = self.error[status] errors = {} for stat in stats: header = stat.header key = (stat.code, header.get('bobo-exception-file'), header.get('bobo-exception-line'), ) err_list = errors.setdefault(key, []) err_list.append(stat) err_types = errors.keys() err_types.sort() self.append(rst_title(status + 's', 3)) for err_type in err_types: stat = errors[err_type][0] if err_type[1]: self.append('* %s time(s), code: %s, %s\n' ' in %s, line %s: %s' %( len(errors[err_type]), err_type[0], header.get('bobo-exception-type'), err_type[1], err_type[2], header.get('bobo-exception-value'))) else: traceback = stat.traceback and stat.traceback.replace( 'File ', '\n File ') or 'No traceback.' self.append('* %s time(s), code: %s::\n\n' ' %s\n' %( len(errors[err_type]), err_type[0], traceback)) def __repr__(self): self.renderConfig() if not self.cycles: self.append('No cycle found') return '\n'.join(self.rst) cycle_r = self.getRepresentativeCycleStat() if cycle_r.has_key('test'): self.renderTestContent(cycle_r['test']) self.renderCyclesStat('test', 'Test stats', 'The number of Successful **Test** Per Second ' '(STPS) over Concurrent Users (CUs).') self.renderCyclesStat('page', 'Page stats', 'The number of Successful **Page** Per Second ' '(SPPS) over Concurrent Users (CUs).\n' 'Note that an XML RPC call count like a page.') self.renderCyclesStat('response', 'Request stats', 'The number of **Request** Per Second (RPS) ' 'successful or not over Concurrent Users (CUs).') self.renderSlowestRequests(self.slowest_items) self.renderMonitors() self.renderPageDetail(cycle_r) self.renderErrors() return '\n'.join(self.rst) # ------------------------------------------------------------ # HTML rendering # class RenderHtml(RenderRst): """Render stats in html. Simply render stuff in ReST than ask docutils to build an html doc. """ chart_size = (350, 250) big_chart_size = (640, 320) color_success = 0x00ff00 color_error = 0xff0000 color_time = 0x0000ff color_time_min_max = 0xccccee color_grid = 0xcccccc color_line = 0x333333 color_plot = 0x003a6b color_bg = 0xffffff color_line = 0x000000 def __init__(self, config, stats, error, monitor, options, css_file=None): RenderRst.__init__(self, config, stats, error, monitor, options) self.css_file = css_file self.report_dir = self.css_path = self.rst_path = self.html_path = None def prepareReportDirectory(self): """Create a folder to save the report.""" # init output dir output_dir = os.path.abspath(self.options.output_dir) if not os.access(output_dir, os.W_OK): os.mkdir(output_dir, 0775) # init report dir config = self.config stamp = config['time'][:19].replace(':', '-') report_dir = os.path.join(output_dir, '%s-%s' % (config['id'], stamp)) if not os.access(report_dir, os.W_OK): os.mkdir(report_dir, 0775) self.report_dir = report_dir def createRstFile(self): """Create the ReST file.""" rst_path = os.path.join(self.report_dir, 'index.rst') f = open(rst_path, 'w') f.write(str(self)) f.close() self.rst_path = rst_path def copyCss(self): """Copy the css to the report dir.""" css_file = self.css_file if css_file is not None: copyfile(css_file, css_dest_path) css_dest_path = os.path.join(self.report_dir, css_file) else: # use the one in our package_data from pkg_resources import resource_string css_content = resource_string('funkload', 'data/funkload.css') css_dest_path = os.path.join(self.report_dir, 'funkload.css') f = open(css_dest_path, 'w') f.write(css_content) f.close() self.css_path = css_dest_path def copyXmlResult(self): """Make a copy of the xml result.""" xml_src_path = self.options.xml_file xml_dest_path = os.path.join(self.report_dir, 'funkload.xml') copyfile(xml_src_path, xml_dest_path) def generateHtml(self): """Ask docutils to convert our rst file into html.""" from docutils.core import publish_cmdline html_path = os.path.join(self.report_dir, 'index.html') cmdline = "-t --stylesheet-path=%s %s %s" % (self.css_path, self.rst_path, html_path) cmd_argv = cmdline.split(' ') publish_cmdline(writer_name='html', argv=cmd_argv) self.html_path = html_path def render(self): """Create the html report.""" self.prepareReportDirectory() self.createRstFile() self.copyCss() try: self.generateHtml() pass except ImportError: print "WARNING docultils not found, no html output." return '' self.createCharts() self.copyXmlResult() return self.html_path __call__ = render # Charts ------------------------------------------------------------ # XXX need some factoring below def getChartSize(self, cvus): """Compute the right size lenght depending on the number of cvus.""" size = list(self.chart_size) len_cvus = len(cvus) if len_cvus > 7: size = list(self.big_chart_size) size[0] = min(800, 50 * len(cvus)) return tuple(size) def createCharts(self): """Create all charts.""" global g_has_gdchart if not g_has_gdchart: return self.createMonitorCharts() self.createTestChart() self.createPageChart() self.createAllResponseChart() for step_name in self.steps: self.createResponseChart(step_name) def createTestChart(self): """Create the test chart.""" image_path = str(os.path.join(self.report_dir, 'tests.png')) stats = self.stats errors = [] stps = [] cvus = [] has_error = False for cycle in self.cycles: if not stats[cycle].has_key('test'): continue test = stats[cycle]['test'] stps.append(test.tps) error = test.error_percent if error: has_error = True errors.append(error) cvus.append(str(test.cvus)) color_error = has_error and self.color_error or self.color_bg gdchart.option(format=gdchart.GDC_PNG, set_color=(self.color_success, self.color_success), vol_color=self.color_error, bg_color=self.color_bg, plot_color=self.color_plot, line_color=self.color_line, title='Successful Tests Per Second', xtitle='CUs', ylabel_fmt='%.2f', ylabel2_fmt='%.2f %%', ytitle='STPS', ytitle2="Errors", ylabel_density=50, ytitle2_color=color_error, ylabel2_color=color_error, requested_ymin=0.0) gdchart.chart(gdchart.GDC_3DCOMBO_LINE_BAR, self.getChartSize(cvus), image_path, cvus, stps, errors) def appendDelays(self, delay, delay_low, delay_high, stats): """ Show percentiles or min, avg and max in chart. """ if self.options.with_percentiles: delay.append(stats.percentiles.perc50) delay_low.append(stats.percentiles.perc10) delay_high.append(stats.percentiles.perc90) else: delay.append(stats.avg) delay_low.append(stats.min) delay_high.append(stats.max) def getYTitle(self): if self.options.with_percentiles: return "Duration (10%, 50% 90%)" else: return "Duration (min, avg, max)" def createPageChart(self): """Create the page chart.""" image_path = str(os.path.join(self.report_dir, 'pages.png')) image2_path = str(os.path.join(self.report_dir, 'pages_spps.png')) stats = self.stats errors = [] delay = [] delay_high = [] delay_low = [] spps = [] cvus = [] has_error = False for cycle in self.cycles: page = stats[cycle]['page'] self.appendDelays(delay, delay_low, delay_high, page) spps.append(page.rps) error = page.error_percent if error: has_error = True errors.append(error) cvus.append(str(page.cvus)) color_error = has_error and self.color_error or self.color_bg gdchart.option(format=gdchart.GDC_PNG, set_color=(self.color_time_min_max, self.color_time_min_max, self.color_time), vol_color=self.color_error, bg_color=self.color_bg, plot_color=self.color_plot, grid_color=self.color_grid, line_color=self.color_line, title='Page response time', xtitle='CUs', ylabel_fmt='%.2fs', ylabel2_fmt='%.2f %%', ytitle=self.getYTitle(), ytitle2="Errors", ylabel_density=50, hlc_style=gdchart.GDC_HLC_I_CAP+gdchart. GDC_HLC_CONNECTING, ytitle2_color=color_error, ylabel2_color=color_error, requested_ymin=0.0) gdchart.chart(gdchart.GDC_3DCOMBO_HLC_BAR, self.getChartSize(cvus), image_path, cvus, (delay_high, delay_low, delay), errors) gdchart.option(format=gdchart.GDC_PNG, set_color=(self.color_success, self.color_success), vol_color=self.color_error, bg_color=self.color_bg, plot_color=self.color_plot, line_color=self.color_line, title='Successful Pages Per Second', xtitle='CUs', ylabel_fmt='%.2f', ylabel2_fmt='%.2f %%', ytitle='SPPS', ytitle2="Errors", ylabel_density=50, requested_ymin=0.0) gdchart.chart(gdchart.GDC_3DCOMBO_LINE_BAR, self.getChartSize(cvus), image2_path, cvus, spps, errors) def createAllResponseChart(self): """Create global responses chart.""" image_path = str(os.path.join(self.report_dir, 'requests.png')) image2_path = str(os.path.join(self.report_dir, 'requests_rps.png')) stats = self.stats errors = [] delay = [] delay_high = [] delay_low = [] rps = [] cvus = [] has_error = False for cycle in self.cycles: resp = stats[cycle]['response'] self.appendDelays(delay, delay_low, delay_high, resp) rps.append(resp.rps) error = resp.error_percent if error: has_error = True errors.append(error) cvus.append(str(resp.cvus)) color_error = has_error and self.color_error or self.color_bg gdchart.option(format=gdchart.GDC_PNG, set_color=(self.color_time_min_max, self.color_time_min_max, self.color_time), vol_color=self.color_error, bg_color=self.color_bg, plot_color=self.color_plot, grid_color=self.color_grid, line_color=self.color_line, title='Request response time', xtitle='CUs', ylabel_fmt='%.2fs', ylabel2_fmt='%.2f %%', ytitle=self.getYTitle(), ytitle2="Errors", ylabel_density=50, hlc_style=gdchart.GDC_HLC_I_CAP+gdchart. GDC_HLC_CONNECTING, ytitle2_color=color_error, ylabel2_color=color_error, requested_ymin=0.0) gdchart.chart(gdchart.GDC_3DCOMBO_HLC_BAR, self.getChartSize(cvus), image_path, cvus, (delay_high, delay_low, delay), errors) gdchart.option(format=gdchart.GDC_PNG, set_color=(self.color_success, self.color_success), vol_color=self.color_error, bg_color=self.color_bg, plot_color=self.color_plot, line_color=self.color_line, title='Requests Per Second', xtitle='CUs', ylabel_fmt='%.2f', ylabel2_fmt='%.2f %%', ytitle='RPS', ytitle2="Errors", ylabel_density=50, ytitle2_color=color_error, ylabel2_color=color_error, requested_ymin=0.0) gdchart.chart(gdchart.GDC_3DCOMBO_LINE_BAR, self.getChartSize(cvus), image2_path, cvus, rps, errors) def createResponseChart(self, step): """Create responses chart.""" stats = self.stats errors = [] delay = [] delay_high = [] delay_low = [] cvus = [] number = 0 has_error = False for cycle in self.cycles: resp = stats[cycle]['response_step'].get(step) if resp is None: delay.append(None) delay_low.append(None) delay_high.append(None) errors.append(None) cvus.append('?') else: self.appendDelays(delay, delay_low, delay_high, resp) error = resp.error_percent if error: has_error = True errors.append(error) cvus.append(str(resp.cvus)) number = resp.number image_path = str(os.path.join(self.report_dir, 'request_%s.png' % step)) title = str('Request %s response time' % step) color_error = has_error and self.color_error or self.color_bg gdchart.option(format=gdchart.GDC_PNG, set_color=(self.color_time_min_max, self.color_time_min_max, self.color_time), vol_color=self.color_error, bg_color=self.color_bg, plot_color=self.color_plot, grid_color=self.color_grid, line_color=self.color_line, title=title, xtitle='CUs', ylabel_fmt='%.2fs', ylabel2_fmt='%.2f %%', ytitle=self.getYTitle(), ytitle2="Errors", ylabel_density=50, hlc_style=gdchart.GDC_HLC_I_CAP+gdchart. GDC_HLC_CONNECTING, ytitle2_color=color_error, ylabel2_color=color_error, requested_ymin=0.0) gdchart.chart(gdchart.GDC_3DCOMBO_HLC_BAR, self.getChartSize(cvus), image_path, cvus, (delay_high, delay_low, delay), errors) # monitoring charts def createMonitorCharts(self): """Create all montirored server charts.""" if not self.monitor or not self.with_chart: return self.append(rst_title("Monitored hosts", 2)) for host in self.monitor.keys(): self.createMonitorChart(host) def createMonitorChart(self, host): """Create monitrored server charts.""" stats = self.monitor[host] time_start = float(stats[0].time) times = [] for stat in stats: test, cycle, cvus = stat.key.split(':') times.append(str('%ss / %s CUs' % ( int(float(stat.time) - time_start), cvus))) mem_total = int(stats[0].memTotal) mem_used = [mem_total - int(x.memFree) for x in stats] mem_used_start = mem_used[0] mem_used = [x - mem_used_start for x in mem_used] swap_total = int(stats[0].swapTotal) swap_used = [swap_total - int(x.swapFree) for x in stats] swap_used_start = swap_used[0] swap_used = [x - swap_used_start for x in swap_used] load_avg_1 = [float(x.loadAvg1min) for x in stats] load_avg_5 = [float(x.loadAvg5min) for x in stats] load_avg_15 = [float(x.loadAvg15min) for x in stats] net_in = [None] net_out = [None] cpu_usage = [0] for i in range(1, len(stats)): if not (hasattr(stats[i], 'CPUTotalJiffies') and hasattr(stats[i-1], 'CPUTotalJiffies')): cpu_usage.append(None) else: dt = ((long(stats[i].IDLTotalJiffies) + long(stats[i].CPUTotalJiffies)) - (long(stats[i-1].IDLTotalJiffies) + long(stats[i-1].CPUTotalJiffies))) if dt: ttl = (float(long(stats[i].CPUTotalJiffies) - long(stats[i-1].CPUTotalJiffies)) / dt) else: ttl = None cpu_usage.append(ttl) if not (hasattr(stats[i], 'receiveBytes') and hasattr(stats[i-1], 'receiveBytes')): net_in.append(None) else: net_in.append((int(stats[i].receiveBytes) - int(stats[i-1].receiveBytes)) / (1024 * (float(stats[i].time) - float(stats[i-1].time)))) if not (hasattr(stats[i], 'transmitBytes') and hasattr(stats[i-1], 'transmitBytes')): net_out.append(None) else: net_out.append((int(stats[i].transmitBytes) - int(stats[i-1].transmitBytes))/ (1024 * (float(stats[i].time) - float(stats[i-1].time)))) image_path = str(os.path.join(self.report_dir, '%s_load.png' % host)) title = str('%s: cpu usage (green 1=100%%) and loadavg 1(red), ' '5 and 15 min' % host) gdchart.option(format=gdchart.GDC_PNG, set_color=(0x00ff00, 0xff0000, 0x0000ff), vol_color=0xff0000, bg_color=self.color_bg, plot_color=self.color_plot, line_color=self.color_line, title=title, xtitle='time and CUs', ylabel_fmt='%.2f', ytitle='loadavg', ylabel_density=50, requested_ymin=0.0) gdchart.chart(gdchart.GDC_LINE, self.big_chart_size, image_path, times, cpu_usage, load_avg_1, load_avg_5, load_avg_15) title = str('%s memory (green) and swap (red) usage' % host) image_path = str(os.path.join(self.report_dir, '%s_mem.png' % host)) gdchart.option(format=gdchart.GDC_PNG, title=title, ylabel_fmt='%.0f kB', ytitle='memory used kB') gdchart.chart(gdchart.GDC_LINE, self.big_chart_size, image_path, times, mem_used, swap_used) title = str('%s network in (green)/out (red)' % host) image_path = str(os.path.join(self.report_dir, '%s_net.png' % host)) gdchart.option(format=gdchart.GDC_PNG, title=title, ylabel_fmt='%.0f kB/s', ytitle='network') gdchart.chart(gdchart.GDC_LINE, self.big_chart_size, image_path, times, net_in, net_out) PKH\b4&22funkload/Recorder.py# (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """TCPWatch FunkLoad Test Recorder. Requires tcpwatch.py available at: * http://hathawaymix.org/Software/TCPWatch/tcpwatch-1.3.tar.gz Credits goes to Ian Bicking for parsing tcpwatch files. $Id: Recorder.py 33463 2006-02-24 14:09:21Z bdelbosc $ """ import os import sys import re from cStringIO import StringIO from optparse import OptionParser, TitledHelpFormatter from tempfile import mkdtemp import rfc822 from cgi import FieldStorage from urlparse import urlsplit from utils import truncate, trace, get_version class Request: """Store a tcpwatch request.""" def __init__(self, file_path): """Load a tcpwatch request file.""" self.file_path = file_path f = open(file_path, 'rb') line = f.readline().split(None, 2) if not line: trace('# Warning: empty first line on %s\n' % self.file_path) line = f.readline().split(None, 2) self.method = line[0] url = line[1] scheme, host, path, query, fragment = urlsplit(url) self.host = scheme + '://' + host self.rurl = url[len(self.host):] self.url = url self.path = path self.version = line[2].strip() self.headers = dict(rfc822.Message(f).items()) self.body = f.read() f.close() def extractParam(self): """Turn muti part encoded form into params.""" environ = { 'CONTENT_TYPE': self.headers['content-type'], 'CONTENT_LENGTH': self.headers['content-length'], 'REQUEST_METHOD': 'POST', } form = FieldStorage(fp=StringIO(self.body), environ=environ, keep_blank_values=True) params = [] try: keys = form.keys() except TypeError: trace('# Warning: skipping invalid http post param in file: %s ' 'may be an xmlrpc call ?\n' % self.file_path) return params for key in keys: if not isinstance(form[key], list): values = [form[key]] else: values = form[key] for form_value in values: filename = form_value.filename if filename is None: params.append([key, form_value.value]) else: # got a file upload filename = filename or '' params.append([key, 'Upload("%s")' % filename]) if filename: if os.path.exists(filename): trace('# Warning: uploaded file: %s already' ' exists, keep it.\n' % filename) else: trace('# Saving uploaded file: %s\n' % filename) f = open(filename, 'w') f.write(str(form_value.value)) f.close() return params def __repr__(self): params = '' if self.body: params = self.extractParam() return '' % ( self.method, self.url, str(params)) class Response: """Store a tcpwatch response.""" def __init__(self, file_path): """Load a tcpwatch response file.""" self.file_path = file_path f = open(file_path, 'rb') line = f.readline().split(None, 2) self.version = line[0] self.status_code = line[1].strip() if len(line) > 2: self.status_message = line[2].strip() else: self.status_message = '' self.headers = dict(rfc822.Message(f).items()) self.body = f.read() f.close() def __repr__(self): return '' % ( self.status_code, self.headers.get('content-type'), self.status_message) class RecorderProgram: """A tcpwatch to funkload recorder.""" USAGE = """%prog [options] [test_name] %prog launch a TCPWatch proxy and record activities, then output a FunkLoad script or generates a FunkLoad unit test if test_name is specified. The default proxy port is 8090. Note that tcpwatch.py executable must be accessible from your env. See http://funkload.nuxeo.org/ for more information. Examples ======== %prog foo_bar Run a proxy and create a FunkLoad test case, generates test_FooBar.py and FooBar.conf file. To test it: fl-run-test -dV test_FooBar.py %prog -p 9090 Run a proxy on port 9090, output script to stdout. %prog -i /tmp/tcpwatch Convert a tcpwatch capture into a script. """ def __init__(self, argv=None): if argv is None: argv = sys.argv[1:] self.verbose = False self.tcpwatch_path = None self.prefix = 'watch' self.port = "8090" self.server_url = None self.class_name = None self.test_name = None self.script_path = None self.configuration_path = None self.parseArgs(argv) def parseArgs(self, argv): """Parse programs args.""" parser = OptionParser(self.USAGE, formatter=TitledHelpFormatter(), version="FunkLoad %s" % get_version()) parser.add_option("-v", "--verbose", action="store_true", help="Verbose output") parser.add_option("-p", "--port", type="string", dest="port", default=self.port, help="The proxy port.") parser.add_option("-i", "--tcp-watch-input", type="string", dest="tcpwatch_path", default=None, help="Path to an existing tcpwatch capture.") options, args = parser.parse_args(argv) if len(args) == 1: test_name = args[0] else: test_name = None self.verbose = options.verbose self.tcpwatch_path = options.tcpwatch_path self.port = options.port if test_name: class_name = ''.join([x.capitalize() for x in re.split('_|-', test_name)]) self.test_name = test_name self.class_name = class_name self.script_path = './test_%s.py' % class_name self.configuration_path = './%s.conf' % class_name def startProxy(self): """Start a tcpwatch session.""" self.tcpwatch_path = mkdtemp('_funkload') cmd = 'tcpwatch.py -p %s -s -r %s' % (self.port, self.tcpwatch_path) if self.verbose: cmd += ' | grep "T http"' else: cmd += ' > /dev/null' trace("Hit Ctrl-C to stop recording.\n") os.system(cmd) def searchFiles(self): """Search tcpwatch file.""" items = {} prefix = self.prefix for filename in os.listdir(self.tcpwatch_path): if not filename.startswith(prefix): continue name, ext = os.path.splitext(filename) name = name[len(self.prefix):] ext = ext[1:] if ext == 'errors': trace("Error in response %s\n" % name) continue assert ext in ('request', 'response'), "Bad extension: %r" % ext items.setdefault(name, {})[ext] = os.path.join( self.tcpwatch_path, filename) items = items.items() items.sort() return [(v['request'], v['response']) for name, v in items if v.has_key('response')] def extractRequests(self, files): """Filter and extract request from tcpwatch files.""" last_code = None filter_ctypes = ('image', 'css', 'javascript') filter_url = ('.jpg', '.png', '.gif', '.css', '.js') requests = [] for request_path, response_path in files: response = Response(response_path) request = Request(request_path) if self.server_url is None: self.server_url = request.host ctype = response.headers.get('content-type', '') url = request.url if request.method != "POST" and ( last_code in ('301', '302') or [x for x in filter_ctypes if x in ctype] or [x for x in filter_url if url.endswith(x)]): last_code = response.status_code continue last_code = response.status_code requests.append(request) return requests def reindent(self, code, indent=8): """Improve indentation.""" spaces = ' ' * indent code = code.replace('], [', '],\n%s [' % spaces) code = code.replace('[[', '[\n%s [' % spaces) code = code.replace(', description=', ',\n%s description=' % spaces) code = code.replace('self.', '\n%sself.' % spaces) return code def convertToFunkLoad(self, request): """return a funkload python instruction.""" text = [] if request.host != self.server_url: text.append('self.%s("%s"' % (request.method.lower(), request.url)) else: text.append('self.%s(server_url + "%s"' % ( request.method.lower(), request.rurl)) description = "%s %s" % (request.method.capitalize(), request.path | truncate(42)) if request.body: params = ('params=%s' % request.extractParam()) params = re.sub("'Upload\(([^\)]*)\)'", "Upload(\\1)", params) text.append(', ' + params) text.append(', description="%s")' % description) return ''.join(text) def extractScript(self): """Convert a tcpwatch capture into a FunkLoad script.""" files = self.searchFiles() requests = self.extractRequests(files) code = [self.convertToFunkLoad(request) for request in requests] if not code: trace("Sorry no action recorded.\n") return '' code.insert(0, '') return self.reindent('\n'.join(code)) def writeScript(self, script): """Write the FunkLoad test script.""" trace('Creating script: %s.\n' % self.script_path) from pkg_resources import resource_string tpl = resource_string('funkload', 'data/ScriptTestCase.tpl') content = tpl % {'script': script, 'test_name': self.test_name, 'class_name': self.class_name} if os.path.exists(self.script_path): trace("Error file %s already exists.\n" % self.script_path) return f = open(self.script_path, 'w') f.write(content) f.close() def writeConfiguration(self): """Write the FunkLoad configuration test script.""" trace('Creating configuration file: %s.\n' % self.configuration_path) from pkg_resources import resource_string tpl = resource_string('funkload', 'data/ConfigurationTestCase.tpl') content = tpl % {'server_url': self.server_url, 'test_name': self.test_name, 'class_name': self.class_name} if os.path.exists(self.configuration_path): trace("Error file %s already exists.\n" % self.configuration_path) return f = open(self.configuration_path, 'w') f.write(content) f.close() def run(self): """run it.""" if self.tcpwatch_path is None: self.startProxy() script = self.extractScript() if not script: return if self.test_name is not None: self.writeScript(script) self.writeConfiguration() else: print script if __name__ == '__main__': RecorderProgram().run() PKT;4o|m<>>funkload/CredentialBase.py# (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """Interface of a Credential Server. $Id: CredentialBase.py 30282 2005-12-05 12:52:30Z bdelbosc $ """ class CredentialBaseServer: """Interface of a Credential server.""" def getCredential(self, group=None): """Return a credential (login, password). If group is not None return a credential that belong to the group. """ def listCredentials(self, group=None): """Return a list of all credentials. If group is not None return a list of credentials that belong to the group. """ def listGroups(self): """Return a list of all groups.""" PKb4!7k88funkload/CPS340TestCase.py# (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """FunkLoad test case for Nuxeo CPS. $Id: CPSTestCase.py 24728 2005-08-31 08:13:54Z bdelbosc $ """ import time import random from Lipsum import Lipsum from ZopeTestCase import ZopeTestCase from webunit.utility import Upload class CPSTestCase(ZopeTestCase): """Common CPS tasks. setUp must set a server_url attribute.""" cps_test_case_version = (3, 4, 0) server_url = None _lipsum = Lipsum() _all_langs = ['en', 'fr', 'de', 'it', 'es', 'pt_BR', 'nl', 'mg', 'ro', 'eu'] _default_langs = _all_langs[:4] _default_extensions = ['CPSForum:default', 'CPSSkins:cps3', 'CPSSubscriptions:default'] _cps_login = None # ------------------------------------------------------------ # cps actions # def cpsLogin(self, login, password, comment=None): """Log in a user. Raise on invalid credential.""" self._cps_login = None params = [['__ac_name', login], ['__ac_password', password], ['__ac_persistent', 'on'], ['submit', 'Login'], ] self.post("%s/logged_in" % self.server_url, params, description="Log in user [%s] %s" % (login, comment or '')) # assume we are logged in if we have a logout link... self.assert_([link for link in self.listHref() if link.endswith('logout')], 'invalid credential: [%s:%s].' % (login, password)) self._cps_login = login def cpsLogout(self): """Log out the current user.""" if self._cps_login is not None: self.get('%s/logout' % self.server_url, description="Log out [%s]" % self._cps_login) def cpsCreateSite(self, admin_id, admin_pwd, manager_id, manager_password, manager_mail, langs=None, title=None, description=None, interface="portlets", zope_url=None, site_id=None, extensions=None): """Create a CPS Site. if zope_url or site_id is not provided guess them from the server_url. """ if zope_url is None or site_id is None: zope_url, site_id = self.cpsGuessZopeUrl() self.setBasicAuth(admin_id, admin_pwd) params = { 'site_id': site_id, 'title': title or "FunkLoad CPS Portal", 'manager_id': manager_id, 'password': manager_password, 'password_confirm': manager_password, 'manager_email': manager_mail, 'manager_firstname': 'Manager', 'manager_lastname': 'CPS Manager', 'extension_ids:list': extensions or self._default_extensions, 'description': description or "A funkload cps test site", 'languages:list': langs or self._default_langs, 'submit': 'Add', 'profile_id': 'CPSDefault:default'} self.post("%s/manage_addProduct/CPSDefault/addConfiguredCPSSite" % zope_url, params, description="Create a CPS Site") self.clearBasicAuth() def cpsCreateGroup(self, group_name): """Create a cps group.""" server_url = self.server_url params = [["dirname", "groups"], ["id", ""], ["widget__group", group_name], ["widget__members:tokens:default", ""], ["cpsdirectory_entry_create_form:method", "Create"]] self.post("%s/" % server_url, params) self.assert_(self.getLastUrl().find('psm_entry_created')!=-1, 'Failed to create group %s' % group_name) def cpsVerifyGroup(self, group_name): """Check existance or create a cps group.""" server_url = self.server_url params = [["dirname", "groups"], ["id", group_name],] if self.exists("%s/cpsdirectory_entry_view" % server_url, params, description="Check that group [%s] exists." % group_name): self.logd('Group %s exists.') else: self.cpsCreateGroup(group_name) def cpsCreateUser(self, user_id=None, user_pwd=None, user_givenName=None, user_sn=None, user_email=None, groups=None): """Create a cps user with the Member role. return login, pwd""" lipsum = self._lipsum sign = lipsum.getUniqWord() user_id = user_id or 'fl_' + sign.lower() user_givenName = user_givenName or lipsum.getWord().capitalize() user_sn = user_sn or user_id.upper() user_email = user_email or "root@127.0.0.01" user_pwd = user_pwd or lipsum.getUniqWord(length_min=6) params = [["dirname", "members"], ["id", ""], ["widget__id", user_id], ["widget__password", user_pwd], ["widget__confirm", user_pwd], ["widget__givenName", user_givenName], ["widget__sn", user_sn], ["widget__email", user_email], ["widget__roles:tokens:default", ""], ["widget__roles:list", "Member"], ["widget__groups:tokens:default", ""], ["widget__homeless:boolean", "False"], ["cpsdirectory_entry_create_form:method", "Create"]] for group in groups: params.append(["widget__groups:list", group]) self.post("%s/" % self.server_url, params, description="Create user [%s]" % user_id) self.assert_(self.getLastUrl().find('psm_entry_created')!=-1, 'Failed to create user %s' % user_id) return user_id, user_pwd def cpsVerifyUser(self, user_id=None, user_pwd=None, user_givenName=None, user_sn=None, user_email=None, groups=None): """Verify if user exists or create him. return login, pwd if user exists pwd is None. """ if user_id: params = [["dirname", "members"], ["id", user_id],] if self.exists( "%s/cpsdirectory_entry_view" % self.server_url, params): self.logd('User %s exists.') return user_id, None return self.cpsCreateUser(user_id, user_pwd, user_givenName, user_sn, user_email, groups) def cpsSetLocalRole(self, url, name, role): """Setup local role role to url.""" params = [["member_ids:list", name], ["member_role", role]] self.post("%s/folder_localrole_add" % url, params, description="Grant local role %s to %s" % (role, name)) def cpsCreateSection(self, parent_url, title, description="ftest section for funkload testing.", lang=None): """Create a section.""" return self.cpsCreateFolder('Section', parent_url, title, description, lang or self.cpsGetRandomLanguage()) def cpsCreateWorkspace(self, parent_url, title, description="ftest workspace for funkload testing.", lang=None): """Create a workspace.""" return self.cpsCreateFolder('Workspace', parent_url, title, description, lang or self.cpsGetRandomLanguage()) def cpsCreateFolder(self, type, parent_url, title, description, lang): """Create a section or a workspace. Return the section full url.""" params = [["type_name", type], ["widget__Title", title], ["widget__Description", description], ["widget__LanguageSelectorCreation", lang], ["widget__hidden_folder:boolean", False], ["cpsdocument_create_button", "Create"]] self.post("%s/cpsdocument_create" % parent_url, params, "Create a %s" % type) return self.cpsCleanUrl(self.getLastBaseUrl()) def cpsCreateDocument(self, parent_url): """Create a simple random document. return a tuple: (doc_url, doc_id) """ language = self.cpsGetRandomLanguage() title = self._lipsum.getSubject(uniq=True, prefix='test %s' % language) params = [["type_name", "Document"], ["widget__Title", title], ["widget__Description", self._lipsum.getSubject(10)], ["widget__LanguageSelectorCreation", language], ["widget__content", self._lipsum.getMessage()], ["widget__content_rformat", "text"], ["cpsdocument_create_button", "Create"]] self.post("%s/cpsdocument_create" % parent_url, params, description="Creating a document") self.assert_(self.getLastUrl().find('psm_content_created')!=-1, 'Failed to create [%s] in %s/.' % (title, parent_url)) doc_url = self.cpsCleanUrl(self.getLastBaseUrl()) doc_id = doc_url.split('/')[-1] return doc_url, doc_id def cpsCreateNewsItem(self, parent_url, photo_path=None): """Create a random news. return a tuple: (doc_url, doc_id).""" language = self.cpsGetRandomLanguage() title = self._lipsum.getSubject(uniq=True, prefix='test %s' % language) params = [["cpsformuid", self._lipsum.getUniqWord()], ["type_name", "News Item"], ["widget__Title", title], ["widget__Description", self._lipsum.getSubject(10)], ['widget__photo_filename', ''], ['widget__photo_choice', photo_path and 'change' or 'keep'], ['widget__photo', Upload(photo_path or '')], ['widget__photo_resize', 'img_auto_size'], ['widget__photo_rposition', 'left'], ['widget__photo_subtitle', ''], ["widget__content", self._lipsum.getMessage()], ["widget__content_rformat", "text"], ['widget__content_fileupload', Upload('')], ["widget__Subject:tokens:default", ""], ["widget__Subject:list", "Business"], # prevent invalid date depending on ui locale ["widget__publication_date_date", time.strftime('01/01/%Y')], ["widget__publication_date_hour", time.strftime('%H')], ["widget__publication_date_minute", time.strftime('%M')], ["cpsdocument_create_button", "Create"]] self.post("%s/cpsdocument_create" % parent_url, params, description="Creating a news item") last_url = self.getLastUrl() self.assert_('psm_content_created' in last_url, 'Failed to create [%s] in %s/.' % (title, parent_url)) doc_url = self.cpsCleanUrl(self.getLastBaseUrl()) doc_id = doc_url.split('/')[-1] return doc_url, doc_id def cpsChangeUiLanguage(self, lang): """Change the ui language and return the referer page.""" self.get("%s/cpsportlet_change_language" % self.server_url, params=[['lang', lang]], description="Change UI language to %s" % lang) # ------------------------------------------------------------ # helpers # def cpsGetRandomLanguage(self): """Return a random language.""" return random.choice(self._all_langs) def cpsGuessZopeUrl(self, cps_url=None): """Guess a zope url and site_id from a CPS Site url. return a tuple (zope_url, site_id) """ if cps_url is None: cps_url = self.server_url site_id = cps_url.split('/')[-1] zope_url = cps_url[:-(len(site_id)+1)] return zope_url, site_id def cpsSearchDocId(self, doc_id): """Return the list of url that ends with doc_id. Using catalog search.""" params = [["SearchableText", doc_id]] self.post("%s/search_form" % self.server_url, params, description="Searching doc_id %s" % doc_id) ret = self.cpsListDocumentHref(pattern='%s$' % doc_id) self.logd('found %i link ends with %s' % (len(ret), doc_id)) return ret def cpsCleanUrl(self, url_in): """Try to remove server_url and clean ending.""" url = url_in server_url = self.server_url for ending in ('/', '/view', '/folder_contents', '/folder_view', '/cpsdocument_metadata', '/cpsdocument_edit_form'): if url.endswith(ending): url = url[:-len(ending)] if url.startswith(server_url): url = url[len(server_url):] return url def cpsListDocumentHref(self, pattern=None): """Return a clean list of document href that matches pattern. Try to remove server_url and other cps trailings, return a list of uniq url.""" ret = [] for href in [self.cpsCleanUrl(x) for x in self.listHref(pattern)]: if href not in ret: ret.append(href) return ret PKT;4aPfunkload/Lipsum.py# -*- coding: ISO-8859-15 -*- # (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """A simple Lorem ipsum generator. $Id: Lipsum.py 24649 2005-08-29 14:20:19Z bdelbosc $ """ import random # vacabulary simple ascii V_ASCII = ('ad', 'aquam', 'albus', 'archaeos', 'arctos', 'argentatus', 'arvensis', 'australis', 'biscort' 'borealis', 'brachy', 'bradus', 'brevis', 'campus', 'cauda', 'caulos', 'cephalus', 'chilensis', 'chloreus', 'cola', 'cristatus', 'cyanos', 'dactylus', 'deca', 'dermis', 'delorum', 'di', 'diplo', 'dodeca', 'dolicho', 'domesticus', 'dorsum', 'dulcis', 'echinus', 'ennea', 'erythro', 'familiaris', 'flora', 'folius', 'fuscus', 'fulvus', 'gaster', 'glycis', 'hexa', 'hortensis', 'it', 'indicus', 'lateralis', 'leucus', 'lineatus', 'lipsem', 'lutea', 'maculatus', 'major', 'maximus', 'melanus', 'minimus', 'minor', 'mono', 'montanus', 'morphos', 'mauro', 'niger', 'nona', 'nothos', 'notos', 'novaehollandiae', 'novaeseelandiae', 'noveboracensis', 'obscurus', 'occidentalis', 'octa', 'oeos', 'officinalis', 'oleum', 'orientalis', 'ortho', 'pachys', 'palustris', 'parvus', 'pedis', 'pelagius', 'penta', 'petra', 'phyllo', 'phyton', 'platy', 'pratensis', 'protos', 'pteron', 'punctatus', 'rhiza', 'rhytis', 'rubra', 'rostra', 'rufus', 'sativus', 'saurus', 'sinensis', 'stoma', 'striatus', 'silvestris', 'sit', 'so', 'tetra', 'tinctorius', 'tomentosus', 'tres', 'tris', 'trich', 'thrix', 'unus', 'variabilis', 'variegatus', 'ventrus', 'verrucosus', 'via', 'viridis', 'vitis', 'volans', 'vulgaris', 'xanthos', 'zygos', ) # vocabulary with some diacritics V_DIAC = ('acanth', 'acro', 'actino', 'adelphe', 'adno', 'aro', 'agogue', 'agro', 'algie', 'allo', 'amphi', 'andro', 'anti', 'anthropo', 'aqui', 'archo', 'archie', 'auto', 'bio', 'calli', 'cephal', 'chiro', 'chromo', 'chrono', 'dactyle', 'dmo', 'eco', 'eudaimonia', 'thos', 'go', 'glyphe', 'gone', 'gramme', 'graphe', 'hiro', 'homo', 'iatrie', 'lipi', 'lipo', 'logie', 'lyco', 'lyse', 'machie', 'mlan', 'mta', 'naute', 'nse', 'pedo', 'phil', 'phobie', 'podo', 'polis', 'poly', 'rhino', 'xeno', 'zoo', ) # latin 9 vocabulary V_8859_15 = ('jcnth', 'zcr', 'bctin', 'zdelphe', 'kdn', 'zr', 'aggu', 'algi', 'all', 'amphi', 'adro', 'ati', 'aqi', 'at', 'bi', 'cai', 'ephal', 'lco', 'rt', 'oi', 'es', 'du', 'de', 'le', 'as', 'us', 'i', 'ave', 'ov ', 'zur ', 'ab ', ) # common char to build identifier CHARS = "abcdefghjkmnopqrstuvwxyz123456789" # separator SEP = ',' * 10 + ';?!' class Lipsum: """Kind of Lorem ipsum generator.""" def __init__(self, vocab=V_ASCII, chars=CHARS, sep=SEP): self.vocab = vocab self.chars = chars self.sep = sep def getWord(self): """Return a random word.""" return random.choice(self.vocab) def getUniqWord(self, length_min=None, length_max=None): """Generate a kind of uniq identifier.""" length_min = length_min or 5 length_max = length_max or 9 length = random.randrange(length_min, length_max) chars = self.chars return ''.join([random.choice(chars) for i in range(length)]) def getSubject(self, length=5, prefix=None, uniq=False, length_min=None, length_max=None): """Return a subject of length words.""" subject = [] if prefix: subject.append(prefix) if uniq: subject.append(self.getUniqWord()) if length_min and length_max: length = random.randrange(length_min, length_max+1) for i in range(length): subject.append(self.getWord()) return ' '.join(subject).capitalize() def getSentence(self): """Return a random sentence.""" sep = self.sep length = random.randrange(5, 20) sentence = [self.getWord() for i in range(length)] for i in range(random.randrange(0, 3)): sentence.insert(random.randrange(length-4)+2, random.choice(sep)) sentence = ' '.join(sentence).capitalize() + '.' sentence = sentence.replace(' ,', ',') sentence = sentence.replace(',,', ',') return sentence def getParagraph(self, length=4): """Return a paragraph.""" return ' '.join([self.getSentence() for i in range(length)]) def getMessage(self, length=7): """Return a message paragraph length.""" return '\n\n'.join([self.getParagraph() for i in range( random.randrange(3,length))]) def getPhoneNumber(self, lang="fr", format="medium"): """Return a random Phone number.""" if lang == "en_US": num = [] num.append("%3.3i" % random.randrange(0, 999)) num.append("%4.4i" % random.randrange(0, 9999)) if format == "short": return "-".join(num) num.insert(0, "%3.3i" % random.randrange(0, 999)) if format == "medium": return "(%s) %s-%s" % tuple(num) # default long return "+00 1 (%s) %s-%s" % tuple(num) # default lang == 'fr': num = ['07'] for i in range(4): num.append('%2.2i' % random.randrange(0, 99)) if format == "medium": return " ".join(num) elif format == "long": num[0] = '(0)7' return "+33 "+ " ".join(num) # default format == 'short': return "".join(num) def getAddress(self, lang="fr"): """Return a random address.""" # default lang == fr return "%i %s %s\n%5.5i %s" % ( random.randrange(1, 100), random.choice(['rue', 'avenue', 'place', 'boulevard']), self.getSubject(length_min=1, length_max=3), random.randrange(99000, 99999), self.getSubject(length_min=1, length_max=2)) def main(): """Testing.""" print 'Word: %s\n' % (Lipsum().getWord()) print 'UniqWord: %s\n' % (Lipsum().getUniqWord()) print 'Subject: %s\n' % (Lipsum().getSubject()) print 'Subject uniq: %s\n' % (Lipsum().getSubject(uniq=True)) print 'Sentence: %s\n' % (Lipsum().getSentence()) print 'Paragraph: %s\n' % (Lipsum().getParagraph()) print 'Message: %s\n' % (Lipsum().getMessage()) print 'Phone number: %s\n' % Lipsum().getPhoneNumber() print 'Phone number fr short: %s\n' % Lipsum().getPhoneNumber( lang="fr", format="short") print 'Phone number fr medium: %s\n' % Lipsum().getPhoneNumber( lang="fr", format="medium") print 'Phone number fr long: %s\n' % Lipsum().getPhoneNumber( lang="fr", format="long") print 'Phone number en_US short: %s\n' % Lipsum().getPhoneNumber( lang="en_US", format="short") print 'Phone number en_US medium: %s\n' % Lipsum().getPhoneNumber( lang="en_US", format="medium") print 'Phone number en_US long: %s\n' % Lipsum().getPhoneNumber( lang="en_US", format="long") print 'Address default: %s' % Lipsum().getAddress() if __name__ == '__main__': main() PKT;4BGGfunkload/BenchRunner.py#!/usr/bin/python # (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """FunkLoad Bench runner. $Id: BenchRunner.py 24746 2005-08-31 09:59:27Z bdelbosc $ """ USAGE = """%prog [options] file class.method %prog launch a FunkLoad unit test as load test. A FunkLoad unittest use a configuration file named [class].conf, this configuration is overriden by the command line options. See http://funkload.nuxeo.org/ for more information. Examples ======== %prog myFile.py MyTestCase.testSomething Bench MyTestCase.testSomething using MyTestCase.conf. %prog -u http://localhost:8080 -c 10:20 -D 30 myFile.py \\ MyTestCase.testSomething Bench MyTestCase.testSomething on localhost:8080 with 2 cycles of 10 and 20 users during 30s. %prog -h More options. """ import os import sys import time from datetime import datetime import traceback import threading from socket import error as SocketError from thread import error as ThreadError from xmlrpclib import ServerProxy import unittest from optparse import OptionParser, TitledHelpFormatter from utils import mmn_encode, set_recording_flag, recording from utils import set_running_flag, running from utils import thread_sleep, trace, red_str, green_str from utils import get_version # ------------------------------------------------------------ # utils # g_failures = 0 # result of the bench g_errors = 0 # result of the bench g_success = 0 def add_cycle_result(status): """Count number of result.""" # XXX use a thread.lock, but we don't mind if it is not accurate # as the report use the xml log global g_success, g_failures, g_errors if status == 'success': g_success += 1 elif status == 'error': g_errors += 1 else: g_failures += 1 def get_cycle_results(): """Return counters.""" global g_success, g_failures, g_errors return g_success, g_failures, g_errors def get_status(success, failures, errors, color=False): """Return a status and an exit code.""" if errors: status = 'ERROR' if color: status = red_str(status) code = -1 elif failures: status = 'FAILURE' if color: status = red_str(status) code = 1 else: status = 'SUCCESSFUL' if color: status = green_str(status) code = 0 return status, code def reset_cycle_results(): """Clear the previous results.""" global g_success, g_failures, g_errors g_success = g_failures = g_errors = 0 def load_unittest(test_module, test_class, test_name, options): """Instanciate a unittest.""" module = __import__(test_module) klass = getattr(module, test_class) return klass(test_name, options) # ------------------------------------------------------------ # Classes # class LoopTestRunner(threading.Thread): """Run a unit test in loop.""" def __init__(self, test_module, test_class, test_name, options, cycle, cvus, thread_id, sleep_time, debug=False): meta_method_name = mmn_encode(test_name, cycle, cvus, thread_id) threading.Thread.__init__(self, target=self.run, name=meta_method_name, args=()) self.test = load_unittest(test_module, test_class, meta_method_name, options) self.color = not options.no_color self.sleep_time = sleep_time self.debug = debug # this makes threads endings if main stop with a KeyboardInterupt self.setDaemon(1) def run(self): """Run a test in loop.""" while (running()): test_result = unittest.TestResult() self.test.clearContext() self.test(test_result) if test_result.wasSuccessful(): if recording(): add_cycle_result('success') if self.color: trace(green_str('.')) else: trace('.') else: if len(test_result.errors): if recording(): add_cycle_result('error') if self.color: trace(red_str('E')) else: trace('E') else: if recording(): add_cycle_result('failure') if self.color: trace(red_str('F')) else: trace('F') if self.debug: for (test, error) in test_result.errors: trace("ERROR %s: %s" % (str(test), str(error))) for (test, error) in test_result.failures: trace("FAILURE %s: %s" % (str(test), str(error))) thread_sleep(self.sleep_time) # ------------------------------------------------------------ # # class BenchRunner: """Run a unit test in bench mode.""" def __init__(self, module_file, class_name, method_name, options): self.threads = [] self.module_name = os.path.basename(os.path.splitext(module_file)[0]) self.class_name = class_name self.method_name = method_name self.options = options self.color = not options.no_color # create a unittest to get the configuration file test = load_unittest(self.module_name, class_name, mmn_encode(method_name, 0, 0, 0), options) self.config_path = test._config_path self.result_path = test.result_path self.class_title = test.conf_get('main', 'title') self.class_description = test.conf_get('main', 'description') self.test_id = self.method_name self.test_description = test.conf_get(self.method_name, 'description', 'No test description') self.test_url = test.conf_get('main', 'url') self.cycles = map(int, test.conf_getList('bench', 'cycles')) self.duration = test.conf_getInt('bench', 'duration') self.startup_delay = test.conf_getFloat('bench', 'startup_delay') self.cycle_time = test.conf_getFloat('bench', 'cycle_time') self.sleep_time = test.conf_getFloat('bench', 'sleep_time') self.sleep_time_min = test.conf_getFloat('bench', 'sleep_time_min') self.sleep_time_max = test.conf_getFloat('bench', 'sleep_time_max') # setup monitoring monitor_hosts = [] # list of (host, port, descr) for host in test.conf_get('monitor', 'hosts', '', quiet=True).split(): host = host.strip() monitor_hosts.append((host, test.conf_getInt(host, 'port'), test.conf_get(host, 'description', ''))) self.monitor_hosts = monitor_hosts # keep the test to use the result logger for monitoring # and call setUp/tearDown Cycle self.test = test def run(self): """Run all the cycles. return 0 on success, 1 if there were some failures and -1 on errors.""" trace(str(self)) trace("Benching\n") trace("========\n\n") cycle = total_success = total_failures = total_errors = 0 self.logr_open() for cvus in self.cycles: t_start = time.time() reset_cycle_results() text = "Cycle #%i with %s virtual users\n" % (cycle, cvus) trace(text) trace('-' * (len(text) - 1) + "\n\n") monitor_key = '%s:%s:%s' % (self.method_name, cycle, cvus) self.test.setUpCycle() self.startMonitors(monitor_key) self.startThreads(cycle, cvus) self.logging() #self.dumpThreads() self.stopThreads() self.stopMonitors(monitor_key) cycle += 1 self.test.tearDownCycle() t_stop = time.time() trace("* End of cycle, %.2fs elapsed.\n" % (t_stop - t_start)) success, failures, errors = get_cycle_results() status, code = get_status(success, failures, errors, self.color) trace("* Cycle result: **%s**, " "%i success, %i failure, %i errors.\n\n" % ( status, success, failures, errors)) total_success += success total_failures += failures total_errors += errors self.logr_close() # display bench result trace("Result\n") trace("======\n\n") trace("* Success: %s\n" % total_success) trace("* Failures: %s\n" % total_failures) trace("* Errors: %s\n\n" % total_errors) status, code = get_status(total_success, total_failures, total_errors) trace("Bench status: **%s**\n" % status) return code def startThreads(self, cycle, number_of_threads): """Starting threads.""" trace("* Current time: %s\n" % datetime.now().isoformat()) trace("* Starting threads: ") threads = [] i = 0 set_running_flag(True) set_recording_flag(False) for thread_id in range(number_of_threads): i += 1 thread = LoopTestRunner(self.module_name, self.class_name, self.method_name, self.options, cycle, number_of_threads, thread_id, self.sleep_time) trace(".") try: thread.start() except ThreadError: trace("\nERROR: Can not create more than %i threads, try a " "smaller stack size using: 'ulimit -s 2048' " "for example\n" % i) raise threads.append(thread) thread_sleep(self.startup_delay) trace(' done.\n') self.threads = threads def logging(self): """Log activity during duration.""" duration = self.duration end_time = time.time() + duration trace("* Logging for %ds (until %s): " % ( duration, datetime.fromtimestamp(end_time).isoformat())) set_recording_flag(True) while time.time() < end_time: # wait time.sleep(1) set_recording_flag(False) trace(" done.\n") def stopThreads(self): """Wait for thread endings.""" set_running_flag(False) trace("* Waiting end of threads: ") for thread in self.threads: thread.join() del thread trace('.') del self.threads trace(" done.\n") trace("* Waiting cycle sleeptime %ds: ..." % self.cycle_time) time.sleep(self.cycle_time) trace(" done.\n") def dumpThreads(self): """Display all different traceback of Threads for debugging. Require threadframe module.""" import threadframe stacks = {} frames = threadframe.dict() for thread_id, frame in frames.iteritems(): stack = ''.join(traceback.format_stack(frame)) stacks[stack] = stacks.setdefault(stack, []) + [thread_id] def sort_stack(x, y): """sort stack by number of thread.""" return cmp(len(x[1]), len(y[1])) stacks = stacks.items() stacks.sort(sort_stack) for stack, thread_ids in stacks: trace('=' * 72 + '\n') trace('%i threads : %s\n' % (len(thread_ids), str(thread_ids))) trace('-' * 72 + '\n') trace(stack + '\n') def startMonitors(self, monitor_key): """Start monitoring on hosts list.""" if not self.monitor_hosts: return monitor_hosts = [] for (host, port, desc) in self.monitor_hosts: trace("* Start monitoring %s: ..." % host) server = ServerProxy("http://%s:%s" % (host, port)) try: server.startRecord(monitor_key) except SocketError: trace(' failed, server is down.\n') else: trace(' done.\n') monitor_hosts.append((host, port, desc)) self.monitor_hosts = monitor_hosts def stopMonitors(self, monitor_key): """Stop monitoring and save xml result.""" if not self.monitor_hosts: return for (host, port, desc) in self.monitor_hosts: trace('* Stop monitoring %s: ' % host) server = ServerProxy("http://%s:%s" % (host, port)) try: server.stopRecord(monitor_key) xml = server.getXmlResult(monitor_key) except SocketError: trace(' failed, server is down.\n') else: trace(' done.\n') self.logr(xml) def logr(self, message): """Log to the test result file.""" self.test._logr(message, force=True) def logr_open(self): """Start logging tag.""" config = {'id': self.test_id, 'description': self.test_description, 'class_title': self.class_title, 'class_description': self.class_description, 'module': self.module_name, 'class': self.class_name, 'method': self.method_name, 'cycles': self.cycles, 'duration': self.duration, 'sleep_time': self.sleep_time, 'startup_delay': self.startup_delay, 'sleep_time_min': self.sleep_time_min, 'sleep_time_max': self.sleep_time_max, 'cycle_time': self.cycle_time, 'configuration_file': self.config_path, 'server_url': self.test_url, 'log_xml': self.result_path,} for (host, port, desc) in self.monitor_hosts: config[host] = desc self.test._open_result_log(**config) def logr_close(self): """Stop logging tag.""" self.test._close_result_log() def __repr__(self): """Display bench information.""" text = [] text.append('=' * 72) text.append('Benching %s.%s' % (self.class_name, self.method_name)) text.append('=' * 72) text.append(self.test_description) text.append('-' * 72 + '\n') text.append("Configuration") text.append("=============\n") text.append("* Current time: %s" % datetime.now().isoformat()) text.append("* Configuration file: %s" % self.config_path) text.append("* Log xml: %s" % self.result_path) text.append("* Server: %s" % self.test_url) text.append("* Cycles: %s" % self.cycles) text.append("* Cycle duration: %ss" % self.duration) text.append("* Sleeptime between request: from %ss to %ss" % ( self.sleep_time_min, self.sleep_time_max)) text.append("* Sleeptime between test case: %ss" % self.sleep_time) text.append("* Startup delay between thread: %ss\n\n" % self.startup_delay) return '\n'.join(text) # ------------------------------------------------------------ # main # def main(): """Default main.""" # enable to load module in the current path cur_path = os.path.abspath(os.path.curdir) sys.path.insert(0, cur_path) parser = OptionParser(USAGE, formatter=TitledHelpFormatter(), version="FunkLoad %s" % get_version()) parser.add_option("-u", "--url", type="string", dest="main_url", help="Base URL to bench.") parser.add_option("-c", "--cycles", type="string", dest="bench_cycles", help="Cycles to bench, this is a list of number of " "virtual concurrent users, " "to run a bench with 3 cycles with 5, 10 and 20 " "users use: -c 2:10:20") parser.add_option("-D", "--duration", type="string", dest="bench_duration", help="Duration of a cycle in seconds.") parser.add_option("-m", "--sleep-time-min", type="string", dest="bench_sleep_time_min", help="Minimum sleep time between request.") parser.add_option("-M", "--sleep-time-max", type="string", dest="bench_sleep_time_max", help="Maximum sleep time between request.") parser.add_option("-s", "--startup-delay", type="string", dest="bench_startup_delay", help="Startup delay between thread.") parser.add_option("", "--no-color", action="store_true", help="Monochrome output.") parser.add_option("", "--accept-invalid-links", action="store_true", help="Do not fail if css/image links are " "not reachable.") parser.add_option("", "--simple-fetch", action="store_true", help="Don't load additional links like css " "or images when fetching an html page.") options, args = parser.parse_args() if len(args) != 2: parser.error("incorrect number of arguments") if not args[1].count('.'): parser.error("invalid argument should be class.method") klass, method = args[1].split('.') bench = BenchRunner(args[0], klass, method, options) ret = bench.run() sys.exit(ret) if __name__ == '__main__': main() PK$M[6RŃIIfunkload/TestRunner.py#!/usr/bin/python # (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """FunkLoad Test runner. Similar to unittest.TestProgram but: * you can pass the python module to load * able to override funkload configuration file using command line options * cool color output * support doctest with python2.4 $Id: TestRunner.py 24758 2005-08-31 12:33:00Z bdelbosc $ """ import os import sys import types import time import unittest import re from StringIO import StringIO from optparse import OptionParser, TitledHelpFormatter from utils import red_str, green_str, get_version from funkload.FunkLoadTestCase import FunkLoadTestCase # ------------------------------------------------------------ # doctest patch to command verbose mode only available with python2.4 # g_doctest_verbose = False try: from doctest import DocTestSuite, DocFileSuite, DocTestCase, DocTestRunner from doctest import REPORTING_FLAGS, _unittest_reportflags g_has_doctest = True except ImportError: g_has_doctest = False else: def DTC_runTest(self): test = self._dt_test old = sys.stdout new = StringIO() optionflags = self._dt_optionflags if not (optionflags & REPORTING_FLAGS): # The option flags don't include any reporting flags, # so add the default reporting flags optionflags |= _unittest_reportflags # Patching doctestcase to enable verbose mode global g_doctest_verbose runner = DocTestRunner(optionflags=optionflags, checker=self._dt_checker, verbose=g_doctest_verbose) # End of patch try: runner.DIVIDER = "-"*70 failures, tries = runner.run( test, out=new.write, clear_globs=False) finally: sys.stdout = old if failures: raise self.failureException(self.format_failure(new.getvalue())) elif g_doctest_verbose: print new.getvalue() DocTestCase.runTest = DTC_runTest # ------------------------------------------------------------ # # class TestLoader(unittest.TestLoader): """Override to add options when instanciating test case.""" def loadTestsFromTestCase(self, testCaseClass): """Return a suite of all tests cases contained in testCaseClass""" if not issubclass(testCaseClass, FunkLoadTestCase): return unittest.TestLoader.loadTestsFromTestCase(self, testCaseClass) options = getattr(self, 'options', None) return self.suiteClass([testCaseClass(name, options) for name in self.getTestCaseNames(testCaseClass)]) def loadTestsFromModule(self, module): """Return a suite of all tests cases contained in the given module""" global g_has_doctest tests = [] doctests = None if g_has_doctest: try: doctests = DocTestSuite(module) except ValueError: pass for name in dir(module): obj = getattr(module, name) if (isinstance(obj, (type, types.ClassType)) and issubclass(obj, unittest.TestCase)): tests.append(self.loadTestsFromTestCase(obj)) suite = self.suiteClass(tests) if doctests is not None: suite.addTest(doctests) return suite def loadTestsFromName(self, name, module=None): """Return a suite of all tests cases given a string specifier. The name may resolve either to a module, a test case class, a test method within a test case class, or a callable object which returns a TestCase or TestSuite instance. The method optionally resolves the names relative to a given module. """ parts = name.split('.') if module is None: if not parts: raise ValueError, "incomplete test name: %s" % name else: parts_copy = parts[:] while parts_copy: try: module = __import__('.'.join(parts_copy)) break except ImportError: del parts_copy[-1] if not parts_copy: raise parts = parts[1:] obj = module for part in parts: obj = getattr(obj, part) import unittest if type(obj) == types.ModuleType: return self.loadTestsFromModule(obj) elif (isinstance(obj, (type, types.ClassType)) and issubclass(obj, unittest.TestCase)): return self.loadTestsFromTestCase(obj) elif type(obj) == types.UnboundMethodType: # pass funkload options if issubclass(obj.im_class, FunkLoadTestCase): return obj.im_class(obj.__name__, self.options) else: return obj.im_class(obj.__name__) elif callable(obj): test = obj() if not isinstance(test, unittest.TestCase) and \ not isinstance(test, unittest.TestSuite): raise ValueError, \ "calling %s returned %s, not a test" % (obj,test) return test else: raise ValueError, "don't know how to make test from: %s" % obj class _ColoredTextTestResult(unittest._TextTestResult): """Colored version.""" def addSuccess(self, test): unittest.TestResult.addSuccess(self, test) if self.showAll: self.stream.writeln(green_str("Ok")) elif self.dots: self.stream.write(green_str('.')) def addError(self, test, err): unittest.TestResult.addError(self, test, err) if self.showAll: self.stream.writeln(red_str("ERROR")) elif self.dots: self.stream.write(red_str('E')) def addFailure(self, test, err): unittest.TestResult.addFailure(self, test, err) if self.showAll: self.stream.writeln(red_str("FAIL")) elif self.dots: self.stream.write(red_str('F')) def printErrorList(self, flavour, errors): for test, err in errors: self.stream.writeln(self.separator1) self.stream.writeln("%s: %s" % (red_str(flavour), self.getDescription(test))) self.stream.writeln(self.separator2) self.stream.writeln("%s" % err) class ColoredTextTestRunner(unittest.TextTestRunner): """Override to be color powered.""" def _makeResult(self): return _ColoredTextTestResult(self.stream, self.descriptions, self.verbosity) def run(self, test): "Run the given test case or test suite." result = self._makeResult() startTime = time.time() test(result) stopTime = time.time() timeTaken = float(stopTime - startTime) result.printErrors() self.stream.writeln(result.separator2) run = result.testsRun self.stream.writeln("Ran %d test%s in %.3fs" % (run, run != 1 and "s" or "", timeTaken)) self.stream.writeln() if not result.wasSuccessful(): self.stream.write(red_str("FAILED") + " (") failed, errored = map(len, (result.failures, result.errors)) if failed: self.stream.write("failures=%d" % failed) if errored: if failed: self.stream.write(", ") self.stream.write("errors=%d" % errored) self.stream.writeln(")") else: self.stream.writeln(green_str("OK")) return result def filter_testcases(suite, cpattern, negative_pattern=False): """Filter a suite with test names that match the compiled regex pattern.""" new = unittest.TestSuite() for test in suite._tests: if isinstance(test, unittest.TestCase): name = test.id() # Full test name: package.module.class.method name = name[1 + name.rfind('.'):] # extract method name if cpattern.search(name): if not negative_pattern: new.addTest(test) elif negative_pattern: new.addTest(test) else: filtered = filter_testcases(test, cpattern, negative_pattern) if filtered: new.addTest(filtered) return new def display_testcases(suite): """Display test cases of the suite.""" for test in suite._tests: if isinstance(test, unittest.TestCase): name = test.id() name = name[1 + name.find('.'):] print name else: display_testcases(test) class TestProgram(unittest.TestProgram): """Override to add a python module and more options.""" USAGE = """%prog [options] file [class.method|class|suite] [...] %prog launch a FunkLoad unit test. A FunkLoad unittest use a configuration file named [class].conf, this configuration is overriden by the command line options. See http://funkload.nuxeo.org/ for more information. Examples ======== %prog myFile.py Run all tests (including doctest with python2.4). %prog myFile.py test_suite Run suite named test_suite. %prog myFile.py MyTestCase.testSomething Run a single test MyTestCase.testSomething. %prog myFile.py MyTestCase Run all 'test*' test methods and doctest in MyTestCase. %prog myFile.py MyTestCase -u http://localhost Same against localhost. %prog myDocTest.txt Run doctest from plain text file (requires python2.4). %prog myDocTest.txt -d Run doctest with debug output (requires python2.4). %prog myfile.py -V Run default set of tests and view in real time each page fetch with firefox. %prog myfile.py MyTestCase.testSomething -l 3 -n 100 Run MyTestCase.testSomething, reload one hundred time the page 3 without concurrency and as fast as possible. Output response time stats. You can loop on many pages using slice -l 2:4. %prog myFile.py -e [Ss]ome Run all tests that match the regex [Ss]ome. %prog myFile.py -e '!xmlrpc$' Run all tests that does not ends with xmlrpc. %prog myFile.py --list List all the test names. %prog -h More options. """ def __init__(self, module=None, defaultTest=None, argv=None, testRunner=None, testLoader=unittest.defaultTestLoader): if argv is None: argv = sys.argv self.module = module self.testNames = None self.verbosity = 1 self.color = True self.defaultTest = defaultTest self.testLoader = testLoader self.progName = os.path.basename(argv[0]) self.parseArgs(argv) self.testRunner = testRunner self.checkAsDocFile = False module = self.module if type(module) == type(''): try: self.module = __import__(module) except ImportError: global g_has_doctest if g_has_doctest: # may be a doc file case self.checkAsDocFile = True else: raise else: for part in module.split('.')[1:]: self.module = getattr(self.module, part) else: self.module = module self.loadTests() if self.list_tests: display_testcases(self.test) else: self.runTests() def loadTests(self): """Load unit and doc tests from modules or names.""" if self.checkAsDocFile: self.test = DocFileSuite(os.path.abspath(self.module), module_relative=False) else: if self.testNames is None: self.test = self.testLoader.loadTestsFromModule(self.module) else: self.test = self.testLoader.loadTestsFromNames(self.testNames, self.module) if self.test_name_pattern is not None: test_name_pattern = self.test_name_pattern negative_pattern = False if test_name_pattern.startswith('!'): test_name_pattern = test_name_pattern[1:] negative_pattern = True cpattern = re.compile(test_name_pattern) self.test = filter_testcases(self.test, cpattern, negative_pattern) def parseArgs(self, argv): """Parse programs args.""" global g_doctest_verbose parser = OptionParser(self.USAGE, formatter=TitledHelpFormatter(), version="FunkLoad %s" % get_version()) parser.add_option("-q", "--quiet", action="store_true", help="Minimal output.") parser.add_option("-v", "--verbose", action="store_true", help="Verbose output.") parser.add_option("-d", "--debug", action="store_true", help="FunkLoad and doctest debug output.") parser.add_option("--debug-level", type="int", help="Debug level 2 is more verbose.") parser.add_option("-u", "--url", type="string", dest="main_url", help="Base URL to bench without ending '/'.") parser.add_option("-m", "--sleep-time-min", type="string", dest="ftest_sleep_time_min", help="Minumum sleep time between request.") parser.add_option("-M", "--sleep-time-max", type="string", dest="ftest_sleep_time_max", help="Maximum sleep time between request.") parser.add_option("--dump-directory", type="string", dest="dump_dir", help="Directory to dump html pages.") parser.add_option("-V", "--firefox-view", action="store_true", help="Real time view using firefox, " "you must have a running instance of firefox " "in the same host.") parser.add_option("--no-color", action="store_true", help="Monochrome output.") parser.add_option("-l", "--loop-on-pages", type="string", dest="loop_steps", help="Loop as fast as possible without concurrency " "on pages, expect a page number or a slice like 3:5." " Output some statistics.") parser.add_option("-n", "--loop-number", type="int", dest="loop_number", default=10, help="Number of loop.") parser.add_option("--accept-invalid-links", action="store_true", help="Do not fail if css/image links are " "not reachable.") parser.add_option("--simple-fetch", action="store_true", help="Don't load additional links like css " "or images when fetching an html page.") parser.add_option("--stop-on-fail", action="store_true", help="Stop tests on first failure or error.") parser.add_option("-e", "--regex", type="string", default=None, help="The test names must match the regex.") parser.add_option("--list", action="store_true", help="Just list the test names.") options, args = parser.parse_args() if self.module is None: if len(args) == 0: parser.error("incorrect number of arguments") # remove the .py module = args[0] if module.endswith('.py'): module = os.path.basename(os.path.splitext(args[0])[0]) self.module = module else: args.insert(0, self.module) if options.verbose: self.verbosity = 2 if options.quiet: self.verbosity = 0 g_doctest_verbose = False if options.debug or options.debug_level: options.ftest_debug_level = 1 options.ftest_log_to = 'console file' g_doctest_verbose = True else: options.ftest_log_to = 'file' if options.debug_level: options.ftest_debug_level = int(options.debug_level) self.color = not options.no_color self.test_name_pattern = options.regex self.list_tests = options.list # set testloader options self.testLoader.options = options if self.defaultTest is not None: self.testNames = [self.defaultTest] elif len(args) > 1: self.testNames = args[1:] # else we have to load all module test def runTests(self): """Launch the tests.""" if self.testRunner is None: if self.color: self.testRunner = ColoredTextTestRunner( verbosity=self.verbosity) else: self.testRunner = unittest.TextTestRunner( verbosity=self.verbosity) result = self.testRunner.run(self.test) sys.exit(not result.wasSuccessful()) # ------------------------------------------------------------ # main # def main(): """Default main.""" # enable to load module in the current path cur_path = os.path.abspath(os.path.curdir) sys.path.insert(0, cur_path) # use our testLoader test_loader = TestLoader() TestProgram(testLoader=test_loader) if __name__ == '__main__': main() PKT;4nRRfunkload/ZopeTestCase.py# (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """FunkLoad test case for Zope. $Id: ZopeTestCase.py 30282 2005-12-05 12:52:30Z bdelbosc $ """ import time from socket import error as SocketError from FunkLoadTestCase import FunkLoadTestCase class ZopeTestCase(FunkLoadTestCase): """Common zope 2.8 tasks.""" def zopeRestart(self, zope_url, admin_id, admin_pwd, time_out=600): """Stop and Start Zope server.""" self.setBasicAuth(admin_id, admin_pwd) params = {"manage_restart:action": "Restart"} url = "%s/Control_Panel" % zope_url self.post(url, params, description="Restarting Zope server") down = True time_start = time.time() while(down): time.sleep(2) try: self.get(url, description="Checking zope presence") except SocketError: if time.time() - time_start > time_out: self.fail('Zope restart time out %ss' % time_out) else: down = False self.clearBasicAuth() def zopePackZodb(self, zope_url, admin_id, admin_pwd, database="main", days=0): """Pack a zodb database.""" self.setBasicAuth(admin_id, admin_pwd) url = '%s/Control_Panel/Database/%s/manage_pack' % ( zope_url, database) params = {'days:float': str(days)} resp = self.post(url, params, description="Packing %s Zodb, removing previous " "revisions of objects that are older than %s day(s)." % (database, days), ok_codes=[200, 302, 500]) if resp.code == 500: if self.getBody().find( "Error Value: The database has already been packed") == -1: self.fail("Pack_zodb return a code 500.") else: self.logd('Zodb has already been packed.') self.clearBasicAuth() def zopeFlushCache(self, zope_url, admin_id, admin_pwd, database="main"): """Remove all objects from all ZODB in-memory caches.""" self.setBasicAuth(admin_id, admin_pwd) url = "%s/Control_Panel/Database/%s/manage_minimize" % (zope_url, database) self.get(url, description="Flush %s Zodb cache" % database) def zopeAddExternalMethod(self, parent_url, admin_id, admin_pwd, method_id, module, function, run_it=True): """Add an External method an run it.""" self.setBasicAuth(admin_id, admin_pwd) params = [["id", method_id], ["title", ""], ["module", module], ["function", function], ["submit", " Add "]] url = parent_url url += "/manage_addProduct/ExternalMethod/manage_addExternalMethod" resp = self.post(url, params, ok_codes=[200, 302, 400], description="Adding %s external method" % method_id) if resp.code == 400: if self.getBody().find('is invalid - it is already in use.') == -1: self.fail('Error got 400 on manage_addExternalMethod') else: self.logd('External method already exists') if run_it: self.get('%s/%s' % (parent_url, method_id), description="Execute %s external method" % method_id) self.clearBasicAuth() PKT;4kϤfunkload/CredentialFile.py# (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """A file credential server/controller. $Id: CredentialFile.py 30282 2005-12-05 12:52:30Z bdelbosc $ """ import sys from ConfigParser import NoOptionError from XmlRpcBase import XmlRpcBaseServer, XmlRpcBaseController from CredentialBase import CredentialBaseServer # ------------------------------------------------------------ # classes # class Group: """A class to handle groups.""" def __init__(self, name): self.name = name self.index = 0 self.count = 0 self.users = [] def add(self, user): """Add a user to the group.""" if not self.users.count(user): self.users.append(user) def __len__(self): """Return the lenght of group.""" return len(self.users) def next(self): """Return the next user or the group. loop from begining.""" nb_users = len(self.users) if nb_users == 0: raise ValueError('No users for group %s' % self.name) self.index = self.count % nb_users user = self.users[self.index] self.count += 1 return user def __repr__(self): """Representation.""" return '' % ( self.name, self.count, self.index, len(self)) # ------------------------------------------------------------ # Server # class CredentialFileServer(XmlRpcBaseServer, CredentialBaseServer): """A file credential server.""" server_name = "file_credential" method_names = XmlRpcBaseServer.method_names + [ 'getCredential', 'listCredentials', 'listGroups'] credential_sep = ':' # login:password users_sep = ',' # group_name:user1, user2 def __init__(self, argv=None): self.lofc = 0 self._groups = {} self._passwords = {} XmlRpcBaseServer.__init__(self, argv) def _init_cb(self, conf, options): """init procedure to override in sub classes.""" credentials_path = conf.get('server', 'credentials_path') self.lofc = conf.getint('server', 'loop_on_first_credentials') self._loadPasswords(credentials_path) try: groups_path = conf.get('server', 'groups_path') self._loadGroups(groups_path) except NoOptionError: pass def _loadPasswords(self, file_path): """Load a password file.""" self.logd("CredentialFile use credential file %s." % file_path) lines = open(file_path).readlines() self._groups = {} group = Group('default') self._groups[None] = group for line in lines: line = line.strip() if not line or line.startswith('#'): continue user, password = [x.strip() for x in line.split( self.credential_sep, 1)] self._passwords[user] = password if not self.lofc or len(group) < self.lofc: group.add(user) def _loadGroups(self, file_path): """Load a group file.""" self.logd("CredentialFile use group file %s." % file_path) lines = open(file_path).readlines() for line in lines: line = line.strip() if not line or line.startswith('#'): continue name, users = [x.strip() for x in line.split( self.credential_sep, 1)] users = filter( None, [user.strip() for user in users.split(self.users_sep)]) group = self._groups.setdefault(name, Group(name)) for user in users: if self.lofc and len(group) >= self.lofc: break if self._passwords.has_key(user): group.add(user) else: self.logd('Missing password for %s in group %s' % (user, name)) # # RPC def getCredential(self, group=None): """Return a credential from group if specified. Credential are taken incrementally in a loop. """ user = self._groups[group].next() password = self._passwords[user] self.logd("getCredential(%s) return (%s, %s)" % ( group, user, password)) return (user, password) def listCredentials(self, group=None): """Return a list of credentials.""" if group is None: ret = list(self._passwords) else: users = self._groups[group].users ret = [(user, self._passwords[user]) for user in users] self.logd("listUsers(%s) return (%s)" % (group, ret)) return ret def listGroups(self): """Return a list of groups.""" ret = filter(None, self._groups.keys()) self.logd("listGroup() return (%s)" % str(ret)) return ret # ------------------------------------------------------------ # Controller # class CredentialFileController(XmlRpcBaseController): """A file credential controller.""" server_class = CredentialFileServer def test(self): """Testing credential server.""" server = self.server self.log(server.listGroups()) for i in range(10): self.log("%s getCredential() ... " % i) user, password = server.getCredential() self.log(" return (%s, %s)\n" % (user, password)) for group in server.listGroups(): self.log("group %s\n" % group) self.log(" content: %s\n" % server.listCredentials(group)) return 0 # ------------------------------------------------------------ # main # def main(): """Control credentiald server.""" ctl = CredentialFileController() sys.exit(ctl()) if __name__ == '__main__': main() PKT;4n$OOfunkload/CredentialRandom.py# (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """A random credential server/controller. $Id: CredentialRandom.py 28385 2005-10-18 09:29:24Z bdelbosc $ """ import sys from Lipsum import Lipsum from XmlRpcBase import XmlRpcBaseServer, XmlRpcBaseController from CredentialBase import CredentialBaseServer # ------------------------------------------------------------ # Server # class CredentialRandomServer(XmlRpcBaseServer, CredentialBaseServer): """A random credential server.""" server_name = "random_credential" method_names = XmlRpcBaseServer.method_names + [ 'getCredential', 'listCredentials', 'listGroups'] def __init__(self, argv=None): XmlRpcBaseServer.__init__(self, argv) self.lipsum = Lipsum() def getCredential(self, group=None): """Return a random (login, password). return a random user login, the login is taken from the lipsum vocabulary so the number of login is limited to the length of the vocabulary. The group asked will prefix the login name. The password is just the reverse of the login, this give a coherent behaviour if it return twice the same credential. """ self.logd('getCredential(%s) request.' % group) # use group as login prefix user = (group or 'user') + '_' + self.lipsum.getWord() # pwd is the reverse of the login tmp = list(user) tmp.reverse() password = ''.join(tmp) self.logd(" return (%s, %s)" % (user, password)) return (user, password) def listCredentials(self, group=None): """Return a list of 10 random credentials.""" self.logd('listCredentials request.') return [self.getCredential(group) for x in range(10)] def listGroups(self): """Retrun a list of 10 random group name.""" self.logd('listGroups request.') lipsum = self.lipsum return ['grp' + lipsum.getUniqWord(length_min=2, length_max=3) for x in range(10)] # ------------------------------------------------------------ # Controller # class CredentialRandomController(XmlRpcBaseController): """A random credential controller.""" server_class = CredentialRandomServer def test(self): """Testing credential server.""" server = self.server self.log(server.listGroups()) for i in range(10): self.log("%s getCredential() ... " % i) user, password = server.getCredential() self.log(" return (%s, %s)\n" % (user, password)) for group in server.listGroups(): self.log("group %s\n" % group) self.log(" content: %s\n" % server.listCredentials(group)) return 0 # ------------------------------------------------------------ # main # def main(): """Control credentiald server.""" ctl = CredentialRandomController() sys.exit(ctl()) if __name__ == '__main__': main() PKb4Q_G66funkload/CPS338TestCase.py# (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """FunkLoad test case for Nuxeo CPS. $Id: CPSTestCase.py 24728 2005-08-31 08:13:54Z bdelbosc $ """ import time import random from Lipsum import Lipsum from ZopeTestCase import ZopeTestCase class CPSTestCase(ZopeTestCase): """Common CPS tasks. setUp must set a server_url attribute.""" cps_test_case_version = (3, 3, 8) server_url = None _lipsum = Lipsum() _all_langs = ['en', 'fr', 'de', 'it', 'es', 'pt_BR', 'nl', 'mg', 'ro', 'eu'] _default_langs = _all_langs[:4] _cps_login = None # ------------------------------------------------------------ # cps actions # def cpsLogin(self, login, password, comment=None): """Log in a user. Raise on invalid credential.""" self._cps_login = None params = [['__ac_name', login], ['__ac_password', password], ['__ac_persistent', 'on'], ['submit', 'Login'], ] self.post("%s/logged_in" % self.server_url, params, description="Log in user [%s] %s" % (login, comment or '')) # assume we are logged in if we have a logout link... self.assert_('%s/logout' % self.server_url in self.listHref(), 'invalid credential: [%s:%s].' % (login, password)) self._cps_login = login def cpsLogout(self): """Log out the current user.""" if self._cps_login is not None: self.get('%s/logout' % self.server_url, description="Log out [%s]" % self._cps_login) def cpsCreateSite(self, admin_id, admin_pwd, manager_id, manager_password, manager_mail, langs=None, title=None, description=None, interface="portlets", zope_url=None, site_id=None): """Create a CPS Site. if zope_url or site_id is not provided guess them from the server_url. """ if zope_url is None or site_id is None: zope_url, site_id = self.cpsGuessZopeUrl() self.setBasicAuth(admin_id, admin_pwd) params = {"id": site_id, "title": title or "CPS Portal", "description": description or "A funkload cps test site", "manager_id": manager_id, "manager_password": manager_password, "manager_password_confirmation": manager_password, "manager_email": manager_mail, "manager_sn": "CPS", "manager_givenName": "Manager", "langs_list:list": langs or self._default_langs, "interface": interface, "submit": "Create"} self.post("%s/manage_addProduct/CPSDefault/manage_addCPSDefaultSite" % zope_url, params, description="Create a CPS Site") self.clearBasicAuth() def cpsCreateGroup(self, group_name): """Create a cps group.""" server_url = self.server_url params = [["dirname", "groups"], ["id", ""], ["widget__group", group_name], ["widget__members:tokens:default", ""], ["cpsdirectory_entry_create_form:method", "Create"]] self.post("%s/" % server_url, params) self.assert_(self.getLastUrl().find('psm_entry_created')!=-1, 'Failed to create group %s' % group_name) def cpsVerifyGroup(self, group_name): """Check existance or create a cps group.""" server_url = self.server_url params = [["dirname", "groups"], ["id", group_name],] if self.exists("%s/cpsdirectory_entry_view" % server_url, params, description="Check that group [%s] exists." % group_name): self.logd('Group %s exists.') else: self.cpsCreateGroup(group_name) def cpsCreateUser(self, user_id=None, user_pwd=None, user_givenName=None, user_sn=None, user_email=None, groups=None): """Create a cps user with the Member role. return login, pwd""" lipsum = self._lipsum sign = lipsum.getUniqWord() user_id = user_id or 'fl_' + sign.lower() user_givenName = user_givenName or lipsum.getWord().capitalize() user_sn = user_sn or user_id.upper() user_email = user_email or "root@127.0.0.01" user_pwd = user_pwd or lipsum.getUniqWord(length_min=6) params = [["dirname", "members"], ["id", ""], ["widget__id", user_id], ["widget__password", user_pwd], ["widget__confirm", user_pwd], ["widget__givenName", user_givenName], ["widget__sn", user_sn], ["widget__email", user_email], ["widget__roles:tokens:default", ""], ["widget__roles:list", "Member"], ["widget__groups:tokens:default", ""], ["widget__homeless", "0"], ["cpsdirectory_entry_create_form:method", "Create"]] for group in groups: params.append(["widget__groups:list", group]) self.post("%s/" % self.server_url, params, description="Create user [%s]" % user_id) self.assert_(self.getLastUrl().find('psm_entry_created')!=-1, 'Failed to create user %s' % user_id) return user_id, user_pwd def cpsVerifyUser(self, user_id=None, user_pwd=None, user_givenName=None, user_sn=None, user_email=None, groups=None): """Verify if user exists or create him. return login, pwd if user exists pwd is None. """ if user_id: params = [["dirname", "members"], ["id", user_id],] if self.exists( "%s/cpsdirectory_entry_view" % self.server_url, params): self.logd('User %s exists.') return user_id, None return self.cpsCreateUser(user_id, user_pwd, user_givenName, user_sn, user_email, groups) def cpsSetLocalRole(self, url, name, role): """Setup local role role to url.""" params = [["member_ids:list", name], ["member_role", role]] self.post("%s/folder_localrole_add" % url, params, description="Grant local role %s to %s" % (role, name)) def cpsCreateSection(self, parent_url, title, description="ftest section for funkload testing.", lang=None): """Create a section.""" return self.cpsCreateFolder('Section', parent_url, title, description, lang or self.cpsGetRandomLanguage()) def cpsCreateWorkspace(self, parent_url, title, description="ftest workspace for funkload testing.", lang=None): """Create a workspace.""" return self.cpsCreateFolder('Workspace', parent_url, title, description, lang or self.cpsGetRandomLanguage()) def cpsCreateFolder(self, type, parent_url, title, description, lang): """Create a section or a workspace. Return the section full url.""" params = [["type_name", type], ["widget__Title", title], ["widget__Description", description], ["widget__LanguageSelectorCreation", lang], ["widget__hidden_folder", "0"], ["cpsdocument_create_button", "Create"]] self.post("%s/cpsdocument_create_form" % parent_url, params, "Create a %s" % type) return self.cpsCleanUrl(self.getLastBaseUrl()) def cpsCreateDocument(self, parent_url): """Create a simple random document. return a tuple: (doc_url, doc_id) """ language = self.cpsGetRandomLanguage() title = self._lipsum.getSubject(uniq=True, prefix='test %s' % language) params = [["type_name", "Document"], ["widget__Title", title], ["widget__Description", self._lipsum.getSubject(10)], ["widget__LanguageSelectorCreation", language], ["widget__content", self._lipsum.getMessage()], ["widget__content_rformat", "text"], ["cpsdocument_create_button", "Create"]] self.post("%s/cpsdocument_create_form" % parent_url, params, description="Creating a document") self.assert_(self.getLastUrl().find('psm_content_created')!=-1, 'Failed to create [%s] in %s/.' % (title, parent_url)) doc_url = self.cpsCleanUrl(self.getLastBaseUrl()) doc_id = doc_url.split('/')[-1] return doc_url, doc_id def cpsCreateNewsItem(self, parent_url): """Create a random news. return a tuple: (doc_url, doc_id).""" language = self.cpsGetRandomLanguage() title = self._lipsum.getSubject(uniq=True, prefix='test %s' % language) params = [["type_name", "News Item"], ["widget__Title", title], ["widget__Description", self._lipsum.getSubject(10)], ["widget__LanguageSelectorCreation", language], ["widget__photo_title", "none"], ["widget__photo_filename", ""], ["widget__photo_choice", "keep"], ["widget__photo", ""], ["widget__photo_resize", "img_auto_size"], ["widget__photo_rposition", "left"], ["widget__photo_subtitle", ""], ["widget__content", self._lipsum.getMessage()], ["widget__content_rformat", "text"], ["widget__Subject:tokens:default", ""], ["widget__Subject:list", "Business"], # prevent invalid date depending on ui locale ["widget__publication_date_date", time.strftime('01/01/%Y')], ["widget__publication_date_hour", time.strftime('%H')], ["widget__publication_date_minute", time.strftime('%M')], ["cpsdocument_create_button", "Create"]] self.post("%s/cpsdocument_create_form" % parent_url, params, description="Creating a news item") last_url = self.getLastUrl() self.assert_('psm_content_created' in last_url, 'Failed to create [%s] in %s/.' % (title, parent_url)) doc_url = self.cpsCleanUrl(self.getLastBaseUrl()) doc_id = doc_url.split('/')[-1] return doc_url, doc_id def cpsChangeUiLanguage(self, lang): """Change the ui language and return the referer page.""" self.get("%s/cpsportlet_change_language" % self.server_url, params=[['lang', lang]], description="Change UI language to %s" % lang) # ------------------------------------------------------------ # helpers # def cpsGetRandomLanguage(self): """Return a random language.""" return random.choice(self._all_langs) def cpsGuessZopeUrl(self, cps_url=None): """Guess a zope url and site_id from a CPS Site url. return a tuple (zope_url, site_id) """ if cps_url is None: cps_url = self.server_url site_id = cps_url.split('/')[-1] zope_url = cps_url[:-(len(site_id)+1)] return zope_url, site_id def cpsSearchDocId(self, doc_id): """Return the list of url that ends with doc_id. Using catalog search.""" params = [["SearchableText", doc_id]] self.post("%s/search_form" % self.server_url, params, description="Searching doc_id %s" % doc_id) ret = self.cpsListDocumentHref(pattern='%s$' % doc_id) self.logd('found %i link ends with %s' % (len(ret), doc_id)) return ret def cpsCleanUrl(self, url_in): """Try to remove server_url and clean ending.""" url = url_in server_url = self.server_url for ending in ('/', '/view', '/folder_contents', '/folder_view', '/cpsdocument_metadata', '/cpsdocument_edit_form'): if url.endswith(ending): url = url[:-len(ending)] if url.startswith(server_url): url = url[len(server_url):] return url def cpsListDocumentHref(self, pattern=None): """Return a clean list of document href that matches pattern. Try to remove server_url and other cps trailings, return a list of uniq url.""" ret = [] for href in [self.cpsCleanUrl(x) for x in self.listHref(pattern)]: if href not in ret: ret.append(href) return ret PKT;4x. ]]funkload/CPSTestCase.py# (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """FunkLoad test case for Nuxeo CPS. $Id: CPSTestCase.py 24728 2005-08-31 08:13:54Z bdelbosc $ """ from CPS340TestCase import CPSTestCase PK$M[6,$$funkload/ReportBuilder.py# (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """Create an ReST or HTML report with charts from a FunkLoad bench xml result. Producing html and png chart require python-docutils and python-gdchart $Id: ReportBuilder.py 24737 2005-08-31 09:00:16Z bdelbosc $ """ USAGE = """%prog [options] xmlfile %prog analyze a FunkLoad bench xml result file and output a report. See http://funkload.nuxeo.org/ for more information. Examples ======== %prog funkload.xml ReST rendering into stdout. %prog --html -o /tmp funkload.xml Build an HTML report in /tmp. %prog -h More options. """ import os import xml.parsers.expat from optparse import OptionParser, TitledHelpFormatter from ReportStats import AllResponseStat, PageStat, ResponseStat, TestStat from ReportStats import MonitorStat, ErrorStat from ReportRenderer import RenderRst, RenderHtml from utils import trace, get_version # ------------------------------------------------------------ # Xml parser # class FunkLoadXmlParser: """Parse a funkload xml results.""" def __init__(self): """Init setup expat handlers.""" parser = xml.parsers.expat.ParserCreate() parser.CharacterDataHandler = self.handleCharacterData parser.StartElementHandler = self.handleStartElement parser.EndElementHandler = self.handleEndElement parser.StartCdataSectionHandler = self.handleStartCdataSection parser.EndCdataSectionHandler = self.handleEndCdataSection self.parser = parser self.current_element = [{'name': 'root'}] self.is_recording_cdata = False self.current_cdata = '' self.cycles = None self.cycle_duration = 0 self.stats = {} # cycle stats self.monitor = {} # monitoring stats self.config = {} self.error = {} def parse(self, xml_file): """Do the parsing.""" try: self.parser.ParseFile(file(xml_file)) except xml.parsers.expat.ExpatError, msg: if (self.current_element[-1]['name'] == 'funkload' and str(msg).startswith('no element found')): print "Missing tag." else: print 'Error: invalid xml bench result file' if len(self.current_element) <= 1 or ( self.current_element[1]['name'] != 'funkload'): print """Note that you can generate a report only for a bench result done with fl-run-bench (and not on a test result done with fl-run-test).""" else: print """You may need to remove non ascii char that comes from error pages catched during the bench. iconv or recode may help you.""" print 'Xml parser element stack: %s' % [ x['name'] for x in self.current_element] raise def handleStartElement(self, name, attrs): """Called by expat parser on start element.""" if name == 'funkload': self.config['version'] = attrs['version'] self.config['time'] = attrs['time'] elif name == 'config': self.config[attrs['key']] = attrs['value'] if attrs['key'] == 'duration': self.cycle_duration = attrs['value'] elif name == 'header': # save header as extra response attribute headers = self.current_element[-2]['attrs'].setdefault( 'headers', {}) headers[str(attrs['name'])] = str(attrs['value']) self.current_element.append({'name': name, 'attrs': attrs}) def handleEndElement(self, name): """Processing element.""" element = self.current_element.pop() attrs = element['attrs'] if name == 'testResult': cycle = attrs['cycle'] stats = self.stats.setdefault(cycle, {'response_step': {}}) stat = stats.setdefault( 'test', TestStat(cycle, self.cycle_duration, attrs['cvus'])) stat.add(attrs['result'], attrs['pages'], attrs.get('xmlrpc', 0), attrs['redirects'], attrs['images'], attrs['links'], attrs['connection_duration'], attrs.get('traceback')) stats['test'] = stat elif name == 'response': cycle = attrs['cycle'] stats = self.stats.setdefault(cycle, {'response_step':{}}) stat = stats.setdefault( 'response', AllResponseStat(cycle, self.cycle_duration, attrs['cvus'])) stat.add(attrs['time'], attrs['result'], attrs['duration']) stats['response'] = stat stat = stats.setdefault( 'page', PageStat(cycle, self.cycle_duration, attrs['cvus'])) stat.add(attrs['thread'], attrs['step'], attrs['time'], attrs['result'], attrs['duration'], attrs['type']) stats['page'] = stat step = '%s.%s' % (attrs['step'], attrs['number']) stat = stats['response_step'].setdefault( step, ResponseStat(attrs['step'], attrs['number'], attrs['cvus'])) stat.add(attrs['type'], attrs['result'], attrs['url'], attrs['duration'], attrs.get('description')) stats['response_step'][step] = stat if attrs['result'] != 'Successful': result = str(attrs['result']) stats = self.error.setdefault(result, []) stats.append(ErrorStat( attrs['cycle'], attrs['step'], attrs['number'], attrs.get('code'), attrs.get('headers'), attrs.get('body'), attrs.get('traceback'))) elif name == 'monitor': host = attrs.get('host') stats = self.monitor.setdefault(host, []) stats.append(MonitorStat(attrs)) def handleStartCdataSection(self): """Start recording cdata.""" self.is_recording_cdata = True self.current_cdata = '' def handleEndCdataSection(self): """Save CDATA content into the parent element.""" self.is_recording_cdata = False # assume CDATA is encapsulate in a container element name = self.current_element[-1]['name'] self.current_element[-2]['attrs'][name] = self.current_cdata self.current_cdata = '' def handleCharacterData(self, data): """Extract cdata.""" if self.is_recording_cdata: self.current_cdata += data # ------------------------------------------------------------ # main # def main(): """ReportBuilder main.""" parser = OptionParser(USAGE, formatter=TitledHelpFormatter(), version="FunkLoad %s" % get_version()) parser.add_option("-H", "--html", action="store_true", default=False, dest="html", help="Produce an html report.") parser.add_option("-P", "--with-percentiles", action="store_true", default=True, dest="with_percentiles", help=("Include percentiles in tables, use 10%, 50% and" " 90% for charts, default option.")) parser.add_option("--no-percentiles", action="store_false", dest="with_percentiles", help=("No percentiles in tables display min, " "avg and max in charts.")) cur_path = os.path.abspath(os.path.curdir) parser.add_option("-o", "--output-directory", type="string", dest="output_dir", help="Directory to store reports.", default=cur_path) options, args = parser.parse_args() if len(args) != 1: parser.error("incorrect number of arguments") options.xml_file = args[0] xml_parser = FunkLoadXmlParser() xml_parser.parse(options.xml_file) if options.html: trace("Creating html report: ...") html_path = RenderHtml(xml_parser.config, xml_parser.stats, xml_parser.error, xml_parser.monitor, options)() trace("done: \n") trace("file://%s\n" % html_path) else: print str(RenderRst(xml_parser.config, xml_parser.stats, xml_parser.error, xml_parser.monitor, options)) if __name__ == '__main__': main() PKLb6 >>funkload/version.py# (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # # """The FunkLoad version. $Id: version.py 51277 2007-03-02 08:38:22Z bdelbosc $ """ __version__ = '1.6.1' PKT;4rMl'l'funkload/Monitor.py# (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """A Linux monitor server/controller. $Id: Monitor.py 28395 2005-10-18 14:20:47Z bdelbosc $ """ import sys import re from time import time, sleep from threading import Thread from XmlRpcBase import XmlRpcBaseServer, XmlRpcBaseController # ------------------------------------------------------------ # monitor readers # def read_load_info(): """Read the current system load from /proc/loadavg.""" loadavg = open("/proc/loadavg").readline() loadavg = loadavg[:-1] # Contents are space separated: # 5, 10, 15 min avg. load, running proc/total threads, last pid stats = loadavg.split() running = stats[3].split("/") load_stats = {} load_stats['loadAvg1min'] = stats[0] load_stats['loadAvg5min'] = stats[1] load_stats['loadAvg15min'] = stats[2] load_stats['running'] = running[0] load_stats['tasks'] = running[1] return load_stats def read_cpu_usage(): """Read the current system cpu usage from /proc/stat.""" lines = open("/proc/stat").readlines() for line in lines: #print "l = %s" % line l = line.split() if len(l) < 5: continue if l[0].startswith('cpu'): # cpu = sum of usr, nice, sys cpu = long(l[1]) + long(l[2]) + long(l[3]) idl = long(l[4]) return {'CPUTotalJiffies': cpu, 'IDLTotalJiffies': idl, } return {} def read_mem_info(kernel_rev): """Read the current status of memory from /proc/meminfo.""" meminfo_fields = ["MemTotal", "MemFree", "SwapTotal", "SwapFree"] meminfo = open("/proc/meminfo") if kernel_rev <= 2.4: # Kernel 2.4 has extra lines of info, duplicate of later info meminfo.readline() meminfo.readline() meminfo.readline() lines = meminfo.readlines() meminfo.close() meminfo_stats = {} for line in lines: line = line[:-1] stats = line.split() field = stats[0][:-1] if field in meminfo_fields: meminfo_stats[field[0].lower()+field[1:]] = stats[1] return meminfo_stats def read_net_info(interface='eth0'): """Read the stats from an interface.""" ifaces = open( "/proc/net/dev" ) # Skip the information banner ifaces.readline() ifaces.readline() # Read the rest of the lines lines = ifaces.readlines() ifaces.close() # Process the interface lines net_stats = {} for line in lines: # Parse the interface line # Interface is followed by a ':' and then bytes, possibly with # no spaces between : and bytes line = line[:-1] (device, data) = line.split(':') # Get rid of leading spaces device = device.lstrip() # get the stats stats = data.split() if device == interface: net_stats['receiveBytes'] = stats[0] net_stats['receivePackets'] = stats[1] net_stats['transmitBytes'] = stats[8] net_stats['transmitPackets'] = stats[9] return net_stats # ------------------------------------------------------------ # classes # class MonitorInfo: """A simple class to collect info.""" def __init__(self, host, kernel_rev, interface): self.time = time() self.host = host self.interface = interface for infos in (read_cpu_usage(), read_load_info(), read_mem_info(kernel_rev), read_net_info(interface)): for key, value in infos.items(): setattr(self, key, value) def __repr__(self, extra_key=None): text = " 2.6) or (kernel_rev < 2.4): sys.stderr.write( "Sorry, kernel v%0.1f is not supported\n" % kernel_rev) sys.exit(-1) self._kernel_rev = kernel_rev def run(self): """Thread jobs.""" self._running = True while self._running: sleep(self._interval) if self._recorder_count > 0: self.monitor() def stop(self): """Stop the thread.""" self._running = False def monitor(self): """The monitor task.""" self.records.append(MonitorInfo(self._host, self._kernel_rev, self._interface)) def startRecord(self): """Enable recording.""" self._recorder_count += 1 def stopRecord(self): """Stop recording.""" self._recorder_count -= 1 def countRecorders(self): """Return the number of recorder.""" return self._recorder_count # ------------------------------------------------------------ # Server # class MonitorServer(XmlRpcBaseServer): """The XML RPC monitor server.""" server_name = "monitor" method_names = XmlRpcBaseServer.method_names + [ 'startRecord', 'stopRecord', 'getResult', 'getXmlResult'] def __init__(self, argv=None): self.interval = None self.interface = None self.records = [] self._keys = {} XmlRpcBaseServer.__init__(self, argv) self._monitor = MonitorThread(self.records, self.host, self.interval, self.interface) self._monitor.start() def _init_cb(self, conf, options): """init callback.""" self.interval = conf.getfloat('server', 'interval') self.interface = conf.get('server', 'interface') def startRecord(self, key): """Start to monitor if it is the first key.""" self.logd('startRecord %s' % key) if not self._keys.has_key(key) or self._keys[key][1] is not None: self._monitor.startRecord() self._keys[key] = [len(self.records), None] return 1 def stopRecord(self, key): """Stop to monitor if it is the last key.""" self.logd('stopRecord %s' % key) if not self._keys.has_key(key) or self._keys[key][1] is not None: return 0 self._keys[key] = [self._keys[key][0], len(self.records)] self._monitor.stopRecord() return 1 def getResult(self, key): """Return stats for key.""" self.logd('getResult %s' % key) if key not in self._keys.keys(): return [] ret = self.records[self._keys[key][0]:self._keys[key][1]] return ret def getXmlResult(self, key): """Return result as xml.""" self.logd('getXmlResult %s' % key) ret = self.getResult(key) ret = [stat.__repr__(key) for stat in ret] return '\n'.join(ret) def test(self): """auto test.""" key = 'internal_test_monitor' self.startRecord(key) sleep(3) self.stopRecord(key) self.log(self.records) self.log(self.getXmlResult(key)) return 1 # ------------------------------------------------------------ # Controller # class MonitorController(XmlRpcBaseController): """Monitor controller.""" server_class = MonitorServer def test(self): """Testing monitor server.""" server = self.server key = 'internal_test_monitor' server.startRecord(key) sleep(2) server.stopRecord(key) self.log(server.getXmlResult(key)) return 0 # ------------------------------------------------------------ # main # def main(): """Control monitord server.""" ctl = MonitorController() sys.exit(ctl()) def test(): """Test wihtout rpc server.""" mon = MonitorServer() mon.test() if __name__ == '__main__': main() PKH\b4<:funkload/CPS340DocTest.py# (C) Copyright 2006 Nuxeo SAS # Author: Olivier Grisel ogrisel@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """Doctest support for CPS340TestCase $Id: CPS340DocTest.py 33698 2006-03-02 08:50:41Z bdelbosc $ """ from CPS340TestCase import CPSTestCase from FunkLoadDocTest import FunkLoadDocTest class CPSDocTest(FunkLoadDocTest, CPSTestCase): """Class to use to doctest a CPS portal >>> from CPS340DocTest import CPSDocTest >>> cps_url = 'http://localhost:8080/cps' >>> fl = CPSDocTest(cps_url) >>> fl.cps_test_case_version (3, 4, 0) >>> fl.server_url == cps_url True Then you can use the CPS340TestCase API like fl.cpsLogin('manager', 'pwd'). """ def __init__(self, server_url, debug=False, debug_level=1): """init CPSDocTest server_url is the CPS server url.""" FunkLoadDocTest.__init__(self, debug=debug, debug_level=debug_level) # FunkLoadDocTest handles the init of FunkLoadTestCase which is the # same as CPSTestCase self.server_url = server_url def _test(): import doctest, CPS340DocTest return doctest.testmod(CPS340DocTest) if __name__ == "__main__": _test() PK]i6]$ funkload/FunkLoadDocTest.pyc; Cc@smdZdkZdklZdklZdkZdefdYZdZedjo endS(sQFunkLoad doc test $Id: FunkLoadDocTest.py 32254 2006-01-26 10:58:02Z bdelbosc $ N(s gettempdir(sFunkLoadTestCasesFunkLoadDocTestcBs&tZdZeddZdZRS(sClass to use in doctest. >>> from FunkLoadDocTest import FunkLoadDocTest >>> fl = FunkLoadDocTest() >>> ret = fl.get('http://localhost') >>> ret.code 200 >>> 'HTML' in ret.body True icCsdfdY}|}d|_d|_|o!d|_|o ||_q_n d|_t}t i i |d|_ t i i |d|_ ti|d|d S( sInitialise the test case.sDummycBstZRS(N(s__name__s __module__(((s6build/bdist.linux-i686/egg/funkload/FunkLoadDocTest.pysDummy)sf0.001s console filesfilesfl-doc-test.logsfl-doc-test.xmlsrunTestN(sDummysoptionsftest_sleep_time_maxsftest_sleep_time_minsdebugs ftest_log_tos debug_levels gettempdirstmp_pathsosspathsjoinsftest_log_pathsftest_result_pathsFunkLoadTestCases__init__sself(sselfsdebugs debug_levelsDummysoptionstmp_path((s6build/bdist.linux-i686/egg/funkload/FunkLoadDocTest.pys__init__'s      cCsdSdS(s FL doctestN((sself((s6build/bdist.linux-i686/egg/funkload/FunkLoadDocTest.pysrunTest9s(s__name__s __module__s__doc__sFalses__init__srunTest(((s6build/bdist.linux-i686/egg/funkload/FunkLoadDocTest.pysFunkLoadDocTests cCs#dk}dk}|i|SdS(N(sdoctestsFunkLoadDocTeststestmod(sFunkLoadDocTestsdoctest((s6build/bdist.linux-i686/egg/funkload/FunkLoadDocTest.pys_test>ss__main__( s__doc__sosstempfiles gettempdirsFunkLoadTestCases PatchWebunitsFunkLoadDocTests_tests__name__(s_testsFunkLoadTestCases gettempdirsFunkLoadDocTestsoss PatchWebunit((s6build/bdist.linux-i686/egg/funkload/FunkLoadDocTest.pys?s    #  PK]i64~w_U;U;funkload/ReportStats.pyc; `:Ec@sdZdfdYZdfdYZdfdYZdfdYZd fd YZd efd YZd fdYZdfdYZdS(s{Classes that collect statistics submitted by the result parser. $Id: ReportStats.py 24737 2005-08-31 09:00:16Z bdelbosc $ s MonitorStatcBstZdZdZRS(sCollect system monitor info.cCs1x*|iD]\}}t|||q WdS(N(sattrssitemsskeysvaluessetattrsself(sselfsattrssvalueskey((s2build/bdist.linux-i686/egg/funkload/ReportStats.pys__init__s (s__name__s __module__s__doc__s__init__(((s2build/bdist.linux-i686/egg/funkload/ReportStats.pys MonitorStats s ErrorStatcBstZdZdZRS(sCollect Error or Failure stats.cCs^||_||_||_||_|o |iph|_|pt|_||_ dS(N( scyclesselfsstepsnumberscodesheaderscopysbodysNones traceback(sselfscyclesstepsnumberscodesheadersbodys traceback((s2build/bdist.linux-i686/egg/funkload/ReportStats.pys__init__s    (s__name__s __module__s__doc__s__init__(((s2build/bdist.linux-i686/egg/funkload/ReportStats.pys ErrorStats s PercentilescBsDtZdZddedZdZdZdZdZRS(s0 Calculate Percentiles with the given stepsize. i sUNKNOWNcCs9||_||_|tjo g|_n ||_dS(N(sstepsizesselfsnamesresultssNone(sselfsstepsizesnamesresults((s2build/bdist.linux-i686/egg/funkload/ReportStats.pys__init__,s     cCs|ii|dS(sAdd a new result.N(sselfsresultssappends newresult(sselfs newresult((s2build/bdist.linux-i686/egg/funkload/ReportStats.pys addResult4scCs|i}|it|}d}x{tdd|iD]d}t |d|}y||}Wnt j o d}nXt |d|t||}q;WdS(sCompute percentiles.iiidf100.0f-1.0sperc%02dN(sselfsresultsssortslens len_resultss old_valuesrangesstepsizespercsintsindexsvalues IndexErrorssetattrsfloat(sselfspercsindexs len_resultss old_valuesresultssvalue((s2build/bdist.linux-i686/egg/funkload/ReportStats.pyscalcPercentiles8s    cCsu|id|ig}xGtdd|iD]0}d|}|id|t||fq0Wdi |SdS(NsPercentiles: %siidsperc%02ds%s=%ss, ( sselfscalcPercentilessnames fmt_stringsrangesstepsizespercsappendsgetattrsjoin(sselfspercs fmt_stringsname((s2build/bdist.linux-i686/egg/funkload/ReportStats.pys__str__Gs  $cCsd|i|i|ifSdS(Ns-Percentiles(stepsize=%r, name=%r, results=%r)(sselfsstepsizesnamesresults(sself((s2build/bdist.linux-i686/egg/funkload/ReportStats.pys__repr__Os( s__name__s __module__s__doc__sNones__init__s addResultscalcPercentiless__str__s__repr__(((s2build/bdist.linux-i686/egg/funkload/ReportStats.pys Percentiles)s    sAllResponseStatcBs)tZdZdZdZdZRS(s)Collect stat for all response in a cycle.cCs||_||_t||_h|_d|_d|_d|_d|_ d|_ d|_ d|_ d|_ d|_d|_d|_t|_tddd||_dS(Niiɚ;sstepsizeisname(scyclesselfscycle_durationsintscvuss per_secondsmaxsminsavgstotalscountssuccessserrors error_percentsrpssrps_minsrps_maxsFalses finalizeds Percentiless percentiles(sselfscyclescycle_durationscvus((s2build/bdist.linux-i686/egg/funkload/ReportStats.pys__init__Us"               cCstt|}|iit|dd|i|<|id7_|djo|i d7_ n|i d7_ t |i t||_ t |i t||_ |it|7_t|_|iit|dS(sAdd a new response to stat.iis SuccessfulN(sintsfloatsdatesdate_ssselfs per_seconds setdefaultscountsresultssuccessserrorsmaxsdurationsminstotalsFalses finalizeds percentiless addResult(sselfsdatesresultsdurationsdate_s((s2build/bdist.linux-i686/egg/funkload/ReportStats.pysaddhs&  cCs<|iodSn|io|it|i|_nt|i|i|_|io!d|it|i|_ nd}}xC|i i D]2}t||i |}t||i |}qW|io:|it|i}|djo d}n||_n||_ ||_ |iit|_dS(sCompute avg times.Nf100.0ii(sselfs finalizedscountstotalsfloatsavgsminsmaxserrors error_percentsrps_minsrps_maxs per_secondskeyssdatescycle_durationsrpss percentilesscalcPercentilessTrue(sselfsrps_maxsrpssrps_minsdate((s2build/bdist.linux-i686/egg/funkload/ReportStats.pysfinalizexs,   !        (s__name__s __module__s__doc__s__init__saddsfinalize(((s2build/bdist.linux-i686/egg/funkload/ReportStats.pysAllResponseStatSs   sSinglePageStatcBs)tZdZdZdZdZRS(sCollect stat for a single page.cCsI||_d|_t|_d|_d|_tddd||_dS(Nif0.0s Successfulsstepsizeisname( sstepsselfscountsNonesdate_ssdurationsresults Percentiless percentiles(sselfsstep((s2build/bdist.linux-i686/egg/funkload/ReportStats.pys__init__s      cCs|id7_|itjott||_n|it|7_|ii t||djo ||_ ndS(sAdd a response to a page.is SuccessfulN( sselfscountsdate_ssNonesintsfloatsdatesdurations percentiless addResultsresult(sselfsdatesresultsduration((s2build/bdist.linux-i686/egg/funkload/ReportStats.pys addResponses cCsd|i|i|ifSdS(sRepresentation.spage %s %s %ssN(sselfsstepsresultsduration(sself((s2build/bdist.linux-i686/egg/funkload/ReportStats.pys__repr__s(s__name__s __module__s__doc__s__init__s addResponses__repr__(((s2build/bdist.linux-i686/egg/funkload/ReportStats.pysSinglePageStats   sPageStatcBs)tZdZdZdZdZRS(s(Collect stat for asked pages in a cycle.cCs#ti||||h|_dS(N(sAllResponseStats__init__sselfscyclescycle_durationscvussthreads(sselfscyclescycle_durationscvus((s2build/bdist.linux-i686/egg/funkload/ReportStats.pys__init__sc Cs|ii|hdd<dh<}t|dddfjo t}nt}|o#|dcd7<|i d7_ n|d odSn|di|dt |}|i ||||iit|t|_dS( sAdd a new response to stat.scountispagesspostsgetsxmlrpciN(sselfsthreadss setdefaultsthreadsstrsrtypesTruesnew_pagesFalsescountsSinglePageStatsstepsstats addResponsesdatesresultsdurations percentiless addResultsfloats finalized( sselfsthreadsstepsdatesresultsdurationsrtypesstatsnew_page((s2build/bdist.linux-i686/egg/funkload/ReportStats.pysadds'  cCsV|iodSnx|iiD]}x|i|diD]}t|idjo_|i o0|i i |i dd}||i |i N(sselfsprotocolsserversportsurlscodesmessage(sself((s3build/bdist.linux-i686/egg/funkload/PatchWebunit.pys HR___repr__s('s__doc__sosssysstimesurlparsesurllibs urlencodeshttplibs cStringIOs mimetypess guess_typeswebunitscookieswebunit.IMGSuckers IMGSuckerswebunit.webunittests WebTestCases WebFetchers HTTPResponses HTTPErrorsVERBOSEswebunit.utilitysUploadsutilss thread_sleepsBOUNDARYs SEP_BOUNDARYs END_BOUNDARYs mimeEncodes FKLIMGSuckersWTC_logslogsNonesWTC_pageImagess pageImagessWF_fetchsfetchs HR___repr__s__repr__(s urlencodes cStringIOs END_BOUNDARYs SEP_BOUNDARYs HR___repr__s mimeEncodes HTTPResponses thread_sleeps FKLIMGSuckersUploadssysscookies IMGSuckersWTC_logs HTTPErrorsVERBOSEs guess_typeshttplibs WebFetchersWF_fetchsurlparsestimesBOUNDARYsoss WebTestCasesWTC_pageImages((s3build/bdist.linux-i686/egg/funkload/PatchWebunit.pys?!s6              %<      PK]i6S funkload/FunkLoadTestCase.pyc; Ec@sdZdkZdkZdkZdkZdklZdklZ dk l Z l Z l Z dklZdkZdkZdklZdklZdklZd klZd klZd klZlZlZd klZlZdk Z d k!l"Z"l#Z#l$Z$dk!l%Z%l&Z&l'Z'l(Z(l)Z)dk*l+Z+gZ,dei-fdYZ.de.fdYZ/e0djoei1ndS(sqFunkLoad test case using Richard Jones' webunit. $Id: FunkLoadTestCase.py 24757 2005-08-31 12:22:19Z bdelbosc $ N(swarn(serror(sDictTypesListTypes TupleType(sdatetime(srandom(s urlencode(smkdtemp(s quoteattr(surljoin(s ConfigParsersNoSectionErrors NoOptionError(s WebTestCases HTTPError(sget_default_loggers mmn_is_benchs mmn_decode(s recordings thread_sleepsis_htmls get_versionstrace(s ServerProxysFunkLoadTestCasecBstZdZdedZdZdZdZeeedeeedZ eeedZ eeed Z ed d Z eed Z eed ZdddZdZdZdZdZdZdZdZdZdZdZedZdZeedZeedZeedZ eeed Z!d!Z"d"Z#d#Z$d$Z%d%Z&ed&Z'd'Z(d(Z)d)Z*ed*Z+d+Z,d,Z-d-Z.ed.Z/RS(/s5Unit test with browser and configuration capabilties.srunTestcCst|o t|_n t|_t|\|_|_|_ |_ ||_ |i i |_tii|d|it|_||_t|dd|_|it|dt|_|iotpt|_t|dt|_t|dt|_t|dt|_t|dt|_|io|i ot|_td |_nt|d t|_|io|i i!d o<|i i"d }t$t%|dt%|d |_&nt%|i g|_&|i'|_(t|_)g|_*nd S(sInitialise the test case. Note that methodName is encoded in bench mode to provide additional information like thread_id, concurrent virtual users...s methodNames debug_levelisdump_dirs firefox_viewsaccept_invalid_linkss simple_fetchs stop_on_fails _funkloads loop_stepss:iN(+s mmn_is_benchs methodNamesTruesselfs in_bench_modesFalses mmn_decodes test_namescyclescvuss thread_idsmeta_method_names __class__s__name__s suite_namesunittestsTestCases__init__sNones _responsesoptionssgetattrs debug_levels_funkload_inits _dump_dirs_dumpings_viewings_accept_invalid_linkss _simple_fetchs _stop_on_failsmkdtemps _loop_modes loop_stepsscountssplitsstepssrangesints _loop_stepss loop_numbers _loop_numbers_loop_recordings _loop_records(sselfs methodNamesoptionsssteps((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pys__init__8s>   $        *  cCstidd}tii||iid}tii |}tii | od|}nt }|i |||_||_|idddtdt|_|io d }nd }|i|d d d dgdt}tt||_|i|dd|_|i|dd|_|i|dd|_|i|dd|_tii |i|dd|_t |i|i|_!t ddd|idd|_"t#dd|_$|i%dS(s;Initialize a funkload test case using a configuration file.s FL_CONF_PATHs.s.confs Missing: smains user_agents FunkLoad/%ssquietsbenchsftestsok_codesii-i.ssleep_time_minissleep_time_maxslog_tos console fileslog_paths funkload.logs result_paths funkload.xmlsxmlsnamesFunkLoadResults methodNameslogN(&sossgetenvsconfig_directoryspathsjoinsselfs __class__s__name__s config_pathsabspathsexistss ConfigParsersconfigsreads_configs _config_pathsconf_gets get_versionsTruesdefault_user_agents in_bench_modessections conf_getListsok_codessmapsints conf_getFloatssleep_time_minssleep_time_maxslog_toslog_paths result_pathsget_default_loggersloggers logger_results WebTestCases_browsers clearContext(sselfs config_pathsok_codessconfig_directoryssectionsconfig((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pys_funkload_init`s>          $  cCs|iih|i_g|i_g|i_t|_d|_d|_ d|_ d|_ d|_ d|_ |_d|_|_d|_|i|i|i|i|iddS(sResset the testcase.s Successfulif0.0s"FunkLoadTestCase.clearContext doneN(sselfs_browsers clearContextscssshistorys extra_headerssTrues step_successs test_statussstepsspage_responsesstotal_responsess total_times total_pagess total_imagess total_linksstotal_redirectss total_xmlrpcsclearBasicAuths clearHeaderss setUserAgentsdefault_user_agentslogdd(sself((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pys clearContexts$             c CsPti}y|ii||d|}Wnt i \} } } ti} | |}|i|7_t|_d|_|id|| tjoY|i| i|||| dt|io|i| in|it| iq5|i||||| | tjotd|nnXti} | |}|i|7_|ddfjo|i d7_ nA|d jo|i!d7_!n!|d jo|i"d7_"n|ddd fjo|i#d |n|ii$i%||f|id ||i||||| |io|i|n|Sd S(s-Handle fetching, logging, errors and history.sok_codessFailures Failed in %.3fsslog_bodysCan't load %s.spostsgetisredirectslinksReferers Done in %.3fsN(&stimest_startsselfs_browsersfetchsurlsparamssok_codessresponsessyssexc_infosetypesvaluestbackst_stopst_deltas total_timesFalses step_successs test_statusslogds HTTPErrors _log_responsesrtypes descriptionsTrues_dumpings _dump_contentsfailureExceptionsstrs_log_response_errors SocketErrors total_pagesstotal_redirectss total_linkss setHeadershistorysappend( sselfsurlsparamssok_codessrtypes descriptionst_deltast_startsresponsestbacksvaluesetypest_stop((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pys_connectsP             spostc  Cs\t|_|iok|i|idjot|_|idn|io,|i i |||||||tfq~n|tjo |i}nt|tjo|i}ng}|ox|D]\}}t|tjo?x|iD]*\}}|o|i ||fqqWqt|ttfjo(x8|D]}|i ||fqMWq|i ||fqWn|djo|o|dt|}t}n|}|djo(|id||i|pdfn4|}|id|t ||i|pdf|i!|||||}|o|i#dd fjod }t%xt|i#dd fjo|oV|i&d }t(||}|id ||i!|t|d t}|d8}qqW| o|idqnt)|i*|_)|o|i)o|i+ o|id|i*}t-i-}|i/}y|i1i2|||Wnt3j o}|i5o|idt |qt-i-} | |} t|_8d|_9|id| |i:|i"dt|| dt|i;t |nX|i/} |id| |n|o|i=n||_|io|i|idjot|_|id|i/}d}xbt?|i@D]Q} |id| x7|i D],}|d7}|id7_|iC|qWqW|i/|} d|| | ||| f} |i| tE| dn|SdS(s?Simulate a browser handle redirects, load/cache css and images.isLoop mode start recordingsgets?sGET: %s Page %i: %s ...ssPOST: %s %s Page %i: %s ...i-i.i sLocations Load redirect link: %ssredirectis$ WARNING Too many redirects give up.s Load css and images...s sFailures Failed in ~ %.2fsslinkslog_bodys Done in %.3fsisLoop mode end recording.sLoop mode replay %is^End of loop: %d pages rendered in %.3fs, avg of %.3fs per page, %.3f SPPS without concurrency.s N(FsNonesselfs _responses _loop_modesstepss _loop_stepssTrues_loop_recordingslogis _loop_recordssappendsurl_ins params_ins descriptionsok_codessmethodsfollow_redirectsload_auto_linkssFalsestypesDictTypesitemssparamsskeysvaluesvalsselectedsListTypes TupleTypes urlencodesurlslogdsstrs_connectsresponsescodesmax_redirect_counts thread_sleepsheaderssnewurlsurljoinsis_htmlsbodys _simple_fetchspagestimest_starts total_timesc_starts_browsers pageImagess HTTPErrorserrors_accept_invalid_linksst_stopst_deltas step_successs test_statuss _log_responsesfailureExceptionsc_stopssleepscountsranges _loop_numbersisrecords_browsestextstrace(sselfsurl_ins params_ins descriptionsok_codessmethodsfollow_redirectsload_auto_linksssleepstextst_deltast_stopsc_stopsisvalsrecordsselectedsresponsesparamssnewurlserrorst_startskeyscountsurlsmax_redirect_countsvaluesc_startspage((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pys_browses    0      (-            !       cCs>|id7_d|_|i||||dd}|SdS(sPOST method on url with params.iismethodspostN( sselfsstepsspage_responsess_browsesurlsparamss descriptionsok_codessresponse(sselfsurlsparamss descriptionsok_codessresponse((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pyspostIs   cCs>|id7_d|_|i||||dd}|SdS(s GET method on url adding params.iismethodsgetN( sselfsstepsspage_responsess_browsesurlsparamss descriptionsok_codessresponse(sselfsurlsparamss descriptionsok_codessresponse((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pysgetQs   sChecking existencec Csx|i||d|ddddddg}|idddgjo|id|tSn|id |t Sd S( s9Try a GET on URL return True if the page exists or False.s descriptionsok_codesii-i.iisPage %s not found.sPage %s exists.N( sselfsgetsurlsparamss descriptionsrespscodeslogdsFalsesTrue(sselfsurlsparamss descriptionsresp((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pysexistsYscCs|id7_d|_|id|||i|pdft} t i }|i tj o|i dd|i } n|} yEt| } t| |}|tj o||} n |} Wnti\}} }t i }||} |i| 7_t|_d|_|id| |i|||| ||d|tjotd | nnXt i }||} |i| 7_|i d7_ |id | |i|||| ||d |i!| Sd S( s/Call an xml rpc method_name on url with params.iisXMLRPC: %s::%s Call %i: %s ...ss//sErrors Failed in %.3fsisCan't access %s.s Done in %.3fsiN("sselfsstepsspage_responsesslogdsurl_ins method_names descriptionsNonesresponsestimest_starts _authinfosreplacesurls ServerProxysserversgetattrsmethodsparamsssyssexc_infosetypesvaluestbackst_stopst_deltas total_timesFalses step_successs test_statuss_log_xmlrpc_responses SocketErrors total_xmlrpcssleep(sselfsurl_ins method_namesparamss descriptionst_stopsetypesmethodst_startst_deltasresponsesurlsvaluesserverstback((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pysxmlrpccsJ '             cCs-tdtdd|i||||SdS(s5BBB of xmlrpc, this method will be removed for 1.6.0.s>Since 1.4.0 the method "xmlrpc_call" is renamed into "xmlrpc".s stackleveliN(swarnsDeprecationWarningsselfsxmlrpcsurl_ins method_namesparamss description(sselfsurl_ins method_namesparamss description((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pys xmlrpc_calls iicCsti}xtoy&|ii|tddddgWnEtj o9ti||jo|i d||fqnXdSti |qWdS(swWait until url is available. Try a get on url every sleep_time until server is reached or time is out.sok_codesii-i.s+Time out service %s not available after %ssN( stimes time_startsTruesselfs_browsersfetchsurlsNones SocketErrorstime_outsfailssleeps sleep_time(sselfsurlstime_outs sleep_times time_start((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pyswaitUntilAvailables & cCs*|ii||d||f|_dS(sSet http basic authentication.s%s:%s@N(sselfs_browsers setBasicAuthsloginspasswords _authinfo(sselfsloginspassword((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pys setBasicAuthscCs|iit|_dS(sRemove basic authentication.N(sselfs_browsersclearBasicAuthsNones _authinfo(sself((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pysclearBasicAuths cCs|iii||fdS(sAdd an http header.N(sselfs_browsers extra_headerssappendskeysvalue(sselfskeysvalue((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pys addHeaderscCs|ii}x~t|D]L\}\}}||jo-|t j o||f||scCsdS(s#Called after a cycle in bench mode.N((sself((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pys tearDownCycleBscCs|ii|id|dS(s Debug log.s: N(sselfsloggersdebugsmeta_method_namesmessage(sselfsmessage((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pyslogdKscCs3|idjo|ii|id|ndS(sVerbose Debug log.is: N(sselfs debug_levelsloggersdebugsmeta_method_namesmessage(sselfsmessage((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pyslogddOscCsCt|do|ii|id|n|id|GHdS(s Info log.sloggers: N(shasattrsselfsloggersinfosmeta_method_namesmessage(sselfsmessage((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pyslogiTscCs4|p|i pto|ii|ndS(s Log a result.N(sforcesselfs in_bench_modes recordings logger_resultsinfosmessage(sselfsmessagesforce((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pys_logr[scKsdttiifg}x=|iD]/\}}|i d|t t |fq/W|i di|dtdS(sOpen the result log.s!ss sforceN(s get_versionsdatetimesnows isoformatsxmlskwsitemsskeysvaluesappends quoteattrsstrsselfs_logrsjoinsTrue(sselfskwsxmlsvalueskey((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pys_open_result_log`s " 'cCs|iddtdS(sClose the result log.s sforceN(sselfs_logrsTrue(sself((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pys_close_result_logiscCs&|id7_|id7_h}|i|d<|i|d<|i|d<|i|d<|i|d<|i |d<|i|d<||d N(sselfstotal_responsesspage_responsessinfoscyclescvuss thread_ids suite_names test_namesstepssrtypes quoteattrsurls descriptions time_starts time_stopsjoins tracebacksformat_exceptionssyssexc_infosmessages_logr(sselfsurlsrtypes descriptions time_starts time_stopsinfosmessage((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pys_log_response_errorms*           ( cCs|id7_|id7_h}|i|d<|i|d<|i|d<|i|d<|i|d<|i |d<|i|d<||d s > s!
s s s" s N(sselfstotal_responsesspage_responsessinfoscyclescvuss thread_ids suite_names test_namesstepssrtypes quoteattrsresponsesurlscodes descriptions time_starts time_stops step_successsresponse_startslog_bodysmessages header_xmlsheaderssitemsskeysvaluesappendsjoinsbodys_logr(sselfsresponsesrtypes descriptions time_starts time_stopslog_bodysinfos header_xmlsmessagesvaluesheadersskeysresponse_start((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pys _log_responses:             !"c Cs|id7_|id7_h}|i|d<|i|d<|i|d<|i|d<|i|d<|i |d<|i|d"N(sselfstotal_responsesspage_responsessinfoscyclescvuss thread_ids suite_names test_namesstepss quoteattrsurlsmethodscodes descriptions time_starts time_stops step_successsmessages_logr( sselfsurlsmethods descriptionsresponses time_starts time_stopscodesinfosmessage((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pys_log_xmlrpc_responses(           cCs=h}|i|d<|i|d<|i|d<|i|d<|i|d<|i|d<||d<|||d<|i |d <|i |d <|i |d <|i |d <|i|d <|i|d<|i|d<|i|d<|idjo4dtdititid|dN(sinfosselfscyclescvuss thread_ids suite_names test_namesstepss time_starts time_stops total_timestotal_responsess total_pagess total_xmlrpcstotal_redirectss total_imagess total_linkss test_statuss quoteattrsjoins tracebacksformat_exceptionssyssexc_infostexts_logr(sselfs time_starts time_stopsinfostext((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pys _log_results.               4  c Cs|i}|tjodSnt|ddddgjodSn|i odSnti|ti  oti |dn|i i d}|djo d}nHtii|id }|id  pt|d jo d }ntiitii|d |i|f}t|d}|i|i|i|ioHd|}ti|}|djo|i d|t!|_qndS(siDump the html content in a file. Use firefox to render the content if we are in rt viewing mode.Nscodei-i.is content-typestext/xmls.xmlis.is.htmls%3.3i%ssws.firefox -remote "openfile(file://%s,new-tab)"is$Failed to remote control firefox: %s("sselfs _dump_dirsdump_dirsNonesgetattrsresponsesbodysossaccesssW_OKsmkdirsheaderssgets content_typesextspathssplitextsurls startswithslensabspathsjoinsstepss file_pathsopensfswritescloses_viewingscmdssystemsretslogisFalse( sselfsresponses content_typesfscmdsexts file_pathsretsdump_dir((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pys _dump_contents4     $ .    cCsti}|tjo|i}n|i|tiddfjot ||i }nt ||i }zt }y1|id|i|idd|iWnUtj o nA|i||id|_|i|tidSnXy|t}Wn|ij oVtiddfjo|i||in|i||id|_nltj o nWtiddfjo|i||in|i||id|_nXy|iWnqtj o n]tiddfjo|i||in|i||id|_t }nX|o|i|nWd|i|ti| o|io|in|i |XdS( s:Run the test method. Override to log test result.iis0Starting ----------------------------------- %ss descriptionssErrorNsFailure(!stimest_startsresultsNonesselfsdefaultTestResults startTestssyss version_infosgetattrs_testMethodNames testMethods_TestCase__testMethodNamesFalsesokslogdsconf_getsmeta_method_namessetUpsKeyboardInterruptsaddErrors_TestCase__exc_infos test_statuss _log_resultsTruesfailureExceptions addFailures _exc_infostearDowns addSuccesss _stop_on_failsstopsstopTest(sselfsresultsoks testMethodst_start((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pys__call__sj          (0s__name__s __module__s__doc__sNones__init__s_funkload_inits clearContexts_connectsTrues_browsespostsgetsexistssxmlrpcs xmlrpc_callswaitUntilAvailables setBasicAuthsclearBasicAuths addHeaders setHeaders delHeaders clearHeaderss setUserAgentssleeps getLastUrlsgetBodyslistHrefsgetLastBaseUrls_markersFalsesconf_gets conf_getInts conf_getFloats conf_getLists setUpCycles tearDownCycleslogdslogddslogis_logrs_open_result_logs_close_result_logs_log_response_errors _log_responses_log_xmlrpc_responses _log_results _dump_contents__call__(((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pysFunkLoadTestCase3sT ( -  -u +                    &   $s DummyTestCasecBstZdZdZRS(sTesting Funkload TestCase.cCs|idxltdD]^}|id|id|i|id|i|idt|iqW|id|i dS( sSimple apache test.sstart apache testishttp://localhost/s base_url: surl: shrefs: sTotal connection time = %sN( sselfslogdsrangesisgetsgetLastBaseUrls getLastUrlsstrslistHrefs total_time(sselfsi((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pys test_apacheIs   !(s__name__s __module__s__doc__s test_apache(((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pys DummyTestCaseFs s__main__(2s__doc__sosssysstimesreswarningsswarnssocketserrors SocketErrorstypessDictTypesListTypes TupleTypesdatetimesunittests tracebacksrandomsurllibs urlencodestempfilesmkdtempsxml.sax.saxutilss quoteattrsurlparsesurljoins ConfigParsersNoSectionErrors NoOptionErrorswebunit.webunittests WebTestCases HTTPErrors PatchWebunitsutilssget_default_loggers mmn_is_benchs mmn_decodes recordings thread_sleepsis_htmls get_versionstraces xmlrpclibs ServerProxys_markersTestCasesFunkLoadTestCases DummyTestCases__name__smain(#s urlencodesurljoinsmkdtempsunittestsrandomsdatetimesget_default_loggers mmn_decodes ServerProxys PatchWebunits mmn_is_benchs DummyTestCases TupleTypes get_versionsres quoteattrs NoOptionErrors thread_sleepsDictTypes_markers SocketErrorstracesis_htmlsFunkLoadTestCaseswarnsListTypes HTTPErrors ConfigParserssyss tracebacks recordingstimesNoSectionErrorsoss WebTestCase((s7build/bdist.linux-i686/egg/funkload/FunkLoadTestCase.pys?s:               %  PK]i6PVfunkload/__init__.pyc; Cc@s dZdS(sOFunkload package init. $Id: __init__.py 24649 2005-08-29 14:20:19Z bdelbosc $ N(s__doc__(((s/build/bdist.linux-i686/egg/funkload/__init__.pys?sPK]i6Xg//funkload/XmlRpcBase.pyc; Cc@sdZdkZdkZdklZdklZdklZl Z dk l Z dk l Z dk Z dklZlZdklZlZlZd klZlZd Zd e fd YZd fdYZdfdYZdZedjo endS(seBase class to build XML RPC daemon server. $Id: XmlRpcBase.py 30282 2005-12-05 12:52:30Z bdelbosc $ N(serror(ssleep(s ConfigParsers NoOptionError(sSimpleXMLRPCServer(s ServerProxy(s OptionParsersTitledHelpFormatter(s create_daemonsget_default_loggers close_logger(straces get_versioncCsFtd||f}y|iWntj o tSnXtSdS(s>Check if the XML/RPC server is running checking getStatus RPC.s http://%s:%sN(s ServerProxyshostsportsservers getStatuss SocketErrorsFalsesTrue(shostsportsserver((s1build/bdist.linux-i686/egg/funkload/XmlRpcBase.pysis_server_running#s sMySimpleXMLRPCServercBstZdZeZRS(s,SimpleXMLRPCServer with allow_reuse_address.(s__name__s __module__s__doc__sTruesallow_reuse_address(((s1build/bdist.linux-i686/egg/funkload/XmlRpcBase.pysMySimpleXMLRPCServer1s sXmlRpcBaseServercBstZdZdZeZddgZedZdZdZ dZ dZ d Z d Z e Zd Zd ZRS( s"The base class for xml rpc server.s9%prog [options] config_file Start %prog XML/RPC daemon. s stopServers getStatuscCso|itjo|ii|_n|tjo ti}n|i|\}}|id|_ |id|_ t|_ t |_t}|i|||_|idd|_|idd|_y|idd|_Wntj o|i |_nXy|idd}Wntj o|i }nXt|i|io+td|i|iftid ntd |i|i|if|io ti}n ti }|i!o d }nd }t#||d |d|i|_$|i%|||i! oCtdt&|it't#||d |d|i|_$n td|i(dS(Ns.logs.pidsservershostsportspid_pathslog_paths Server already running on %s:%s.is#Starting %s server at http://%s:%s/s file consolesfileslevelsnames as daemon. s in debug mode. ()sselfs server_namesNones __class__s__name__sargvssyss parseArgss conf_pathsoptionssdefault_log_pathsdefault_pid_pathsserversFalsesquits ConfigParsersconfsreadsgetshostsgetintsportspid_paths NoOptionErrorslog_pathsis_server_runningstracesexitsverbosesloggingsDEBUGslevelsINFOsdebugslog_tosget_default_loggersloggers_init_cbs close_loggers create_daemons initServer(sselfsargvslog_toslevelslog_paths conf_pathsconfsoptions((s1build/bdist.linux-i686/egg/funkload/XmlRpcBase.pys__init__GsV                 cCsdS(sinit procedure intend to be implemented by subclasses. This method is called before to switch in daemon mode. conf is a ConfigParser object.N((sselfsconfsoptions((s1build/bdist.linux-i686/egg/funkload/XmlRpcBase.pys_init_cbscCs|ii|dS(s Debug log.N(sselfsloggersdebugsmessage(sselfsmessage((s1build/bdist.linux-i686/egg/funkload/XmlRpcBase.pyslogdscCs|ii|dS(sLog information.N(sselfsloggersinfosmessage(sselfsmessage((s1build/bdist.linux-i686/egg/funkload/XmlRpcBase.pyslogscCst|idtddt}|idddddd |id d dddd |i|\}}t |d jo|i dn|d|fSdS(sParse programs args.s formattersversions FunkLoad %ss-vs --verbosesactions store_trueshelpsVerbose outputs-ds--debugs&debug mode, server is run in forgroundis#Missing configuration file argumentiN( s OptionParsersselfsusagesTitledHelpFormatters get_versionsparsers add_options parse_argssargvsoptionssargsslenserror(sselfsargvsargssparsersoptions((s1build/bdist.linux-i686/egg/funkload/XmlRpcBase.pys parseArgss  cCs}|id|i|ift|i|if}x8|iD]-}|id||i t ||q?W||_dS(sinit the XMLR/PC Server.sInit XML/RPC server %s:%s.s register %sN( sselfslogshostsportsMySimpleXMLRPCServersservers method_namess method_nameslogdsregister_functionsgetattr(sselfs method_namesserver((s1build/bdist.linux-i686/egg/funkload/XmlRpcBase.pys initServers cCs|i}ti}t|idit||i d|x|i o|i qHWt d|i |i d|ti|idS(smain server loop.swsXML/RPC server pid=%i running.f0.5sXML/RPC server pid=%i stopped.N(sselfsserversossgetpidspidsopenspid_pathswritesstrslogsquitshandle_requestssleeps server_closesremove(sselfspidsserver((s1build/bdist.linux-i686/egg/funkload/XmlRpcBase.pysruns     cCs|idt|_dSdS(sStop the server.sstopServer request.iN(sselfslogsTruesquit(sself((s1build/bdist.linux-i686/egg/funkload/XmlRpcBase.pys stopServers  cCs(|idd|itifSdS(sReturn a status.sgetStatus request.s%s running pid = %sN(sselfslogds server_namesossgetpid(sself((s1build/bdist.linux-i686/egg/funkload/XmlRpcBase.pys getStatuss (s__name__s __module__s__doc__susagesNones server_names method_namess__init__s_init_cbslogdslogs parseArgss initServersruns__call__s stopServers getStatus(((s1build/bdist.linux-i686/egg/funkload/XmlRpcBase.pysXmlRpcBaseServer<s   <      sXmlRpcBaseControllercBs\tZdZdZeZedZdZe dZ e dZ edZ dZ RS(sAn XML/RPC controller.sv%prog config_file action action can be: start|startd|stop|restart|status|test Execute action on the XML/RPC server. cCs|tjo ti}n|i|\}|_}t}|i ||i dd|_ ||_|i dd|_d|i |if|_|i |_t|i|_dS(Nsservershostsports http://%s:%s/(sargvsNonessyssselfs parseArgss conf_pathsactionsoptionss ConfigParsersconfsreadsgetshostsgetintsportsurlsquietsverboses ServerProxysserver(sselfsargvs conf_pathsconfsoptions((s1build/bdist.linux-i686/egg/funkload/XmlRpcBase.pys__init__s      cCst|idtddt}|idddddd |i|\}}t |d jo|i d n|d |d |fSdS(sParse programs args.s formattersversions FunkLoad %ss-qs--quietsactions store_trueshelpsVerbose outputisMissing argumentiiN( s OptionParsersselfsusagesTitledHelpFormatters get_versionsparsers add_options parse_argssargvsoptionssargsslenserror(sselfsargvsargssparsersoptions((s1build/bdist.linux-i686/egg/funkload/XmlRpcBase.pys parseArgss cCs)|p|iott|ndS(sLog a message.N(sforcesselfsverbosestracesstrsmessage(sselfsmessagesforce((s1build/bdist.linux-i686/egg/funkload/XmlRpcBase.pyslogscCsDd|ig}|o|idn|i|}|idS(sStart an XML/RPC server.scmds-dvN(sselfs conf_pathsargvsdebugsappends server_classsdaemonsrun(sselfsdebugsdaemonsargv((s1build/bdist.linux-i686/egg/funkload/XmlRpcBase.pys startServers cCs|i}|tjo |i}nt|i|i}|djoM|o*|i}|i d|i |fn|i d|i dSnE|ddfjou|o*|i }|i d|i t }n&|djo|i d|i n|djo|dqnd|jo6|o|i d |i q|i|d jSnz| o|i d|i d SnV|d jo|i}|i d n,|djo|iSntd|dSdS(sCall the xml rpc actionsstatuss%s %s. sNo server reachable at %s. isstopsrestartsServer %s is stopped. sstartsServer %s is already running. sstartdisreloadsdone stestsUnknow action %sN(sselfsserversactionsNonesis_server_runningshostsports is_runnings getStatussretslogsurls stopServersFalses startServers reloadConfstestsNotImplementedError(sselfsactions is_runningsserversret((s1build/bdist.linux-i686/egg/funkload/XmlRpcBase.pys__call__sD             cCs(|ii}|id|dSdS(sOTesting the XML/RPC. Must return an exit code, 0 for success. sTesting getStatus: %s iN(sselfsservers getStatussretslog(sselfsret((s1build/bdist.linux-i686/egg/funkload/XmlRpcBase.pystest's(s__name__s __module__s__doc__susagesXmlRpcBaseServers server_classsNones__init__s parseArgssFalseslogs startServers__call__stest(((s1build/bdist.linux-i686/egg/funkload/XmlRpcBase.pysXmlRpcBaseControllers     (cCs#t}|}ti|dS(sMainN(sXmlRpcBaseControllersctlsretssyssexit(sctlsret((s1build/bdist.linux-i686/egg/funkload/XmlRpcBase.pysmain0s  s__main__(s__doc__ssyssosssocketserrors SocketErrorstimessleeps ConfigParsers NoOptionErrorsSimpleXMLRPCServers xmlrpclibs ServerProxysloggingsoptparses OptionParsersTitledHelpFormattersutilss create_daemonsget_default_loggers close_loggerstraces get_versionsis_server_runningsMySimpleXMLRPCServersXmlRpcBaseServersXmlRpcBaseControllersmains__name__(ssleepsMySimpleXMLRPCServersget_default_loggers ServerProxysTitledHelpFormatters get_versions NoOptionErrorsmains OptionParsersXmlRpcBaseControllers SocketErrorstracesSimpleXMLRPCServerssyssis_server_runnings create_daemons ConfigParsersloggingsXmlRpcBaseServersoss close_logger((s1build/bdist.linux-i686/egg/funkload/XmlRpcBase.pys?s"       d  PK]i6--funkload/utils.pyc; (Dc@sdZdkZdkZdkZdkZdklZdklZdk l Z dZ ddZ e ae adZd Zd Zd Zd Zd ZdZdZdZeeiddZdZdZedZdZedZ dZ!hdd<dd<ddtd|D]-}yti|Wq(tj oq(Xq(WtidtitiddtidddSdS( saDetach a process from the controlling terminal and run it in the background as a daemon. s%s [%d]if0.5Niis /dev/nulli(sossforkspidsOSErrorsmsgs Exceptionsstrerrorserrnossetsidsumasks_exitssleepsresources getrlimits RLIMIT_NOFILEsmaxfds RLIM_INFINITYsrangesfdsclosesopensO_RDWRsdup2(sresourcesmaxfdspidsmsgsfd((s,build/bdist.linux-i686/egg/funkload/utils.pys create_daemonJs<        s:cCs|itotptSdS(sIs it a meta method name ?.N(smeta_method_namescountsMMN_SEPsTruesFalse(smeta_method_name((s,build/bdist.linux-i686/egg/funkload/utils.pys mmn_is_benchsscCs/ti|t|t|t|fSdS(s.Encode a extra information into a method_name.N(sMMN_SEPsjoins method_namesstrscyclescvuss thread_id(s method_namescyclescvuss thread_id((s,build/bdist.linux-i686/egg/funkload/utils.pys mmn_encodewscCsbt|oA|it\}}}}|t|t|t|fSn|dddfSdS(sDecode a meta method name.iiN( s mmn_is_benchsmeta_method_namessplitsMMN_SEPs method_namescyclescvuss thread_idsint(smeta_method_names method_namescvuss thread_idscycle((s,build/bdist.linux-i686/egg/funkload/utils.pys mmn_decode{s  &sFunkLoadcCs1ti|}|io|Sn|idoti}|i |n|ido|o<ti d}ti |}|i||i |n|ido|odti|tio.ti||dtttinti |}|i |n|i||SdS(s Get a logger.sconsolesfiles%%(asctime)s %(levelname)s %(message)ssxmls.bak-N(sloggings getLoggersnamesloggershandlersslog_toscounts StreamHandlershdlrs addHandlerslog_paths Formatters formatters FileHandlers setFormattersossaccesssF_OKsrenamesstrsintstimessetLevelslevel(slog_toslog_pathslevelsnamesloggers formattershdlr((s,build/bdist.linux-i686/egg/funkload/utils.pysget_default_loggers&   . cCs4ti|}x|iD]}|i|qWdS(sClose the logger.N(sloggings getLoggersnamesloggershandlersshdlrs removeHandler(snamesloggershdlr((s,build/bdist.linux-i686/egg/funkload/utils.pys close_loggers  cCs!tii|tiidS(s,Simple print to stdout Not thread safe.N(ssyssstdoutswritesmessagesflush(smessage((s,build/bdist.linux-i686/egg/funkload/utils.pystracescCsWd||f}t|}y|i|SWn#tj otd|nXdS(s-Get credential thru xmlrpc credential_server.s http://%s:%ss[No Credential server reachable at %s, use fl-credential-ctl to start the credential server.N(shostsportsurls ServerProxysservers getCredentialsgroups SocketError(shostsportsgroupsurlsserver((s,build/bdist.linux-i686/egg/funkload/utils.pysxmlrpc_get_credentials cCsTd||f}t|}y|iSWn#tj otd|nXdS(s1Get list of groups thru xmlrpc credential_server.s http://%s:%ss[No Credential server reachable at %s, use fl-credential-ctl to start the credential server.N(shostsportsurls ServerProxysservers listGroupss SocketError(shostsportsurlsserver((s,build/bdist.linux-i686/egg/funkload/utils.pysxmlrpc_list_groupss cCsWd||f}t|}y|i|SWn#tj otd|nXdS(s0Get list of users thru xmlrpc credential_server.s http://%s:%ss[No Credential server reachable at %s, use fl-credential-ctl to start the credential server.N(shostsportsurls ServerProxysserverslistCredentialssgroups SocketError(shostsportsgroupsurlsserver((s,build/bdist.linux-i686/egg/funkload/utils.pysxmlrpc_list_credentialss cCsdkl}|diSdS(s$Retrun the FunkLoad package version.(sget_distributionsfunkloadN(s pkg_resourcessget_distributionsversion(sget_distribution((s,build/bdist.linux-i686/egg/funkload/utils.pys get_versions sgreenssredssresetscCstd|tdSdS(sReturn red text.sredsresetN(s_COLORstext(stext((s,build/bdist.linux-i686/egg/funkload/utils.pysred_strscCstd|tdSdS(sReturn green text.sgreensresetN(s_COLORstext(stext((s,build/bdist.linux-i686/egg/funkload/utils.pys green_strscCs'd|d ijotSntSdS(s:Simple check that return True if the text is an html page.sCompute the right size lenght depending on the number of cvus.ii i2iN( slistsselfs chart_sizessizeslenscvusslen_cvussbig_chart_sizesminstuple(sselfscvusslen_cvusssize((s5build/bdist.linux-i686/egg/funkload/ReportRenderer.pys getChartSizems  !cCs]t odSn|i|i|i|ix|iD]}|i|qBWdS(sCreate all charts.N( s g_has_gdchartsselfscreateMonitorChartsscreateTestChartscreatePageChartscreateAllResponseChartsstepss step_namescreateResponseChart(sselfs step_name((s5build/bdist.linux-i686/egg/funkload/ReportRenderer.pys createChartsvs     c !Csttii|id}|i}g}g}g}t }x|i D]}} || id oqIn|| d} |i| i| i}|o t}n|i||it| i qIW|o|ip|i}tidtid|i|ifd|id|id|id|id d d d d dddddddddd|d|ddtiti|i |||||dS(sCreate the test chart.s tests.pngstestsformats set_colors vol_colorsbg_colors plot_colors line_colorstitlesSuccessful Tests Per SecondsxtitlesCUss ylabel_fmts%.2fs ylabel2_fmts%.2f %%sytitlesSTPSsytitle2sErrorssylabel_densityi2s ytitle2_colors ylabel2_colorsrequested_yminf0.0N(!sstrsosspathsjoinsselfs report_dirs image_pathsstatsserrorssstpsscvussFalses has_errorscyclesscycleshas_keystestsappendstpss error_percentserrorsTrues color_errorscolor_bgsgdchartsoptionsGDC_PNGs color_successs color_plots color_lineschartsGDC_3DCOMBO_LINE_BARs getChartSize( sselfs color_errorserrorssstatss image_paths has_errorscvussstpsserrorstestscycle((s5build/bdist.linux-i686/egg/funkload/ReportRenderer.pyscreateTestChartsD              cCs~|iio=|i|ii|i|ii |i|ii n1|i|i |i|i |i|idS(s0 Show percentiles or min, avg and max in chart. N(sselfsoptionsswith_percentilessdelaysappendsstatss percentilessperc50s delay_lowsperc10s delay_highsperc90savgsminsmax(sselfsdelays delay_lows delay_highsstats((s5build/bdist.linux-i686/egg/funkload/ReportRenderer.pys appendDelayss cCs|iiodSndSdS(NsDuration (10%, 50% 90%)sDuration (min, avg, max)(sselfsoptionsswith_percentiles(sself((s5build/bdist.linux-i686/egg/funkload/ReportRenderer.pys getYTitles c%Csttii|id}ttii|id} |i}g}g}g} g}g}g}t}x|iD]w} || d} |i||| | |i| i| i} | o t}n|i| |it| iqyW|o|ip|i}tidtid|i|i|i fd|id|id|i!d |i"d |i#d d d dddddd|i$dddddti%ti&d|d|ddti'ti(|i)|||| ||f|tidtid|i*|i*fd|id|id|i!d |i#d dd dddddddddddddti'ti+|i)|| |||d S(!sCreate the page chart.s pages.pngspages_spps.pngspagesformats set_colors vol_colorsbg_colors plot_colors grid_colors line_colorstitlesPage response timesxtitlesCUss ylabel_fmts%.2fss ylabel2_fmts%.2f %%sytitlesytitle2sErrorssylabel_densityi2s hlc_styles ytitle2_colors ylabel2_colorsrequested_yminf0.0sSuccessful Pages Per Seconds%.2fsSPPSN(,sstrsosspathsjoinsselfs report_dirs image_paths image2_pathsstatsserrorssdelays delay_highs delay_lowssppsscvussFalses has_errorscyclesscyclespages appendDelayssappendsrpss error_percentserrorsTrues color_errorscolor_bgsgdchartsoptionsGDC_PNGscolor_time_min_maxs color_times color_plots color_grids color_lines getYTitles GDC_HLC_I_CAPsGDC_HLC_CONNECTINGschartsGDC_3DCOMBO_HLC_BARs getChartSizes color_successsGDC_3DCOMBO_LINE_BAR(sselfs color_errorssppsserrorssstatss image_pathscvussdelays has_errors image2_pathserrorscyclespages delay_highs delay_low((s5build/bdist.linux-i686/egg/funkload/ReportRenderer.pyscreatePageChartsj                      c%Csttii|id}ttii|id} |i}g}g}g} g}g}g}t}x|iD]w} || d} |i||| | |i| i | i} | o t}n|i| |it| iqyW|o|ip|i}tidtid|i|i|ifd|id|id|i d |i!d |i"d d d dddddd|i#dddddti$ti%d|d|ddti&ti'|i(|||| ||f|tidtid|i)|i)fd|id|id|i d |i"d dd dddddddddddd|d|ddti&ti*|i(|| |||d S(!sCreate global responses chart.s requests.pngsrequests_rps.pngsresponsesformats set_colors vol_colorsbg_colors plot_colors grid_colors line_colorstitlesRequest response timesxtitlesCUss ylabel_fmts%.2fss ylabel2_fmts%.2f %%sytitlesytitle2sErrorssylabel_densityi2s hlc_styles ytitle2_colors ylabel2_colorsrequested_yminf0.0sRequests Per Seconds%.2fsRPSN(+sstrsosspathsjoinsselfs report_dirs image_paths image2_pathsstatsserrorssdelays delay_highs delay_lowsrpsscvussFalses has_errorscyclesscyclesresps appendDelayssappends error_percentserrorsTrues color_errorscolor_bgsgdchartsoptionsGDC_PNGscolor_time_min_maxs color_times color_plots color_grids color_lines getYTitles GDC_HLC_I_CAPsGDC_HLC_CONNECTINGschartsGDC_3DCOMBO_HLC_BARs getChartSizes color_successsGDC_3DCOMBO_LINE_BAR(sselfs color_errorsrpsserrorssstatss image_pathscvussdelays has_errors image2_pathserrorscyclesresps delay_highs delay_low((s5build/bdist.linux-i686/egg/funkload/ReportRenderer.pyscreateAllResponseChartsl                       c%Cs7|i}g}g} g}g} g} d}t}x|i D]} || di |}|tjoE| it| it|it|it| idq=|i| | |||i}|o t}n|i|| it|i|i}q=Wttii|id|} td|}|o|ip|i}tidti d|i!|i!|i"fd|id |id |i#d |i$d |i%d |ddddddd|i&dddddti'ti(d|d|ddti)ti*|i+| | | || | f|dS(sCreate responses chart.is response_steps?srequest_%s.pngsRequest %s response timesformats set_colors vol_colorsbg_colors plot_colors grid_colors line_colorstitlesxtitlesCUss ylabel_fmts%.2fss ylabel2_fmts%.2f %%sytitlesytitle2sErrorssylabel_densityi2s hlc_styles ytitle2_colors ylabel2_colorsrequested_yminf0.0N(,sselfsstatsserrorssdelays delay_highs delay_lowscvussnumbersFalses has_errorscyclesscyclesgetsstepsrespsNonesappends appendDelayss error_percentserrorsTruesstrsosspathsjoins report_dirs image_pathstitles color_errorscolor_bgsgdchartsoptionsGDC_PNGscolor_time_min_maxs color_times color_plots color_grids color_lines getYTitles GDC_HLC_I_CAPsGDC_HLC_CONNECTINGschartsGDC_3DCOMBO_HLC_BARs getChartSize(sselfsstepsrespsnumbers delay_highs color_errorserrorssstatsstitlesdelays delay_lows image_pathscvusscycles has_errorserror((s5build/bdist.linux-i686/egg/funkload/ReportRenderer.pyscreateResponseChart,s\                    cCs_|i p|i odSn|itddx$|iiD]}|i|qDWdS(s$Create all montirored server charts.NsMonitored hostsi(sselfsmonitors with_chartsappends rst_titleskeysshostscreateMonitorChart(sselfshost((s5build/bdist.linux-i686/egg/funkload/ReportRenderer.pyscreateMonitorCharts_scCs|i|}t|di} g}xY|D]Q}|i i d\}}}|itdtt|i| |fq-Wt|di}gi}|D]}||t|iq~}|d}gi}|D]}|||q~}t|di} gi}|D]}|| t|iq~}|d}gi}|D]}|||q]~}gi}|D]}|t|iq~}gi}|D]}|t|iq~}gi}|D]}|t|i!q~}t#g}t#g} dg}x't'dt(|D]}t*||dot*||dd o|it#nt+||i,t+||i-t+||di,t+||di-}|o6tt+||i-t+||di-|}nt#}|i|t*||dot*||dd o|it#nZ|it||i0t||di0dt||it||dit*||dot*||dd o| it#q;| it||i1t||di1dt||it||diq;Wtt2i3i4|i5d |} td |} t8i9d t8i:d d ddfddd|i;d|i<d|i=d| dddddddddd t8i>t8i?|i@| |||||td|} tt2i3i4|i5d |} t8i9d t8i:d| dd!dd"t8i>t8i?|i@| |||td#|} tt2i3i4|i5d$|} t8i9d t8i:d| dd%dd&t8i>t8i?|i@| ||| d'S((s Create monitrored server charts.is:s %ss / %s CUsisCPUTotalJiffiess receiveBytesis transmitBytess %s_load.pngs>%s: cpu usage (green 1=100%%) and loadavg 1(red), 5 and 15 minsformats set_coloriiis vol_colorsbg_colors plot_colors line_colorstitlesxtitles time and CUss ylabel_fmts%.2fsytitlesloadavgsylabel_densityi2srequested_yminf0.0s&%s memory (green) and swap (red) usages %s_mem.pngs%.0f kBsmemory used kBs%s network in (green)/out (red)s %s_net.pngs %.0f kB/ssnetworkN(Asselfsmonitorshostsstatssfloatstimes time_startstimessstatskeyssplitstestscyclescvussappendsstrsintsmemTotals mem_totals_[1]sxsmemFreesmem_usedsmem_used_starts swapTotals swap_totalsswapFrees swap_usedsswap_used_starts loadAvg1mins load_avg_1s loadAvg5mins load_avg_5s loadAvg15mins load_avg_15sNonesnet_insnet_outs cpu_usagesrangeslensishasattrslongsIDLTotalJiffiessCPUTotalJiffiessdtsttls receiveBytess transmitBytessosspathsjoins report_dirs image_pathstitlesgdchartsoptionsGDC_PNGscolor_bgs color_plots color_lineschartsGDC_LINEsbig_chart_size(sselfshosts cpu_usages swap_usedsmem_useds mem_totalsttlsswap_used_startsmem_used_starts image_paths time_startstitles swap_totalsnet_outstestsstats load_avg_15scvussstatssdtscycles load_avg_1s load_avg_5sistimess_[1]snet_insx((s5build/bdist.linux-i686/egg/funkload/ReportRenderer.pyscreateMonitorCharths 44 +4 +000   -N6 -Y-]"  "  " ( s__name__s __module__s__doc__s chart_sizesbig_chart_sizes color_successs color_errors color_timescolor_time_min_maxs color_grids color_lines color_plotscolor_bgsNones__init__sprepareReportDirectorys createRstFilescopyCsss copyXmlResults generateHtmlsrenders__call__s getChartSizes createChartsscreateTestCharts appendDelayss getYTitlescreatePageChartscreateAllResponseChartscreateResponseChartscreateMonitorChartsscreateMonitorChart(((s5build/bdist.linux-i686/egg/funkload/ReportRenderer.pys RenderHtml s<          #  : < 3 (s__doc__sossgdcharts g_has_gdcharts ImportErrorsshutilscopyfiles rst_titlesBaseRstsAllResponseRstsPageRsts ResponseRstsTestRsts RenderRsts RenderHtml( scopyfiles ResponseRstsAllResponseRstsBaseRstsgdcharts rst_titlesTestRsts RenderRstsPageRstsoss RenderHtml((s5build/bdist.linux-i686/egg/funkload/ReportRenderer.pys?s       L?PK]i6d<<funkload/Recorder.pyc; (Dc@sdZdkZdkZdkZdklZdklZlZdk l Z dk Z dk l Z dklZdklZlZlZdfd YZd fd YZd fd YZedjoeindS(sTCPWatch FunkLoad Test Recorder. Requires tcpwatch.py available at: * http://hathawaymix.org/Software/TCPWatch/tcpwatch-1.3.tar.gz Credits goes to Ian Bicking for parsing tcpwatch files. $Id: Recorder.py 33463 2006-02-24 14:09:21Z bdelbosc $ N(sStringIO(s OptionParsersTitledHelpFormatter(smkdtemp(s FieldStorage(surlsplit(struncatestraces get_versionsRequestcBs)tZdZdZdZdZRS(sStore a tcpwatch request.c Cs||_t|d}|iitd}| o-td|i|iitd}n|d|_ |d}t |\} }}}}| d||_ |t|i |_||_ ||_|di|_tti|i|_|i|_|idS(sLoad a tcpwatch request file.srbis"# Warning: empty first line on %s iis://N(s file_pathsselfsopensfsreadlinessplitsNoneslinestracesmethodsurlsurlsplitsschemeshostspathsquerysfragmentslensrurlsstripsversionsdictsrfc822sMessagesitemssheaderssreadsbodysclose( sselfs file_pathsfsurlsfragmentshostsqueryspathslinesscheme((s/build/bdist.linux-i686/egg/funkload/Recorder.pys__init__)s$     c Cshd|id<d|id<dd<}tdt|id|d t}g}y|i }Wn(t j ot d |i |SnXx|D]}t||t o||g}n ||}x|D]}|i}|tjo|i||igq|pd }|i|d |g|oftii|ot d |qt d|t|d} | it|i| iqqWqW|SdS(s(Turn muti part encoded form into params.s CONTENT_TYPEs content-typesCONTENT_LENGTHscontent-lengthsREQUEST_METHODsPOSTsfpsenvironskeep_blank_valuessP# Warning: skipping invalid http post param in file: %s may be an xmlrpc call ? ss Upload("%s")s6# Warning: uploaded file: %s already exists, keep it. s# Saving uploaded file: %s swN(sselfsheaderssenvirons FieldStoragesStringIOsbodysTruesformsparamsskeyss TypeErrorstraces file_pathskeys isinstanceslistsvaluess form_valuesfilenamesNonesappendsvaluesosspathsexistssopensfswritesstrsclose( sselfsformskeyssvaluessfilenames form_valuesenvironskeysparamssf((s/build/bdist.linux-i686/egg/funkload/Recorder.pys extractParam=s>/      cCsAd}|io|i}nd|i|it|fSdS(Nss"(sparamssselfsbodys extractParamsmethodsurlsstr(sselfsparams((s/build/bdist.linux-i686/egg/funkload/Recorder.pys__repr__gs (s__name__s __module__s__doc__s__init__s extractParams__repr__(((s/build/bdist.linux-i686/egg/funkload/Recorder.pysRequest's   *sResponsecBs tZdZdZdZRS(sStore a tcpwatch response.cCs||_t|d}|iitd}|d|_|di |_ t |djo|di |_ n d|_ t ti|i|_|i|_|idS(sLoad a tcpwatch response file.srbiiisN(s file_pathsselfsopensfsreadlinessplitsNoneslinesversionsstrips status_codeslensstatus_messagesdictsrfc822sMessagesitemssheaderssreadsbodysclose(sselfs file_pathsfsline((s/build/bdist.linux-i686/egg/funkload/Recorder.pys__init__qs   cCs'd|i|iid|ifSdS(Ns,s content-type(sselfs status_codesheaderssgetsstatus_message(sself((s/build/bdist.linux-i686/egg/funkload/Recorder.pys__repr__s(s__name__s __module__s__doc__s__init__s__repr__(((s/build/bdist.linux-i686/egg/funkload/Recorder.pysResponseos  sRecorderProgramcBs}tZdZdZedZdZdZdZdZ ddZ d Z d Z d Z d Zd ZRS(s A tcpwatch to funkload recorder.s%prog [options] [test_name] %prog launch a TCPWatch proxy and record activities, then output a FunkLoad script or generates a FunkLoad unit test if test_name is specified. The default proxy port is 8090. Note that tcpwatch.py executable must be accessible from your env. See http://funkload.nuxeo.org/ for more information. Examples ======== %prog foo_bar Run a proxy and create a FunkLoad test case, generates test_FooBar.py and FooBar.conf file. To test it: fl-run-test -dV test_FooBar.py %prog -p 9090 Run a proxy on port 9090, output script to stdout. %prog -i /tmp/tcpwatch Convert a tcpwatch capture into a script. cCs|tjotid}nt|_t|_d|_d|_t|_ t|_ t|_ t|_ t|_ |i|dS(Niswatchs8090(sargvsNonessyssFalsesselfsverboses tcpwatch_pathsprefixsports server_urls class_names test_names script_pathsconfiguration_paths parseArgs(sselfsargv((s/build/bdist.linux-i686/egg/funkload/Recorder.pys__init__s          c Csqt|idtddt}|idddddd |id d d d ddd|idd|iddd d dddtdd|i |\}}t |djo|d}nt}|i|_|i|_|i|_|ordigi}tid|D]}||iq~}||_||_d||_d||_ndS(sParse programs args.s formattersversions FunkLoad %ss-vs --verbosesactions store_trueshelpsVerbose outputs-ps--portstypesstringsdestsportsdefaultsThe proxy port.s-is--tcp-watch-inputs tcpwatch_paths%Path to an existing tcpwatch capture.iiss_|-s ./test_%s.pys ./%s.confN(s OptionParsersselfsUSAGEsTitledHelpFormatters get_versionsparsers add_optionsportsNones parse_argssargvsoptionssargsslens test_namesverboses tcpwatch_pathsjoinsappends_[1]sressplitsxs capitalizes class_names script_pathsconfiguration_path( sselfsargvsargssparsersoptionss_[1]s class_names test_namesx((s/build/bdist.linux-i686/egg/funkload/Recorder.pys parseArgss.      B   cCsbtd|_d|i|if}|io|d7}n |d7}tdti|dS(sStart a tcpwatch session.s _funkloadstcpwatch.py -p %s -s -r %ss | grep "T http"s > /dev/nullsHit Ctrl-C to stop recording. N( smkdtempsselfs tcpwatch_pathsportscmdsverbosestracesosssystem(sselfscmd((s/build/bdist.linux-i686/egg/funkload/Recorder.pys startProxys   cCsKh}|i}xti|iD]}|i| oq"ntii |\}}|t |i}|d}|djot d|q"n|ddfjptd|tii|i||i|h|>funkload/CPS340TestCase.pyc; Dc@sYdZdkZdkZdklZdklZdklZdefdYZdS(s]FunkLoad test case for Nuxeo CPS. $Id: CPSTestCase.py 24728 2005-08-31 08:13:54Z bdelbosc $ N(sLipsum(s ZopeTestCase(sUploads CPSTestCasec BsktZdZdddfZeZeZdddddd d d d d g Zed Z dddgZ eZ edZ dZ eeedeeedZdZdZeeeeeedZeeeeeedZdZdedZdedZdZdZed Zd!Zd"Zed#Zd$Zd%Zed&ZRS('s=Common CPS tasks. setUp must set a server_url attribute.iiisensfrsdesitsesspt_BRsnlsmgsroseusCPSForum:defaults CPSSkins:cps3sCPSSubscriptions:defaultcCst|_d|gd|gddgddgg}|id|i|dd ||pd f|i gi }|i D]$}|id o||q{q{~d ||f||_d S(s4Log in a user. Raise on invalid credential.s __ac_names __ac_passwords__ac_persistentsonssubmitsLogins %s/logged_ins descriptionsLog in user [%s] %ssslogoutsinvalid credential: [%s:%s].N(sNonesselfs _cps_loginsloginspasswordsparamssposts server_urlscommentsassert_sappends_[1]slistHrefslinksendswith(sselfsloginspasswordscomments_[1]sparamsslink((s5build/bdist.linux-i686/egg/funkload/CPS340TestCase.pyscpsLogin.s *DcCs9|itj o%|id|idd|indS(sLog out the current user.s %s/logouts descriptions Log out [%s]N(sselfs _cps_loginsNonesgets server_url(sself((s5build/bdist.linux-i686/egg/funkload/CPS340TestCase.pys cpsLogout@ssportletsc Cs| tjp | tjo|i\} } n|i||hd| <d|pd<d|<d|<d|<d|<dd <d d <d | p|i <d |pd<d|p|i<dd<dd<} |id| | d d|idS(skCreate a CPS Site. if zope_url or site_id is not provided guess them from the server_url. ssite_idstitlesFunkLoad CPS Portals manager_idspasswordspassword_confirms manager_emailsmanager_firstnamesManagersmanager_lastnames CPS Managersextension_ids:lists descriptionsA funkload cps test siteslanguages:listssubmitsAdds profile_idsCPSDefault:defaults4%s/manage_addProduct/CPSDefault/addConfiguredCPSSitesCreate a CPS SiteN(szope_urlsNonessite_idsselfscpsGuessZopeUrls setBasicAuthsadmin_ids admin_pwdstitles manager_idsmanager_passwords manager_mails extensionss_default_extensionss descriptionslangss_default_langssparamsspostsclearBasicAuth(sselfsadmin_ids admin_pwds manager_idsmanager_passwords manager_mailslangsstitles descriptions interfaceszope_urlssite_ids extensionssparams((s5build/bdist.linux-i686/egg/funkload/CPS340TestCase.pys cpsCreateSiteFs   cCs}|i}ddgddgd|gddgddgg}|id |||i|iid d jd |d S(sCreate a cps group.sdirnamesgroupssidss widget__groupswidget__members:tokens:defaults%cpsdirectory_entry_create_form:methodsCreates%s/spsm_entry_createdisFailed to create group %sN(sselfs server_urls group_namesparamsspostsassert_s getLastUrlsfind(sselfs group_namesparamss server_url((s5build/bdist.linux-i686/egg/funkload/CPS340TestCase.pyscpsCreateGroupgs  3cCsd|i}ddgd|gg}|id||dd|o|idn|i|dS( s&Check existance or create a cps group.sdirnamesgroupssids%s/cpsdirectory_entry_views descriptionsCheck that group [%s] exists.sGroup %s exists.N(sselfs server_urls group_namesparamssexistsslogdscpsCreateGroup(sselfs group_namesparamss server_url((s5build/bdist.linux-i686/egg/funkload/CPS340TestCase.pyscpsVerifyGroupss c Csu|i}|i}|pd|i}|p|ii }|p |i }|pd}|p|idd}ddgddgd |gd |gd |gd |gd |gd|gddgddgddgddgddgg } x!|D]} | id| gqW|id|i| dd||i|iiddjd|||fSdS(sBCreate a cps user with the Member role. return login, pwdsfl_sroot@127.0.0.01s length_minisdirnamesmemberssidss widget__idswidget__passwordswidget__confirmswidget__givenNames widget__sns widget__emailswidget__roles:tokens:defaultswidget__roles:listsMemberswidget__groups:tokens:defaultswidget__homeless:booleansFalses%cpsdirectory_entry_create_form:methodsCreateswidget__groups:lists%s/s descriptionsCreate user [%s]spsm_entry_createdisFailed to create user %sN(sselfs_lipsumslipsums getUniqWordssignsuser_idslowersuser_givenNamesgetWords capitalizesuser_snsuppers user_emailsuser_pwdsparamssgroupssgroupsappendsposts server_urlsassert_s getLastUrlsfind( sselfsuser_idsuser_pwdsuser_givenNamesuser_sns user_emailsgroupsslipsumssignsparamssgroup((s5build/bdist.linux-i686/egg/funkload/CPS340TestCase.pys cpsCreateUsers"   {  cCsx|oQddgd|gg}|id|i|o|id|tfSqXn|i||||||SdS(smVerify if user exists or create him. return login, pwd if user exists pwd is None. sdirnamesmemberssids%s/cpsdirectory_entry_viewsUser %s exists.N( suser_idsparamssselfsexistss server_urlslogdsNones cpsCreateUsersuser_pwdsuser_givenNamesuser_sns user_emailsgroups(sselfsuser_idsuser_pwdsuser_givenNamesuser_sns user_emailsgroupssparams((s5build/bdist.linux-i686/egg/funkload/CPS340TestCase.pys cpsVerifyUsers cCs@d|gd|gg}|id||dd||fdS(sSetup local role role to url.smember_ids:lists member_roles%s/folder_localrole_adds descriptionsGrant local role %s to %sN(snamesrolesparamssselfspostsurl(sselfsurlsnamesrolesparams((s5build/bdist.linux-i686/egg/funkload/CPS340TestCase.pyscpsSetLocalRoless#ftest section for funkload testing.cCs*|id||||p |iSdS(sCreate a section.sSectionN(sselfscpsCreateFolders parent_urlstitles descriptionslangscpsGetRandomLanguage(sselfs parent_urlstitles descriptionslang((s5build/bdist.linux-i686/egg/funkload/CPS340TestCase.pyscpsCreateSectionss%ftest workspace for funkload testing.cCs*|id||||p |iSdS(sCreate a workspace.s WorkspaceN(sselfscpsCreateFolders parent_urlstitles descriptionslangscpsGetRandomLanguage(sselfs parent_urlstitles descriptionslang((s5build/bdist.linux-i686/egg/funkload/CPS340TestCase.pyscpsCreateWorkspacescCsnd|gd|gd|gd|gdtgddgg}|id||d ||i |i Sd S( sFCreate a section or a workspace. Return the section full url.s type_names widget__Titleswidget__Descriptions widget__LanguageSelectorCreationswidget__hidden_folder:booleanscpsdocument_create_buttonsCreates%s/cpsdocument_creates Create a %sN( stypestitles descriptionslangsFalsesparamssselfsposts parent_urls cpsCleanUrlsgetLastBaseUrl(sselfstypes parent_urlstitles descriptionslangsparams((s5build/bdist.linux-i686/egg/funkload/CPS340TestCase.pyscpsCreateFolders < cCs|i}|iidtdd|}ddgd|gd|iidgd |gd |iigd d gd dgg}|i d||dd|i |i i ddjd||f|i|i}|idd}||fSdS(sTCreate a simple random document. return a tuple: (doc_url, doc_id) suniqsprefixstest %ss type_namesDocuments widget__Titleswidget__Descriptioni s widget__LanguageSelectorCreationswidget__contentswidget__content_rformatstextscpsdocument_create_buttonsCreates%s/cpsdocument_creates descriptionsCreating a documentspsm_content_createdisFailed to create [%s] in %s/.s/N(sselfscpsGetRandomLanguageslanguages_lipsums getSubjectsTruestitles getMessagesparamssposts parent_urlsassert_s getLastUrlsfinds cpsCleanUrlsgetLastBaseUrlsdoc_urlssplitsdoc_id(sselfs parent_urlslanguagestitlesdoc_idsparamssdoc_url((s5build/bdist.linux-i686/egg/funkload/CPS340TestCase.pyscpsCreateDocuments Z c Cs|i}|iidtdd|}d|iigddgd|gd|iid gd d gd |od pdgdt |pd gddgddgdd gd|ii gddgdt d gdd gddgdt i dgdt i dgd t i d!gd"d#gg}|id$||d%d&|i}|id'|jd(||f|i|i}|id)d*}||fSd+S(,sACreate a random news. return a tuple: (doc_url, doc_id).suniqsprefixstest %ss cpsformuids type_names News Items widget__Titleswidget__Descriptioni swidget__photo_filenamesswidget__photo_choiceschangeskeeps widget__photoswidget__photo_resizes img_auto_sizeswidget__photo_rpositionsleftswidget__photo_subtitleswidget__contentswidget__content_rformatstextswidget__content_fileuploadswidget__Subject:tokens:defaultswidget__Subject:listsBusinessswidget__publication_date_dates01/01/%Yswidget__publication_date_hours%Hswidget__publication_date_minutes%Mscpsdocument_create_buttonsCreates%s/cpsdocument_creates descriptionsCreating a news itemspsm_content_createdsFailed to create [%s] in %s/.s/iN(sselfscpsGetRandomLanguageslanguages_lipsums getSubjectsTruestitles getUniqWords photo_pathsUploads getMessagestimesstrftimesparamssposts parent_urls getLastUrlslast_urlsassert_s cpsCleanUrlsgetLastBaseUrlsdoc_urlssplitsdoc_id( sselfs parent_urls photo_pathslanguagestitlesdoc_idsparamsslast_urlsdoc_url((s5build/bdist.linux-i686/egg/funkload/CPS340TestCase.pyscpsCreateNewsItems    cCs1|id|idd|ggdd|dS(s3Change the ui language and return the referer page.s%s/cpsportlet_change_languagesparamsslangs descriptionsChange UI language to %sN(sselfsgets server_urlslang(sselfslang((s5build/bdist.linux-i686/egg/funkload/CPS340TestCase.pyscpsChangeUiLanguagescCsti|iSdS(sReturn a random language.N(srandomschoicesselfs _all_langs(sself((s5build/bdist.linux-i686/egg/funkload/CPS340TestCase.pyscpsGetRandomLanguage scCsP|tjo |i}n|idd}|t|d }||fSdS(sfGuess a zope url and site_id from a CPS Site url. return a tuple (zope_url, site_id) s/iiN(scps_urlsNonesselfs server_urlssplitssite_idslenszope_url(sselfscps_urlssite_idszope_url((s5build/bdist.linux-i686/egg/funkload/CPS340TestCase.pyscpsGuessZopeUrl$s   cCskd|gg}|id|i|dd||idd|}|idt||f|SdS( sLReturn the list of url that ends with doc_id. Using catalog search.sSearchableTexts%s/search_forms descriptionsSearching doc_id %sspatterns%s$sfound %i link ends with %sN( sdoc_idsparamssselfsposts server_urlscpsListDocumentHrefsretslogdslen(sselfsdoc_idsparamssret((s5build/bdist.linux-i686/egg/funkload/CPS340TestCase.pyscpsSearchDocId/scCs|}|i}xiddddddfD]O}|i|o|t| }n|i|o|t|}q(q(W|SdS(s*Try to remove server_url and clean ending.s/s/views/folder_contentss /folder_views/cpsdocument_metadatas/cpsdocument_edit_formN(surl_insurlsselfs server_urlsendingsendswithslens startswith(sselfsurl_insurls server_urlsending((s5build/bdist.linux-i686/egg/funkload/CPS340TestCase.pys cpsCleanUrl:s cCspg}x_gi}|i|D]}||i|q ~D]$}||jo|i|q@q@W|SdS(sReturn a clean list of document href that matches pattern. Try to remove server_url and other cps trailings, return a list of uniq url.N( sretsappends_[1]sselfslistHrefspatternsxs cpsCleanUrlshref(sselfspatternsrets_[1]shrefsx((s5build/bdist.linux-i686/egg/funkload/CPS340TestCase.pyscpsListDocumentHrefGs: (s__name__s __module__s__doc__scps_test_case_versionsNones server_urlsLipsums_lipsums _all_langss_default_langss_default_extensionss _cps_loginscpsLogins cpsLogouts cpsCreateSitescpsCreateGroupscpsVerifyGroups cpsCreateUsers cpsVerifyUserscpsSetLocalRolescpsCreateSectionscpsCreateWorkspacescpsCreateFolderscpsCreateDocumentscpsCreateNewsItemscpsChangeUiLanguagescpsGetRandomLanguagescpsGuessZopeUrlscpsSearchDocIds cpsCleanUrlscpsListDocumentHref(((s5build/bdist.linux-i686/egg/funkload/CPS340TestCase.pys CPSTestCases6  $   ! "    $  (s__doc__stimesrandomsLipsums ZopeTestCaseswebunit.utilitysUploads CPSTestCase(s ZopeTestCasesrandomsUploadsLipsumstimes CPSTestCase((s5build/bdist.linux-i686/egg/funkload/CPS340TestCase.pys?s      PK]i6 >%>%funkload/Lipsum.pyc; Ccz@sdZdkZdddddddd d d d d ddddddddddddddddddd d!d"d#d$d%d&d'd(d)d*d+d,d-d.d/d0d1d2d3d4d5d6d7d8d9d:d;d<d=d>d?d@dAdBdCdDdEdFdGdHdIdJdKdLdMdNdOdPdQdRdSdTdUdVdWdXdYdZd[d\d]d^d_d`dadbdcdddedfdgdhdidjdkdldmdndodpdqdrdsdtdudvdwdxdydzd{fzZd|d}d~dddddddddddddddddddddddddddddddddddddddddddddddddddddf8ZdddddddddddddddddddddddddddddddfZdZdddZdfdYZdZe djo endS(sVA simple Lorem ipsum generator. $Id: Lipsum.py 24649 2005-08-29 14:20:19Z bdelbosc $ Nsadsaquamsalbussarchaeossarctoss argentatussarvensiss australissbiscortborealissbrachysbradussbrevisscampusscaudascaulosscephaluss chilensisschloreusscolas cristatusscyanossdactylussdecasdermissdelorumsdisdiplosdodecasdolichos domesticussdorsumsdulcissechinussenneaserythros familiarissflorasfoliussfuscussfulvussgastersglycisshexas hortensissitsindicuss lateralissleucusslineatusslipsemsluteas maculatussmajorsmaximussmelanussminimussminorsmonosmontanussmorphossmaurosnigersnonasnothossnotossnovaehollandiaesnovaeseelandiaesnoveboracensissobscuruss occidentalissoctasoeoss officinalissoleums orientalissorthospachyss palustrissparvusspedisspelagiusspentaspetrasphyllosphytonsplatys pratensissprotosspterons punctatussrhizasrhytissrubrasrostrasrufusssativusssaurusssinensissstomasstriatuss silvestrisssitssostetras tinctoriuss tomentosusstresstrisstrichsthrixsunuss variabiliss variegatussventruss verrucosussviasviridissvitissvolanssvulgarissxanthosszygossacanthsacrosactinosadelphesadnosarosagoguesagrosalgiesallosamphisandrosantisanthroposaquisarchosarchiesautosbioscalliscephalschiroschromoschronosdactylesdmosecos eudaimoniasthossgosglyphesgonesgrammesgrapheshiroshomosiatrieslipisliposlogieslycoslysesmachiesmlansmtasnautesnsespedosphilsphobiespodospolisspolysrhinosxenoszoosjcnthszcrsbctinszdelpheskdnszrsaggusalgisallsadrosatisaqisatsbiscaisephalslcosrtsoisessdusdeslesassussisavesov szur sab s!abcdefghjkmnopqrstuvwxyz123456789s,i s;?!sLipsumcBstZdZeeedZdZeedZ dee eedZ dZ ddZ d d Zd d d Zd dZRS(sKind of Lorem ipsum generator.cCs||_||_||_dS(N(svocabsselfscharsssep(sselfsvocabscharsssep((s-build/bdist.linux-i686/egg/funkload/Lipsum.pys__init__Ms  cCsti|iSdS(sReturn a random word.N(srandomschoicesselfsvocab(sself((s-build/bdist.linux-i686/egg/funkload/Lipsum.pysgetWordSscCsv|pd}|pd}ti||}|i}digi}t |D]}|ti |qO~SdS(s#Generate a kind of uniq identifier.ii sN( s length_mins length_maxsrandoms randrangeslengthsselfscharssjoinsappends_[1]srangesischoice(sselfs length_mins length_maxsis_[1]slengthschars((s-build/bdist.linux-i686/egg/funkload/Lipsum.pys getUniqWordWs    icCsg}|o|i|n|o|i|in|o|oti ||d}nx't |D]}|i|i qqWdi|iSdS(s!Return a subject of length words.is N(ssubjectsprefixsappendsuniqsselfs getUniqWords length_mins length_maxsrandoms randrangeslengthsrangesisgetWordsjoins capitalize(sselfslengthsprefixsuniqs length_mins length_maxsissubject((s-build/bdist.linux-i686/egg/funkload/Lipsum.pys getSubject_s cCs|i}tidd}gi}t|D]}||i q/~}xJttiddD]0}|i ti|ddti |qgWdi |id}|id d }|id d }|Sd S( sReturn a random sentence.iiiiiis s.s ,s,s,,N(sselfssepsrandoms randrangeslengthsappends_[1]srangesisgetWordssentencesinsertschoicesjoins capitalizesreplace(sselfssentencesis_[1]slengthssep((s-build/bdist.linux-i686/egg/funkload/Lipsum.pys getSentencems 3.icCs>digi}t|D]}||iq~SdS(sReturn a paragraph.s N(sjoinsappends_[1]srangeslengthsisselfs getSentence(sselfslengths_[1]si((s-build/bdist.linux-i686/egg/funkload/Lipsum.pys getParagraphysicCsJdigi}ttid|D]}||i q&~SdS(s"Return a message paragraph length.s iN( sjoinsappends_[1]srangesrandoms randrangeslengthsisselfs getParagraph(sselfslengthsis_[1]((s-build/bdist.linux-i686/egg/funkload/Lipsum.pys getMessage}ssfrsmediumcCsT|djog}|idtidd|idtidd|djodi|Sn|iddtidd|d jod t|Snd t|Snd g}x1t d D]#}|idtiddqW|d jodi|Sn-|djod|d               $ ((s__name__s __module__s__doc__sFalses__init__srun(((s2build/bdist.linux-i686/egg/funkload/BenchRunner.pysLoopTestRunner|s  s BenchRunnercBsztZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z d ZRS( sRun a unit test in bench mode.cCsg|_tiitii|d|_||_||_ ||_ |i |_ t |i|t|ddd|}|i|_|i|_|idd|_|idd|_|i |_|i|i dd|_|idd|_tt|idd|_|idd |_|idd |_ |idd |_!|idd |_"|idd |_#|idd|_$g}xf|iddddt&i'D]C}|i)}|i*||i|d|i|ddfqW||_%||_dS(Nismainstitles descriptionsNo test descriptionsurlsbenchscyclessdurations startup_delays cycle_times sleep_timessleep_time_minssleep_time_maxsmonitorshostsssquietsport(+sselfsthreadssosspathsbasenamessplitexts module_files module_names class_names method_namesoptionssno_colorscolors load_unittests mmn_encodestests _config_paths config_paths result_pathsconf_gets class_titlesclass_descriptionstest_idstest_descriptionstest_urlsmapsints conf_getListscycless conf_getIntsdurations conf_getFloats startup_delays cycle_times sleep_timessleep_time_minssleep_time_maxs monitor_hostssTruessplitshostsstripsappend(sselfs module_files class_names method_namesoptionsshoststests monitor_hosts((s2build/bdist.linux-i686/egg/funkload/BenchRunner.pys__init__s< %         " 5 cCstt|tdtdd} }}} |ixX|iD]M} t i } t d| | f}t|tdt|ddd|i| | f}|ii|i||i| | |i|i|i|| d7} |iit i }td || t\} }}t| |||i\}}td || ||f|| 7}||7}| |7} qJW|i"td td td |td|td| t||| \}}td||SdS(saRun all the cycles. return 0 on success, 1 if there were some failures and -1 on errors.s Benching s ======== is Cycle #%i with %s virtual users s-is s%s:%s:%ss* End of cycle, %.2fs elapsed. s<* Cycle result: **%s**, %i success, %i failure, %i errors. sResult s====== s* Success: %s s* Failures: %s s* Errors: %s sBench status: **%s** N(#stracesstrsselfscycles total_successstotal_failuress total_errorss logr_openscyclesscvusstimest_startsreset_cycle_resultsstextslens method_names monitor_keystests setUpCycles startMonitorss startThreadssloggings stopThreadss stopMonitorss tearDownCyclest_stopsget_cycle_resultsssuccesssfailuresserrorss get_statusscolorsstatusscodes logr_close(sselfscodestextst_stops total_successs monitor_keyserrorssstatusstotal_failuresst_startscvusscycles total_errorsssuccesssfailures((s2build/bdist.linux-i686/egg/funkload/BenchRunner.pysrunsN                   c Cstdtiitdg}d}tttt xt |D]}|d7}t |i|i|i|i||||i}tdy|iWn$tj otd|nX|i|t|iqQWtd||_dS( sStarting threads.s* Current time: %s s* Starting threads: iis.sj ERROR: Can not create more than %i threads, try a smaller stack size using: 'ulimit -s 2048' for example s done. N(stracesdatetimesnows isoformatsthreadssisset_running_flagsTruesset_recording_flagsFalsesrangesnumber_of_threadss thread_idsLoopTestRunnersselfs module_names class_names method_namesoptionsscycles sleep_timesthreadsstarts ThreadErrorsappends thread_sleeps startup_delay(sselfscyclesnumber_of_threadssthreadsis thread_idsthreads((s2build/bdist.linux-i686/egg/funkload/BenchRunner.pys startThreadss0         cCs|i}ti|}td|ti|iftt x%ti|joti dqIWtt tddS(sLog activity during duration.s* Logging for %ds (until %s): is done. N( sselfsdurationstimesend_timestracesdatetimes fromtimestamps isoformatsset_recording_flagsTruessleepsFalse(sselfsend_timesduration((s2build/bdist.linux-i686/egg/funkload/BenchRunner.pyslogging+s #  cCs~tttdx(|iD]}|i~tdqW|`tdtd|iti |itddS(sWait for thread endings.s* Waiting end of threads: s.s done. s"* Waiting cycle sleeptime %ds: ...N( sset_running_flagsFalsestracesselfsthreadssthreadsjoins cycle_timestimessleep(sselfsthread((s2build/bdist.linux-i686/egg/funkload/BenchRunner.pys stopThreads9s     c Csdk}h}|i}xO|iD]A\}}diti |}|i |g|g|||i\}}|i tjout |d?jo|i d@n|d?}|idAo*tiitii|d?d?}n||_ n|id?|i |io dB|_n|iod?|_tan|ip|iodC|_dD|_tan dE|_|iot|i|_n|i |_ |i!|_"|i#|_$||i%_ |i&tj o|i&g|_'n%t |dCjo|dC|_'ndFS(GsParse programs args.s formattersversions FunkLoad %ss-qs--quietsactions store_trueshelpsMinimal output.s-vs --verbosesVerbose output.s-ds--debugs"FunkLoad and doctest debug output.s --debug-levelstypesintsDebug level 2 is more verbose.s-us--urlsstringsdestsmain_urls%Base URL to bench without ending '/'.s-ms--sleep-time-minsftest_sleep_time_mins#Minumum sleep time between request.s-Ms--sleep-time-maxsftest_sleep_time_maxs#Maximum sleep time between request.s--dump-directorysdump_dirsDirectory to dump html pages.s-Vs--firefox-views[Real time view using firefox, you must have a running instance of firefox in the same host.s --no-colorsMonochrome output.s-ls--loop-on-pagess loop_stepssxLoop as fast as possible without concurrency on pages, expect a page number or a slice like 3:5. Output some statistics.s-ns --loop-numbers loop_numbersdefaulti sNumber of loop.s--accept-invalid-linkss1Do not fail if css/image links are not reachable.s--simple-fetchsJDon't load additional links like css or images when fetching an html page.s--stop-on-fails%Stop tests on first failure or error.s-es--regexs$The test names must match the regex.s--listsJust list the test names.isincorrect number of argumentss.pyiis console filesfileN((s OptionParsersselfsUSAGEsTitledHelpFormatters get_versionsparsers add_optionsNones parse_argssoptionssargssmoduleslenserrorsendswithsosspathsbasenamessplitextsinsertsverboses verbositysquietsFalsesg_doctest_verbosesdebugs debug_levelsftest_debug_levels ftest_log_tosTruesintsno_colorscolorsregexstest_name_patternslists list_testss testLoaders defaultTests testNames(sselfsargvsargssmodulesparsersoptions((s1build/bdist.linux-i686/egg/funkload/TestRunner.pys parseArgsks                   *               cCs||itjo?|iotd|i|_qOtid|i|_n|ii|i }t i |i dS(sLaunch the tests.s verbosityN(sselfs testRunnersNonescolorsColoredTextTestRunners verbositysunittestsTextTestRunnersrunstestsresultssyssexits wasSuccessful(sselfsresult((s1build/bdist.linux-i686/egg/funkload/TestRunner.pysrunTestss ( s__name__s __module__s__doc__sUSAGEsNonesunittestsdefaultTestLoaders__init__s loadTestss parseArgssrunTests(((s1build/bdist.linux-i686/egg/funkload/TestRunner.pys TestPrograms +&  XcCsEtiitii}tiid|t}t d|dS(s Default main.is testLoaderN( sosspathsabspathscurdirscur_pathssyssinserts TestLoaders test_loaders TestProgram(s test_loaderscur_path((s1build/bdist.linux-i686/egg/funkload/TestRunner.pysmains  s__main__()s__doc__sosssysstypesstimesunittestsresStringIOsoptparses OptionParsersTitledHelpFormattersutilssred_strs green_strs get_versionsfunkload.FunkLoadTestCasesFunkLoadTestCasesFalsesg_doctest_verbosesdoctests DocTestSuites DocFileSuites DocTestCases DocTestRunnersREPORTING_FLAGSs_unittest_reportflagssTrues g_has_doctests ImportErrors DTC_runTestsrunTests TestLoaders_TextTestResults_ColoredTextTestResultsTextTestRunnersColoredTextTestRunnersfilter_testcasessdisplay_testcasess TestProgramsmains__name__(s_unittest_reportflagssunittestsfilter_testcasess DocTestCasesTitledHelpFormatters get_versions DocTestRunnersrestypessdisplay_testcasessmains DocTestSuites OptionParsers TestLoaders DocFileSuites TestProgramsFunkLoadTestCasessyssColoredTextTestRunnersred_strsStringIOs green_strsREPORTING_FLAGSs DTC_runTeststimesoss_ColoredTextTestResult((s1build/bdist.linux-i686/egg/funkload/TestRunner.pys?s8            R    PK]i6;nfunkload/ZopeTestCase.pyc; Cc@sCdZdkZdklZdklZdefdYZdS(sYFunkLoad test case for Zope. $Id: ZopeTestCase.py 30282 2005-12-05 12:52:30Z bdelbosc $ N(serror(sFunkLoadTestCases ZopeTestCasecBsAtZdZddZdddZddZedZRS(sCommon zope 2.8 tasks.iXc Cs|i||hdd<}d|}|i||ddt}t i }xx|opt i dy|i |ddWn?tj o3t i ||jo|id|qqTXt}qTW|id S( sStop and Start Zope server.smanage_restart:actionsRestarts%s/Control_Panels descriptionsRestarting Zope serverisChecking zope presencesZope restart time out %ssN(sselfs setBasicAuthsadmin_ids admin_pwdsparamsszope_urlsurlspostsTruesdownstimes time_startssleepsgets SocketErrorstime_outsfailsFalsesclearBasicAuth( sselfszope_urlsadmin_ids admin_pwdstime_outsdowns time_startsurlsparams((s3build/bdist.linux-i686/egg/funkload/ZopeTestCase.pys zopeRestarts"    smainic Cs|i||d||f}hdt|<}|i ||dd||fddddg}|i djo>|i id d jo|id q|id n|id S(sPack a zodb database.s(%s/Control_Panel/Database/%s/manage_packs days:floats descriptionsVPacking %s Zodb, removing previous revisions of objects that are older than %s day(s).sok_codesii.is1Error Value: The database has already been packedisPack_zodb return a code 500.sZodb has already been packed.N(sselfs setBasicAuthsadmin_ids admin_pwdszope_urlsdatabasesurlsstrsdayssparamsspostsrespscodesgetBodysfindsfailslogdsclearBasicAuth( sselfszope_urlsadmin_ids admin_pwdsdatabasesdayssurlsparamssresp((s3build/bdist.linux-i686/egg/funkload/ZopeTestCase.pys zopePackZodb2s cCs;|i||d||f}|i|dd|dS(s2Remove all objects from all ZODB in-memory caches.s,%s/Control_Panel/Database/%s/manage_minimizes descriptionsFlush %s Zodb cacheN(sselfs setBasicAuthsadmin_ids admin_pwdszope_urlsdatabasesurlsget(sselfszope_urlsadmin_ids admin_pwdsdatabasesurl((s3build/bdist.linux-i686/egg/funkload/ZopeTestCase.pyszopeFlushCacheEsc Cs|i||d|gddgd|gd|gddgg} |}|d7}|i || d d d d gd d|} | i d jo>|i iddjo|idq|idn|o%|id||fd d|n|idS(s!Add an External method an run it.sidstitlessmodulesfunctionssubmits Add s:/manage_addProduct/ExternalMethod/manage_addExternalMethodsok_codesii.is descriptionsAdding %s external methods"is invalid - it is already in use.is)Error got 400 on manage_addExternalMethodsExternal method already existss%s/%ssExecute %s external methodN(sselfs setBasicAuthsadmin_ids admin_pwds method_idsmodulesfunctionsparamss parent_urlsurlspostsrespscodesgetBodysfindsfailslogdsrun_itsgetsclearBasicAuth( sselfs parent_urlsadmin_ids admin_pwds method_idsmodulesfunctionsrun_itsurlsparamssresp((s3build/bdist.linux-i686/egg/funkload/ZopeTestCase.pyszopeAddExternalMethodLs3 (s__name__s __module__s__doc__s zopeRestarts zopePackZodbszopeFlushCachesTrueszopeAddExternalMethod(((s3build/bdist.linux-i686/egg/funkload/ZopeTestCase.pys ZopeTestCases   (s__doc__stimessocketserrors SocketErrorsFunkLoadTestCases ZopeTestCase(s ZopeTestCases SocketErrorsFunkLoadTestCasestime((s3build/bdist.linux-i686/egg/funkload/ZopeTestCase.pys?s   PK]i6d x""funkload/CredentialFile.pyc; Cc@sdZdkZdklZdklZlZdklZdfdYZ deefdYZ d efd YZ d Z e d jo e ndS( scA file credential server/controller. $Id: CredentialFile.py 30282 2005-12-05 12:52:30Z bdelbosc $ N(s NoOptionError(sXmlRpcBaseServersXmlRpcBaseController(sCredentialBaseServersGroupcBs;tZdZdZdZdZdZdZRS(sA class to handle groups.cCs(||_d|_d|_g|_dS(Ni(snamesselfsindexscountsusers(sselfsname((s5build/bdist.linux-i686/egg/funkload/CredentialFile.pys__init__"s   cCs,|ii| o|ii|ndS(sAdd a user to the group.N(sselfsusersscountsusersappend(sselfsuser((s5build/bdist.linux-i686/egg/funkload/CredentialFile.pysadd(scCst|iSdS(sReturn the lenght of group.N(slensselfsusers(sself((s5build/bdist.linux-i686/egg/funkload/CredentialFile.pys__len__-scCsjt|i}|djotd|in|i||_|i|i}|id7_|SdS(s?Return the next user or the group. loop from begining.isNo users for group %siN( slensselfsuserssnb_userss ValueErrorsnamescountsindexsuser(sselfsnb_userssuser((s5build/bdist.linux-i686/egg/funkload/CredentialFile.pysnext1s cCs'd|i|i|it|fSdS(sRepresentation.s2N(sselfsnamescountsindexslen(sself((s5build/bdist.linux-i686/egg/funkload/CredentialFile.pys__repr__=s(s__name__s __module__s__doc__s__init__sadds__len__snexts__repr__(((s5build/bdist.linux-i686/egg/funkload/CredentialFile.pysGroup s     sCredentialFileServercBs~tZdZdZeidddgZdZdZedZ dZ d Z d Z ed Z ed Zd ZRS(sA file credential server.sfile_credentials getCredentialslistCredentialss listGroupss:s,cCs/d|_h|_h|_ti||dS(Ni(sselfslofcs_groupss _passwordssXmlRpcBaseServers__init__sargv(sselfsargv((s5build/bdist.linux-i686/egg/funkload/CredentialFile.pys__init__Ps   cCsq|idd}|idd|_|i|y#|idd}|i|Wnt j onXdS(s*init procedure to override in sub classes.sserverscredentials_pathsloop_on_first_credentialss groups_pathN( sconfsgetscredentials_pathsgetintsselfslofcs_loadPasswordss groups_paths _loadGroupss NoOptionError(sselfsconfsoptionss groups_pathscredentials_path((s5build/bdist.linux-i686/egg/funkload/CredentialFile.pys_init_cbVs c Cs|id|t|i}h|_td}||it ~}|i d||f|SdS(sReturn a list of credentials.slistUsers(%s) return (%s)N( sgroupsNoneslistsselfs _passwordssrets_groupssuserssappends_[1]suserslogd(sselfsgroupsuserssrets_[1]suser((s5build/bdist.linux-i686/egg/funkload/CredentialFile.pyslistCredentialss 4cCs7tt|ii}|idt||SdS(sReturn a list of groups.slistGroup() return (%s)N(sfiltersNonesselfs_groupsskeyssretslogdsstr(sselfsret((s5build/bdist.linux-i686/egg/funkload/CredentialFile.pys listGroupss(s__name__s __module__s__doc__s server_namesXmlRpcBaseServers method_namesscredential_seps users_sepsNones__init__s_init_cbs_loadPasswordss _loadGroupss getCredentialslistCredentialss listGroups(((s5build/bdist.linux-i686/egg/funkload/CredentialFile.pysCredentialFileServerGs     sCredentialFileControllercBstZdZeZdZRS(sA file credential controller.cCs|i}|i|ixNtdD]@}|id||i\}}|id||fq)Wx?|iD]1}|id||id|i |qzWdSdS(sTesting credential server.i s%s getCredential() ... s return (%s, %s) s group %s s content: %s iN( sselfsserverslogs listGroupssrangesis getCredentialsuserspasswordsgroupslistCredentials(sselfsgroupsisserversuserspassword((s5build/bdist.linux-i686/egg/funkload/CredentialFile.pystests   (s__name__s __module__s__doc__sCredentialFileServers server_classstest(((s5build/bdist.linux-i686/egg/funkload/CredentialFile.pysCredentialFileControllers cCst}ti|dS(sControl credentiald server.N(sCredentialFileControllersctlssyssexit(sctl((s5build/bdist.linux-i686/egg/funkload/CredentialFile.pysmains s__main__(s__doc__ssyss ConfigParsers NoOptionErrors XmlRpcBasesXmlRpcBaseServersXmlRpcBaseControllersCredentialBasesCredentialBaseServersGroupsCredentialFileServersCredentialFileControllersmains__name__( sCredentialBaseServersGroupsXmlRpcBaseServersCredentialFileControllerssyssCredentialFileServers NoOptionErrorsmainsXmlRpcBaseController((s5build/bdist.linux-i686/egg/funkload/CredentialFile.pys?s   'b  PK]i6N9ccfunkload/CredentialRandom.pyc; Cc@sdZdkZdklZdklZlZdklZdeefdYZdefdYZ d Z e d jo e ndS( sgA random credential server/controller. $Id: CredentialRandom.py 28385 2005-10-18 09:29:24Z bdelbosc $ N(sLipsum(sXmlRpcBaseServersXmlRpcBaseController(sCredentialBaseServersCredentialRandomServercBsWtZdZdZeidddgZedZedZedZ dZ RS( sA random credential server.srandom_credentials getCredentialslistCredentialss listGroupscCs ti||t|_dS(N(sXmlRpcBaseServers__init__sselfsargvsLipsumslipsum(sselfsargv((s7build/bdist.linux-i686/egg/funkload/CredentialRandom.pys__init__%scCsy|id||pdd|ii}t|}|idi |}|id||f||fSdS(sReturn a random (login, password). return a random user login, the login is taken from the lipsum vocabulary so the number of login is limited to the length of the vocabulary. The group asked will prefix the login name. The password is just the reverse of the login, this give a coherent behaviour if it return twice the same credential. sgetCredential(%s) request.susers_ss return (%s, %s)N( sselfslogdsgroupslipsumsgetWordsusersliststmpsreversesjoinspassword(sselfsgroupstmpsuserspassword((s7build/bdist.linux-i686/egg/funkload/CredentialRandom.pys getCredential)s   cCsE|idgi}tdD]}||i|q!~SdS(s'Return a list of 10 random credentials.slistCredentials request.i N(sselfslogdsappends_[1]srangesxs getCredentialsgroup(sselfsgroups_[1]sx((s7build/bdist.linux-i686/egg/funkload/CredentialRandom.pyslistCredentials=s c Cs[|id|i}gi}tdD]&}|d|iddddq*~SdS( s&Retrun a list of 10 random group name.slistGroups request.i sgrps length_minis length_maxiN(sselfslogdslipsumsappends_[1]srangesxs getUniqWord(sselfs_[1]sxslipsum((s7build/bdist.linux-i686/egg/funkload/CredentialRandom.pys listGroupsBs   ,( s__name__s __module__s__doc__s server_namesXmlRpcBaseServers method_namessNones__init__s getCredentialslistCredentialss listGroups(((s7build/bdist.linux-i686/egg/funkload/CredentialRandom.pysCredentialRandomServers    sCredentialRandomControllercBstZdZeZdZRS(sA random credential controller.cCs|i}|i|ixNtdD]@}|id||i\}}|id||fq)Wx?|iD]1}|id||id|i |qzWdSdS(sTesting credential server.i s%s getCredential() ... s return (%s, %s) s group %s s content: %s iN( sselfsserverslogs listGroupssrangesis getCredentialsuserspasswordsgroupslistCredentials(sselfsgroupsisserversuserspassword((s7build/bdist.linux-i686/egg/funkload/CredentialRandom.pystestPs   (s__name__s __module__s__doc__sCredentialRandomServers server_classstest(((s7build/bdist.linux-i686/egg/funkload/CredentialRandom.pysCredentialRandomControllerLs cCst}ti|dS(sControl credentiald server.N(sCredentialRandomControllersctlssyssexit(sctl((s7build/bdist.linux-i686/egg/funkload/CredentialRandom.pysmain`s s__main__( s__doc__ssyssLipsums XmlRpcBasesXmlRpcBaseServersXmlRpcBaseControllersCredentialBasesCredentialBaseServersCredentialRandomServersCredentialRandomControllersmains__name__(sCredentialBaseServersXmlRpcBaseServersLipsumssyssCredentialRandomControllersCredentialRandomServersmainsXmlRpcBaseController((s7build/bdist.linux-i686/egg/funkload/CredentialRandom.pys?s   -  PK]i6/]m<<funkload/CPS338TestCase.pyc; Dc@sLdZdkZdkZdklZdklZdefdYZdS(s]FunkLoad test case for Nuxeo CPS. $Id: CPSTestCase.py 24728 2005-08-31 08:13:54Z bdelbosc $ N(sLipsum(s ZopeTestCases CPSTestCasec BsVtZdZdddfZeZeZddddddd d d d g Zed Z eZ edZ dZ eeedeedZ dZdZeeeeeedZeeeeeedZdZdedZdedZdZdZdZdZdZed Zd!Zd"Zed#ZRS($s=Common CPS tasks. setUp must set a server_url attribute.iisensfrsdesitsesspt_BRsnlsmgsroseuicCst|_d|gd|gddgddgg}|id|i|dd ||pd f|i d |i|i jd ||f||_d S(s4Log in a user. Raise on invalid credential.s __ac_names __ac_passwords__ac_persistentsonssubmitsLogins %s/logged_ins descriptionsLog in user [%s] %sss %s/logoutsinvalid credential: [%s:%s].N( sNonesselfs _cps_loginsloginspasswordsparamssposts server_urlscommentsassert_slistHref(sselfsloginspasswordscommentsparams((s5build/bdist.linux-i686/egg/funkload/CPS338TestCase.pyscpsLogin*s *cCs9|itj o%|id|idd|indS(sLog out the current user.s %s/logouts descriptions Log out [%s]N(sselfs _cps_loginsNonesgets server_url(sself((s5build/bdist.linux-i686/egg/funkload/CPS338TestCase.pys cpsLogout;ssportletsc Cs| tjp | tjo|i\} } n|i||hd| <d|pd<d|pd<d|<d|<d|<d |<d d <d d <d|p|i<d| <dd<} |id| | dd|idS(skCreate a CPS Site. if zope_url or site_id is not provided guess them from the server_url. sidstitles CPS Portals descriptionsA funkload cps test sites manager_idsmanager_passwordsmanager_password_confirmations manager_emails manager_snsCPSsmanager_givenNamesManagerslangs_list:lists interfacessubmitsCreates8%s/manage_addProduct/CPSDefault/manage_addCPSDefaultSitesCreate a CPS SiteN(szope_urlsNonessite_idsselfscpsGuessZopeUrls setBasicAuthsadmin_ids admin_pwdstitles descriptions manager_idsmanager_passwords manager_mailslangss_default_langss interfacesparamsspostsclearBasicAuth( sselfsadmin_ids admin_pwds manager_idsmanager_passwords manager_mailslangsstitles descriptions interfaceszope_urlssite_idsparams((s5build/bdist.linux-i686/egg/funkload/CPS338TestCase.pys cpsCreateSiteAs   cCs}|i}ddgddgd|gddgddgg}|id |||i|iid d jd |d S(sCreate a cps group.sdirnamesgroupssidss widget__groupswidget__members:tokens:defaults%cpsdirectory_entry_create_form:methodsCreates%s/spsm_entry_createdisFailed to create group %sN(sselfs server_urls group_namesparamsspostsassert_s getLastUrlsfind(sselfs group_namesparamss server_url((s5build/bdist.linux-i686/egg/funkload/CPS338TestCase.pyscpsCreateGroup_s  3cCsd|i}ddgd|gg}|id||dd|o|idn|i|dS( s&Check existance or create a cps group.sdirnamesgroupssids%s/cpsdirectory_entry_views descriptionsCheck that group [%s] exists.sGroup %s exists.N(sselfs server_urls group_namesparamssexistsslogdscpsCreateGroup(sselfs group_namesparamss server_url((s5build/bdist.linux-i686/egg/funkload/CPS338TestCase.pyscpsVerifyGroupks c Csu|i}|i}|pd|i}|p|ii }|p |i }|pd}|p|idd}ddgddgd |gd |gd |gd |gd |gd|gddgddgddgddgddgg } x!|D]} | id| gqW|id|i| dd||i|iiddjd|||fSdS(sBCreate a cps user with the Member role. return login, pwdsfl_sroot@127.0.0.01s length_minisdirnamesmemberssidss widget__idswidget__passwordswidget__confirmswidget__givenNames widget__sns widget__emailswidget__roles:tokens:defaultswidget__roles:listsMemberswidget__groups:tokens:defaultswidget__homelesss0s%cpsdirectory_entry_create_form:methodsCreateswidget__groups:lists%s/s descriptionsCreate user [%s]spsm_entry_createdisFailed to create user %sN(sselfs_lipsumslipsums getUniqWordssignsuser_idslowersuser_givenNamesgetWords capitalizesuser_snsuppers user_emailsuser_pwdsparamssgroupssgroupsappendsposts server_urlsassert_s getLastUrlsfind( sselfsuser_idsuser_pwdsuser_givenNamesuser_sns user_emailsgroupsslipsumssignsparamssgroup((s5build/bdist.linux-i686/egg/funkload/CPS338TestCase.pys cpsCreateUserws"   {  cCsx|oQddgd|gg}|id|i|o|id|tfSqXn|i||||||SdS(smVerify if user exists or create him. return login, pwd if user exists pwd is None. sdirnamesmemberssids%s/cpsdirectory_entry_viewsUser %s exists.N( suser_idsparamssselfsexistss server_urlslogdsNones cpsCreateUsersuser_pwdsuser_givenNamesuser_sns user_emailsgroups(sselfsuser_idsuser_pwdsuser_givenNamesuser_sns user_emailsgroupssparams((s5build/bdist.linux-i686/egg/funkload/CPS338TestCase.pys cpsVerifyUsers cCs@d|gd|gg}|id||dd||fdS(sSetup local role role to url.smember_ids:lists member_roles%s/folder_localrole_adds descriptionsGrant local role %s to %sN(snamesrolesparamssselfspostsurl(sselfsurlsnamesrolesparams((s5build/bdist.linux-i686/egg/funkload/CPS338TestCase.pyscpsSetLocalRoless#ftest section for funkload testing.cCs*|id||||p |iSdS(sCreate a section.sSectionN(sselfscpsCreateFolders parent_urlstitles descriptionslangscpsGetRandomLanguage(sselfs parent_urlstitles descriptionslang((s5build/bdist.linux-i686/egg/funkload/CPS338TestCase.pyscpsCreateSectionss%ftest workspace for funkload testing.cCs*|id||||p |iSdS(sCreate a workspace.s WorkspaceN(sselfscpsCreateFolders parent_urlstitles descriptionslangscpsGetRandomLanguage(sselfs parent_urlstitles descriptionslang((s5build/bdist.linux-i686/egg/funkload/CPS338TestCase.pyscpsCreateWorkspacescCsnd|gd|gd|gd|gddgddgg}|id ||d ||i|i Sd S( sFCreate a section or a workspace. Return the section full url.s type_names widget__Titleswidget__Descriptions widget__LanguageSelectorCreationswidget__hidden_folders0scpsdocument_create_buttonsCreates%s/cpsdocument_create_forms Create a %sN( stypestitles descriptionslangsparamssselfsposts parent_urls cpsCleanUrlsgetLastBaseUrl(sselfstypes parent_urlstitles descriptionslangsparams((s5build/bdist.linux-i686/egg/funkload/CPS338TestCase.pyscpsCreateFolders < cCs|i}|iidtdd|}ddgd|gd|iidgd |gd |iigd d gd dgg}|i d||dd|i |i i ddjd||f|i|i}|idd}||fSdS(sTCreate a simple random document. return a tuple: (doc_url, doc_id) suniqsprefixstest %ss type_namesDocuments widget__Titleswidget__Descriptioni s widget__LanguageSelectorCreationswidget__contentswidget__content_rformatstextscpsdocument_create_buttonsCreates%s/cpsdocument_create_forms descriptionsCreating a documentspsm_content_createdisFailed to create [%s] in %s/.s/N(sselfscpsGetRandomLanguageslanguages_lipsums getSubjectsTruestitles getMessagesparamssposts parent_urlsassert_s getLastUrlsfinds cpsCleanUrlsgetLastBaseUrlsdoc_urlssplitsdoc_id(sselfs parent_urlslanguagestitlesdoc_idsparamssdoc_url((s5build/bdist.linux-i686/egg/funkload/CPS338TestCase.pyscpsCreateDocuments Z cCs|i}|iidtdd|}ddgd|gd|iidgd |gd d gd d gddgdd gddgddgdd gd|iigddgdd gddgdti dgdti dgd ti d!gd"d#gg}|i d$||d%d&|i }|id'|jd(||f|i|i}|id)d*}||fSd+S(,sACreate a random news. return a tuple: (doc_url, doc_id).suniqsprefixstest %ss type_names News Items widget__Titleswidget__Descriptioni s widget__LanguageSelectorCreationswidget__photo_titlesnoneswidget__photo_filenamesswidget__photo_choiceskeeps widget__photoswidget__photo_resizes img_auto_sizeswidget__photo_rpositionsleftswidget__photo_subtitleswidget__contentswidget__content_rformatstextswidget__Subject:tokens:defaultswidget__Subject:listsBusinessswidget__publication_date_dates01/01/%Yswidget__publication_date_hours%Hswidget__publication_date_minutes%Mscpsdocument_create_buttonsCreates%s/cpsdocument_create_forms descriptionsCreating a news itemspsm_content_createdsFailed to create [%s] in %s/.s/iN(sselfscpsGetRandomLanguageslanguages_lipsums getSubjectsTruestitles getMessagestimesstrftimesparamssposts parent_urls getLastUrlslast_urlsassert_s cpsCleanUrlsgetLastBaseUrlsdoc_urlssplitsdoc_id(sselfs parent_urlslanguagestitlesdoc_idsparamsslast_urlsdoc_url((s5build/bdist.linux-i686/egg/funkload/CPS338TestCase.pyscpsCreateNewsItems   cCs1|id|idd|ggdd|dS(s3Change the ui language and return the referer page.s%s/cpsportlet_change_languagesparamsslangs descriptionsChange UI language to %sN(sselfsgets server_urlslang(sselfslang((s5build/bdist.linux-i686/egg/funkload/CPS338TestCase.pyscpsChangeUiLanguagescCsti|iSdS(sReturn a random language.N(srandomschoicesselfs _all_langs(sself((s5build/bdist.linux-i686/egg/funkload/CPS338TestCase.pyscpsGetRandomLanguagescCsP|tjo |i}n|idd}|t|d }||fSdS(sfGuess a zope url and site_id from a CPS Site url. return a tuple (zope_url, site_id) s/iiN(scps_urlsNonesselfs server_urlssplitssite_idslenszope_url(sselfscps_urlssite_idszope_url((s5build/bdist.linux-i686/egg/funkload/CPS338TestCase.pyscpsGuessZopeUrls   cCskd|gg}|id|i|dd||idd|}|idt||f|SdS( sLReturn the list of url that ends with doc_id. Using catalog search.sSearchableTexts%s/search_forms descriptionsSearching doc_id %sspatterns%s$sfound %i link ends with %sN( sdoc_idsparamssselfsposts server_urlscpsListDocumentHrefsretslogdslen(sselfsdoc_idsparamssret((s5build/bdist.linux-i686/egg/funkload/CPS338TestCase.pyscpsSearchDocId'scCs|}|i}xiddddddfD]O}|i|o|t| }n|i|o|t|}q(q(W|SdS(s*Try to remove server_url and clean ending.s/s/views/folder_contentss /folder_views/cpsdocument_metadatas/cpsdocument_edit_formN(surl_insurlsselfs server_urlsendingsendswithslens startswith(sselfsurl_insurls server_urlsending((s5build/bdist.linux-i686/egg/funkload/CPS338TestCase.pys cpsCleanUrl2s cCspg}x_gi}|i|D]}||i|q ~D]$}||jo|i|q@q@W|SdS(sReturn a clean list of document href that matches pattern. Try to remove server_url and other cps trailings, return a list of uniq url.N( sretsappends_[1]sselfslistHrefspatternsxs cpsCleanUrlshref(sselfspatternsrets_[1]shrefsx((s5build/bdist.linux-i686/egg/funkload/CPS338TestCase.pyscpsListDocumentHref?s: (s__name__s __module__s__doc__scps_test_case_versionsNones server_urlsLipsums_lipsums _all_langss_default_langss _cps_loginscpsLogins cpsLogouts cpsCreateSitescpsCreateGroupscpsVerifyGroups cpsCreateUsers cpsVerifyUserscpsSetLocalRolescpsCreateSectionscpsCreateWorkspacescpsCreateFolderscpsCreateDocumentscpsCreateNewsItemscpsChangeUiLanguagescpsGetRandomLanguagescpsGuessZopeUrlscpsSearchDocIds cpsCleanUrlscpsListDocumentHref(((s5build/bdist.linux-i686/egg/funkload/CPS338TestCase.pys CPSTestCases4  $    "    $  (s__doc__stimesrandomsLipsums ZopeTestCases CPSTestCase(s ZopeTestCases CPSTestCasesrandomsLipsumstime((s5build/bdist.linux-i686/egg/funkload/CPS338TestCase.pys?s     PK]i6MMfunkload/CPSTestCase.pyc; Cc@sdZdklZdS(s]FunkLoad test case for Nuxeo CPS. $Id: CPSTestCase.py 24728 2005-08-31 08:13:54Z bdelbosc $ (s CPSTestCaseN(s__doc__sCPS340TestCases CPSTestCase(s CPSTestCase((s2build/bdist.linux-i686/egg/funkload/CPSTestCase.pys?sPK]i6ݕު$$funkload/ReportBuilder.pyc; Ec@sdZdZdkZdkZdklZlZdkl Z l Z l Z l Z dkl Z lZdklZlZdklZlZdfd YZd Zed jo endS( sCreate an ReST or HTML report with charts from a FunkLoad bench xml result. Producing html and png chart require python-docutils and python-gdchart $Id: ReportBuilder.py 24737 2005-08-31 09:00:16Z bdelbosc $ sz%prog [options] xmlfile %prog analyze a FunkLoad bench xml result file and output a report. See http://funkload.nuxeo.org/ for more information. Examples ======== %prog funkload.xml ReST rendering into stdout. %prog --html -o /tmp funkload.xml Build an HTML report in /tmp. %prog -h More options. N(s OptionParsersTitledHelpFormatter(sAllResponseStatsPageStats ResponseStatsTestStat(s MonitorStats ErrorStat(s RenderRsts RenderHtml(straces get_versionsFunkLoadXmlParsercBsMtZdZdZdZdZdZdZdZdZ RS(sParse a funkload xml results.cCstiii}|i|_|i|_ |i |_ |i |_ |i|_||_hdd tag.s$Error: invalid xml bench result fileisNote that you can generate a report only for a bench result done with fl-run-bench (and not on a test result done with fl-run-test).sYou may need to remove non ascii char that comes from error pages catched during the bench. iconv or recode may help you.sXml parser element stack: %sN(sselfsparsers ParseFilesfilesxml_filesxmlsparserssexpats ExpatErrorsmsgscurrent_elementsstrs startswithslensappends_[1]sx(sselfsxml_files_[1]smsgsx((s4build/bdist.linux-i686/egg/funkload/ReportBuilder.pysparseKs. . 1cCs|djo&|d|id<|d|id(stexts extra_keysNonesselfs__dict__sitemsskeysvalue(sselfs extra_keystextsvalueskey((s.build/bdist.linux-i686/egg/funkload/Monitor.pys__repr__s   (s__name__s __module__s__doc__s__init__sNones__repr__(((s.build/bdist.linux-i686/egg/funkload/Monitor.pys MonitorInfo{s  s MonitorThreadcBsztZdZeeedZdZdZdZdZdZ dZ dZ d Z d Z d ZRS( s,The monitor thread that collect information.cCsti|||_d|_t|_t|_t|_ t|_ |i ||i ||i|t|_|i|iddS(Nii(sThreads__init__sselfsrecordss_recorder_countsFalses_runningsNones _interfaces _intervals_hosts setIntervalsintervals setInterfaces interfacessetHostshosts _kernel_revscheckKernelRevs setDaemon(sselfsrecordsshostsintervals interface((s.build/bdist.linux-i686/egg/funkload/Monitor.pys__init__s            cCs ||_dS(s$Set the interval between monitoring.N(sintervalsselfs _interval(sselfsinterval((s.build/bdist.linux-i686/egg/funkload/Monitor.pys setIntervalscCs ||_dS(s%Set the network interface to monitor.N(s interfacesselfs _interface(sselfs interface((s.build/bdist.linux-i686/egg/funkload/Monitor.pys setInterfacescCs ||_dS(sSet the monitored host.N(shostsselfs_host(sselfshost((s.build/bdist.linux-i686/egg/funkload/Monitor.pyssetHostscCstdi}ttid|id}|djp |djo%ti i d|ti dn||_ dS( s Check the linux kernel revision.s /proc/versionsversion (\d+\.\d+)\.\d+if2.6000000000000001f2.3999999999999999s&Sorry, kernel v%0.1f is not supported iN(sopensreadlinesversionsfloatsressearchsgroups kernel_revssyssstderrswritesexitsselfs _kernel_rev(sselfsversions kernel_rev((s.build/bdist.linux-i686/egg/funkload/Monitor.pyscheckKernelRevs cCsJt|_x:|io/t|i|idjo|iq q WdS(s Thread jobs.iN(sTruesselfs_runningssleeps _intervals_recorder_countsmonitor(sself((s.build/bdist.linux-i686/egg/funkload/Monitor.pysruns   cCs t|_dS(sStop the thread.N(sFalsesselfs_running(sself((s.build/bdist.linux-i686/egg/funkload/Monitor.pysstopscCs)|iit|i|i|idS(sThe monitor task.N(sselfsrecordssappends MonitorInfos_hosts _kernel_revs _interface(sself((s.build/bdist.linux-i686/egg/funkload/Monitor.pysmonitorscCs|id7_dS(sEnable recording.iN(sselfs_recorder_count(sself((s.build/bdist.linux-i686/egg/funkload/Monitor.pys startRecordscCs|id8_dS(sStop recording.iN(sselfs_recorder_count(sself((s.build/bdist.linux-i686/egg/funkload/Monitor.pys stopRecordscCs |iSdS(sReturn the number of recorder.N(sselfs_recorder_count(sself((s.build/bdist.linux-i686/egg/funkload/Monitor.pyscountRecorderss(s__name__s __module__s__doc__sNones__init__s setIntervals setInterfacessetHostscheckKernelRevsrunsstopsmonitors startRecords stopRecordscountRecorders(((s.build/bdist.linux-i686/egg/funkload/Monitor.pys MonitorThreads         s MonitorServercBsotZdZdZeiddddgZedZdZdZ d Z d Z d Z d Z RS( sThe XML RPC monitor server.smonitors startRecords stopRecords getResults getXmlResultcCsit|_t|_g|_h|_ti||t |i|i |i|i|_ |i i dS(N( sNonesselfsintervals interfacesrecordss_keyssXmlRpcBaseServers__init__sargvs MonitorThreadshosts_monitorsstart(sselfsargv((s.build/bdist.linux-i686/egg/funkload/Monitor.pys__init__s     cCs.|idd|_|idd|_dS(sinit callback.sserversintervals interfaceN(sconfsgetfloatsselfsintervalsgets interface(sselfsconfsoptions((s.build/bdist.linux-i686/egg/funkload/Monitor.pys_init_cbscCsr|id||ii| p|i|dtj o|iint|i tg|i|>> from CPS340DocTest import CPSDocTest >>> cps_url = 'http://localhost:8080/cps' >>> fl = CPSDocTest(cps_url) >>> fl.cps_test_case_version (3, 4, 0) >>> fl.server_url == cps_url True Then you can use the CPS340TestCase API like fl.cpsLogin('manager', 'pwd'). icCs&ti|d|d|||_dS(s:init CPSDocTest server_url is the CPS server url.sdebugs debug_levelN(sFunkLoadDocTests__init__sselfsdebugs debug_levels server_url(sselfs server_urlsdebugs debug_level((s4build/bdist.linux-i686/egg/funkload/CPS340DocTest.pys__init__(s(s__name__s __module__s__doc__sFalses__init__(((s4build/bdist.linux-i686/egg/funkload/CPS340DocTest.pys CPSDocTests cCs#dk}dk}|i|SdS(N(sdoctests CPS340DocTeststestmod(s CPS340DocTestsdoctest((s4build/bdist.linux-i686/egg/funkload/CPS340DocTest.pys_test1ss__main__N(s__doc__sCPS340TestCases CPSTestCasesFunkLoadDocTests CPSDocTests_tests__name__(s CPSDocTests_tests CPSTestCasesFunkLoadDocTest((s4build/bdist.linux-i686/egg/funkload/CPS340DocTest.pys?s     PKT;4!N 'funkload/data/ConfigurationTestCase.tpl# FunkLoad test configuration file # $Id: $ # ------------------------------------------------------------ # Main section # [main] title=%(class_name)s description=XXX the TestCase class description # the server url to test url=%(server_url)s # the User-Agent header to send default is 'FunkLoad/1.xx' examples: #user_agent = Opera/8.0 (Windows NT 5.1; U; en) #user_agent = Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) #user_agent = Mozilla/5.0 (X11; U; Linux i686; en; rv:1.7.10) Gecko/20050912 Firefox/1.0.6 # ------------------------------------------------------------ # Tests description and configuration # [test_%(test_name)s] description=XXX the test case description # ------------------------------------------------------------ # Credential access # [credential] host=localhost port=8007 # ------------------------------------------------------------ # Monitoring configuration # [monitor] #hosts=localhost # Each host in [monitor]hosts should have a section # with a 'port' and 'description' keys [localhost] port=8008 description=The benching machine # ------------------------------------------------------------ # Configuration for unit test mode fl-run-test # [ftest] # log_to destination = # console - to the screen # file - to a file log_to = console file # log_path = path and file name to store log file log_path = %(test_name)s-test.log # result_path = path to store the xml result file result_path = %(test_name)s-test.xml # ok_codes = list of successfull HTTP response code default is 200:301:302 # ok_codes = 200:301:302 # sleeptime_min = minimum amount of time in seconds to sleep between requests # to the host sleep_time_min = 0 # sleeptime_max = maximum amount of time in seconds to sleep between requests # to the host sleep_time_max = 0 # ------------------------------------------------------------ # Configuration for bench mode fl-run-bench # [bench] # cycles = list of cycles with their number of concurrent users cycles = 1:2:3 # duration = duration of a cycle in seconds duration = 30 # startup_delay = time to wait between starting-up threads in seconds startup_delay = 0.2 # sleep_time = time to wait between test in seconds sleep_time = 1 # cycle_time = time to wait between cycle in seconds cycle_time = 1 # same keys than in [ftest] section log_to = file log_path = %(test_name)s-bench.log result_path = %(test_name)s-bench.xml #ok_codes = 200:301:302 sleep_time_min = 0 sleep_time_max = 2 PKT;4 funkload/data/funkload.css/* funkload doc css */ /* $Id: nuxeo_doc.css 21596 2005-02-15 10:01:33Z bdelbosc $ */ body { font: 90% 'Lucida Grande', Verdana, Geneva, Lucida, Arial, Helvetica, sans-serif; background: #ffffff; color: black; margin: 2em; padding: 2em; } a[href] { color: #436976; background-color: transparent; } h1 a[href] { text-decoration: none; color: #fcb100; background-color: transparent; } a.strong { font-weight: bold; } img { margin: 0; border: 0; } p { margin: 0.5em 0 1em 0; line-height: 1.5em; } p a { text-decoration: underline; } p a:visited { color: purple; background-color: transparent; } p a:active { color: red; background-color: transparent; } a:hover { text-decoration: none; } p img { border: 0; margin: 0; } h1, h2, h3, h4, h5, h6 { color: #003a6b; background-color: transparent; font: 100% 'Lucida Grande', Verdana, Geneva, Lucida, Arial, Helvetica, sans-serif; margin: 0; padding-top: 0.5em; } h1 { font-size: 160%; margin-bottom: 0.5em; border-bottom: 1px solid #888; margin-top: 1em; } h1.title { font-size: 200%; } h2 { font-size: 140%; margin-bottom: 0.5em; } h3 { font-size: 120%; margin-bottom: 0.5em; } h4 { font-size: 110%; font-weight: bold; } h5 { font-size: 100%; font-weight: bold; } h6 { font-size: 80%; font-weight: bold; } ul a, ol a { text-decoration: underline; } dt { font-weight: bold; } dt a { text-decoration: none; } dd { line-height: 1.5em; margin-bottom: 1em; } legend { background: #ffffff; padding: 0.5em; } form { margin: 0; } dl.form { margin: 0; padding: 1em; } dl.form dt { width: 30%; float: left; margin: 0; padding: 0 0.5em 0.5em 0; text-align: right; } input { font: 100% 'Lucida Grande', Verdana, Geneva, Lucida, Arial, Helvetica, sans-serif; color: black; background-color: white; vertical-align: middle; } abbr, acronym, .explain { color: black; background-color: transparent; } q, blockquote { } code, pre { font-family: monospace; font-size: 1.2em; display: block; padding: 10px; border: 1px solid #838183; background-color: #eee; color: #000; overflow: auto; margin: 0.5em 1em; } table.docutils { border: 1px solid black; font-size: 0.6em; border-spacing: 0; padding: 0; margin: 1em; } table.docutils td { border: 1px solid #CCC; text-align: right; padding: 0 0.3em; margin: 0; } table.docutils tr { padding: 0; margin: 0; } table.docutils th { border: 1px solid #CCC; border-bottom: 1px solid black; padding: 0.3em; font-weight: bold; margin: 0; } table.docutils td p, table.docutils th p { margin: 0; padding: 0; } table.docutils th.field-name { border: 1px solid #CCC; } div.abstract { padding: 0.5em; background-color: #eef; border: 1px solid #838183; margin: 0.5em 1em; } div.abstract { padding: 0.5em; background-color: #eef; border: 1px solid #838183; margin: 0.5em 1em; } div.warning, div.note { padding: 0.5em; background-color: #fee; border: 1px solid #838183; margin: 0.5em 1em; } div.warning p.admonition-title { color: red ; font-weight: bold ; } div.abstract p.topic-title { font-weight: bold } th.field-name { font-weight: bold; font-size: 1.5em; } td.field-body { font-size: 1.5em; } tr.field { border: none; } div.contents p.first a { font-size: 150%; border-bottom: 1px solid #888; color: #fcb100; } div.contents a { text-decoration: none } pre.address { display: inline; border: none; padding: 0; margin: 0; } PK$M[6,vjj funkload/data/ScriptTestCase.tpl# -*- coding: iso-8859-15 -*- """%(test_name)s FunkLoad test $Id: $ """ import unittest from funkload.FunkLoadTestCase import FunkLoadTestCase from webunit.utility import Upload #from funkload.utils import xmlrpc_get_credential class %(class_name)s(FunkLoadTestCase): """XXX This test use a configuration file %(class_name)s.conf. """ def setUp(self): """Setting up test.""" self.logd("setUp") self.server_url = self.conf_get('main', 'url') # XXX here you can setup the credential access like this # credential_host = self.conf_get('credential', 'host') # credential_port = self.conf_getInt('credential', 'port') # self.login, self.password = xmlrpc_get_credential(credential_host, # credential_port, # XXX replace with a valid group # 'members') def test_%(test_name)s(self): # The description should be set in the configuration file server_url = self.server_url # begin of test --------------------------------------------- %(script)s # end of test ----------------------------------------------- def tearDown(self): """Setting up test.""" self.logd("tearDown.\n") if __name__ in ('main', '__main__'): unittest.main() PKT;4#4)Jfunkload/demo/README.txt============= FunkLoad demo ============= $Id: README.txt 29245 2005-11-08 13:46:17Z bdelbosc $ You can find 4 examples of FunkLoad usage here: * simple/ An example on how to use test and bench runner with monitoring. * zope/ A basic ZopeTestCase example. * cmf/ An test case that requires a credential server. * xmlrpc/ An example on how to test/bench an XML RPC server with a Makefile example. PKT;4H#funkload/demo/simple/test_Simple.py# -*- coding: iso-8859-15 -*- """Simple FunkLoad test $Id: test_Simple.py 29381 2005-11-09 10:38:21Z bdelbosc $ """ import unittest from random import random from funkload.FunkLoadTestCase import FunkLoadTestCase class Simple(FunkLoadTestCase): """This test use a configuration file Simple.conf.""" def setUp(self): """Setting up test.""" self.logd("setUp") self.server_url = self.conf_get('main', 'url') def test_simple(self): # The description should be set in the configuration file server_url = self.server_url # begin of test --------------------------------------------- nb_time = self.conf_getInt('test_simple', 'nb_time') pages = self.conf_getList('test_simple', 'pages') for i in range(nb_time): self.logd('Try %i' % i) for page in pages: self.get(server_url + page, description='Get %s' % page) # end of test ----------------------------------------------- def tearDown(self): """Setting up test.""" self.logd("tearDown.\n") if __name__ in ('main', '__main__'): unittest.main() PKT;4YKfunkload/demo/simple/README.txt==================== FunkLoad demo/simple ==================== $Id: README.txt 29437 2005-11-10 10:41:30Z bdelbosc $ This is a simple FunkLoadTestCase demonstration. It requires an web test server (configuration is done for an apache2 default install) WARNING: You should *not* run this script against a server that is not under your responsablity as it can result a DOS in bench mode. 1/ Modify the Simple.conf file Set the [main] url and pages keys 2/ Test it verbose mode:: fl-run-test -v test_Simple.py debug mode:: fl-run-test -d test_Simple.py view the downloaded page in real time using firefox:: fl-run-test -V test_Simple.py check performance of a single page:: fl-run-test -l 4 -n 100 test_Simple.py 3/ Bench it Start a monitord server to log server activities:: fl-monitor-ctl monitor.conf start Bench it with few cycles:: fl-run-bench -c 1:25:50:75 test_Simple.py Simple.test_simple Note that for correct interpretation you should run the FunkLoad bencher in a different host than the server, the server should be 100% dedicated to the application. If you want to bench with more than 200 users, you need to reduce the default stack size used by a thread, for example try a `ulimit -s 2048` before running the bench. Performance limits are hit by FunkLoad before apache's limit is reached, since it uses significant CPU resources. 4/ Build the report:: fl-build-report --html simple-bench.xml PKT;4 \\!funkload/demo/simple/monitor.conf# default configuration file for the monitor server # note that %(FLOAD_HOME)s is accessible # # $Id: credential.conf 22780 2005-06-06 09:43:52Z bdelbosc $ # ------------------------------------------------------------ [server] # configuration used by monitord host = localhost port = 8008 # sleeptime between monitoring in second # note that load average is updated by the system only every 5s interval = .5 # network interface to monitor lo, eth0 interface = lo # ------------------------------------------------------------ [client] # configuration used by monitorctl host = localhost port = 8008 PKT;4%A funkload/demo/simple/Simple.conf# FunkLoad test configuration file # $Id: $ # ------------------------------------------------------------ # Main section # [main] title=Simple FunkLoad tests description=Simply testing a default apache 2 server # the server url to test url=http://localhost/apache2-default # the User-Agent header to send #user_agent = Mozilla/5.0 Firefox/1.0.6 # ------------------------------------------------------------ # Tests description and configuration # [test_simple] description=Access %(nb_time)s times the following pages: %(pages)s. nb_time=1 # list of page separated by ':' pages=/index.html.de:/index.html.dk:/index.html.ee:/index.html.es:/index.html.fr:/index.html.it:/index.html.ja.iso2022-jp:/index.html.no:/index.html.pt-br:/index.html.ru.utf8 # ------------------------------------------------------------ # Credential access # [credential] host=localhost port=8007 # ------------------------------------------------------------ # Monitoring configuration # [monitor] hosts=localhost # Each host in [monitor]hosts should have a section # with a 'port' and 'description' keys [localhost] port=8008 description=The benching and benched machine # ------------------------------------------------------------ # Configuration for unit test mode fl-run-test # [ftest] # log_to destination = # console - to the screen # file - to a file log_to = console file # log_path = path and file name to store log file log_path = simple-test.log # result_path = path to store the xml result file result_path = simple-test.xml # ok_codes = list of successfull HTTP response code #ok_codes = 200:301:302 # sleeptime_min = minimum amount of time in seconds to sleep between requests # to the host sleep_time_min = 0 # sleeptime_max = maximum amount of time in seconds to sleep between requests # to the host sleep_time_max = 0 # ------------------------------------------------------------ # Configuration for bench mode fl-run-bench # [bench] # cycles = list of cycles with their number of concurrent users cycles = 50:75:100:125 # duration = duration of a cycle in seconds duration = 20 # startup_delay = time to wait between starting-up threads in seconds startup_delay = 0.05 # sleep_time = time to wait between test in seconds sleep_time = 1 # cycle_time = time to wait between cycle in seconds cycle_time = 1 # same keys than in [ftest] section log_to = file log_path = simple-bench.log result_path = simple-bench.xml #ok_codes = 200:301:302 sleep_time_min = 0 sleep_time_max = 0.5 PK]i6ҟ$funkload/demo/simple/test_Simple.pyc; Cc@sddZdkZdklZdklZdefdYZeddfjoeindS(sPSimple FunkLoad test $Id: test_Simple.py 29381 2005-11-09 10:38:21Z bdelbosc $ N(srandom(sFunkLoadTestCasesSimplecBs)tZdZdZdZdZRS(s/This test use a configuration file Simple.conf.cCs&|id|idd|_dS(sSetting up test.ssetUpsmainsurlN(sselfslogdsconf_gets server_url(sself((s>build/bdist.linux-i686/egg/funkload/demo/simple/test_Simple.pyssetUp s cCs|i}|idd}|idd}xQt|D]C}|id|x)|D]!}|i ||dd|qXWq:WdS(Ns test_simplesnb_timespagessTry %is descriptionsGet %s( sselfs server_urls conf_getIntsnb_times conf_getListspagessrangesislogdspagesget(sselfsis server_urlspagesnb_timespages((s>build/bdist.linux-i686/egg/funkload/demo/simple/test_Simple.pys test_simples  cCs|iddS(sSetting up test.s tearDown. N(sselfslogd(sself((s>build/bdist.linux-i686/egg/funkload/demo/simple/test_Simple.pystearDown s(s__name__s __module__s__doc__ssetUps test_simplestearDown(((s>build/bdist.linux-i686/egg/funkload/demo/simple/test_Simple.pysSimple s   smains__main__(s__doc__sunittestsrandomsfunkload.FunkLoadTestCasesFunkLoadTestCasesSimples__name__smain(sSimplesunittestsrandomsFunkLoadTestCase((s>build/bdist.linux-i686/egg/funkload/demo/simple/test_Simple.pys?s    PKT;48 ;funkload/demo/zope/Zope.conf# FunkLoad test configuration file # $Id: $ # ------------------------------------------------------------ # Main section # [main] title=Simple Zope tests description=Testing funkload ZopeTestCase # the server url to test without the trailing '/' url=http://localhost:8080 # zope admin credential admin_id=admin admin_pwd=admin # ------------------------------------------------------------ # Tests description and configuration # [test_flushCache] description=Flush the Zodb cache [test_restart] description=Restart the Zope server [test_packZodb] description=Packing the main Zodb # ------------------------------------------------------------ # Monitoring configuration # [monitor] #hosts=localhost # Each host in [monitor]hosts should have a section # with a 'port' and 'description' keys [localhost] port=8008 description=The benching machine # ------------------------------------------------------------ # Configuration for unit test mode fl-run-test # [ftest] # log_to destination = # console - to the screen # file - to a file log_to = console file # log_path = path and file name to store log file log_path = zope-test.log # result_path = path to store the xml result file result_path = zope-test.xml # ok_codes = list of successfull HTTP response code # ok_codes = 200:301:302 # sleeptime_min = minimum amount of time in seconds to sleep between requests # to the host sleep_time_min = 0 # sleeptime_max = maximum amount of time in seconds to sleep between requests # to the host sleep_time_max = 0 # ------------------------------------------------------------ # Configuration for bench mode fl-run-bench # [bench] # cycles = list of cycles with their number of concurrent users cycles = 1:2:3 # duration = duration of a cycle in seconds duration = 30 # startup_delay = time to wait between starting-up threads in seconds startup_delay = 0.2 # sleep_time = time to wait between test in seconds sleep_time = 1 # cycle_time = time to wait between cycle in seconds cycle_time = 1 # same keys than in [ftest] section log_to = file log_path = zope-bench.log result_path = zope-bench.xml #ok_codes = 200:301:302 sleep_time_min = 0 sleep_time_max = 1 PKT;4funkload/demo/zope/test_Zope.py# (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """Simple funkload zope tests $Id: test_Zope.py 27640 2005-09-27 14:31:12Z bdelbosc $ """ import unittest from random import random from funkload.ZopeTestCase import ZopeTestCase from funkload.Lipsum import Lipsum class Zope(ZopeTestCase): """Testing the funkload ZopeTestCase This test use a configuration file Zope.conf. """ def setUp(self): """Setting up test.""" self.logd("setUp.") self.zope_url = self.conf_get('main', 'url') self.admin_id = self.conf_get('main', 'admin_id') self.admin_pwd = self.conf_get('main', 'admin_pwd') def test_flushCache(self): self.zopeFlushCache(self.zope_url, self.admin_id, self.admin_pwd) def test_restart(self): self.zopeRestart(self.zope_url, self.admin_id, self.admin_pwd, time_out=10) def test_packZodb(self): self.zopePackZodb(self.zope_url, self.admin_id, self.admin_pwd) def test_00_verifyExample(self): if not self.exists(self.zope_url + '/Examples'): self.setBasicAuth(self.admin_id, self.admin_pwd) self.get(self.zope_url + '/manage_importObject?file=Examples.zexp&set_owner:int=1') self.assert_('successfully imported' in self.getBody()) self.clearBasicAuth() self.get(self.zope_url + '/Examples') def test_exampleNavigation(self): server_url = self.zope_url self.get("%s/Examples" % server_url) self.get("%s/Examples/Navigation" % server_url) self.get("%s/Examples/Navigation/Mammals" % server_url) self.get("%s/Examples/Navigation/Mammals/Primates" % server_url) self.get("%s/Examples/Navigation/Mammals/Primates/Monkeys" % server_url) self.get("%s/Examples/Navigation/Mammals/Whales" % server_url) self.get("%s/Examples/Navigation/Mammals/Bats" % server_url) self.get("%s/Examples" % server_url) def test_exampleGuestBook(self): server_url = self.zope_url self.get("%s/Examples/GuestBook" % server_url) server_url = self.zope_url self.setBasicAuth(self.admin_id, self.admin_pwd) lipsum = Lipsum() self.get("%s/Examples/GuestBook/addEntry.html" % server_url) params = [["guest_name", lipsum.getWord().capitalize()], ["comments", lipsum.getParagraph()]] self.post("%s/Examples/GuestBook/addEntry" % server_url, params) self.clearBasicAuth() def test_exampleFileLibrary(self): server_url = self.zope_url self.get("%s/Examples/FileLibrary" % server_url) for sort in ('type', 'size', 'date'): params = [["sort", sort], ["reverse:int", "0"]] self.post("%s/Examples/FileLibrary/index_html" % server_url, params, description="File Library sort by %s" % sort) def test_exampleShoppingCart(self): server_url = self.zope_url self.get("%s/Examples/ShoppingCart" % server_url) params = [["orders.id:records", "510-115"], ["orders.quantity:records", "1"], ["orders.id:records", "510-122"], ["orders.quantity:records", "2"], ["orders.id:records", "510-007"], ["orders.quantity:records", "3"]] self.post("%s/Examples/ShoppingCart/addItems" % server_url, params) def test_anonymous_reader(self): server_url = self.zope_url self.get("%s/Examples/Navigation/Mammals/Whales" % server_url) self.get("%s/Examples/GuestBook" % server_url) self.get("%s/Examples/GuestBook/addEntry.html" % server_url) params = [["sort", 'date'], ["reverse:int", "0"]] self.get("%s/Examples/FileLibrary/index_html" % server_url, params) self.get("%s/Examples/ShoppingCart" % server_url) def tearDown(self): """Setting up test.""" self.logd("tearDown.") if __name__ in ('main', '__main__'): unittest.main() PKT;4 funkload/demo/zope/README.txt================== FunkLoad demo/zope ================== $Id: README.txt 29245 2005-11-08 13:46:17Z bdelbosc $ This is a simple ZopeTestCase demonstration. It requires a zope 2.7 or 2.8 test server running, you should *not* run this script against a production server as it will try to pack the main Zodb, and setup the default Zope Examples. Modify the Zope.conf funkload configuration file and set the zope server url and admin credential ([main] section, url, admin_id and admin_pwd keys). The test will setup the zope Examples and test them, then it will flush the zope cache, pack the zodb and restart the zope server. To run the test:: fl-run-test -v test_Zope.py You can view the debug information:: fl-run-test -d test_Zope.py PK]i64o'' funkload/demo/zope/test_Zope.pyc; Cc@sqdZdkZdklZdklZdklZdefdYZeddfjoei ndS( sTSimple funkload zope tests $Id: test_Zope.py 27640 2005-09-27 14:31:12Z bdelbosc $ N(srandom(s ZopeTestCase(sLipsumsZopecBsqtZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z RS( sYTesting the funkload ZopeTestCase This test use a configuration file Zope.conf. cCsP|id|idd|_|idd|_|idd|_dS(sSetting up test.ssetUp.smainsurlsadmin_ids admin_pwdN(sselfslogdsconf_getszope_urlsadmin_ids admin_pwd(sself((s:build/bdist.linux-i686/egg/funkload/demo/zope/test_Zope.pyssetUp"s  cCs |i|i|i|idS(N(sselfszopeFlushCacheszope_urlsadmin_ids admin_pwd(sself((s:build/bdist.linux-i686/egg/funkload/demo/zope/test_Zope.pystest_flushCache)scCs&|i|i|i|idddS(Nstime_outi (sselfs zopeRestartszope_urlsadmin_ids admin_pwd(sself((s:build/bdist.linux-i686/egg/funkload/demo/zope/test_Zope.pys test_restart,scCs |i|i|i|idS(N(sselfs zopePackZodbszope_urlsadmin_ids admin_pwd(sself((s:build/bdist.linux-i686/egg/funkload/demo/zope/test_Zope.pys test_packZodb0scCs|i|id oQ|i|i|i|i|id|id|ij|i n|i|iddS(Ns /Exampless7/manage_importObject?file=Examples.zexp&set_owner:int=1ssuccessfully imported( sselfsexistsszope_urls setBasicAuthsadmin_ids admin_pwdsgetsassert_sgetBodysclearBasicAuth(sself((s:build/bdist.linux-i686/egg/funkload/demo/zope/test_Zope.pystest_00_verifyExample3s cCs|i}|id||id||id||id||id||id||id||id|dS(Ns %s/Exampless%s/Examples/Navigations%s/Examples/Navigation/Mammalss'%s/Examples/Navigation/Mammals/Primatess/%s/Examples/Navigation/Mammals/Primates/Monkeyss%%s/Examples/Navigation/Mammals/Whaless#%s/Examples/Navigation/Mammals/Bats(sselfszope_urls server_urlsget(sselfs server_url((s:build/bdist.linux-i686/egg/funkload/demo/zope/test_Zope.pystest_exampleNavigation<s cCs|i}|id||i}|i|i|it}|id|d|i i gd|i gg}|i d|||idS(Ns%s/Examples/GuestBooks#%s/Examples/GuestBook/addEntry.htmls guest_namescommentss%s/Examples/GuestBook/addEntry(sselfszope_urls server_urlsgets setBasicAuthsadmin_ids admin_pwdsLipsumslipsumsgetWords capitalizes getParagraphsparamsspostsclearBasicAuth(sselfsparamss server_urlslipsum((s:build/bdist.linux-i686/egg/funkload/demo/zope/test_Zope.pystest_exampleGuestBookIs   *cCsn|i}|id|xMdddfD]<}d|gddgg}|id||d d |q*WdS( Ns%s/Examples/FileLibrarystypessizesdatessorts reverse:ints0s"%s/Examples/FileLibrary/index_htmls descriptionsFile Library sort by %s(sselfszope_urls server_urlsgetssortsparamsspost(sselfssortsparamss server_url((s:build/bdist.linux-i686/egg/funkload/demo/zope/test_Zope.pystest_exampleFileLibraryVs  cCsn|i}|id|ddgddgddgddgddgdd gg}|id ||dS( Ns%s/Examples/ShoppingCartsorders.id:recordss510-115sorders.quantity:recordss1s510-122s2s510-007s3s!%s/Examples/ShoppingCart/addItems(sselfszope_urls server_urlsgetsparamsspost(sselfsparamss server_url((s:build/bdist.linux-i686/egg/funkload/demo/zope/test_Zope.pystest_exampleShoppingCart`s <cCs}|i}|id||id||id|ddgddgg}|id|||id |dS( Ns%%s/Examples/Navigation/Mammals/Whaless%s/Examples/GuestBooks#%s/Examples/GuestBook/addEntry.htmlssortsdates reverse:ints0s"%s/Examples/FileLibrary/index_htmls%s/Examples/ShoppingCart(sselfszope_urls server_urlsgetsparams(sselfsparamss server_url((s:build/bdist.linux-i686/egg/funkload/demo/zope/test_Zope.pystest_anonymous_readerms cCs|iddS(sSetting up test.s tearDown.N(sselfslogd(sself((s:build/bdist.linux-i686/egg/funkload/demo/zope/test_Zope.pystearDownws(s__name__s __module__s__doc__ssetUpstest_flushCaches test_restarts test_packZodbstest_00_verifyExamplestest_exampleNavigationstest_exampleGuestBookstest_exampleFileLibrarystest_exampleShoppingCartstest_anonymous_readerstearDown(((s:build/bdist.linux-i686/egg/funkload/demo/zope/test_Zope.pysZopes      smains__main__( s__doc__sunittestsrandomsfunkload.ZopeTestCases ZopeTestCasesfunkload.LipsumsLipsumsZopes__name__smain(s ZopeTestCasesunittestsrandomsLipsumsZope((s:build/bdist.linux-i686/egg/funkload/demo/zope/test_Zope.pys?s    _PKT;419funkload/demo/cmf/passwords.txt# You must modify this file before launching tests # $Id: passwords.txt 27890 2005-10-03 17:25:23Z bdelbosc $ # # the zope admin account admin:admin # test members fl_member_01:bom8ohhd fl_member_02:h93b6fvz fl_member_03:ozbdqmk fl_member_04:x4rpn5 fl_member_05:1wjxer87 fl_member_06:kmfueth fl_member_07:guar8d fl_member_08:up9dcrh6 fl_member_09:3xju4waq fl_member_10:ffywgt7a fl_review_01:gnu27jah fl_review_02:66s8to8 fl_review_03:e34bf94c fl_review_04:kagbnm fl_manager_01:1fzmu96w fl_manager_02:d2p3yq8r PKT;4@| | funkload/demo/cmf/Cmf.conf# FunkLoad test configuration file # $Id: $ # ------------------------------------------------------------ # Main section # [main] title=Cmf simple tests description=Some basic CMF default examples tests # the server url to test url=http://localhost:33380 # the User-Agent header to send #user_agent = Mozilla/5.0 Firefox/1.0.6 # ------------------------------------------------------------ # Tests description and configuration # [test_00_verifyCmfSite] description=Create a cmf site [test_05_verifyUsers] description="Create users served by credentiald" mail=root@foo.bar [test_10_create_doc] description=Create %(nb_docs)s news items in the private workspace. nb_docs = 5 # ------------------------------------------------------------ # Credential access # [credential] host=localhost port=22207 # ------------------------------------------------------------ # Monitoring configuration # [monitor] #hosts=localhost # Each host in [monitor]hosts should have a section # with a 'port' and 'description' keys [localhost] port=8008 description=The benching machine # ------------------------------------------------------------ # Configuration for unit test mode fl-run-test # [ftest] # log_to destination = # console - to the screen # file - to a file log_to = console file # log_path = path and file name to store log file log_path = cmf-test.log # result_path = path to store the xml result file result_path = cmf-test.xml # ok_codes = list of successfull HTTP response code # ok_codes = 200:301:302 # sleeptime_min = minimum amount of time in seconds to sleep between requests # to the host sleep_time_min = 0 # sleeptime_max = maximum amount of time in seconds to sleep between requests # to the host sleep_time_max = 0 # ------------------------------------------------------------ # Configuration for bench mode fl-run-bench # [bench] # cycles = list of cycles with their number of concurrent users cycles = 1:2:3 # duration = duration of a cycle in seconds duration = 30 # startup_delay = time to wait between starting-up threads in seconds startup_delay = 0.2 # sleep_time = time to wait between test in seconds sleep_time = 1 # cycle_time = time to wait between cycle in seconds cycle_time = 1 # same keys than in [ftest] section log_to = file log_path = cmf-bench.log result_path = cmf-bench.xml #ok_codes = 200:301:302 sleep_time_min = 0 sleep_time_max = 1 PKT;4;!!funkload/demo/cmf/README.txt================= FunkLoad demo/cmf ================= $Id: README.txt 29245 2005-11-08 13:46:17Z bdelbosc $ This is a simple CMF tests. It requires a zope 2.7 or 2.8 test server running, you should *not* run this script against a production server as it will try to create a CMF Site and setup test accounts. You need to have the CMF 1.5.4 products installed on your Zope server. You need to edit the Cmf.conf configuration file to point to your zope server (section main url key). Then you need to edit the passwords.txt file to set the Zope admin credential. If your zope admin is not called ``admin`` add your credential to the `passwords.txt` file and edit the `groups.txt` file to add your login in the ``AdminZope`` group. To run the test:: fl-credential-ctl credential.conf start fl-run-test -v test_Cmf.py You can view the debug information:: fl-run-test -d test_Zope.py If something goes wrong try to view the html output:: fl-run-test -dV test_Zope.py Note that all errors are logged in the xml output file ``cmf-test.xml``. PKT;4afunkload/demo/cmf/test_Cmf.py# -*- coding: iso-8859-15 -*- # (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """cmf FunkLoad test $Id: test_Cmf.py 27639 2005-09-27 14:30:22Z bdelbosc $ """ import unittest from random import random from funkload.FunkLoadTestCase import FunkLoadTestCase from funkload.utils import xmlrpc_get_credential, xmlrpc_list_credentials from funkload.Lipsum import Lipsum class CmfTestCase(FunkLoadTestCase): """FL TestCase with common cmf tasks. self.server_url must be set. """ def cmfLogin(self, login, pwd): params = [["__ac_name", login], ["__ac_password", pwd], ["__ac_persistent", "1"], ["submit", " Login "]] self.post('%s/logged_in' % self.server_url, params, description="Log xin user %s" % login) self.assert_('Login success' in self.getBody(), "Invalid credential %s:%s" % (login, pwd)) self._cmf_login = login def cmfLogout(self): self.get('%s/logout' % self.server_url, description="logout %s" % self._cmf_login) def cmfCreateNews(self, parent_url): # return the doc_url lipsum = Lipsum() doc_id = lipsum.getUniqWord().lower() params = [["type_name", "News Item"], ["id", doc_id], ["add", "Add"]] self.post("%s/folder_factories" % parent_url, params, description="Create an empty news") params = [["allow_discussion", "default"], ["title", lipsum.getSubject()], ["description:text", lipsum.getParagraph()], ["subject:lines", lipsum.getWord()], ["format", "text/plain"], ["change_and_view", "Change and View"]] doc_url = "%s/%s" % (parent_url, doc_id) self.post("%s/metadata_edit_form" % doc_url, params, description="Set metadata") self.assert_('Metadata changed.' in self.getBody()) params = [["text_format", "plain"], ["description:text", lipsum.getParagraph()], ["text:text", lipsum.getMessage()], ["change_and_view", "Change and View"]] self.post("%s/newsitem_edit_form" % doc_url, params, description="Set news content") self.assert_('News Item changed.' in self.getBody()) return doc_url class Cmf(CmfTestCase): """Simple test of default CMF Site This test use a configuration file Cmf.conf. """ def setUp(self): """Setting up test.""" self.logd("setUp") self.server_url = self.conf_get('main', 'url') credential_host = self.conf_get('credential', 'host') credential_port = self.conf_getInt('credential', 'port') self.credential_host = credential_host self.credential_port = credential_port self.cred_admin = xmlrpc_get_credential(credential_host, credential_port, 'AdminZope') self.cred_member = xmlrpc_get_credential(credential_host, credential_port, 'FL_Member') def test_00_verifyCmfSite(self): server_url = self.server_url if self.exists(server_url): self.logd('CMF Site already exists') return site_id = server_url.split('/')[-1] zope_url = server_url[:-(len(site_id)+1)] self.setBasicAuth(*self.cred_admin) self.get("%s/manage_addProduct/CMFDefault/addPortal" % zope_url) params = [["id", site_id], ["title", "FunkLoad CMF Site"], ["create_userfolder", "1"], ["description", "See http://svn.nuxeo.org/pub/funkload/trunk/README.txt " "for more info about FunkLoad"], ["submit", " Add "]] self.post("%s/manage_addProduct/CMFDefault/manage_addCMFSite" % zope_url, params, description="Create a CMF Site") self.get(server_url, description="View home page") self.clearBasicAuth() def test_05_verifyUsers(self): server_url = self.server_url user_mail = self.conf_get('test_05_verifyUsers', 'mail') lipsum = Lipsum() self.setBasicAuth(*self.cred_admin) for user_id, user_pwd in xmlrpc_list_credentials( self.credential_host, self.credential_port, 'FL_Member'): params = [["member_id", user_id], ["member_email", user_mail], ["password", user_pwd], ["confirm", user_pwd], ["add", "Register"]] self.post("%s/join_form" % server_url, params) html = self.getBody() self.assert_( 'Member registered' in html or 'The login name you selected is already in use' in html, "Member %s not created" % user_id) self.clearBasicAuth() def test_anonymous_reader(self): server_url = self.server_url self.get("%s/Members" % server_url, description="Try to see Members area") self.get("%s/recent_news" % server_url, description="Recent news") self.get("%s/search_form" % server_url, description="View search form") self.get("%s/login_form" % server_url, description="View login form") self.get("%s/join_form" % server_url, description="View join form") def test_member_reader(self): server_url = self.server_url self.cmfLogin(*self.cred_member) url = '%s/Members/%s/folder_contents' % (server_url, self.cred_member[0]) self.get(url, description="Personal workspace") self.get('%s/personalize_form' % server_url, description="Preference page") self.cmfLogout() def test_10_create_doc(self): nb_docs = self.conf_getInt('test_10_create_doc', 'nb_docs') server_url = self.server_url login = self.cred_member[0] self.cmfLogin(*self.cred_member) for i in range(nb_docs): self.cmfCreateNews("%s/Members/%s" % (server_url, login)) self.cmfLogout() # end of test ----------------------------------------------- def tearDown(self): """Setting up test.""" self.logd("tearDown.\n") if __name__ in ('main', '__main__'): unittest.main() PKT;4 z  funkload/demo/cmf/groups.txt# $Id: groups.txt 27592 2005-09-26 15:48:28Z bdelbosc $ # # The Zope admin group AdminZope:admin # CPS Test groups FL_Member:fl_member_01,fl_member_02,fl_member_03,fl_member_04,fl_member_05 FL_Member:fl_member_06,fl_member_07,fl_member_08,fl_member_09,fl_member_10 PKT;4e!funkload/demo/cmf/credential.conf# Default configuration file for crendential server # note that %(FLOAD_HOME)s is accessible # # $Id: credential.conf 24523 2005-08-25 16:31:42Z bdelbosc $ [server] host=localhost port=22207 # In file mode loop on the n first credential # to loop over the entire file set the value to 0 loop_on_first_credentials=0 # Credentials file path must contain lines like: # login:pwd credentials_path=passwords.txt # Groups file path must contains lines like: # group_name:login1, login2, ..., loginn groups_path=groups.txt PK]i6{Y0 0 funkload/demo/cmf/test_Cmf.pyc; Cc@sdZdkZdklZdklZdklZlZdkl Z defdYZ de fd YZ e d d fjoei ndS( sJcmf FunkLoad test $Id: test_Cmf.py 27639 2005-09-27 14:30:22Z bdelbosc $ N(srandom(sFunkLoadTestCase(sxmlrpc_get_credentialsxmlrpc_list_credentials(sLipsums CmfTestCasecBs)tZdZdZdZdZRS(sIFL TestCase with common cmf tasks. self.server_url must be set. cCs~d|gd|gddgddgg}|id|i|dd ||id |ijd ||f||_dS( Ns __ac_names __ac_passwords__ac_persistents1ssubmits Login s %s/logged_ins descriptionsLog xin user %ss Login successsInvalid credential %s:%s( sloginspwdsparamssselfsposts server_urlsassert_sgetBodys _cmf_login(sselfsloginspwdsparams((s8build/bdist.linux-i686/egg/funkload/demo/cmf/test_Cmf.pyscmfLogin#s *cCs%|id|idd|idS(Ns %s/logouts descriptions logout %s(sselfsgets server_urls _cmf_login(sself((s8build/bdist.linux-i686/egg/funkload/demo/cmf/test_Cmf.pys cmfLogout.scCsXt}|ii}ddgd|gddgg}|id||ddd d gd |i gd |i gd |i gddgddgg}d||f}|id||dd|i d|ijddgd |i gd|igddgg}|id||dd|i d|ij|SdS(Ns type_names News ItemsidsaddsAdds%s/folder_factoriess descriptionsCreate an empty newssallow_discussionsdefaultstitlesdescription:texts subject:linessformats text/plainschange_and_viewsChange and Views%s/%ss%s/metadata_edit_forms Set metadatasMetadata changed.s text_formatsplains text:texts%s/newsitem_edit_formsSet news contentsNews Item changed.(sLipsumslipsums getUniqWordslowersdoc_idsparamssselfsposts parent_urls getSubjects getParagraphsgetWordsdoc_urlsassert_sgetBodys getMessage(sselfs parent_urlsparamsslipsumsdoc_urlsdoc_id((s8build/bdist.linux-i686/egg/funkload/demo/cmf/test_Cmf.pys cmfCreateNews3s ! N 6 (s__name__s __module__s__doc__scmfLogins cmfLogouts cmfCreateNews(((s8build/bdist.linux-i686/egg/funkload/demo/cmf/test_Cmf.pys CmfTestCases  sCmfcBsMtZdZdZdZdZdZdZdZdZ RS(sVSimple test of default CMF Site This test use a configuration file Cmf.conf. cCs|id|idd|_|idd}|idd}||_||_t||d|_t||d|_ d S( sSetting up test.ssetUpsmainsurls credentialshostsports AdminZopes FL_MemberN( sselfslogdsconf_gets server_urlscredential_hosts conf_getIntscredential_portsxmlrpc_get_credentials cred_admins cred_member(sselfscredential_portscredential_host((s8build/bdist.linux-i686/egg/funkload/demo/cmf/test_Cmf.pyssetUpYs    cCs|i}|i|o|iddSn|idd}|t|d }|i|i |i d|d|gddgd d gd d gd dgg}|i d||d d|i |d d|i dS(NsCMF Site already existss/iis)%s/manage_addProduct/CMFDefault/addPortalsidstitlesFunkLoad CMF Sitescreate_userfolders1s descriptionsSSee http://svn.nuxeo.org/pub/funkload/trunk/README.txt for more info about FunkLoadssubmits Add s1%s/manage_addProduct/CMFDefault/manage_addCMFSitesCreate a CMF SitesView home page(sselfs server_urlsexistsslogdssplitssite_idslenszope_urls setBasicAuths cred_adminsgetsparamsspostsclearBasicAuth(sselfssite_ids server_urlsparamsszope_url((s8build/bdist.linux-i686/egg/funkload/demo/cmf/test_Cmf.pystest_00_verifyCmfSitehs  3  cCs|i}|idd}t}|i|ixt|i |i dD]\}}d|gd|gd|gd|gdd gg}|id |||i}|id |jp d |jd |qMW|idS(Nstest_05_verifyUserssmails FL_Members member_ids member_emailspasswordsconfirmsaddsRegisters %s/join_formsMember registereds-The login name you selected is already in usesMember %s not created(sselfs server_urlsconf_gets user_mailsLipsumslipsums setBasicAuths cred_adminsxmlrpc_list_credentialsscredential_hostscredential_portsuser_idsuser_pwdsparamsspostsgetBodyshtmlsassert_sclearBasicAuth(sselfsuser_ids server_urlsuser_pwds user_mailshtmlsparamsslipsum((s8build/bdist.linux-i686/egg/funkload/demo/cmf/test_Cmf.pystest_05_verifyUsers~s   3 cCs|i}|id|dd|id|dd|id|dd|id|dd |id |dd dS( Ns %s/Memberss descriptionsTry to see Members areas%s/recent_newss Recent newss%s/search_formsView search forms %s/login_formsView login forms %s/join_formsView join form(sselfs server_urlsget(sselfs server_url((s8build/bdist.linux-i686/egg/funkload/demo/cmf/test_Cmf.pystest_anonymous_readers          cCsh|i}|i|id||idf}|i|dd|id|dd|idS(Ns%s/Members/%s/folder_contentsis descriptionsPersonal workspaces%s/personalize_formsPreference page(sselfs server_urlscmfLogins cred_membersurlsgets cmfLogout(sselfsurls server_url((s8build/bdist.linux-i686/egg/funkload/demo/cmf/test_Cmf.pystest_member_readers   cCst|idd}|i}|id}|i|ix+t|D]}|i d||fqEW|i dS(Nstest_10_create_docsnb_docsis %s/Members/%s( sselfs conf_getIntsnb_docss server_urls cred_membersloginscmfLoginsrangesis cmfCreateNewss cmfLogout(sselfsis server_urlsnb_docsslogin((s8build/bdist.linux-i686/egg/funkload/demo/cmf/test_Cmf.pystest_10_create_docs   cCs|iddS(sSetting up test.s tearDown. N(sselfslogd(sself((s8build/bdist.linux-i686/egg/funkload/demo/cmf/test_Cmf.pystearDowns( s__name__s __module__s__doc__ssetUpstest_00_verifyCmfSitestest_05_verifyUsersstest_anonymous_readerstest_member_readerstest_10_create_docstearDown(((s8build/bdist.linux-i686/egg/funkload/demo/cmf/test_Cmf.pysCmfTs     smains__main__(s__doc__sunittestsrandomsfunkload.FunkLoadTestCasesFunkLoadTestCasesfunkload.utilssxmlrpc_get_credentialsxmlrpc_list_credentialssfunkload.LipsumsLipsums CmfTestCasesCmfs__name__smain(srandomsCmfsunittestsxmlrpc_list_credentialssLipsumsFunkLoadTestCasesxmlrpc_get_credentials CmfTestCase((s8build/bdist.linux-i686/egg/funkload/demo/cmf/test_Cmf.pys?s    6gPKT;4Tx4~~'funkload/demo/xmlrpc/test_Credential.py# -*- coding: iso-8859-15 -*- """Simple FunkLoad test $Id: test_Credential.py 30285 2005-12-05 14:02:28Z bdelbosc $ """ import unittest from random import random from funkload.FunkLoadTestCase import FunkLoadTestCase class Credential(FunkLoadTestCase): """This test use a configuration file Credential.conf.""" def setUp(self): """Setting up test.""" self.logd("setUp") self.server_url = self.conf_get('main', 'url') def test_credential(self): server_url = self.server_url ret = self.xmlrpc(server_url, 'getStatus', description="Check getStatus") self.assert_('running' in ret, 'Server is down %s' % ret) self.logd('ret %s' % ret) ret = self.xmlrpc(server_url, 'getCredential', description="Get a credential from a file") self.logd('ret %s' % ret) self.assertEquals(len(ret), 2, 'Invalid return %s' % ret) ret = self.xmlrpc(server_url, 'listGroups', description="list groups from the group file") self.logd('ret %s' % ret) a_group = ret[0] ret = self.xmlrpc(server_url, 'listCredentials', description="list all credential of the file") self.logd('ret %s' % ret) ret = self.xmlrpc(server_url, 'listCredentials', (a_group,), description="list credentials of group " + a_group) self.logd('ret %s' % ret) def tearDown(self): """Setting up test.""" self.logd("tearDown.\n") if __name__ in ('main', '__main__'): unittest.main() PKT;4 funkload/demo/xmlrpc/cred.conf# Default configuration file for crendential server # note that %(FLOAD_HOME)s is accessible # # $Id: credential.conf 24523 2005-08-25 16:31:42Z bdelbosc $ [server] host=localhost port=44401 # In file mode loop on the n first credential # to loop over the entire file set the value to 0 loop_on_first_credentials=0 # Credentials file path must contain lines like: # login:pwd credentials_path=../cmf/passwords.txt # Groups file path must contains lines like: # group_name:login1, login2, ..., loginn groups_path=../cmf/groups.txt PKT;4x1=funkload/demo/xmlrpc/README.txt==================== FunkLoad demo/xmlrpc ==================== $Id: README.txt 27908 2005-10-04 09:16:58Z bdelbosc $ By using ``xmlrpc_call`` you can bench an xmlrpc service, in this small example we test the credentiald XML RPC service. This demo use a Makefile to drive tests. To test it just:: make To bench it:: make bench To test another server that the one define in the Credential.conf:: make URL=http://localhost:33301 PKT;4#jj!funkload/demo/xmlrpc/monitor.conf# default configuration file for the monitor server # note that %(FLOAD_HOME)s is accessible # # $Id: credential.conf 22780 2005-06-06 09:43:52Z bdelbosc $ # ------------------------------------------------------------ [server] # configuration used by monitord host = localhost port = 44402 # sleeptime between monitoring in second # note that load average is updated by the system only every 5s interval = .5 # network interface to monitor lo, eth0 interface = lo # ------------------------------------------------------------ [client] # configuration used by monitorctl host = localhost port = 44402 verbose = 0 PKT;4 T-6funkload/demo/xmlrpc/Makefile# Makefile of FunkLoad xmlrpc demo .PHONY: clean all start stop restart status .PHONY: test credential_test bench credential_bench .PHONY: start_monitor stop_monitor restart_monitor .PHONY: start_credential stop_credential restart_credential CREDCTL := fl-credential-ctl cred.conf MONCTL := fl-monitor-ctl monitor.conf ifdef URL # FunkLoad options FLOPS = -u $(URL) else FLOPS = endif all: test # testing test: credential_test credential_test: $(CREDCTL) restart fl-run-test test_Credential.py -v $(FLOPS) $(CREDCTL) stop # benching bench: credential_bench credential_bench: @$(CREDCTL) restart @$(MONCTL) restart -fl-run-bench -c 1:20:40:60:80:100 -D 10 test_Credential.py Credential.test_credential $(FLOPS) -fl-build-report credential-bench.xml --html @$(MONCTL) stop @$(CREDCTL) stop # monitor ctl start_monitor: $(MONCTL) start stop_monitor: -$(MONCTL) stop restart_monitor: $(MONCTL) restart # credential ctl start_credential: $(CREDCTL) start stop_credential: $(CREDCTL) stop restart_credential: $(CREDCTL) restart # misc status: $(MONCTL) status; $(CREDCTL) status; stop: stop_monitor stop_credential start: start_monitor start_credential restart: restart_monitor restart_credential clean: -find . "(" -name "*~" -or -name ".#*" ")" -print0 | xargs -0 rm -f PKT;47..$funkload/demo/xmlrpc/Credential.conf# FunkLoad test configuration file # $Id: $ # ------------------------------------------------------------ # Main section # [main] title=Test the credential server description=Try to test all xml rpc method # the credential server url to test url=http://localhost:44401/ # the User-Agent header to send #user_agent = Mozilla/5.0 Firefox/1.0.6 # ------------------------------------------------------------ # Tests description and configuration # [test_credential] description=Check all credentiald methods [monitor] hosts=localhost # Each host in [monitor]hosts should have a section # with a 'port' and 'description' keys [localhost] port=44402 description=The benching and benched machine # ------------------------------------------------------------ # Configuration for unit test mode fl-run-test # [ftest] # log_to destination = # console - to the screen # file - to a file log_to = console file # log_path = path and file name to store log file log_path = credential-test.log # result_path = path to store the xml result file result_path = credential-test.xml # ok_codes = list of successfull HTTP response code #ok_codes = 200:301:302 # sleeptime_min = minimum amount of time in seconds to sleep between requests # to the host sleep_time_min = 0 # sleeptime_max = maximum amount of time in seconds to sleep between requests # to the host sleep_time_max = 0 # ------------------------------------------------------------ # Configuration for bench mode fl-run-bench # [bench] # cycles = list of cycles with their number of concurrent users cycles = 1:20:40:60:80:100 # duration = duration of a cycle in seconds duration = 20 # startup_delay = time to wait between starting-up threads in seconds startup_delay = 0.05 # sleep_time = time to wait between test in seconds sleep_time = 0.5 # cycle_time = time to wait between cycle in seconds cycle_time = 1 # same keys than in [ftest] section log_to = file log_path = credential-bench.log result_path = credential-bench.xml #ok_codes = 200:301:302 sleep_time_min = .1 sleep_time_max = .2 PK]i6ĮR R (funkload/demo/xmlrpc/test_Credential.pyc; Cc@sddZdkZdklZdklZdefdYZeddfjoeindS(sTSimple FunkLoad test $Id: test_Credential.py 30285 2005-12-05 14:02:28Z bdelbosc $ N(srandom(sFunkLoadTestCases CredentialcBs)tZdZdZdZdZRS(s3This test use a configuration file Credential.conf.cCs&|id|idd|_dS(sSetting up test.ssetUpsmainsurlN(sselfslogdsconf_gets server_url(sself((sBbuild/bdist.linux-i686/egg/funkload/demo/xmlrpc/test_Credential.pyssetUp s cCs%|i}|i|ddd}|id|jd||id||i|ddd}|id||it|d d ||i|d dd }|id||d }|i|ddd}|id||i|d|fdd|}|id|dS(Ns getStatuss descriptionsCheck getStatussrunningsServer is down %ssret %ss getCredentialsGet a credential from a fileisInvalid return %ss listGroupsslist groups from the group fileislistCredentialsslist all credential of the fileslist credentials of group ( sselfs server_urlsxmlrpcsretsassert_slogds assertEqualsslensa_group(sselfsa_groups server_urlsret((sBbuild/bdist.linux-i686/egg/funkload/demo/xmlrpc/test_Credential.pystest_credentials&          cCs|iddS(sSetting up test.s tearDown. N(sselfslogd(sself((sBbuild/bdist.linux-i686/egg/funkload/demo/xmlrpc/test_Credential.pystearDown-s(s__name__s __module__s__doc__ssetUpstest_credentialstearDown(((sBbuild/bdist.linux-i686/egg/funkload/demo/xmlrpc/test_Credential.pys Credential s   smains__main__(s__doc__sunittestsrandomsfunkload.FunkLoadTestCasesFunkLoadTestCases Credentials__name__smain(s CredentialsunittestsrandomsFunkLoadTestCase((sBbuild/bdist.linux-i686/egg/funkload/demo/xmlrpc/test_Credential.pys?s    (PKT;48 funkload/tests/doctest_dummy.txt============= Dummy DocTest ============= This is a dummy doc test to check fl-run-test doctest support: >>> 1 + 1 2 Check FunkLoad doctest: >>> from funkload.FunkLoadDocTest import FunkLoadDocTest >>> fl = FunkLoadDocTest() >>> fl.get('http://localhost/') See http://funkload.nuxeo.org/ for more information about FunkLoad PKT;4E`funkload/tests/test_dummy.py# (C) Copyright 2006 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # # """Dummy test used by test_Install.py $Id: test_dummy.py 32255 2006-01-26 10:58:39Z bdelbosc $ simple doctest in a docstring: >>> 1 + 1 2 """ import os import unittest import commands class TestDummy1(unittest.TestCase): """Dummy test case.""" def test_dummy1_1(self): self.assertEquals(1+1, 2) def test_dummy1_2(self): self.assertEquals(1+1, 2) class TestDummy2(unittest.TestCase): """Dummy test case.""" def test_dummy2_1(self): self.assertEquals(1+1, 2) def test_dummy2_2(self): self.assertEquals(1+1, 2) class TestDummy3(unittest.TestCase): """Failing test case not part of the test_suite.""" def test_dummy3_1(self): self.assertEquals(1+1, 2) def test_dummy3_2(self): # failing test case self.assertEquals(1+1, 3, 'example of a failing test') def test_dummy3_3(self): # error test case impossible = 1/0 self.assert_(1+1, 2) class Dummy: """Testing docstring.""" def __init__(self, value): self.value = value def double(self): """Return the double of the initial value. >>> d = Dummy(1) >>> d.double() 2 """ return self.value * 2 def test_suite(): """Return a test suite.""" suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(TestDummy1)) suite.addTest(unittest.makeSuite(TestDummy2)) return suite if __name__ in ('main', '__main__'): unittest.main() PKT;4g22VVfunkload/tests/__init__.py"""FunkLoad test package. $Id: __init__.py 30338 2005-12-06 10:20:56Z bdelbosc $ """ PKT;4l=funkload/tests/test_Install.py# (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # # """Check an installed FunkLoad. $Id: test_Install.py 32271 2006-01-26 14:21:01Z bdelbosc $ """ import os import unittest import commands class TestInstall(unittest.TestCase): """Check installation.""" def setUp(self): self.test_file = 'test_dummy.py' self.doctest_file = 'doctest_dummy.txt' def system(self, cmd, expected_code=0): """Execute a cmd and exit on fail return cmd output.""" ret = commands.getstatusoutput(cmd) if ret[0] != expected_code: self.fail("exec [%s] return code %s != %s output:\n%s" % (cmd, ret[0], expected_code, ret[1])) return ret[1] def test_01_requires(self): try: import webunit except ImportError: self.fail('Missing Required module webunit') try: import funkload except ImportError: self.fail('Unable to import funkload module.') try: import docutils except ImportError: print ("WARNING: missing docutils module, " "no HTML report available.") try: import gdchart except ImportError: print ("WARNING: missing gdchart module, " "no charts available in the HTML report.") from funkload.TestRunner import g_has_doctest if not g_has_doctest: print "WARNING: Python 2.4 is required to support doctest" def test_testloader(self): # check testrunner loader test_file = self.test_file # listing test output = self.system("fl-run-test %s --list" % test_file) self.assert_('test_dummy1_1' in output) self.assert_('test_dummy2_1' in output) self.assert_('test_dummy3_1' in output) # list a test suite output = self.system("fl-run-test %s test_suite --list" % test_file) self.assert_('test_dummy1_1' in output) self.assert_('test_dummy2_1' in output) self.assert_('test_dummy3_1' not in output) # list all test in a test case class output = self.system("fl-run-test %s TestDummy1 --list" % test_file) self.assert_('test_dummy1_1' in output) self.assert_('test_dummy1_2' in output) self.assert_('test_dummy2_1' not in output) # match regex output = self.system("fl-run-test %s --list -e dummy1_1" % test_file) self.assert_('test_dummy1_1' in output) self.assert_('test_dummy2_1' not in output) output = self.system("fl-run-test %s TestDummy1 --list -e dummy1_1" % test_file) self.assert_('test_dummy1_1' in output) self.assert_('test_dummy2_1' not in output) output = self.system("fl-run-test %s --list -e 2$" % test_file) self.assert_('test_dummy1_2' in output) self.assert_('test_dummy2_2' in output) self.assert_('test_dummy1_1' not in output) self.assert_('test_dummy2_1' not in output) output = self.system("fl-run-test %s --list -e '!2$'" % test_file) self.assert_('test_dummy1_1' in output, output) self.assert_('test_dummy2_1' in output) self.assert_('test_dummy1_2' not in output) self.assert_('test_dummy2_2' not in output) def test_doctestloader(self): # check testrunner loader from funkload.TestRunner import g_has_doctest if not g_has_doctest: self.fail('Python 2.4 is required to support doctest') test_file = self.test_file # listing test output = self.system("fl-run-test %s --list" % test_file) self.assert_('Dummy.double' in output, 'missing doctest') # list a test suite output = self.system("fl-run-test %s test_suite --list" % test_file) self.assert_('Dummy.double' not in output, 'doctest is not part of the suite') # list all test in a test case class output = self.system("fl-run-test %s TestDummy1 --list" % test_file) self.assert_('Dummy.double' not in output, 'doctest is not part of the testcase') # pure doctest doctest_file = self.doctest_file output = self.system("fl-run-test %s --list" % doctest_file) self.assert_(doctest_file.replace('.', '_') in output, 'no %s in output %s' % (doctest_file, output)) # match regex output = self.system("fl-run-test %s --list -e dummy1_1" % test_file) def test_testrunner(self): # try to launch a test test_file = self.test_file output = self.system('fl-run-test %s TestDummy1 -v' % test_file) self.assert_('Ran 0 tests' not in output, 'not expected output:"""%s"""' % output) output = self.system('fl-run-test %s TestDummy2 -v' % test_file) self.assert_('Ran 0 tests' not in output, 'not expected output:"""%s"""' % output) # doctest from funkload.TestRunner import g_has_doctest if g_has_doctest: output = self.system('fl-run-test %s -e double -v' % test_file) self.assert_('Ran 0 tests' not in output, 'not expected output:"""%s"""' % output) # failing test output = self.system('fl-run-test %s TestDummy3 -v' % test_file, expected_code=256) self.assert_('Ran 0 tests' not in output, 'not expected output:"""%s"""' % output) self.assert_('FAILED' in output) self.assert_('ERROR' in output) def test_xmlrpc(self): # extract demo example and run the xmlrpc test from tempfile import mkdtemp pwd = os.getcwd() tmp_path = mkdtemp('funkload') os.chdir(tmp_path) self.system('fl-install-demo') os.chdir(os.path.join(tmp_path, 'funkload-demo', 'xmlrpc')) self.system("fl-credential-ctl cred.conf restart") self.system("fl-monitor-ctl monitor.conf restart") self.system("fl-run-test -v test_Credential.py") self.system("fl-run-bench -c 1:10:20 -D 4 " "test_Credential.py Credential.test_credential") self.system("fl-monitor-ctl monitor.conf stop") self.system("fl-credential-ctl cred.conf stop") self.system("fl-build-report credential-bench.xml --html") os.chdir(pwd) def test_suite(): """Return a test suite.""" suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(TestInstall)) return suite if __name__ in ('main', '__main__'): unittest.main() PK]i6ufunkload/tests/test_dummy.pyc; Cc@sdZdkZdkZdkZdeifdYZdeifdYZdeifdYZdfd YZd Z e d d fjoei ndS( sDummy test used by test_Install.py $Id: test_dummy.py 32255 2006-01-26 10:58:39Z bdelbosc $ simple doctest in a docstring: >>> 1 + 1 2 Ns TestDummy1cBs tZdZdZdZRS(sDummy test case.cCs|iddddS(Nii(sselfs assertEquals(sself((s7build/bdist.linux-i686/egg/funkload/tests/test_dummy.pys test_dummy1_1#scCs|iddddS(Nii(sselfs assertEquals(sself((s7build/bdist.linux-i686/egg/funkload/tests/test_dummy.pys test_dummy1_2&s(s__name__s __module__s__doc__s test_dummy1_1s test_dummy1_2(((s7build/bdist.linux-i686/egg/funkload/tests/test_dummy.pys TestDummy1!s  s TestDummy2cBs tZdZdZdZRS(sDummy test case.cCs|iddddS(Nii(sselfs assertEquals(sself((s7build/bdist.linux-i686/egg/funkload/tests/test_dummy.pys test_dummy2_1,scCs|iddddS(Nii(sselfs assertEquals(sself((s7build/bdist.linux-i686/egg/funkload/tests/test_dummy.pys test_dummy2_2/s(s__name__s __module__s__doc__s test_dummy2_1s test_dummy2_2(((s7build/bdist.linux-i686/egg/funkload/tests/test_dummy.pys TestDummy2*s  s TestDummy3cBs)tZdZdZdZdZRS(s-Failing test case not part of the test_suite.cCs|iddddS(Nii(sselfs assertEquals(sself((s7build/bdist.linux-i686/egg/funkload/tests/test_dummy.pys test_dummy3_14scCs|idddddS(Niisexample of a failing test(sselfs assertEquals(sself((s7build/bdist.linux-i686/egg/funkload/tests/test_dummy.pys test_dummy3_27scCs"dd}|iddddS(Niii(s impossiblesselfsassert_(sselfs impossible((s7build/bdist.linux-i686/egg/funkload/tests/test_dummy.pys test_dummy3_3;s (s__name__s __module__s__doc__s test_dummy3_1s test_dummy3_2s test_dummy3_3(((s7build/bdist.linux-i686/egg/funkload/tests/test_dummy.pys TestDummy32s   sDummycBs tZdZdZdZRS(sTesting docstring.cCs ||_dS(N(svaluesself(sselfsvalue((s7build/bdist.linux-i686/egg/funkload/tests/test_dummy.pys__init__CscCs|idSdS(slReturn the double of the initial value. >>> d = Dummy(1) >>> d.double() 2 iN(sselfsvalue(sself((s7build/bdist.linux-i686/egg/funkload/tests/test_dummy.pysdoubleFs(s__name__s __module__s__doc__s__init__sdouble(((s7build/bdist.linux-i686/egg/funkload/tests/test_dummy.pysDummyAs  cCs@ti}|itit|itit|SdS(sReturn a test suite.N(sunittests TestSuitessuitesaddTests makeSuites TestDummy1s TestDummy2(ssuite((s7build/bdist.linux-i686/egg/funkload/tests/test_dummy.pys test_suitePs  smains__main__( s__doc__sossunittestscommandssTestCases TestDummy1s TestDummy2s TestDummy3sDummys test_suites__name__smain(sDummyscommandssunittests TestDummy2s TestDummy3s TestDummy1s test_suitesos((s7build/bdist.linux-i686/egg/funkload/tests/test_dummy.pys?s     PK]i6Ifunkload/tests/__init__.pyc; Cc@s dZdS(sOFunkLoad test package. $Id: __init__.py 30338 2005-12-06 10:20:56Z bdelbosc $ N(s__doc__(((s5build/bdist.linux-i686/egg/funkload/tests/__init__.pys?sPK]i6i-ifunkload/tests/test_Install.pyc; Cc@shdZdkZdkZdkZdeifdYZdZeddfjoeindS(sYCheck an installed FunkLoad. $Id: test_Install.py 32271 2006-01-26 14:21:01Z bdelbosc $ Ns TestInstallcBsPtZdZdZddZdZdZdZdZdZ RS( sCheck installation.cCsd|_d|_dS(Ns test_dummy.pysdoctest_dummy.txt(sselfs test_files doctest_file(sself((s9build/bdist.linux-i686/egg/funkload/tests/test_Install.pyssetUps icCsUti|}|d|jo)|id||d||dfn|dSdS(s1Execute a cmd and exit on fail return cmd output.is)exec [%s] return code %s != %s output: %siN(scommandssgetstatusoutputscmdsrets expected_codesselfsfail(sselfscmds expected_codesret((s9build/bdist.linux-i686/egg/funkload/tests/test_Install.pyssystem"s )cCsy dk}Wn tj o|idnXy dk}Wn tj o|idnXy dk}Wntj o dGHnXy dk}Wntj o dGHnXdkl}| o dGHndS(NsMissing Required module webunits!Unable to import funkload module.s;WARNING: missing docutils module, no HTML report available.sHWARNING: missing gdchart module, no charts available in the HTML report.(s g_has_doctests2WARNING: Python 2.4 is required to support doctest( swebunits ImportErrorsselfsfailsfunkloadsdocutilssgdchartsfunkload.TestRunners g_has_doctest(sselfsfunkloadswebunitsdocutilssgdcharts g_has_doctest((s9build/bdist.linux-i686/egg/funkload/tests/test_Install.pystest_01_requires*s&       cCs$|i}|id|}|id|j|id|j|id|j|id|}|id|j|id|j|id|j|id|}|id|j|id|j|id|j|id|}|id|j|id|j|id |}|id|j|id|j|id |}|id|j|id |j|id|j|id|j|id |}|id|j||id|j|id|j|id |jdS( Nsfl-run-test %s --lists test_dummy1_1s test_dummy2_1s test_dummy3_1s fl-run-test %s test_suite --lists fl-run-test %s TestDummy1 --lists test_dummy1_2s!fl-run-test %s --list -e dummy1_1s,fl-run-test %s TestDummy1 --list -e dummy1_1sfl-run-test %s --list -e 2$s test_dummy2_2sfl-run-test %s --list -e '!2$'(sselfs test_filessystemsoutputsassert_(sselfsoutputs test_file((s9build/bdist.linux-i686/egg/funkload/tests/test_Install.pystest_testloaderCs: cCs dkl}| o|idn|i}|id|}|id|jd|id|}|id|jd|id|}|id|jd |i}|id|}|i|i d d |jd ||f|id |}dS(N(s g_has_doctests)Python 2.4 is required to support doctestsfl-run-test %s --lists Dummy.doublesmissing doctests fl-run-test %s test_suite --lists doctest is not part of the suites fl-run-test %s TestDummy1 --lists#doctest is not part of the testcases.s_sno %s in output %ss!fl-run-test %s --list -e dummy1_1( sfunkload.TestRunners g_has_doctestsselfsfails test_filessystemsoutputsassert_s doctest_filesreplace(sselfs test_files doctest_files g_has_doctestsoutput((s9build/bdist.linux-i686/egg/funkload/tests/test_Install.pystest_doctestloaderos"   cCs|i}|id|}|id|jd||id|}|id|jd|dkl}|o1|id|}|id|jd|n|id|dd }|id|jd||id |j|id |jdS( Nsfl-run-test %s TestDummy1 -vs Ran 0 testssnot expected output:"""%s"""sfl-run-test %s TestDummy2 -v(s g_has_doctestsfl-run-test %s -e double -vsfl-run-test %s TestDummy3 -vs expected_codeisFAILEDsERROR(sselfs test_filessystemsoutputsassert_sfunkload.TestRunners g_has_doctest(sselfsoutputs test_files g_has_doctest((s9build/bdist.linux-i686/egg/funkload/tests/test_Install.pystest_testrunners$       cCsdkl}ti}|d}ti||idtiti i |dd|id|id|id|id |id |id |id ti|dS( N(smkdtempsfunkloadsfl-install-demos funkload-demosxmlrpcs#fl-credential-ctl cred.conf restarts#fl-monitor-ctl monitor.conf restarts!fl-run-test -v test_Credential.pysJfl-run-bench -c 1:10:20 -D 4 test_Credential.py Credential.test_credentials fl-monitor-ctl monitor.conf stops fl-credential-ctl cred.conf stops+fl-build-report credential-bench.xml --html( stempfilesmkdtempsossgetcwdspwdstmp_pathschdirsselfssystemspathsjoin(sselfstmp_pathspwdsmkdtemp((s9build/bdist.linux-i686/egg/funkload/tests/test_Install.pys test_xmlrpcs            ( s__name__s __module__s__doc__ssetUpssystemstest_01_requiresstest_testloaderstest_doctestloaderstest_testrunners test_xmlrpc(((s9build/bdist.linux-i686/egg/funkload/tests/test_Install.pys TestInstalls     ,  cCs*ti}|itit|SdS(sReturn a test suite.N(sunittests TestSuitessuitesaddTests makeSuites TestInstall(ssuite((s9build/bdist.linux-i686/egg/funkload/tests/test_Install.pys test_suites smains__main__( s__doc__sossunittestscommandssTestCases TestInstalls test_suites__name__smain(scommandssunittests test_suitesoss TestInstall((s9build/bdist.linux-i686/egg/funkload/tests/test_Install.pys?s    PK]i66UHRREGG-INFO/PKG-INFOMetadata-Version: 1.0 Name: funkload Version: 1.6.1 Summary: Functional and load web tester. Home-page: http://funkload.nuxeo.org/ Author: Benoit Delbosc Author-email: bdelbosc@nuxeo.com License: GPL Download-URL: http://funkload.nuxeo.org/funkload-1.6.1.tar.gz Description: FunkLoad is a functional and load web tester, written in Python, whose main use cases are: * Functional testing of web projects, and thus regression testing as well. * Performance testing: by loading the web application and monitoring your servers it helps you to pinpoint bottlenecks, giving a detailed report of performance measurement. * Load testing tool to expose bugs that do not surface in cursory testing, like volume testing or longevity testing. * Stress testing tool to overwhelm the web application resources and test the application recoverability. * Writing web agents by scripting any web repetitive task, like checking if a site is alive. Main FunkLoad features are: * FunkLoad is free software distributed under the `GNU GPL`. * Functional test are pure Python scripts using the pyUnit framework like normal unit test. Python enable complex scenarios to handle real world applications. * Truly emulates a web browser (single-threaded) using Richard Jones' webunit: - basic authentication support - cookies support - referrer support - http proxy support - fetching css, javascript and images - emulating a browser cache - file upload and multipart/form-data submission - https support * Advanced test runner with many command-line options: - set the target server url - display the fetched page in real time in your browser - debug mode - green/red color mode - select test case using a regex - support normal pyUnit test - support doctest from a plain text file or embedded in python docstring * Turn a functional test into a load test: just by invoking the bench runner you can identify scalability and performance problems. * Detailed bench reports in ReST or HTML (and PDF via ps2pdf) containing: - the bench configuration - tests, pages, requests stats and charts with percentiles. - the 5 slowest requests. - servers cpu usage, load average, memory/swap usage and network traffic charts. - an http error summary list * Easy test customization using a configuration file or command line options. * Easy test creation using TCPWatch as proxy recorder, so you can use your web browser and produce a FunkLoad test automatically. * Provides web assertion helpers. * Provides a funkload.CPSTestCase to ease Zope and Nuxeo CPS testing. * Easy to install (EasyInstall) and use, see examples in the demo folder. Keywords: testing benching load performance functional monitoring Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: Intended Audience :: System Administrators Classifier: Natural Language :: English Classifier: License :: OSI Approved :: GNU General Public License (GPL) Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Topic :: Internet :: WWW/HTTP :: Site Management Classifier: Topic :: Software Development :: Testing Classifier: Topic :: Software Development :: Quality Assurance Classifier: Topic :: System :: Benchmark Classifier: Topic :: System :: Monitoring PK]i6d}}EGG-INFO/SOURCES.txtCHANGES.txt INSTALL.txt LICENSE.txt Makefile README.txt THANKS TODO.txt ez_setup.py setup.py doc/Makefile funkload/BenchRunner.py funkload/CPS338TestCase.py funkload/CPS340DocTest.py funkload/CPS340TestCase.py funkload/CPSTestCase.py funkload/CredentialBase.py funkload/CredentialFile.py funkload/CredentialRandom.py funkload/FunkLoadDocTest.py funkload/FunkLoadTestCase.py funkload/Lipsum.py funkload/Makefile funkload/Monitor.py funkload/PatchWebunit.py funkload/Recorder.py funkload/ReportBuilder.py funkload/ReportRenderer.py funkload/ReportStats.py funkload/TestRunner.py funkload/XmlRpcBase.py funkload/ZopeTestCase.py funkload/__init__.py funkload/utils.py funkload/version.py funkload.egg-info/PKG-INFO funkload.egg-info/SOURCES.txt funkload.egg-info/dependency_links.txt funkload.egg-info/requires.txt funkload.egg-info/top_level.txt funkload.egg-info/zip-safe funkload/data/ConfigurationTestCase.tpl funkload/data/ScriptTestCase.tpl funkload/data/funkload.css funkload/demo/README.txt funkload/demo/cmf/Cmf.conf funkload/demo/cmf/README.txt funkload/demo/cmf/credential.conf funkload/demo/cmf/groups.txt funkload/demo/cmf/passwords.txt funkload/demo/cmf/test_Cmf.py funkload/demo/simple/README.txt funkload/demo/simple/Simple.conf funkload/demo/simple/monitor.conf funkload/demo/simple/test_Simple.py funkload/demo/xmlrpc/Credential.conf funkload/demo/xmlrpc/Makefile funkload/demo/xmlrpc/README.txt funkload/demo/xmlrpc/cred.conf funkload/demo/xmlrpc/monitor.conf funkload/demo/xmlrpc/test_Credential.py funkload/demo/zope/README.txt funkload/demo/zope/Zope.conf funkload/demo/zope/test_Zope.py funkload/tests/__init__.py funkload/tests/doctest_dummy.txt funkload/tests/test_Install.py funkload/tests/test_dummy.py scripts/fl-build-report scripts/fl-credential-ctl scripts/fl-import-from-tm-recorder scripts/fl-install-demo scripts/fl-monitor-ctl scripts/fl-record scripts/fl-run-bench scripts/fl-run-test PK]i62EGG-INFO/dependency_links.txt PK]i6Ս.##EGG-INFO/requires.txtwebunit == 1.3.8 docutils >= 0.3.7PK]i6  EGG-INFO/top_level.txtfunkload PK]i62EGG-INFO/zip-safe PK]i68=EGG-INFO/scripts/fl-monitor-ctl#!/usr/bin/python2.3 # (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """Simple client that control the monitor server.""" import sys from funkload.Monitor import MonitorController def main(): """Control monitor server.""" ctl = MonitorController() sys.exit(ctl()) if __name__ == '__main__': main() PK]i6,<<"EGG-INFO/scripts/fl-credential-ctl#!/usr/bin/python2.3 # (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """Simple client that control the credential server.""" import sys from funkload.CredentialFile import CredentialFileController def main(): """Control credentiald server.""" ctl = CredentialFileController() sys.exit(ctl()) if __name__ == '__main__': main() PK]i6-q}}EGG-INFO/scripts/fl-run-bench#!/usr/bin/python2.3 # (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """Run a funkload unit test in bench mode. $Id: fl-run-bench 24568 2005-08-26 15:23:49Z bdelbosc $ """ from funkload.BenchRunner import main main() PK]i6;nnEGG-INFO/scripts/fl-run-test#!/usr/bin/python2.3 # (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """Run a funkload unit test. $Id: fl-run-bench 24487 2005-08-24 16:13:39Z bdelbosc $ """ from funkload.TestRunner import main main() PK]i6qkڋ EGG-INFO/scripts/fl-build-report#!/usr/bin/python2.3 # (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """Convert a testmaker script into a FunkLoad test. $Id: ftest_utils.py 22915 2005-06-09 15:38:07Z bdelbosc $ """ from funkload.ReportBuilder import main main() PK]i6a+EGG-INFO/scripts/fl-import-from-tm-recorder#!/usr/bin/python2.3 # (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """Convert a unit Test build with the TestMaker Recorder into a FunkLoad test. $Id: ftest_utils.py 22915 2005-06-09 15:38:07Z bdelbosc $ """ import os import re from optparse import OptionParser, TitledHelpFormatter from funkload.utils import trace class TMImportProgram: """See usage.""" usage = """%prog tm_script This will convert a TestMaker script build with the TM Recorder into a FunkLoad script and configuration file. Examples ======== %prog scenarioName.tm This will generate scenario_name.py and scenario_name.conf. Then you can use fl-run-test scenarionName.py """ def __init__(self): self.tm_path = self.scenario = self.server_url = self.options = None self.parseArgs() test_name = os.path.splitext(os.path.basename(self.tm_path))[0] class_name = ''.join([x.capitalize() for x in re.split('_|-', test_name)]) self.script_path = os.path.join(os.path.abspath( self.options.output_dir), 'test_%s.py' % class_name) self.configuration_path = os.path.join(os.path.abspath( self.options.output_dir), class_name + '.conf') self.test_name = test_name self.class_name = class_name def parseArgs(self): """Parse command line.""" parser = OptionParser(self.usage, formatter=TitledHelpFormatter()) cur_path = os.path.abspath(os.path.curdir) parser.add_option("-o", "--output-directory", type="string", dest="output_dir", help="Directory to dump html pages.", default=cur_path) self.options, args = parser.parse_args() if len(args) != 1: parser.error("incorrect number of arguments") self.tm_path = os.path.abspath(args[0]) def grep(self, text): """Grep interesting lines.""" patterns = ('self.get(', 'self.post(', 'self.params = ') for pattern in patterns: if text.find(pattern) != -1: return 1 return 0 def format(self, text, server_url): """Reformat python code.""" text = text.replace("'''", '"') text = text.replace("self.params", "params") if text.find('params') != -1: # always use post if we have some params text = text.replace('self.get', 'self.post') text = text.replace('( ', '(') text = text.replace(' )', ')') text = text.replace('[ ', '[') text = text.replace(' ]', ']') text = text.replace('],[', '],\n [') if text.find(server_url) != -1: text = text.replace(server_url, '%s') text = text.replace('",', '" % server_url,') text = text.replace('")', '" % server_url)') return text def extractScenario(self): """Extract and format testmaker action.""" lines = open(self.tm_path).readlines() server_url = '?' for line in lines: match = re.search('\'(https?://[^\'\/]*)', line) if match is not None: server_url = match.group(1) break self.scenario = ''.join([self.format(line, server_url) for line in lines if self.grep(line)]) self.server_url = server_url def writeScript(self): """Write the FunkLoad test script.""" from pkg_resources import resource_string tpl = resource_string('funkload', 'data/ScriptTestCase.tpl') content = tpl % {'script': self.scenario, 'test_name': self.test_name, 'class_name': self.class_name} if os.path.exists(self.script_path): trace("\nError file %s already exists.\n" % self.script_path) return f = open(self.script_path, 'w') f.write(content) f.close() def writeConfiguration(self): """Write the FunkLoad configuration test script.""" from pkg_resources import resource_string tpl = resource_string('funkload', 'data/ConfigurationTestCase.tpl') content = tpl % {'server_url': self.server_url, 'test_name': self.test_name, 'class_name': self.class_name} if os.path.exists(self.configuration_path): trace("\nError file %s already exists.\n" % self.configuration_path) return f = open(self.configuration_path, 'w') f.write(content) f.close() def main(self): """Convert.""" self.parseArgs() trace("Importing %s: ... " % self.tm_path) self.extractScenario() trace('done.\n') trace("Creating %s: ... " % self.script_path) self.writeScript() trace('done.\n') trace("Creating %s: ... " % self.configuration_path) self.writeConfiguration() trace('done.\n') __call__ = main def main(): """main.""" importer = TMImportProgram() importer() if __name__ == '__main__': main() PK]i6Mm EGG-INFO/scripts/fl-install-demo#!/usr/bin/python2.3 # (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """Extract the demo from the funkload egg into the current path.""" import os from shutil import copytree from pkg_resources import resource_filename, cleanup_resources def main(): """main.""" demo_path = 'funkload-demo' print "Extract FunkLoad examples into ./%s : ... " % demo_path, cache_path = resource_filename('funkload', 'demo') demo_path = os.path.join(os.path.abspath(os.path.curdir), demo_path) copytree(cache_path, demo_path) cleanup_resources() print "done." if __name__ == '__main__': main() PK]i6EGG-INFO/scripts/fl-record#!/usr/bin/python2.3 # (C) Copyright 2005 Nuxeo SAS # Author: bdelbosc@nuxeo.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # 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. # """tcpwatch Proxy recorder that output FunkLoad instruction $Id: fl-run-bench 24487 2005-08-24 16:13:39Z bdelbosc $ """ from funkload.Recorder import RecorderProgram RecorderProgram().run() PKT;4 funkload/FunkLoadDocTest.pyPKv]i6dzF,F,Nfunkload/ReportStats.pyPKLb6HY8Y84funkload/PatchWebunit.pyPKLb6MHXmfunkload/FunkLoadTestCase.pyPKT;4* X**)funkload/__init__.pyPKT;4QL1'1'funkload/XmlRpcBase.pyPKH\b4@U!U!funkload/utils.pyPK$M[6BLo>>n?funkload/ReportRenderer.pyPKH\b4&22funkload/Recorder.pyPKT;4o|m<>>$funkload/CredentialBase.pyPKb4!7k88 funkload/CPS340TestCase.pyPKT;4aPBfunkload/Lipsum.pyPKT;4BGGbfunkload/BenchRunner.pyPK$M[6RŃIIfunkload/TestRunner.pyPKT;4nRRfunkload/ZopeTestCase.pyPKT;4kϤ&funkload/CredentialFile.pyPKT;4n$OOfunkload/CredentialRandom.pyPKb4Q_G66-funkload/CPS338TestCase.pyPKT;4x. ]]Udfunkload/CPSTestCase.pyPK$M[6,$$gfunkload/ReportBuilder.pyPKLb6 >>funkload/version.pyPKT;4rMl'l' funkload/Monitor.pyPKH\b4<:funkload/CPS340DocTest.pyPK]i6]$ funkload/FunkLoadDocTest.pycPK]i64~w_U;U;funkload/ReportStats.pycPK]i6 8080Ufunkload/PatchWebunit.pycPK]i6S 4funkload/FunkLoadTestCase.pycPK]i6PVfunkload/__init__.pycPK]i6Xg//funkload/XmlRpcBase.pycPK]i6--funkload/utils.pycPK]i6׻w֞֞"funkload/ReportRenderer.pycPK]i6d<<funkload/Recorder.pycPK]i6S˦;funkload/CredentialBase.pycPK]i6(y>>funkload/CPS340TestCase.pycPK]i6 >%>%Bfunkload/Lipsum.pycPK]i6UNNZhfunkload/BenchRunner.pycPK]i6 HMHM8funkload/TestRunner.pycPK]i6;nfunkload/ZopeTestCase.pycPK]i6d x""wfunkload/CredentialFile.pycPK]i6N9ccE9funkload/CredentialRandom.pycPK]i6/]m<<Kfunkload/CPS338TestCase.pycPK]i6MM͈funkload/CPSTestCase.pycPK]i6ݕު$$Pfunkload/ReportBuilder.pycPK]i6h][funkload/version.pycPK]i6bE55funkload/Monitor.pycPK]i6Mtfunkload/CPS340DocTest.pycPKT;4!N 'funkload/data/ConfigurationTestCase.tplPKT;4 funkload/data/funkload.cssPK$M[6,vjj funkload/data/ScriptTestCase.tplPKT;4#4)Jf funkload/demo/README.txtPKT;4H#5 funkload/demo/simple/test_Simple.pyPKT;4YKfunkload/demo/simple/README.txtPKT;4 \\!funkload/demo/simple/monitor.confPKT;4%A funkload/demo/simple/Simple.confPK]i6ҟ$$funkload/demo/simple/test_Simple.pycPKT;48 ;,funkload/demo/zope/Zope.confPKT;45funkload/demo/zope/test_Zope.pyPKT;4 Hfunkload/demo/zope/README.txtPK]i64o'' Kfunkload/demo/zope/test_Zope.pycPKT;419dfunkload/demo/cmf/passwords.txtPKT;4@| | Rffunkload/demo/cmf/Cmf.confPKT;4;!!pfunkload/demo/cmf/README.txtPKT;4aatfunkload/demo/cmf/test_Cmf.pyPKT;4 z  kfunkload/demo/cmf/groups.txtPKT;4e!funkload/demo/cmf/credential.confPK]i6{Y0 0 funkload/demo/cmf/test_Cmf.pycPKT;4Tx4~~'cfunkload/demo/xmlrpc/test_Credential.pyPKT;4 &funkload/demo/xmlrpc/cred.confPKT;4x1=xfunkload/demo/xmlrpc/README.txtPKT;4#jj!nfunkload/demo/xmlrpc/monitor.confPKT;4 T-6funkload/demo/xmlrpc/MakefilePKT;47..$lfunkload/demo/xmlrpc/Credential.confPK]i6ĮR R (funkload/demo/xmlrpc/test_Credential.pycPKT;48 tfunkload/tests/doctest_dummy.txtPKT;4E`=funkload/tests/test_dummy.pyPKT;4g22VV(funkload/tests/__init__.pyPKT;4l=funkload/tests/test_Install.pyPK]i6u funkload/tests/test_dummy.pycPK]i6I funkload/tests/__init__.pycPK]i6i-i funkload/tests/test_Install.pycPK]i66UHRRz/ EGG-INFO/PKG-INFOPK]i6d}}> EGG-INFO/SOURCES.txtPK]i62F EGG-INFO/dependency_links.txtPK]i6Ս.##F EGG-INFO/requires.txtPK]i6