<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[15570] CalendarServer/trunk/contrib/performance/loadtest</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.calendarserver.org//changeset/15570">15570</a></dd>
<dt>Author</dt> <dd>sagen@apple.com</dd>
<dt>Date</dt> <dd>2016-05-02 14:17:48 -0700 (Mon, 02 May 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>After the sim creates/updates an event, fetch the etag iff the etag header was not present in the response.  The AlarmAcknowledger sim profile comes up with unique resource names now, to avoid colliding with existing data.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#CalendarServertrunkcontribperformanceloadtesticalpy">CalendarServer/trunk/contrib/performance/loadtest/ical.py</a></li>
<li><a href="#CalendarServertrunkcontribperformanceloadtestprofilespy">CalendarServer/trunk/contrib/performance/loadtest/profiles.py</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="CalendarServertrunkcontribperformanceloadtesticalpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/contrib/performance/loadtest/ical.py (15569 => 15570)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/contrib/performance/loadtest/ical.py        2016-05-02 19:12:26 UTC (rev 15569)
+++ CalendarServer/trunk/contrib/performance/loadtest/ical.py        2016-05-02 21:17:48 UTC (rev 15570)
</span><span class="lines">@@ -350,6 +350,13 @@
</span><span class="cx">         del self._calendars[calendar + '/'].events[basePath]
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def eventByHref(self, href):
+        &quot;&quot;&quot;
+        Return the locally cached event by its href
+        &quot;&quot;&quot;
+        return self._events[href]
+
+
</ins><span class="cx">     def addEvent(self, href, calendar):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Called when a profile needs to add an event (no scheduling).
</span><span class="lines">@@ -1698,22 +1705,28 @@
</span><span class="cx">         if len(attendees) &gt; 75:
</span><span class="cx">             label_suffix = &quot;huge&quot;
</span><span class="cx"> 
</span><ins>+        headers = Headers({
+            'content-type': ['text/calendar'],
+            'if-match': [event.etag]})
+        if event.etag is None:
+            headers.removeHeader('if-match')
+
</ins><span class="cx">         # At last, upload the new event definition
</span><span class="cx">         response = yield self._request(
</span><span class="cx">             (NO_CONTENT, PRECONDITION_FAILED,),
</span><span class="cx">             'PUT',
</span><span class="cx">             self.server[&quot;uri&quot;] + href.encode('utf-8'),
</span><del>-            Headers({
-                    'content-type': ['text/calendar'],
-                    'if-match': [event.etag]}),
</del><ins>+            headers,
</ins><span class="cx">             StringProducer(component.getTextWithTimezones(includeTimezones=True)),
</span><span class="cx">             method_label=&quot;PUT{organizer-%s}&quot; % (label_suffix,)
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         # Finally, re-retrieve the event to update the etag
</span><del>-        yield self._updateEvent(response, href)
</del><ins>+        if not response.headers.hasHeader(&quot;etag&quot;):
+            response = yield self.updateEvent(href)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def _attendeeAutoComplete(self, component, attendee):
</span><span class="cx"> 
</span><span class="lines">@@ -1803,7 +1816,8 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         # Finally, re-retrieve the event to update the etag
</span><del>-        yield self._updateEvent(response, href)
</del><ins>+        if not response.headers.hasHeader(&quot;etag&quot;):
+            response = yield self.updateEvent(href)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="lines">@@ -1849,7 +1863,10 @@
</span><span class="cx">         )
</span><span class="cx">         self._localUpdateEvent(response, href, component)
</span><span class="cx"> 
</span><ins>+        if not response.headers.hasHeader(&quot;etag&quot;):
+            response = yield self.updateEvent(href)
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def addInvite(self, href, component):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -1874,21 +1891,25 @@
</span><span class="cx">         event = self._events[href]
</span><span class="cx">         component = event.component
</span><span class="cx"> 
</span><ins>+        headers = Headers({
+            'content-type': ['text/calendar'],
+            'if-match': [event.etag]})
+        if event.etag is None:
+            headers.removeHeader('if-match')
+
</ins><span class="cx">         # At last, upload the new event definition
</span><span class="cx">         response = yield self._request(
</span><span class="cx">             (NO_CONTENT, PRECONDITION_FAILED,),
</span><span class="cx">             'PUT',
</span><span class="cx">             self.server[&quot;uri&quot;] + href.encode('utf-8'),
</span><del>-            Headers({
-                'content-type': ['text/calendar'],
-                'if-match': [event.etag]
-            }),
</del><ins>+            headers,
</ins><span class="cx">             StringProducer(component.getTextWithTimezones(includeTimezones=True)),
</span><span class="cx">             method_label=&quot;PUT{update}&quot;
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         # Finally, re-retrieve the event to update the etag
</span><del>-        yield self._updateEvent(response, href)
</del><ins>+        if not response.headers.hasHeader(&quot;etag&quot;):
+            response = yield self.updateEvent(href)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def _localUpdateEvent(self, response, href, component):
</span><span class="lines">@@ -1901,12 +1922,8 @@
</span><span class="cx">         self._setEvent(href, event)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    @inlineCallbacks
</ins><span class="cx">     def updateEvent(self, href):
</span><del>-        return self._updateEvent(None, href)
-
-
-    @inlineCallbacks
-    def _updateEvent(self, ignored, href):
</del><span class="cx">         response = yield self._request(
</span><span class="cx">             OK,
</span><span class="cx">             'GET',
</span><span class="lines">@@ -1918,6 +1935,7 @@
</span><span class="cx">         scheduleTag = headers.getRawHeaders('schedule-tag', [None])[0]
</span><span class="cx">         body = yield readBody(response)
</span><span class="cx">         self.eventChanged(href, etag, scheduleTag, body)
</span><ins>+        returnValue(response)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span></span></pre></div>
<a id="CalendarServertrunkcontribperformanceloadtestprofilespy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/contrib/performance/loadtest/profiles.py (15569 => 15570)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/contrib/performance/loadtest/profiles.py        2016-05-02 19:12:26 UTC (rev 15569)
+++ CalendarServer/trunk/contrib/performance/loadtest/profiles.py        2016-05-02 21:17:48 UTC (rev 15570)
</span><span class="lines">@@ -886,7 +886,7 @@
</span><span class="cx"> 
</span><span class="cx">         @return: a L{Deferred} that fires when initialization is done
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-
</del><ins>+        self.myEventHref = None
</ins><span class="cx">         return self._initEvent()
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -900,13 +900,13 @@
</span><span class="cx">         # Don't perform any operations until the client is up and running
</span><span class="cx">         if not self._client.started:
</span><span class="cx">             return succeed(None)
</span><ins>+        try:
+            calendar = self._calendarsOfType(caldavxml.calendar, &quot;VEVENT&quot;)[0]
+        except IndexError:
+            # There is no calendar
+            return succeed(None)
</ins><span class="cx"> 
</span><del>-        # If it already exists, don't re-create
-        calendar = self._calendarsOfType(caldavxml.calendar, &quot;VEVENT&quot;)[0]
-        if calendar.events:
-            events = [event for event in calendar.events.values() if event.url.endswith(&quot;event_to_update.ics&quot;)]
-            if events:
-                return succeed(None)
</del><ins>+        self.myEventHref = '{}{}.ics'.format(calendar.url, str(uuid4()))
</ins><span class="cx"> 
</span><span class="cx">         # Copy the template event and fill in some of its fields
</span><span class="cx">         # to make a new event to create on the calendar.
</span><span class="lines">@@ -920,13 +920,13 @@
</span><span class="cx">         vevent.replaceProperty(Property(&quot;DTSTART&quot;, dtstart))
</span><span class="cx">         vevent.replaceProperty(Property(&quot;DTEND&quot;, dtend))
</span><span class="cx">         vevent.replaceProperty(Property(&quot;UID&quot;, uid))
</span><ins>+        vevent.replaceProperty(Property(&quot;DESCRIPTION&quot;, &quot;AlarmAcknowledger&quot;))
</ins><span class="cx"> 
</span><span class="cx">         rrule = self._recurrenceDistribution.sample()
</span><span class="cx">         if rrule is not None:
</span><span class="cx">             vevent.addProperty(Property(None, None, None, pycalendar=rrule))
</span><span class="cx"> 
</span><del>-        href = '%s%s' % (calendar.url, &quot;event_to_update.ics&quot;)
-        d = self._client.addEvent(href, vcalendar)
</del><ins>+        d = self._client.addEvent(self.myEventHref, vcalendar)
</ins><span class="cx">         return self._newOperation(&quot;create&quot;, d)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -962,19 +962,11 @@
</span><span class="cx">         if not self._client.started:
</span><span class="cx">             return succeed(None)
</span><span class="cx"> 
</span><del>-        # If it does not exist, try to create it
-        try:
-            calendar = self._calendarsOfType(caldavxml.calendar, &quot;VEVENT&quot;)[0]
-        except IndexError:
-            # There is no calendar
-            return succeed(None)
-        if not calendar.events:
</del><ins>+        if self.myEventHref is None:
</ins><span class="cx">             return self._initEvent()
</span><del>-        events = [event for event in calendar.events.values() if event.url.endswith(&quot;event_to_update.ics&quot;)]
-        if not events:
-            return self._initEvent()
-        event = events[0]
</del><span class="cx"> 
</span><ins>+        event = self._client.eventByHref(self.myEventHref)
+
</ins><span class="cx">         # Add/update the ACKNOWLEDGED property
</span><span class="cx">         component = event.component.mainComponent()
</span><span class="cx">         component.replaceProperty(Property(&quot;ACKNOWLEDGED&quot;, DateTime.getNowUTC()))
</span></span></pre>
</div>
</div>

</body>
</html>