<?xml version="1.0" encoding="UTF-8"?>

<!--
    Copyright (c) 2011-2012 Apple Inc. All rights reserved.

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
  -->

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
	<dict>
		<!-- Define the kinds of software and user behavior the load simulation
			will simulate. -->
		<key>clients</key>

		<!-- Have as many different kinds of software and user behavior configurations
			as you want. Each is a dict -->
		<array>

			<dict>

				<!-- Here is a Lion iCal simulator. -->
				<key>software</key>
				<string>contrib.performance.loadtest.ical.OS_X_10_7</string>

				<!-- Arguments to use to initialize the client instance. -->
				<key>params</key>
				<dict>
					<!-- Name that appears in logs. -->
					<key>title</key>
					<string>10.7</string>

					<!-- Client can poll the calendar home at some interval. This is 
						in seconds. -->
					<key>calendarHomePollInterval</key>
					<integer>300000</integer>

					<!-- If the server advertises xmpp push, OS X 10.6 can wait for notifications 
						about calendar home changes instead of polling for them periodically. If 
						this option is true, then look for the server advertisement for xmpp push 
						and use it if possible. Still fall back to polling if there is no xmpp push 
						advertised. -->
					<key>supportPush</key>
					<false />
					<key>supportAmpPush</key>
					<false />
				</dict>

				<!-- The profiles define certain types of user behavior on top of the 
					client software being simulated. -->
				<key>profiles</key>
				<array>

					<!-- First an event-creating profile, which will periodically create 
						new events at a random time on a random calendar. -->
					<dict>
						<key>class</key>
						<string>contrib.performance.loadtest.profiles.Eventer</string>

						<key>params</key>
						<dict>
							<key>enabled</key>
							<false/>

							<!-- Define the interval (in seconds) at which this profile will use 
								its client to create a new event. -->
							<key>interval</key>
							<integer>20</integer>

							<!-- Define how start times (DTSTART) for the randomly generated events 
								will be selected. This is an example of a "Distribution" parameter. The value 
								for most "Distribution" parameters are interchangeable and extensible. -->
							<key>eventStartDistribution</key>
							<dict>

								<!-- This distribution is pretty specialized. It produces timestamps 
									in the near future, limited to certain days of the week and certain hours 
									of the day. -->
								<key>type</key>
								<string>contrib.performance.stats.WorkDistribution</string>

								<key>params</key>
								<dict>
									<!-- These are the days of the week the distribution will use. -->
									<key>daysOfWeek</key>
									<array>
										<string>mon</string>
										<string>tue</string>
										<string>wed</string>
										<string>thu</string>
										<string>fri</string>
									</array>

									<!-- The earliest hour of a day at which an event might be scheduled. -->
									<key>beginHour</key>
									<integer>8</integer>

									<!-- And the latest hour of a day (at which an event will be scheduled 
										to begin!). -->
									<key>endHour</key>
									<integer>16</integer>

									<!-- The timezone in which the event is scheduled. (XXX Does this 
										really work right?) -->
									<key>tzname</key>
									<string>America/Los_Angeles</string>
								</dict>
							</dict>

							<!-- Define how recurrences are created. -->
							<key>recurrenceDistribution</key>
							<dict>

								<!-- This distribution is pretty specialized.  We have a fixed set of
								     RRULEs defined for this distribution and pick each based on a
								     weight. -->
								<key>type</key>
								<string>contrib.performance.stats.RecurrenceDistribution</string>

								<key>params</key>
								<dict>
									<!-- False to disable RRULEs -->
									<key>allowRecurrence</key>
									<false/>

									<!-- These are the weights for the specific set of RRULEs. -->
									<key>weights</key>
									<dict>
										<!-- Half of all events will be non-recurring -->
										<key>none</key>
										<integer>50</integer>
										
										<!-- Daily and weekly are pretty common -->
										<key>daily</key>
										<integer>10</integer>
										<key>weekly</key>
										<integer>20</integer>
										
										<!-- Monthly, yearly, daily & weekly limit not so common -->
										<key>monthly</key>
										<integer>2</integer>
										<key>yearly</key>
										<integer>1</integer>
										<key>dailylimit</key>
										<integer>2</integer>
										<key>weeklylimit</key>
										<integer>5</integer>
										
										<!-- Work days pretty common -->
										<key>workdays</key>
										<integer>10</integer>
									</dict>
								</dict>
							</dict>
						</dict>
					</dict>

					<!-- This profile invites some number of new attendees to new events. -->
					<dict>
						<key>class</key>
						<string>contrib.performance.loadtest.profiles.RealisticInviter</string>

						<key>params</key>
						<dict>
							<key>enabled</key>
							<true/>

							<!-- Define the frequency at which new invitations will be sent out. -->
							<key>sendInvitationDistribution</key>
							<dict>
								<key>type</key>
								<string>contrib.performance.stats.FixedDistribution</string>
								<key>params</key>
								<dict>
									<!-- interval (in seconds). -->
									<key>value</key>
									<integer>120</integer>
								</dict>
							</dict>

							<!-- Define the distribution of who will be invited to an event.
							
								When inviteeClumping is turned on each invitee is based on a sample of
								users "close to" the organizer based on account index. If the clumping
								is too "tight" for the requested number of attendees, then invites for
								those larger numbers will simply fail (the sim will report that situation).
								
								When inviteeClumping is off invitees will be sampled across an entire
								range of account indexes. In this case the distribution ought to be a
								UniformIntegerDistribution with min=0 and max set to the number of accounts.
							-->
							<key>inviteeDistribution</key>
							<dict>
								<key>type</key>
								<string>contrib.performance.stats.UniformIntegerDistribution</string>
								<key>params</key>
								<dict>
									<!-- The minimum value (inclusive) of the uniform distribution. -->
									<key>min</key>
									<integer>0</integer>
									<!-- The maximum value (exclusive) of the uniform distribution. -->
									<key>max</key>
									<integer>99</integer>
								</dict>
							</dict>

							<key>inviteeClumping</key>
							<true/>

							<!-- Define the distribution of how many attendees will be invited to an event.
							
								LogNormal is the best fit to observed data.


								For LogNormal "mode" is the peak, "mean" is the mean value.	For invites,
								mode should typically be 1, and mean whatever matches the user behavior.
								Our typical mean is 6. 							
							     -->
							<key>inviteeCountDistribution</key>
							<dict>
								<key>type</key>
								<string>contrib.performance.stats.FixedDistribution</string>
								<key>params</key>
								<dict>
									<!-- Number of attendees. -->
									<key>value</key>
									<integer>5</integer>
								</dict>
							</dict>

							<!-- Define how start times (DTSTART) for the randomly generated events 
								will be selected. This is an example of a "Distribution" parameter. The value 
								for most "Distribution" parameters are interchangeable and extensible. -->
							<key>eventStartDistribution</key>
							<dict>

								<!-- This distribution is pretty specialized. It produces timestamps 
									in the near future, limited to certain days of the week and certain hours 
									of the day. -->
								<key>type</key>
								<string>contrib.performance.stats.WorkDistribution</string>

								<key>params</key>
								<dict>
									<!-- These are the days of the week the distribution will use. -->
									<key>daysOfWeek</key>
									<array>
										<string>mon</string>
										<string>tue</string>
										<string>wed</string>
										<string>thu</string>
										<string>fri</string>
									</array>

									<!-- The earliest hour of a day at which an event might be scheduled. -->
									<key>beginHour</key>
									<integer>8</integer>

									<!-- And the latest hour of a day (at which an event will be scheduled 
										to begin!). -->
									<key>endHour</key>
									<integer>16</integer>

									<!-- The timezone in which the event is scheduled. (XXX Does this 
										really work right?) -->
									<key>tzname</key>
									<string>America/Los_Angeles</string>
								</dict>
							</dict>

							<!-- Define how recurrences are created. -->
							<key>recurrenceDistribution</key>
							<dict>

								<!-- This distribution is pretty specialized.  We have a fixed set of
								     RRULEs defined for this distribution and pick each based on a
								     weight. -->
								<key>type</key>
								<string>contrib.performance.stats.RecurrenceDistribution</string>

								<key>params</key>
								<dict>
									<!-- False to disable RRULEs -->
									<key>allowRecurrence</key>
									<true/>

									<!-- These are the weights for the specific set of RRULEs. -->
									<key>weights</key>
									<dict>
										<!-- Daily and weekly are pretty common -->
										<key>daily</key>
										<integer>100</integer>
									</dict>
								</dict>
							</dict>
						</dict>
					</dict>

					<!-- This profile accepts invitations to events, handles cancels, and
					     handles replies received. -->
					<dict>
						<key>class</key>
						<string>contrib.performance.loadtest.profiles.Accepter</string>

						<key>params</key>
						<dict>
							<key>enabled</key>
							<false/>

							<!-- Define how long to wait after seeing a new invitation before
								accepting it.

								For LogNormal "mode" is the peak, "median" is the 50% cummulative value
								(i.e., half of the user have accepted by that time).								
							-->
							<key>acceptDelayDistribution</key>
							<dict>
								<key>type</key>
								<string>contrib.performance.stats.LogNormalDistribution</string>
								<key>params</key>
								<dict>
									<!-- mode - peak-->
									<key>mode</key>
									<integer>300</integer>
									<!-- median - 50% done-->
									<key>median</key>
									<integer>1800</integer>
								</dict>
							</dict>
						</dict>
					</dict>

					<!-- A task-creating profile, which will periodically create 
						new tasks at a random time on a random calendar. -->
					<dict>
						<key>class</key>
						<string>contrib.performance.loadtest.profiles.Tasker</string>

						<key>params</key>
						<dict>
							<key>enabled</key>
							<false/>

							<!-- Define the interval (in seconds) at which this profile will use 
								its client to create a new task. -->
							<key>interval</key>
							<integer>300</integer>

							<!-- Define how due times (DUE) for the randomly generated tasks 
								will be selected. This is an example of a "Distribution" parameter. The value 
								for most "Distribution" parameters are interchangeable and extensible. -->
							<key>taskDueDistribution</key>
							<dict>

								<!-- This distribution is pretty specialized. It produces timestamps 
									in the near future, limited to certain days of the week and certain hours 
									of the day. -->
								<key>type</key>
								<string>contrib.performance.stats.WorkDistribution</string>

								<key>params</key>
								<dict>
									<!-- These are the days of the week the distribution will use. -->
									<key>daysOfWeek</key>
									<array>
										<string>mon</string>
										<string>tue</string>
										<string>wed</string>
										<string>thu</string>
										<string>fri</string>
									</array>

									<!-- The earliest hour of a day at which an event might be scheduled. -->
									<key>beginHour</key>
									<integer>8</integer>

									<!-- And the latest hour of a day (at which an event will be scheduled 
										to begin!). -->
									<key>endHour</key>
									<integer>16</integer>

									<!-- The timezone in which the event is scheduled. (XXX Does this 
										really work right?) -->
									<key>tzname</key>
									<string>America/Los_Angeles</string>
								</dict>
							</dict>
						</dict>
					</dict>

				</array>

				<!-- Determine the frequency at which this client configuration will 
					appear in the clients which are created by the load tester. -->
				<key>weight</key>
				<integer>1</integer>
			</dict>
		</array>

		<!-- Determine the interval between client creation. -->
		<key>arrivalInterval</key>
		<integer>4</integer>
	</dict>
</plist>
