[CalendarServer-changes] [7070] CalendarServer/trunk/contrib/performance/loadtest
source_changes at macosforge.org
source_changes at macosforge.org
Wed Feb 23 10:11:25 PST 2011
Revision: 7070
http://trac.macosforge.org/projects/calendarserver/changeset/7070
Author: exarkun at twistedmatrix.com
Date: 2011-02-23 10:11:24 -0800 (Wed, 23 Feb 2011)
Log Message:
-----------
Remove some bogus error handling from ical.SnowLeopard; start adding configurable observer stuff.
Modified Paths:
--------------
CalendarServer/trunk/contrib/performance/loadtest/config.plist
CalendarServer/trunk/contrib/performance/loadtest/ical.py
CalendarServer/trunk/contrib/performance/loadtest/population.py
CalendarServer/trunk/contrib/performance/loadtest/sim.py
CalendarServer/trunk/contrib/performance/loadtest/test_sim.py
Modified: CalendarServer/trunk/contrib/performance/loadtest/config.plist
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/config.plist 2011-02-22 20:46:57 UTC (rev 7069)
+++ CalendarServer/trunk/contrib/performance/loadtest/config.plist 2011-02-23 18:11:24 UTC (rev 7070)
@@ -63,5 +63,10 @@
</dict>
</array>
+ <key>observers</key>
+ <array>
+ <string>loadtest.population.ReportStatistics</string>
+ </array>
+
</dict>
</plist>
Modified: CalendarServer/trunk/contrib/performance/loadtest/ical.py
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/ical.py 2011-02-22 20:46:57 UTC (rev 7069)
+++ CalendarServer/trunk/contrib/performance/loadtest/ical.py 2011-02-23 18:11:24 UTC (rev 7070)
@@ -51,7 +51,22 @@
SUPPORTED_REPORT_SET = '{DAV:}supported-report-set'
+class IncorrectResponseCode(Exception):
+ """
+ Raised when a response has a code other than the one expected.
+ @ivar expected: The response code which was expected.
+ @type expected: C{int}
+
+ @ivar response: The response which was received
+ @type response: L{twisted.web.client.Response}
+ """
+ def __init__(self, expected, response):
+ self.expected = expected
+ self.response = response
+
+
+
class Event(object):
def __init__(self, url, etag, vevent=None):
self.url = url
@@ -123,7 +138,10 @@
USER_AGENT = "DAVKit/4.0.3 (732); CalendarStore/4.0.3 (991); iCal/4.0.3 (1388); Mac OS X/10.6.4 (10F569)"
- CALENDAR_HOME_POLL_INTERVAL = 60 * 3
+ # The default interval, used if none is specified in external
+ # configuration. This is also the actual value used by Snow
+ # Leopard iCal.
+ CALENDAR_HOME_POLL_INTERVAL = 60 * 15
_STARTUP_PRINCIPAL_PROPFIND = loadRequestBody('sl_startup_principal_propfind')
_STARTUP_PRINCIPALS_REPORT = loadRequestBody('sl_startup_principals_report')
@@ -139,12 +157,16 @@
email = None
- def __init__(self, reactor, host, port, user, auth):
+ def __init__(self, reactor, host, port, user, auth, calendarHomePollInterval=None):
self.reactor = reactor
self.agent = AuthHandlerAgent(Agent(self.reactor), auth)
self.root = 'http://%s:%d/' % (host, port)
self.user = user
+ if calendarHomePollInterval is None:
+ calendarHomePollInterval = self.CALENDAR_HOME_POLL_INTERVAL
+ self.calendarHomePollInterval = calendarHomePollInterval
+
# Keep track of the calendars on this account, keys are
# Calendar URIs, values are Calendar instances.
self._calendars = {}
@@ -169,18 +191,26 @@
d = self.agent.request(method, url, headers, body)
before = self.reactor.seconds()
def report(response):
+ # XXX This is time to receive response headers, not time
+ # to receive full response. Should measure the latter, if
+ # not both.
+ after = self.reactor.seconds()
+
+ # XXX If the response code is wrong, there's probably not
+ # point passing the response down the callback chain.
+ # errback?
success = response.code == expectedResponseCode
+
# if not success:
# import pdb; pdb.set_trace()
- after = self.reactor.seconds()
- # XXX This is time to receive response headers, not time
- # to receive full response. Should measure the latter, if
- # not both.
msg(
type="response", success=success, method=method,
headers=headers, body=body,
duration=(after - before), url=url)
- return response
+
+ if success:
+ return response
+ raise IncorrectResponseCode(expectedResponseCode, response)
d.addCallback(report)
return d
@@ -357,7 +387,11 @@
for cal in calendars:
if self._calendars.setdefault(cal.url, cal).ctag != cal.ctag or True:
self._updateCalendar(cal)
- d.addCallback(cbCalendars)
+ def ebCalendars(reason):
+ reason.trap(IncorrectResponseCode)
+ msg(type="aggregate", operation="poll", success=False)
+ d.addCallbacks(cbCalendars, ebCalendars)
+ d.addErrback(err, "Unexpected failure during calendar home poll")
return d
@@ -395,11 +429,7 @@
@inlineCallbacks
def startup(self):
# Orient ourselves, or something
- try:
- principal = yield self._principalPropfind(self.user)
- except:
- err(None, "Startup principal PROPFIND failed")
- return
+ principal = yield self._principalPropfind(self.user)
hrefs = principal.getHrefProperties()
@@ -431,12 +461,11 @@
def _calendarCheckLoop(self, calendarHome):
"""
- Poll Calendar Home (and notifications?) every 15 (or whatever)
- minutes
+ Periodically check the calendar home for changes to calendars.
"""
pollCalendarHome = LoopingCall(
self._checkCalendarsForEvents, calendarHome)
- pollCalendarHome.start(self.CALENDAR_HOME_POLL_INTERVAL)
+ pollCalendarHome.start(self.calendarHomePollInterval)
@inlineCallbacks
@@ -446,9 +475,9 @@
"""
principal = yield self.startup()
hrefs = principal.getHrefProperties()
-
self._calendarCheckLoop(hrefs[caldavxml.calendar_home_set].toString())
+ # XXX Oops, should probably stop sometime.
yield Deferred()
Modified: CalendarServer/trunk/contrib/performance/loadtest/population.py
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/population.py 2011-02-22 20:46:57 UTC (rev 7069)
+++ CalendarServer/trunk/contrib/performance/loadtest/population.py 2011-02-23 18:11:24 UTC (rev 7070)
@@ -23,7 +23,7 @@
from itertools import izip
from twisted.python.util import FancyEqMixin
-from twisted.python.log import msg
+from twisted.python.log import msg, err
from stats import mean, median, stddev, mad
from loadtest.ical import SnowLeopard, RequestLogger
@@ -147,14 +147,23 @@
clientType = self._pop.next()
client = clientType.clientType(
self.reactor, self.host, self.port, user, auth)
- client.run()
+ d = client.run()
+ d.addCallbacks(self._clientSuccess, self._clientFailure)
for profileType in clientType.profileTypes:
profileType(self.reactor, client, number).run()
msg(type="status", clientCount=self._user - 1)
+ def _clientSuccess(self, result):
+ pass
+
+ def _clientFailure(self, reason):
+ err(reason, "Client stopped with error")
+
+
+
class SmoothRampUp(object):
def __init__(self, reactor, groups, groupSize, interval):
self.reactor = reactor
Modified: CalendarServer/trunk/contrib/performance/loadtest/sim.py
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/sim.py 2011-02-22 20:46:57 UTC (rev 7069)
+++ CalendarServer/trunk/contrib/performance/loadtest/sim.py 2011-02-23 18:11:24 UTC (rev 7070)
@@ -21,6 +21,7 @@
from collections import namedtuple
from twisted.python.filepath import FilePath
+from twisted.python.log import addObserver
from twisted.python.usage import UsageError, Options
from twisted.python.reflect import namedAny
@@ -95,12 +96,13 @@
@type arrival: L{Arrival}
@type parameters: L{PopulationParameters}
"""
- def __init__(self, server, arrival, parameters, reactor=None):
+ def __init__(self, server, arrival, parameters, observers=None, reactor=None):
if reactor is None:
from twisted.internet import reactor
self.server = server
self.arrival = arrival
self.parameters = parameters
+ self.observers = observers
self.reactor = reactor
@@ -130,7 +132,6 @@
arrival = Arrival(
SmoothRampUp, dict(groups=10, groupSize=1, interval=3))
-
parameters = PopulationParameters()
if 'clients' in options.config:
for clientConfig in options.config['clients']:
@@ -144,9 +145,14 @@
parameters.addClient(
1, ClientType(SnowLeopard, [Eventer, Inviter, Accepter]))
- return cls(server, arrival, parameters)
+ observers = []
+ if 'observers' in options.config:
+ for observerName in options.config['observers']:
+ observers.append(namedAny(observerName)())
+ return cls(server, arrival, parameters, observers)
+
@classmethod
def main(cls, args=None):
simulator = cls.fromCommandLine(args)
@@ -170,6 +176,7 @@
arrivalPolicy = self.createArrivalPolicy()
arrivalPolicy.run(sim)
self.reactor.run()
+ for obs in self.observers:
+ obs.report()
-
main = LoadSimulator.main
Modified: CalendarServer/trunk/contrib/performance/loadtest/test_sim.py
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/test_sim.py 2011-02-22 20:46:57 UTC (rev 7069)
+++ CalendarServer/trunk/contrib/performance/loadtest/test_sim.py 2011-02-23 18:11:24 UTC (rev 7070)
@@ -15,8 +15,10 @@
#
##
+from operator import setitem
from plistlib import writePlistToString
+from twisted.python.log import LogPublisher, theLogPublisher
from twisted.python.usage import UsageError
from twisted.python.filepath import FilePath
from twisted.trial.unittest import TestCase
@@ -26,7 +28,8 @@
from loadtest.ical import SnowLeopard
from loadtest.profiles import Eventer, Inviter, Accepter
from loadtest.population import (
- SmoothRampUp, ClientType, PopulationParameters, CalendarClientSimulator)
+ SmoothRampUp, ClientType, PopulationParameters, CalendarClientSimulator,
+ SimpleStatistics)
from loadtest.sim import Server, Arrival, SimOptions, LoadSimulator, main
VALID_CONFIG = {
@@ -90,6 +93,32 @@
+class Reactor(object):
+ def run(self):
+ pass
+
+
+class Observer(object):
+ def __init__(self):
+ self.reported = False
+ self.events = []
+
+
+ def observe(self, event):
+ self.events.append(event)
+
+
+ def report(self):
+ self.reported = True
+
+
+
+class NullArrival(object):
+ def run(self, sim):
+ pass
+
+
+
class StubSimulator(LoadSimulator):
def run(self):
return 3
@@ -107,7 +136,8 @@
exc = self.assertRaises(
SystemExit, StubSimulator.main, ['--config', config.path])
- self.assertEquals(exc.args, (StubSimulator(None, None, None).run(),))
+ self.assertEquals(
+ exc.args, (StubSimulator(None, None, None).run(),))
def test_createSimulator(self):
@@ -119,7 +149,7 @@
host = '127.0.0.7'
port = 1243
reactor = object()
- sim = LoadSimulator(Server(host, port), None, None, reactor)
+ sim = LoadSimulator(Server(host, port), None, None, reactor=reactor)
calsim = sim.createSimulator()
self.assertIsInstance(calsim, CalendarClientSimulator)
self.assertIdentical(calsim.reactor, reactor)
@@ -176,7 +206,7 @@
reactor = object()
sim = LoadSimulator(
- None, Arrival(FakeArrival, {'x': 3, 'y': 2}), None, reactor)
+ None, Arrival(FakeArrival, {'x': 3, 'y': 2}), None, reactor=reactor)
arrival = sim.createArrivalPolicy()
self.assertIsInstance(arrival, FakeArrival)
self.assertIdentical(arrival.reactor, reactor)
@@ -215,3 +245,38 @@
expectedParameters.addClient(
1, ClientType(SnowLeopard, [Eventer, Inviter, Accepter]))
self.assertEquals(sim.parameters, expectedParameters)
+
+
+ def test_loadLogObservers(self):
+ """
+ Log observers specified in the [observers] section of the
+ configuration file are added to the logging system.
+ """
+ config = FilePath(self.mktemp())
+ config.setContent(writePlistToString({
+ "observers": ["loadtest.population.SimpleStatistics"]}))
+ sim = LoadSimulator.fromCommandLine(['--config', config.path])
+ self.assertEquals(len(sim.observers), 1)
+ self.assertIsInstance(sim.observers[0], SimpleStatistics)
+
+ def test_observeBeforeRun(self):
+ """
+ Each log observer is added to the log publisher before the
+ simulation run is started.
+ """
+ self.fail("implement me")
+
+
+ def test_reportAfterRun(self):
+ """
+ Each log observer also has its C{report} method called after
+ the simulation run completes.
+ """
+ observers = [Observer()]
+ sim = LoadSimulator(
+ Server('example.com', 123),
+ Arrival(lambda reactor: NullArrival(), {}),
+ None, observers, Reactor())
+ sim.run()
+ self.assertTrue(observers[0].reported)
+
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20110223/c80679aa/attachment-0001.html>
More information about the calendarserver-changes
mailing list