You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@usergrid.apache.org by to...@apache.org on 2014/10/23 02:05:28 UTC

[2/2] git commit: Initial commit of move into it's own project so the tests can be developed and debugged within an IDE.

Initial commit of move into it's own project so the tests can be developed and debugged within an IDE.


Project: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/commit/bfc4d0fc
Tree: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/tree/bfc4d0fc
Diff: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/diff/bfc4d0fc

Branch: refs/heads/gatlingdev
Commit: bfc4d0fce4dddb02e8d3bfdbea43ea67592c3f38
Parents: d183fbe
Author: Todd Nine <tn...@apigee.com>
Authored: Wed Oct 22 18:05:24 2014 -0600
Committer: Todd Nine <tn...@apigee.com>
Committed: Wed Oct 22 18:05:24 2014 -0600

----------------------------------------------------------------------
 stack/gatling/pom.xml                           | 135 ++++++++++++++++
 .../data-generators/EntityDataGenerator.scala   |  57 +++++++
 .../data-generators/FeederGenerator.scala       | 101 ++++++++++++
 .../scenarios/ApplicationScenarios.scala        |  45 ++++++
 .../scenarios/ConnectionScenarios.scala         |  30 ++++
 .../usergrid/scenarios/DeviceScenarios.scala    |  65 ++++++++
 .../usergrid/scenarios/GeoScenarios.scala       |  43 ++++++
 .../scenarios/NotificationScenarios.scala       |  71 +++++++++
 .../usergrid/scenarios/NotifierScenarios.scala  |  65 ++++++++
 .../scenarios/OrganizationScenarios.scala       |  42 +++++
 .../usergrid/scenarios/TokenScenarios.scala     |  59 +++++++
 .../usergrid/scenarios/UserScenarios.scala      |  50 ++++++
 .../org/apache/usergrid/settings/Headers.scala  |  43 ++++++
 .../org/apache/usergrid/settings/Settings.scala |  54 +++++++
 .../org/apache/usergrid/settings/Utils.scala    |  87 +++++++++++
 .../simulations/GetEntitySimulation.scala       |  42 +++++
 .../simulations/PostDevicesSimulation.scala     |  43 ++++++
 .../simulations/PostUsersSimulation.scala       |  48 ++++++
 ...PushNotificationTargetDeviceSimulation.scala |  54 +++++++
 .../PushNotificationTargetUserSimulation.scala  |  68 ++++++++
 stack/gatling/src/test/resources/gatling.conf   | 154 +++++++++++++++++++
 stack/gatling/src/test/resources/logback.xml    |  20 +++
 stack/gatling/src/test/resources/recorder.conf  |  37 +++++
 stack/gatling/src/test/scala/Engine.scala       |  16 ++
 .../gatling/src/test/scala/IDEPathHelper.scala  |  21 +++
 stack/gatling/src/test/scala/Recorder.scala     |  12 ++
 .../usergrid/scenarios/DeviceScenarios.scala    |   4 +-
 ...PushNotificationTargetDeviceSimulation.scala |  53 +++++++
 .../PushNotificationTargetUserSimulation.scala  |  67 ++++++++
 .../PushTargetDeviceSimulation.scala            |  53 -------
 .../simulations/PushTargetUserSimulation.scala  |  68 --------
 31 files changed, 1584 insertions(+), 123 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/gatling/pom.xml
----------------------------------------------------------------------
diff --git a/stack/gatling/pom.xml b/stack/gatling/pom.xml
new file mode 100644
index 0000000..3d748cc
--- /dev/null
+++ b/stack/gatling/pom.xml
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<groupId>org.apache.usergrid</groupId>
+	<artifactId>gatling</artifactId>
+	<version>1.0-SNAPSHOT</version>
+
+	<repositories>
+		<repository>
+			<id>sonatype</id>
+			<name>Sonatype OSS</name>
+			<url>https://oss.sonatype.org/content/groups/public</url>
+			<releases>
+				<updatePolicy>never</updatePolicy>
+			</releases>
+			<snapshots>
+				<enabled>true</enabled>
+			</snapshots>
+		</repository>
+	</repositories>
+	<pluginRepositories>
+		<pluginRepository>
+			<id>sonatype</id>
+			<name>Sonatype OSS</name>
+			<url>https://oss.sonatype.org/content/groups/public</url>
+			<snapshots>
+				<enabled>true</enabled>
+			</snapshots>
+		</pluginRepository>
+	</pluginRepositories>
+
+	<properties>
+		<maven.compiler.source>1.7</maven.compiler.source>
+		<maven.compiler.target>1.6</maven.compiler.target>
+		<scala.version>2.10.4</scala.version>
+		<encoding>UTF-8</encoding>
+
+		<gatling.version>2.0.0</gatling.version>
+		<gatling-highcharts.version>2.0.0</gatling-highcharts.version>
+
+		<scala-maven-plugin.version>3.1.6</scala-maven-plugin.version>
+	</properties>
+
+	<dependencyManagement>
+		<dependencies>
+			<dependency>
+				<groupId>io.gatling</groupId>
+				<artifactId>gatling-app</artifactId>
+				<version>${gatling.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>io.gatling</groupId>
+				<artifactId>gatling-recorder</artifactId>
+				<version>${gatling.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>io.gatling.highcharts</groupId>
+				<artifactId>gatling-charts-highcharts</artifactId>
+				<version>${gatling-highcharts.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.scala-lang</groupId>
+				<artifactId>scala-library</artifactId>
+				<version>${scala.version}</version>
+			</dependency>
+		</dependencies>
+	</dependencyManagement>
+
+	<dependencies>
+		<dependency>
+			<groupId>io.gatling.highcharts</groupId>
+			<artifactId>gatling-charts-highcharts</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>io.gatling</groupId>
+			<artifactId>gatling-app</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>io.gatling</groupId>
+			<artifactId>gatling-recorder</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.scala-lang</groupId>
+			<artifactId>scala-library</artifactId>
+		</dependency>
+	</dependencies>
+
+	<build>
+		<sourceDirectory>src/main/scala</sourceDirectory>
+		<testSourceDirectory>src/test/scala</testSourceDirectory>
+		<pluginManagement>
+			<plugins>
+				<plugin>
+					<groupId>net.alchim31.maven</groupId>
+					<artifactId>scala-maven-plugin</artifactId>
+					<version>${scala-maven-plugin.version}</version>
+				</plugin>
+				<plugin>
+					<groupId>io.gatling</groupId>
+					<artifactId>gatling-maven-plugin</artifactId>
+					<version>${gatling.version}</version>
+				</plugin>
+			</plugins>
+		</pluginManagement>
+		<plugins>
+			<plugin>
+				<groupId>net.alchim31.maven</groupId>
+				<artifactId>scala-maven-plugin</artifactId>
+				<executions>
+					<execution>
+						<goals>
+							<goal>compile</goal>
+							<goal>testCompile</goal>
+						</goals>
+						<configuration>
+							<args>
+								<arg>-target:jvm-1.6</arg>
+								<arg>-deprecation</arg>
+								<arg>-feature</arg>
+								<arg>-unchecked</arg>
+								<arg>-language:implicitConversions</arg>
+								<arg>-language:postfixOps</arg>
+							</args>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<groupId>io.gatling</groupId>
+				<artifactId>gatling-maven-plugin</artifactId>
+			</plugin>
+		</plugins>
+	</build>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/gatling/src/main/scala/org/apache/usergrid/data-generators/EntityDataGenerator.scala
----------------------------------------------------------------------
diff --git a/stack/gatling/src/main/scala/org/apache/usergrid/data-generators/EntityDataGenerator.scala b/stack/gatling/src/main/scala/org/apache/usergrid/data-generators/EntityDataGenerator.scala
new file mode 100755
index 0000000..b1a7a90
--- /dev/null
+++ b/stack/gatling/src/main/scala/org/apache/usergrid/data-generators/EntityDataGenerator.scala
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+ package org.apache.usergrid
+
+import scala.collection.mutable.ArrayBuffer
+
+object EntityDataGenerator {
+
+  def generateBlockUserLists(numUsers: Int): Map[String, String] = {
+
+    var blocks: ArrayBuffer[String] = new ArrayBuffer[String]
+    var blockedBy: ArrayBuffer[String] = new ArrayBuffer[String]
+
+    for (numBlock <- 1 to Utils.generateRandomInt(1, 7)) {
+      blocks += "user".concat(Utils.generateRandomInt(1, numUsers).toString)
+    }
+
+    for (numBlockedBy <- 1 to Utils.generateRandomInt(1, 7)) {
+      blockedBy += "user".concat(Utils.generateRandomInt(1, numUsers).toString)
+    }
+
+    return Map("blocks" -> blocks.toArray.mkString(","), "blockedBy" -> blockedBy.toArray.mkString(","))
+
+  }
+
+  def generateUser(userId: Int): Map[String,String] = {
+
+    return Map("username" -> "user".concat(userId.toString),
+      "profileId" -> Utils.generateRandomInt(10000, 1000000).toString,
+      "displayName" -> Utils.generateRandomInt(10000, 1000000).toString,
+      "showAge" -> Utils.generateRandomInt(0, 1).toString,
+      "ethnicity" -> Utils.generateRandomInt(1, 15).toString,
+      "relationshipStatus" -> Utils.generateRandomInt(1, 4).toString,
+      "headline" -> "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
+      "aboutMe" -> "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.",
+      "age" -> Utils.generateRandomInt(18, 65).toString,
+      "height" -> Utils.generateRandomInt(48, 84).toString,
+      "weight" -> Utils.generateRandomInt(120, 350).toString,
+      "seen" -> Utils.generateRandomInt(50, 100000).toString
+    )
+  }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/gatling/src/main/scala/org/apache/usergrid/data-generators/FeederGenerator.scala
----------------------------------------------------------------------
diff --git a/stack/gatling/src/main/scala/org/apache/usergrid/data-generators/FeederGenerator.scala b/stack/gatling/src/main/scala/org/apache/usergrid/data-generators/FeederGenerator.scala
new file mode 100755
index 0000000..ffe324c
--- /dev/null
+++ b/stack/gatling/src/main/scala/org/apache/usergrid/data-generators/FeederGenerator.scala
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+ package org.apache.usergrid
+
+import io.gatling.core.Predef._
+import scala.collection.mutable.ArrayBuffer
+
+object FeederGenerator {
+
+  def generateUserWithGeolocationFeeder(numUsers: Int, radius: Double, centerLatitude: Double, centerLongitude: Double): Array[Map[String, String]] = {
+    var userArray: ArrayBuffer[Map[String, String]] = new ArrayBuffer[Map[String, String]]
+    for (userCount <- 1 to numUsers) {
+      var user: Map[String, String] = EntityDataGenerator.generateUser(userCount)
+      var geolocation: Map[String, String] = Utils.generateRandomGeolocation(radius, centerLatitude, centerLongitude)
+      var blockLists: Map[String, String] = EntityDataGenerator.generateBlockUserLists(numUsers)
+
+      user = user ++ geolocation ++ blockLists
+
+      userArray += user
+    }
+    return userArray.toArray
+  }
+
+  def generateGeolocationFeeder(radius: Double, centerLatitude: Double, centerLongitude: Double): Feeder[String] = {
+
+    val geolocationFeeder = new Feeder[String] {
+
+      // always return true as this feeder can be polled infinitively
+      override def hasNext = true
+
+      override def next: Map[String, String] = {
+        var geolocation: Map[String, String] = Utils.generateRandomGeolocation(radius, centerLatitude, centerLongitude)
+        Map("latitude" -> geolocation("latitude"), "longitude" -> geolocation("longitude"))
+      }
+    }
+
+    return geolocationFeeder
+
+  }
+
+  def generateGeolocationWithQueryFeeder(radius: Double, centerLatitude: Double, centerLongitude: Double): Feeder[String] = {
+
+    val geolocationFeeder = new Feeder[String] {
+
+      // always return true as this feeder can be polled infinitively
+      override def hasNext = true
+
+      override def next: Map[String, String] = {
+        var geolocation: Map[String, String] = Utils.generateRandomGeolocation(radius, centerLatitude, centerLongitude)
+        var queryParams = Utils.generateRandomQueryString
+        Map("latitude" -> geolocation("latitude"), "longitude" -> geolocation("longitude"), "queryParams" -> queryParams)
+      }
+    }
+
+    return geolocationFeeder
+
+  }
+
+  def generateUserConnectionFeeder(numUsers: Int): Feeder[String] = {
+
+    val userIdFeeder = new Feeder[String] {
+
+      // always return true as this feeder can be polled infinitively
+      override def hasNext = true
+
+      override def next: Map[String, String] = {
+        Map("user1" -> "user".concat(Utils.generateRandomInt(1, numUsers).toString), "user2" -> "user".concat(Utils.generateRandomInt(1, numUsers).toString))
+      }
+    }
+
+    return userIdFeeder
+
+  }
+
+  def generateEntityNameFeeder(prefix: String, numEntities: Int): Array[Map[String, String]] = {
+
+    var nameArray: ArrayBuffer[Map[String, String]] = new ArrayBuffer[Map[String, String]]
+
+    for (entityCount <- 1 to numEntities) {
+      nameArray += Map("entityName" -> prefix.concat(entityCount.toString))
+    }
+
+    return nameArray.toArray
+
+  }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/ApplicationScenarios.scala
----------------------------------------------------------------------
diff --git a/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/ApplicationScenarios.scala b/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/ApplicationScenarios.scala
new file mode 100755
index 0000000..f5f7901
--- /dev/null
+++ b/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/ApplicationScenarios.scala
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+ package org.apache.usergrid
+
+import io.gatling.core.Predef._
+import io.gatling.http.Predef._
+
+/**
+ * Performs organization registration
+ *
+ *
+ * Expects:
+ *
+ * authToken The auth token to use when creating the application
+ * orgName The organization name
+ *
+ * Produces:
+ *
+ * appName The name of the created application
+ */
+object ApplicationScenarios {
+
+  val createApplication = exec(http("Create Application")
+    .post("/management/organizations/${org}/applications")
+    .headers(Headers.jsonAuthorized)
+    .body(StringBody("{\"name\":\"" + Settings.app + "\"}"))
+    .check(status.is(200))
+
+    )
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/ConnectionScenarios.scala
----------------------------------------------------------------------
diff --git a/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/ConnectionScenarios.scala b/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/ConnectionScenarios.scala
new file mode 100755
index 0000000..ba2449f
--- /dev/null
+++ b/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/ConnectionScenarios.scala
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+ package org.apache.usergrid
+
+import io.gatling.core.Predef._
+import io.gatling.http.Predef._
+
+object ConnectionScenarios {
+
+  val postConnection = exec(
+    http("POST connection")
+      .post("/users/${user1}/likes/users/${user2}")
+      .check(status.is(200))
+  )
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/DeviceScenarios.scala
----------------------------------------------------------------------
diff --git a/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/DeviceScenarios.scala b/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/DeviceScenarios.scala
new file mode 100755
index 0000000..e86bd42
--- /dev/null
+++ b/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/DeviceScenarios.scala
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+ package org.apache.usergrid
+
+import io.gatling.core.Predef._
+import io.gatling.http.Predef._
+
+/**
+ *
+ * Creates a new device
+ *
+ * Expects:
+ *
+ * authToken The auth token to use when creating the application
+ * orgName The name of the org
+ * appName The name of the app
+ * notifierName The name of the created notifier
+ *
+ * Produces:
+ *
+ * deviceName the name of the device created
+ *
+ */
+object DeviceScenarios {
+
+  /**
+   * Create a device
+   */
+  val postDeviceWithNotifier = exec(http("Create device with notifier")
+    .post("/devices")
+    .body(StringBody("{\"name\":\"${entityName}\"," +
+      "\"deviceModel\":\"Fake Device\"," +
+      " \"deviceOSVerion\":\"Negative Version\", " +
+      "\"${notifier}.notifier.id\":\"${entityName}\"}"))
+    .check(status.is(200), jsonPath("$.entities[0].uuid").saveAs("deviceId")))
+
+  val postDeviceWithNotifier400ok = exec(http("Create device with notifier")
+    .post("/devices")
+    .body(StringBody("{\"name\":\"${entityName}\"," +
+    "\"deviceModel\":\"Fake Device\"," +
+    " \"deviceOSVerion\":\"Negative Version\", " +
+    "\"${notifier}.notifier.id\":\"${entityName}\"}"))
+    .check(status.in(200 to 400), jsonPath("$.entities[0].uuid").saveAs("deviceId")))
+
+  /**
+   * TODO: Add a device to a user, which would expect a user in the session
+   */
+
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/GeoScenarios.scala
----------------------------------------------------------------------
diff --git a/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/GeoScenarios.scala b/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/GeoScenarios.scala
new file mode 100755
index 0000000..94bf0af
--- /dev/null
+++ b/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/GeoScenarios.scala
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+ package org.apache.usergrid
+
+import io.gatling.core.Predef._
+import io.gatling.http.Predef._
+
+object GeoScenarios {
+
+  val getGeolocation = exec(
+      http("GET geolocated user")
+        .get("/users?ql=location%20within%20" + Settings.geosearchRadius + "%20of%20${latitude},${longitude}")
+        .check(status.is(200))
+    )
+
+  val getGeolocationWithQuery = exec(
+      http("GET geolocated user with query")
+        .get("/users?ql=${queryParams}%20AND%20location%20within%20" + Settings.geosearchRadius + "%20of%20${latitude},${longitude}")
+        .check(status.is(200))
+    )
+
+  val updateGeolocation = exec(
+    http("PUT user location")
+      .put("/users/user" + Utils.generateRandomInt(1, Settings.numUsers))
+      .body(StringBody("{\"location\":{\"latitude\":\"${latitude}\",\"longitude\":\"${longitude}\"}}"))
+      .check(status.is(200))
+  )
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/NotificationScenarios.scala
----------------------------------------------------------------------
diff --git a/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/NotificationScenarios.scala b/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/NotificationScenarios.scala
new file mode 100755
index 0000000..91d6754
--- /dev/null
+++ b/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/NotificationScenarios.scala
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+ package org.apache.usergrid
+
+import java.io.File
+import java.nio.file.{Paths, Files}
+
+import io.gatling.core.Predef._
+import io.gatling.http.Predef._
+import scala.concurrent.duration._
+
+import scala.io.Source
+
+/**
+ *
+ * Creates a new device
+ *
+ * Expects:
+ *
+ * authToken The auth token to use when creating the application
+ * orgName The name of the org
+ * appName The name of the app
+ * notifierName The name of the created notifier
+ * deviceName the name of the device created to send the notification to
+ *
+ * Produces:
+ *
+ * N/A
+ *
+ *
+ */
+object NotificationScenarios {
+
+
+  /**
+   * send the notification now
+   */
+  val sendNotification = exec(http("Send Single Notification")
+      .post("/devices/${entityName}/notifications")
+      .body(StringBody("{\"payloads\":{\"${notifier}\":\"testmessage\"}}"))
+      .check(status.is(200))
+    )
+
+  val sendNotificationToUser= exec(http("Send Notification to All Devices")
+    .post("/users/${user}/notifications")
+    .body(StringBody("{\"payloads\":{\"${notifier}\":\"testmessage\"}}"))
+    .check(status.is(200))
+  )
+
+  /**
+   * TODO: Add posting to users, which would expect a user in the session
+   */
+
+
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/NotifierScenarios.scala
----------------------------------------------------------------------
diff --git a/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/NotifierScenarios.scala b/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/NotifierScenarios.scala
new file mode 100755
index 0000000..0c2fc0c
--- /dev/null
+++ b/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/NotifierScenarios.scala
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+ package org.apache.usergrid
+
+import io.gatling.core.Predef._
+import io.gatling.http.Predef._
+import scala.concurrent.duration._
+
+/**
+ *
+ * Creates a new no-op notifier
+ *
+ *
+ * Expects:
+ *
+ * authToken The auth token to use when creating the application
+ * orgName The name of the org
+ * appName The name of the app
+ *
+ * Produces:
+ *
+ * notifierName The name of the created notifier
+ *
+ */
+object NotifierScenarios {
+  
+  val notifier = Settings.pushNotifier
+  val provider = Settings.pushProvider
+
+  /**
+   * Create a notifier
+   */
+  val createNotifier = exec(
+      session => {
+        session.set("notifier", notifier)
+        session.set("provider", provider)
+      }
+    )
+
+    .exec(http("Create Notifier")
+    .post("/notifiers")
+    .body(StringBody("{\"name\":\"${notifier}\",\"provider\":\"${provider}\"}"))
+    //remnants of trying to upload an apple certificate
+//    .param("name", "${notifierName}")
+//    .param("provider", "apple")
+//    .param("environment", "mock")
+//    .fileBody("p12Certificate", Map).fileBody(pkcs12Cert)
+    .check(status.is(200)))
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/OrganizationScenarios.scala
----------------------------------------------------------------------
diff --git a/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/OrganizationScenarios.scala b/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/OrganizationScenarios.scala
new file mode 100755
index 0000000..7c411b0
--- /dev/null
+++ b/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/OrganizationScenarios.scala
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+ package org.apache.usergrid
+
+import io.gatling.core.Predef._
+import io.gatling.http.Predef._
+import scala.concurrent.duration._
+
+/**
+ * Performs organization registration
+ *
+ *
+ * Produces:
+ *
+ * orgName The name of the created organization
+ * userName  The user name of the admin to log in with
+ * password The password of the admin to use
+ */
+object OrganizationScenarios {
+
+  //register the org with the randomly generated org
+  val createOrgAndAdmin = exec(http("Create Organization")
+  .post("/management/organizations")
+  .headers(Headers.jsonAnonymous)
+  .body(StringBody("{\"organization\":\"" + Settings.org + "\",\"username\":\"${username}\",\"name\":\"${username}\",\"email\":\"${username}@apigee.com\",\"password\":\"${password}\"}"))
+  .check(status.is(200)))
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/TokenScenarios.scala
----------------------------------------------------------------------
diff --git a/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/TokenScenarios.scala b/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/TokenScenarios.scala
new file mode 100755
index 0000000..9dff0df
--- /dev/null
+++ b/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/TokenScenarios.scala
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+ package org.apache.usergrid
+
+import io.gatling.core.Predef._
+import io.gatling.http.Predef._
+import scala.concurrent.duration._
+
+/**
+ * Class that will get the token and insert it into the test session.
+ * Assumes that  the following values are present in the session.
+ *
+ * Expects:
+ *
+ * userName  The user name to log in with
+ * password The password to use
+ *
+ * Produces:
+ *
+ * authToken A valid access token if the login attempt is successful
+ */
+
+object TokenScenarios {
+
+
+  val getManagementToken =
+    exec(
+      http("POST Org Token")
+        .post("/management/token")
+        .headers(Headers.jsonAnonymous)
+        //pass in the the username and password, store the "access_token" json response element as the var "authToken" in the session
+        .body(StringBody("{\"username\":\"${username}\",\"password\":\"${password}\",\"grant_type\":\"password\"}"))
+        .check(jsonPath("access_token")
+        .saveAs("authToken"))
+    )
+
+  val getUserToken =
+    exec(
+      http("POST user token")
+        .post("/token")
+        .body(StringBody("{\"grant_type\":\"password\",\"username\":\"${user1}\",\"password\":\"password\"}"))
+        .check(status.is(200))
+    )
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/UserScenarios.scala
----------------------------------------------------------------------
diff --git a/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/UserScenarios.scala b/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/UserScenarios.scala
new file mode 100755
index 0000000..843bc2e
--- /dev/null
+++ b/stack/gatling/src/main/scala/org/apache/usergrid/scenarios/UserScenarios.scala
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+ package org.apache.usergrid
+
+import io.gatling.core.Predef._
+import io.gatling.http.Predef._
+
+object UserScenarios {
+
+  val getRandomUser = exec(
+    http("GET user")
+      .get("/users/user" + Utils.generateRandomInt(1, Settings.numEntities))
+      .check(status.is(200))
+  )
+
+  val postUser = exec(
+    http("POST geolocated Users")
+      .post("/users")
+      .body(StringBody("{\"location\":{\"latitude\":\"${latitude}\",\"longitude\":\"${longitude}\"},\"username\":\"${username}\"," +
+      "\"displayName\":\"${displayName}\",\"age\":\"${age}\",\"seen\":\"${seen}\",\"weight\":\"${weight}\"," +
+      "\"height\":\"${height}\",\"aboutMe\":\"${aboutMe}\",\"profileId\":\"${profileId}\",\"headline\":\"${headline}\"," +
+      "\"showAge\":\"${showAge}\",\"relationshipStatus\":\"${relationshipStatus}\",\"ethnicity\":\"${ethnicity}\",\"password\":\"password\"}"))
+      .check(status.is(200))
+  )
+
+  val postUser400ok = exec(
+    http("POST geolocated Users")
+      .post("/users")
+      .body(StringBody("{\"location\":{\"latitude\":\"${latitude}\",\"longitude\":\"${longitude}\"},\"username\":\"${username}\"," +
+      "\"displayName\":\"${displayName}\",\"age\":\"${age}\",\"seen\":\"${seen}\",\"weight\":\"${weight}\"," +
+      "\"height\":\"${height}\",\"aboutMe\":\"${aboutMe}\",\"profileId\":\"${profileId}\",\"headline\":\"${headline}\"," +
+      "\"showAge\":\"${showAge}\",\"relationshipStatus\":\"${relationshipStatus}\",\"ethnicity\":\"${ethnicity}\",\"password\":\"password\"}"))
+      .check(status.in(200 to 400))
+  )
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/gatling/src/main/scala/org/apache/usergrid/settings/Headers.scala
----------------------------------------------------------------------
diff --git a/stack/gatling/src/main/scala/org/apache/usergrid/settings/Headers.scala b/stack/gatling/src/main/scala/org/apache/usergrid/settings/Headers.scala
new file mode 100755
index 0000000..319bdcf
--- /dev/null
+++ b/stack/gatling/src/main/scala/org/apache/usergrid/settings/Headers.scala
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+ package org.apache.usergrid
+
+/**
+ *
+ */
+object Headers {
+
+  /**
+   * Headers for anonymous posts
+   */
+  val jsonAnonymous = Map(
+    "Cache-Control" -> """no-cache""",
+    "Content-Type" -> """application/json; charset=UTF-8"""
+  )
+
+  /**
+   * Headers for authorized users with token and json content type
+   */
+  val jsonAuthorized = Map(
+    "Cache-Control" -> """no-cache""",
+    "Content-Type" -> """application/json; charset=UTF-8""",
+    "Authorization" -> "Bearer ${authToken}"
+  )
+
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/gatling/src/main/scala/org/apache/usergrid/settings/Settings.scala
----------------------------------------------------------------------
diff --git a/stack/gatling/src/main/scala/org/apache/usergrid/settings/Settings.scala b/stack/gatling/src/main/scala/org/apache/usergrid/settings/Settings.scala
new file mode 100755
index 0000000..5588b67
--- /dev/null
+++ b/stack/gatling/src/main/scala/org/apache/usergrid/settings/Settings.scala
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+ package org.apache.usergrid
+
+import io.gatling.core.Predef._
+import io.gatling.http.Predef._
+import scala.concurrent.duration._
+
+object Settings {
+
+  // Target settings
+  val org = System.getProperty("org")
+  val app = System.getProperty("app")
+  val baseUrl = System.getProperty("baseurl")
+  val httpConf = http.baseURL(baseUrl + "/" + org + "/" + app)
+
+  // Simulation settings
+  val numUsers:Int = Integer.getInteger("numUsers", 10).toInt
+  val numEntities:Int = Integer.getInteger("numEntities", 5000).toInt
+  val numDevices:Int = Integer.getInteger("numDevices", 2000).toInt
+
+  val rampTime:Int = Integer.getInteger("rampTime", 0).toInt // in seconds
+  val duration:Int = Integer.getInteger("duration", 300).toInt // in seconds
+  val throttle:Int = Integer.getInteger("throttle", 50).toInt // in seconds
+
+  // Geolocation settings
+  val centerLatitude:Double = 37.442348 // latitude of center point
+  val centerLongitude:Double = -122.138268 // longitude of center point
+  val userLocationRadius:Double = 32000 // location of requesting user in meters
+  val geosearchRadius:Int = 8000 // search area in meters
+
+  // Push Notification settings
+  val pushNotifier = System.getProperty("notifier")
+  val pushProvider = System.getProperty("provider")
+
+  def createRandomPushNotifier:String = {
+    return Utils.generateUniqueName("notifier")
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/gatling/src/main/scala/org/apache/usergrid/settings/Utils.scala
----------------------------------------------------------------------
diff --git a/stack/gatling/src/main/scala/org/apache/usergrid/settings/Utils.scala b/stack/gatling/src/main/scala/org/apache/usergrid/settings/Utils.scala
new file mode 100755
index 0000000..396f0b9
--- /dev/null
+++ b/stack/gatling/src/main/scala/org/apache/usergrid/settings/Utils.scala
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+ package org.apache.usergrid
+
+import scala.util.Random
+import scala.math
+import Array._
+
+/**
+ *
+ * Utility for creating various data elements
+ *
+ */
+object Utils {
+
+  private val RNG = new Random
+
+  /**
+   * Generate a new uuid and replace the '-' with empty
+   */
+  def generateUUIDString(): String = {
+    return java.util.UUID.randomUUID.toString.replace("-", "")
+  }
+
+  /**
+   * Generate a unique string with a prefix
+   *
+   * @param prefix
+   * @return
+   */
+  def generateUniqueName(prefix : String): String = {
+     return prefix + generateUUIDString()
+  }
+
+  // random number in between [a...b]
+  def generateRandomInt(lowerBound: Int, upperBound: Int) = RNG.nextInt(upperBound - lowerBound) + lowerBound
+
+  def generateRandomGeolocation(radius: Double, centerLatitude: Double, centerLongitude: Double):Map[String, String] = {
+
+    var rd = radius / 111300 // Convert Radius from meters to degrees.
+    var u = RNG.nextFloat()
+    var v = RNG.nextFloat()
+    var q = math.sqrt(u) * rd
+    var w = q * rd
+    var t = 2 * math.Pi * v
+    var x = math.cos(t) * w
+    var y = math.sin(t) * w
+    var xp = x/math.cos(centerLatitude)
+    var latitude = (y + centerLatitude).toString
+    var longitude = (xp + centerLongitude).toString
+    var geolocation: Map[String, String] = Map("latitude"->latitude,"longitude"->longitude)
+
+    return geolocation
+  }
+
+  def generateRandomQueryString: String = {
+
+    val queryParams = Array("age", "height", "weight")
+    var queryString = ""
+
+    for (numParams <- 1 to generateRandomInt(1, queryParams.length)) {
+      queryString = "age=" + Utils.generateRandomInt(18, 65).toString
+      if (numParams == 2) {
+        queryString += "%20AND%20height=" + Utils.generateRandomInt(48, 84).toString
+      } else if (numParams == 3) {
+        queryString += "%20AND%20weight=" + Utils.generateRandomInt(120, 350).toString
+      }
+    }
+
+    return queryString
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/gatling/src/main/scala/org/apache/usergrid/simulations/GetEntitySimulation.scala
----------------------------------------------------------------------
diff --git a/stack/gatling/src/main/scala/org/apache/usergrid/simulations/GetEntitySimulation.scala b/stack/gatling/src/main/scala/org/apache/usergrid/simulations/GetEntitySimulation.scala
new file mode 100644
index 0000000..46d5abe
--- /dev/null
+++ b/stack/gatling/src/main/scala/org/apache/usergrid/simulations/GetEntitySimulation.scala
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+ package org.apache.usergrid.simulations
+
+import io.gatling.core.Predef._
+import io.gatling.http.Predef._
+ import org.apache.usergrid.{UserScenarios, Settings, FeederGenerator}
+ import scala.concurrent.duration._
+
+class GetEntitySimulation extends Simulation {
+
+  // Target settings
+  val httpConf = Settings.httpConf
+
+  // Simulation settings
+  val numUsers:Int = Settings.numUsers
+  val numEntities:Int = Settings.numEntities
+  val rampTime:Int = Settings.rampTime
+  val throttle:Int = Settings.throttle
+
+  val feeder = FeederGenerator.generateEntityNameFeeder("user", numEntities).circular
+
+  val scnToRun = scenario("GET entity")
+    .exec(UserScenarios.getRandomUser)
+
+  setUp(scnToRun.inject(atOnceUsers(numUsers)).throttle(reachRps(throttle) in (rampTime.seconds)).protocols(httpConf)).maxDuration(Settings.duration)
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/gatling/src/main/scala/org/apache/usergrid/simulations/PostDevicesSimulation.scala
----------------------------------------------------------------------
diff --git a/stack/gatling/src/main/scala/org/apache/usergrid/simulations/PostDevicesSimulation.scala b/stack/gatling/src/main/scala/org/apache/usergrid/simulations/PostDevicesSimulation.scala
new file mode 100755
index 0000000..394144b
--- /dev/null
+++ b/stack/gatling/src/main/scala/org/apache/usergrid/simulations/PostDevicesSimulation.scala
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+ package org.apache.usergrid.simulations
+
+import io.gatling.core.Predef._
+import io.gatling.http.Predef._
+ import org.apache.usergrid.{DeviceScenarios, FeederGenerator, Settings}
+ import scala.concurrent.duration._
+
+class PostDevicesSimulation extends Simulation {
+
+  // Target settings
+  val httpConf = Settings.httpConf
+
+  // Simulation settings
+  val numUsers:Int = Settings.numUsers
+  val numEntities:Int = Settings.numEntities
+  val rampTime:Int = Settings.rampTime
+  val throttle:Int = Settings.throttle
+
+  val feeder = FeederGenerator.generateEntityNameFeeder("device", numEntities)
+
+  val scnToRun = scenario("POST device")
+    .feed(feeder)
+    .exec(DeviceScenarios.postDeviceWithNotifier)
+
+  setUp(scnToRun.inject(atOnceUsers(numUsers)).throttle(reachRps(throttle) in (rampTime.seconds)).protocols(httpConf))
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/gatling/src/main/scala/org/apache/usergrid/simulations/PostUsersSimulation.scala
----------------------------------------------------------------------
diff --git a/stack/gatling/src/main/scala/org/apache/usergrid/simulations/PostUsersSimulation.scala b/stack/gatling/src/main/scala/org/apache/usergrid/simulations/PostUsersSimulation.scala
new file mode 100755
index 0000000..aef394c
--- /dev/null
+++ b/stack/gatling/src/main/scala/org/apache/usergrid/simulations/PostUsersSimulation.scala
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+ package org.apache.usergrid.simulations
+
+import io.gatling.core.Predef._
+import org.apache.usergrid.{UserScenarios, FeederGenerator, Settings}
+
+import scala.concurrent.duration._
+
+class PostUsersSimulation extends Simulation {
+
+  // Target settings
+  val httpConf = Settings.httpConf
+
+  // Simulation settings
+  val numUsers:Int = Settings.numUsers
+  val rampTime:Int = Settings.rampTime
+  val throttle:Int = Settings.throttle
+
+  // Geolocation settings
+  val centerLatitude:Double = Settings.centerLatitude
+  val centerLongitude:Double = Settings.centerLongitude
+  val userLocationRadius:Double = Settings.userLocationRadius
+  val geosearchRadius:Int = Settings.geosearchRadius
+
+  val feeder = FeederGenerator.generateUserWithGeolocationFeeder(numUsers, userLocationRadius, centerLatitude, centerLongitude).queue
+
+  val scnToRun = scenario("POST geolocated users")
+    .feed(feeder)
+    .exec(UserScenarios.postUser)
+
+  setUp(scnToRun.inject(atOnceUsers(numUsers)).throttle(reachRps(throttle) in (rampTime.seconds)).protocols(httpConf))
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/gatling/src/main/scala/org/apache/usergrid/simulations/PushNotificationTargetDeviceSimulation.scala
----------------------------------------------------------------------
diff --git a/stack/gatling/src/main/scala/org/apache/usergrid/simulations/PushNotificationTargetDeviceSimulation.scala b/stack/gatling/src/main/scala/org/apache/usergrid/simulations/PushNotificationTargetDeviceSimulation.scala
new file mode 100755
index 0000000..2e6a2ba
--- /dev/null
+++ b/stack/gatling/src/main/scala/org/apache/usergrid/simulations/PushNotificationTargetDeviceSimulation.scala
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+ package org.apache.usergrid.simulations
+
+import io.gatling.core.Predef._
+import io.gatling.http.Predef._
+ import org.apache.usergrid._
+ import scala.concurrent.duration._
+
+/**
+ *
+ * Simple test for setting up multiple orgs and creating push notifications
+ *
+ */
+class PushNotificationTargetDeviceSimulation extends Simulation {
+
+  val numUsers:Int = Settings.numUsers
+  val numEntities:Int = Settings.numEntities
+  val rampTime:Int = Settings.rampTime
+  val throttle:Int = Settings.throttle
+  val duration:Int = Settings.duration  
+  val httpConf = Settings.httpConf
+    .acceptHeader("application/json")
+
+  val createNotifier = NotifierScenarios.createNotifier
+  val createDevice = DeviceScenarios.postDeviceWithNotifier
+  val sendNotification = NotificationScenarios.sendNotification
+
+  val deviceNameFeeder = FeederGenerator.generateEntityNameFeeder("device", numEntities).circular
+
+  val scnToRun = scenario("Create Push Notification")    
+    .during(duration.seconds) {
+      feed(deviceNameFeeder)
+      .exec(sendNotification)
+    }
+
+
+  setUp(scnToRun.inject(atOnceUsers(numUsers)).throttle(reachRps(throttle) in (rampTime.seconds)).protocols(httpConf))
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/gatling/src/main/scala/org/apache/usergrid/simulations/PushNotificationTargetUserSimulation.scala
----------------------------------------------------------------------
diff --git a/stack/gatling/src/main/scala/org/apache/usergrid/simulations/PushNotificationTargetUserSimulation.scala b/stack/gatling/src/main/scala/org/apache/usergrid/simulations/PushNotificationTargetUserSimulation.scala
new file mode 100644
index 0000000..acef447
--- /dev/null
+++ b/stack/gatling/src/main/scala/org/apache/usergrid/simulations/PushNotificationTargetUserSimulation.scala
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+ package org.apache.usergrid.simulations
+
+import io.gatling.core.Predef._
+import io.gatling.http.Predef._
+ import org.apache.usergrid._
+ import scala.concurrent.duration._
+
+class PushNotificationTargetUserSimulation extends Simulation {
+
+  val numUsers:Int = Settings.numUsers
+  val numEntities:Int = Settings.numEntities
+  val rampTime:Int = Settings.rampTime
+  val throttle:Int = Settings.throttle
+  val duration:Int = Settings.duration
+  val httpConf = Settings.httpConf.acceptHeader("application/json")
+
+  val notifier = Settings.pushNotifier
+  val createDevice = DeviceScenarios.postDeviceWithNotifier400ok
+  val sendNotification = NotificationScenarios.sendNotification
+  val createUser = UserScenarios.postUser400ok
+  val deviceNameFeeder = FeederGenerator.generateEntityNameFeeder("device", numEntities).circular
+  val userFeeder = FeederGenerator.generateUserWithGeolocationFeeder(numEntities, Settings.userLocationRadius, Settings.centerLatitude, Settings.centerLongitude)
+
+  val scnToRun = scenario("Create Push Notification")
+    .feed(userFeeder)
+    .exec(createUser)
+//    .pause(1000)
+    .exec(http("Check user and user devices")
+      .get("/users/${username}/devices")
+      .check(status.is(200))
+    )
+    .feed(deviceNameFeeder)
+    .exec(createDevice)
+//    .pause(1000)
+    .exec(http("Check device connections")
+      .get("/devices/${entityName}/users")
+      .check(status.is(200))
+    )
+    .exec(http("Connect user with device")
+      .post("/users/${username}/devices/${deviceId}")
+      .check(status.is(200))
+    )
+    .exec(http("Send Notification to All Devices")
+      .post("/users/${username}/notifications")
+      .body(StringBody("{\"payloads\":{\"" + notifier + "\":\"testmessage\"}}"))
+      .check(status.is(200))
+    )
+
+
+  setUp(scnToRun.inject(constantUsersPerSec(numUsers) during (duration)).throttle(reachRps(throttle) in (rampTime.seconds)).protocols(httpConf))
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/gatling/src/test/resources/gatling.conf
----------------------------------------------------------------------
diff --git a/stack/gatling/src/test/resources/gatling.conf b/stack/gatling/src/test/resources/gatling.conf
new file mode 100644
index 0000000..1455242
--- /dev/null
+++ b/stack/gatling/src/test/resources/gatling.conf
@@ -0,0 +1,154 @@
+#########################
+# Gatling Configuration #
+#########################
+
+# This file contains all the settings configurable for Gatling with their default values
+
+gatling {
+  core {
+    #outputDirectoryBaseName = "" # The prefix for each simulation result folder (then suffixed by the report generation timestamp)
+    #runDescription = ""          # The description for this simulation run, displayed in each report
+    #encoding = "utf-8"           # Encoding to use throughout Gatling for file and string manipulation
+    #simulationClass = ""         # The FQCN of the simulation to run (when used in conjunction with noReports, the simulation for which assertions will be validated)
+    #disableCompiler = false      # When set to true, skip compiling and load an already compiled simulation (used in conjunction with simulationClass)
+    #mute = false                 # When set to true, don't ask for simulation name nor run description (currently only used by Gatling SBT plugin)
+
+    extract {
+      regex {
+        #cacheMaxCapacity = 200 # Cache size for the compiled regexes, set to 0 to disable caching
+      }
+      xpath {
+        #cacheMaxCapacity = 200 # Cache size for the compiled XPath queries,  set to 0 to disable caching
+      }
+      jsonPath {
+        #cacheMaxCapacity = 200 # Cache size for the compiled jsonPath queries, set to 0 to disable caching
+        #preferJackson = false  # When set to true, prefer Jackson over Boon for JSON-related operations
+        jackson {
+          #allowComments = false           # Allow comments in JSON files
+          #allowUnquotedFieldNames = false # Allow unquoted JSON fields names
+          #allowSingleQuotes = false       # Allow single quoted JSON field names
+        }
+
+      }
+      css {
+        #cacheMaxCapacity = 200 # Cache size for the compiled CSS selectors queries,  set to 0 to disable caching
+      }
+    }
+
+    timeOut {
+      #simulation = 8640000 # Absolute timeout, in seconds, of a simulation
+    }
+    directory {
+      #data = user-files/data                    # Folder where user's data (e.g. files used by Feeders) is located
+      #requestBodies = user-files/request-bodies # Folder where request bodies are located
+      #simulations = user-files/simulations      # Folder where the bundle's simulations are located
+      simulations = src/main/scala              # Folder where the bundle's simulations are located
+      #reportsOnly = ""                          # If set, name of report folder to look for in order to generate its report
+      #binaries = ""                             # If set, name of the folder where compiles classes are located
+      #results = results                         # Name of the folder where all reports folder are located
+    }
+    zinc {
+      #jvmArgs = "-Xss10M" # JVM args passed to Zinc (in charge of compiling Gatling Simulations)
+    }
+  }
+  charting {
+    #noReports = false       # When set to true, don't generate HTML reports
+    #maxPlotPerSeries = 1000 # Number of points per graph in Gatling reports
+    #accuracy = 10           # Accuracy, in milliseconds, of the report's stats
+    indicators {
+      #lowerBound = 800      # Lower bound for the requests' response time to track in the reports and the console summary
+      #higherBound = 1200    # Higher bound for the requests' response time to track in the reports and the console summary
+      #percentile1 = 95      # Value for the first percentile to track in the reports, the console summary and GraphiteDataWriter
+      #percentile2 = 99      # Value for the second percentile to track in the reports, the console summary and GraphiteDataWriter
+    }
+  }
+  http {
+    #elFileBodiesCacheMaxCapacity = 200        # Cache size for request body EL templates, set to 0 to disable
+    #rawFileBodiesCacheMaxCapacity = 200       # Cache size for request body Raw templates, set to 0 to disable
+    #fetchedCssCacheMaxCapacity = 200          # Cache size for CSS parsed content, set to 0 to disable
+    #fetchedHtmlCacheMaxCapacity = 200         # Cache size for HTML parsed content, set to 0 to disable
+    #redirectPerUserCacheMaxCapacity = 200     # Per virtual user cache size for permanent redirects, set to 0 to disable
+    #expirePerUserCacheMaxCapacity = 200       # Per virtual user cache size for permanent 'Expire' headers, set to 0 to disable
+    #lastModifiedPerUserCacheMaxCapacity = 200 # Per virtual user cache size for permanent 'Last-Modified' headers, set to 0 to disable
+    #etagPerUserCacheMaxCapacity = 200         # Per virtual user cache size for permanent ETag headers, set to 0 to disable
+    #warmUpUrl = "http://goo.gl/pq1Xwu"        # The URL to use to warm-up the HTTP stack (blank means disabled)
+    ssl {
+      trustStore {
+        #type = ""      # Type of SSLContext's TrustManagers store
+        #file = ""      # Location of SSLContext's TrustManagers store
+        #password = ""  # Password for SSLContext's TrustManagers store
+        #algorithm = "" # Algorithm used by SSLContext's TrustManagers store
+      }
+      keyStore {
+        #type = ""      # Type of SSLContext's KeyManagers store
+        #file = ""      # Location of SSLContext's KeyManagers store
+        #password = ""  # Password for SSLContext's KeyManagers store
+        #algorithm = "" # Algorithm used SSLContext's KeyManagers store
+      }
+    }
+    ahc {
+      #allowPoolingConnections = true             # Allow pooling HTTP connections (keep-alive header automatically added)
+      #allowPoolingSslConnections = true          # Allow pooling HTTPS connections (keep-alive header automatically added)
+      #compressionEnforced = false                # Enforce gzip/deflate when Accept-Encoding header is not defined
+      #connectTimeout = 60000                     # Timeout when establishing a connection
+      #pooledConnectionIdleTimeout = 60000        # Timeout when a connection stays unused in the pool
+      #readTimeout = 60000                        # Timeout when a used connection stays idle
+      #connectionTTL = -1                         # Max duration a connection can stay open (-1 means no limit)
+      #ioThreadMultiplier = 2                     # Number of Netty worker threads per core
+      #maxConnectionsPerHost = -1                 # Max number of connections per host (-1 means no limit)
+      #maxConnections = -1                        # Max number of connections (-1 means no limit)
+      #maxRetry = 0                               # Number of times that a request should be tried again
+      #requestTimeout = 60000                     # Timeout of the requests
+      #useProxyProperties = false                 # When set to true, supports standard Proxy System properties
+      #webSocketTimeout = 60000                   # Timeout when a used websocket connection stays idle
+      #useRelativeURIsWithConnectProxies = true   # When set to true, use relative URIs when talking with an SSL proxy or a WebSocket proxy
+      #acceptAnyCertificate = true                # When set to true, doesn't validate SSL certificates
+      #httpClientCodecMaxInitialLineLength = 4096 # Maximum length of the initial line of the response (e.g. "HTTP/1.0 200 OK")
+      #httpClientCodecMaxHeaderSize = 8192        # Maximum size, in bytes, of each request's headers
+      #httpClientCodecMaxChunkSize = 8192         # Maximum length of the content or each chunk
+      #keepEncodingHeader = true                  # Don't drop Encoding response header after decoding
+      #webSocketMaxFrameSize = 10240              # Maximum frame payload size
+    }
+  }
+  data {
+    #writers = "console, file" # The lists of DataWriters to which Gatling write simulation data (currently supported : "console", "file", "graphite", "jdbc")
+    #reader = file             # The DataReader used by the charting engine for reading simulation results
+    console {
+      #light = false           # When set to true, displays a light version without detailed request stats
+    }
+    file {
+      #bufferSize = 8192       # FileDataWriter's internal data buffer size, in bytes
+    }
+    leak {
+      #noActivityTimeout = 30  # Period, in seconds, for which Gatling may have no activity before considering a leak may be happening
+    }
+    jdbc {
+      db {
+        #url = "jdbc:mysql://localhost:3306/temp" # The JDBC URL used by the JDBC DataWriter
+        #username = "root"                        # The database user used by the JDBC DataWriter
+        #password = "123123q"                     # The password for the specified user
+      }
+      #bufferSize = 20                            # The size for each batch of SQL inserts to send to the database
+      create {
+        #createRunRecordTable = "CREATE TABLE IF NOT EXISTS `RunRecords` ( `id` INT NOT NULL AUTO_INCREMENT , `runDate` DATETIME NULL , `simulationId` VARCHAR(45) NULL , `runDescription` VARCHAR(45) NULL , PRIMARY KEY (`id`) )"
+        #createRequestRecordTable = "CREATE TABLE IF NOT EXISTS `RequestRecords` (`id` int(11) NOT NULL AUTO_INCREMENT, `runId` int DEFAULT NULL, `scenario` varchar(45) DEFAULT NULL, `userId` VARCHAR(20) NULL, `name` varchar(50) DEFAULT NULL, `requestStartDate` bigint DEFAULT NULL, `requestEndDate` bigint DEFAULT NULL, `responseStartDate` bigint DEFAULT NULL, `responseEndDate` bigint DEFAULT NULL, `status` varchar(2) DEFAULT NULL, `message` varchar(4500) DEFAULT NULL, `responseTime` bigint DEFAULT NULL, PRIMARY KEY (`id`) )"
+        #createScenarioRecordTable = "CREATE TABLE IF NOT EXISTS `ScenarioRecords` (`id` int(11) NOT NULL AUTO_INCREMENT, `runId` int DEFAULT NULL, `scenarioName` varchar(45) DEFAULT NULL, `userId` VARCHAR(20) NULL, `event` varchar(50) DEFAULT NULL, `startDate` bigint DEFAULT NULL, `endDate` bigint DEFAULT NULL, PRIMARY KEY (`id`) )"
+        #createGroupRecordTable = "CREATE TABLE IF NOT EXISTS `GroupRecords` (`id` int(11) NOT NULL AUTO_INCREMENT, `runId` int DEFAULT NULL, `scenarioName` varchar(45) DEFAULT NULL, `userId` VARCHAR(20) NULL, `entryDate` bigint DEFAULT NULL, `exitDate` bigint DEFAULT NULL, `status` varchar(2) DEFAULT NULL, PRIMARY KEY (`id`) )"
+      }
+      insert {
+        #insertRunRecord = "INSERT INTO RunRecords (runDate, simulationId, runDescription) VALUES (?,?,?)"
+        #insertRequestRecord = "INSERT INTO RequestRecords (runId, scenario, userId, name, requestStartDate, requestEndDate, responseStartDate, responseEndDate, status, message, responseTime) VALUES (?,?,?,?,?,?,?,?,?,?,?)"
+        #insertScenarioRecord = "INSERT INTO ScenarioRecords (runId, scenarioName, userId, event, startDate, endDate) VALUES (?,?,?,?,?,?)"
+        #insertGroupRecord = "INSERT INTO GroupRecords (runId, scenarioName, userId, entryDate, exitDate, status) VALUES (?,?,?,?,?,?)"
+      }
+    }
+    graphite {
+      #light = false              # only send the all* stats
+      #host = "localhost"         # The host where the Carbon server is located
+      #port = 2003                # The port to which the Carbon server listens to
+      #protocol = "tcp"           # The protocol used to send data to Carbon (currently supported : "tcp", "udp")
+      #rootPathPrefix = "gatling" # The common prefix of all metrics sent to Graphite
+      #bufferSize = 8192          # GraphiteDataWriter's internal data buffer size, in bytes
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/gatling/src/test/resources/logback.xml
----------------------------------------------------------------------
diff --git a/stack/gatling/src/test/resources/logback.xml b/stack/gatling/src/test/resources/logback.xml
new file mode 100644
index 0000000..aa637a8
--- /dev/null
+++ b/stack/gatling/src/test/resources/logback.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+
+	<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+		<encoder>
+			<pattern>%d{HH:mm:ss.SSS} [%-5level] %logger{15} - %msg%n%rEx</pattern>
+			<immediateFlush>false</immediateFlush>
+		</encoder>
+	</appender>
+
+	<!-- Uncomment for logging ALL HTTP request and responses -->
+	<!-- 	<logger name="io.gatling.http.ahc.AsyncHandlerActor" level="TRACE" /> -->
+	<!-- Uncomment for logging ONLY FAILED HTTP request and responses -->
+	<!-- 	<logger name="io.gatling.http.ahc.AsyncHandlerActor" level="DEBUG" /> -->
+
+	<root level="WARN">
+		<appender-ref ref="CONSOLE" />
+	</root>
+
+</configuration>

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/gatling/src/test/resources/recorder.conf
----------------------------------------------------------------------
diff --git a/stack/gatling/src/test/resources/recorder.conf b/stack/gatling/src/test/resources/recorder.conf
new file mode 100644
index 0000000..6c2366e
--- /dev/null
+++ b/stack/gatling/src/test/resources/recorder.conf
@@ -0,0 +1,37 @@
+recorder {
+  core {
+    #encoding = "utf-8"               # The encoding used for reading/writing request bodies and the generated simulation
+    #outputFolder = ""                # The folder where generated simulation will we written
+    #package = ""                     # The package's name of the generated simulation
+    #className = "RecordedSimulation" # The name of the generated Simulation class
+    #thresholdForPauseCreation = 100  # The minimum time, in milliseconds, that must pass between requests to trigger a pause creation
+    #saveConfig = false               # When set to true, the configuration from the Recorder GUI overwrites this configuration
+  }
+  filters {
+    #filterStrategy = "Disabled" # The selected filter resources filter strategy (currently supported : "Disabled", "BlackList", "WhiteList")
+    #whitelist = []              # The list of ressources patterns that are part of the Recorder's whitelist
+    #blacklist = []              # The list of ressources patterns that are part of the Recorder's blacklist
+  }
+  http {
+    #automaticReferer = true       # When set to false, write the referer + enable 'disableAutoReferer' in the generated simulation
+    #followRedirect = true         # When set to false, write redirect requests + enable 'disableFollowRedirect' in the generated simulation
+    #removeConditionalCache = true # When set to true, removes from the generated requests headers leading to request caching
+    #inferHtmlResources = true     # When set to true, add inferred resources + set 'inferHtmlResources' with the configured blacklist/whitelist in the generated simulation
+  }
+  proxy {
+    #port = 8000     # Local port used by Gatling's Proxy for HTTP/HTTPS
+    outgoing {
+      #host = ""     # The outgoing proxy's hostname
+      #username = "" # The username to use to connect to the outgoing proxy
+      #password = "" # The password corresponding to the user to use to connect to the outgoing proxy
+      #port = 0      # The HTTP port to use to connect to the outgoing proxy
+      #sslPort = 0   # If set, The HTTPS port to use to connect to the outgoing proxy
+    }
+  }
+  netty {
+    #maxInitialLineLength = 10000 # Maximum length of the initial line of the response (e.g. "HTTP/1.0 200 OK")
+    #maxHeaderSize = 20000        # Maximum size, in bytes, of each request's headers
+    #maxChunkSize = 8192          # Maximum length of the content or each chunk
+    #maxContentLength = 100000000 # Maximum length of the aggregated content of each response
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/gatling/src/test/scala/Engine.scala
----------------------------------------------------------------------
diff --git a/stack/gatling/src/test/scala/Engine.scala b/stack/gatling/src/test/scala/Engine.scala
new file mode 100644
index 0000000..b6dfa44
--- /dev/null
+++ b/stack/gatling/src/test/scala/Engine.scala
@@ -0,0 +1,16 @@
+import io.gatling.app.Gatling
+import io.gatling.core.config.GatlingPropertiesBuilder
+
+object Engine extends App {
+
+	val props = new GatlingPropertiesBuilder
+	props.disableCompiler
+	props.dataDirectory(IDEPathHelper.dataDirectory.toString)
+	props.resultsDirectory(IDEPathHelper.resultsDirectory.toString)
+	props.requestBodiesDirectory(IDEPathHelper.requestBodiesDirectory.toString)
+	props.binariesDirectory(IDEPathHelper.mavenBinariesDirectory.toString)
+
+  props.simulationClass("org.apache.usergrid.simulations.PushNotificationTargetUserSimulation")
+
+	Gatling.fromMap(props.build)
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/gatling/src/test/scala/IDEPathHelper.scala
----------------------------------------------------------------------
diff --git a/stack/gatling/src/test/scala/IDEPathHelper.scala b/stack/gatling/src/test/scala/IDEPathHelper.scala
new file mode 100644
index 0000000..988b616
--- /dev/null
+++ b/stack/gatling/src/test/scala/IDEPathHelper.scala
@@ -0,0 +1,21 @@
+import scala.tools.nsc.io.File
+import scala.tools.nsc.io.Path.string2path
+
+object IDEPathHelper {
+
+	val gatlingConfUrl = getClass.getClassLoader.getResource("gatling.conf").getPath
+	val projectRootDir = File(gatlingConfUrl).parents(2)
+
+	val mavenSourcesDirectory = projectRootDir / "src" / "test" / "scala"
+	val mavenResourcesDirectory = projectRootDir / "src" / "test" / "resources"
+	val mavenTargetDirectory = projectRootDir / "target"
+	val mavenBinariesDirectory = mavenTargetDirectory / "test-classes"
+
+	val dataDirectory = mavenResourcesDirectory / "data"
+	val requestBodiesDirectory = mavenResourcesDirectory / "request-bodies"
+
+	val recorderOutputDirectory = mavenSourcesDirectory
+	val resultsDirectory = mavenTargetDirectory / "results"
+
+	val recorderConfigFile = (mavenResourcesDirectory / "recorder.conf").toFile
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/gatling/src/test/scala/Recorder.scala
----------------------------------------------------------------------
diff --git a/stack/gatling/src/test/scala/Recorder.scala b/stack/gatling/src/test/scala/Recorder.scala
new file mode 100644
index 0000000..b132063
--- /dev/null
+++ b/stack/gatling/src/test/scala/Recorder.scala
@@ -0,0 +1,12 @@
+import io.gatling.recorder.config.RecorderPropertiesBuilder
+import io.gatling.recorder.controller.RecorderController
+
+object Recorder extends App {
+
+	val props = new RecorderPropertiesBuilder
+	props.simulationOutputFolder(IDEPathHelper.recorderOutputDirectory.toString)
+	props.simulationPackage("org.apache.usergrid")
+	props.requestBodiesFolder(IDEPathHelper.requestBodiesDirectory.toString)
+
+	RecorderController(props.build, Some(IDEPathHelper.recorderConfigFile))
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/loadtests/simulations/test/scala/org/apache/usergrid/scenarios/DeviceScenarios.scala
----------------------------------------------------------------------
diff --git a/stack/loadtests/simulations/test/scala/org/apache/usergrid/scenarios/DeviceScenarios.scala b/stack/loadtests/simulations/test/scala/org/apache/usergrid/scenarios/DeviceScenarios.scala
index d8d8af0..e86bd42 100755
--- a/stack/loadtests/simulations/test/scala/org/apache/usergrid/scenarios/DeviceScenarios.scala
+++ b/stack/loadtests/simulations/test/scala/org/apache/usergrid/scenarios/DeviceScenarios.scala
@@ -46,7 +46,7 @@ object DeviceScenarios {
       "\"deviceModel\":\"Fake Device\"," +
       " \"deviceOSVerion\":\"Negative Version\", " +
       "\"${notifier}.notifier.id\":\"${entityName}\"}"))
-    .check(status.is(200)))
+    .check(status.is(200), jsonPath("$.entities[0].uuid").saveAs("deviceId")))
 
   val postDeviceWithNotifier400ok = exec(http("Create device with notifier")
     .post("/devices")
@@ -54,7 +54,7 @@ object DeviceScenarios {
     "\"deviceModel\":\"Fake Device\"," +
     " \"deviceOSVerion\":\"Negative Version\", " +
     "\"${notifier}.notifier.id\":\"${entityName}\"}"))
-    .check(status.in(200 to 400)))
+    .check(status.in(200 to 400), jsonPath("$.entities[0].uuid").saveAs("deviceId")))
 
   /**
    * TODO: Add a device to a user, which would expect a user in the session

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/loadtests/simulations/test/scala/org/apache/usergrid/simulations/PushNotificationTargetDeviceSimulation.scala
----------------------------------------------------------------------
diff --git a/stack/loadtests/simulations/test/scala/org/apache/usergrid/simulations/PushNotificationTargetDeviceSimulation.scala b/stack/loadtests/simulations/test/scala/org/apache/usergrid/simulations/PushNotificationTargetDeviceSimulation.scala
new file mode 100755
index 0000000..66b3c5d
--- /dev/null
+++ b/stack/loadtests/simulations/test/scala/org/apache/usergrid/simulations/PushNotificationTargetDeviceSimulation.scala
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+ package org.apache.usergrid
+
+import io.gatling.core.Predef._
+import io.gatling.http.Predef._
+import scala.concurrent.duration._
+
+/**
+ *
+ * Simple test for setting up multiple orgs and creating push notifications
+ *
+ */
+class PushNotificationTargetDeviceSimulation extends Simulation {
+
+  val numUsers:Int = Settings.numUsers
+  val numEntities:Int = Settings.numEntities
+  val rampTime:Int = Settings.rampTime
+  val throttle:Int = Settings.throttle
+  val duration:Int = Settings.duration  
+  val httpConf = Settings.httpConf
+    .acceptHeader("application/json")
+
+  val createNotifier = NotifierScenarios.createNotifier
+  val createDevice = DeviceScenarios.postDeviceWithNotifier
+  val sendNotification = NotificationScenarios.sendNotification
+
+  val deviceNameFeeder = FeederGenerator.generateEntityNameFeeder("device", numEntities).circular
+
+  val scnToRun = scenario("Create Push Notification")    
+    .during(duration.seconds) {
+      feed(deviceNameFeeder)
+      .exec(sendNotification)
+    }
+
+
+  setUp(scnToRun.inject(atOnceUsers(numUsers)).throttle(reachRps(throttle) in (rampTime.seconds)).protocols(httpConf))
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/loadtests/simulations/test/scala/org/apache/usergrid/simulations/PushNotificationTargetUserSimulation.scala
----------------------------------------------------------------------
diff --git a/stack/loadtests/simulations/test/scala/org/apache/usergrid/simulations/PushNotificationTargetUserSimulation.scala b/stack/loadtests/simulations/test/scala/org/apache/usergrid/simulations/PushNotificationTargetUserSimulation.scala
new file mode 100644
index 0000000..67ee20a
--- /dev/null
+++ b/stack/loadtests/simulations/test/scala/org/apache/usergrid/simulations/PushNotificationTargetUserSimulation.scala
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+ package org.apache.usergrid
+
+import io.gatling.core.Predef._
+import io.gatling.http.Predef._
+import scala.concurrent.duration._
+
+class PushNotificationTargetUserSimulation extends Simulation {
+
+  val numUsers:Int = Settings.numUsers
+  val numEntities:Int = Settings.numEntities
+  val rampTime:Int = Settings.rampTime
+  val throttle:Int = Settings.throttle
+  val duration:Int = Settings.duration
+  val httpConf = Settings.httpConf.acceptHeader("application/json")
+
+  val notifier = Settings.pushNotifier
+  val createDevice = DeviceScenarios.postDeviceWithNotifier400ok
+  val sendNotification = NotificationScenarios.sendNotification
+  val createUser = UserScenarios.postUser400ok
+  val deviceNameFeeder = FeederGenerator.generateEntityNameFeeder("device", numEntities).circular
+  val userFeeder = FeederGenerator.generateUserWithGeolocationFeeder(numEntities, Settings.userLocationRadius, Settings.centerLatitude, Settings.centerLongitude)
+
+  val scnToRun = scenario("Create Push Notification")
+    .feed(userFeeder)
+    .exec(createUser)
+//    .pause(1000)
+    .exec(http("Check user and user devices")
+      .get("/users/${username}/devices")
+      .check(status.is(200))
+    )
+    .feed(deviceNameFeeder)
+    .exec(createDevice)
+//    .pause(1000)
+    .exec(http("Check device connections")
+      .get("/devices/${entityName}/users")
+      .check(status.is(200))
+    )
+    .exec(http("Connect user with device")
+      .post("/users/${username}/devices/${deviceId}")
+      .check(status.is(200))
+    )
+    .exec(http("Send Notification to All Devices")
+      .post("/users/${username}/notifications")
+      .body(StringBody("{\"payloads\":{\"" + notifier + "\":\"testmessage\"}}"))
+      .check(status.is(200))
+    )
+
+
+  setUp(scnToRun.inject(constantUsersPerSec(numUsers) during (duration)).throttle(reachRps(throttle) in (rampTime.seconds)).protocols(httpConf))
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/bfc4d0fc/stack/loadtests/simulations/test/scala/org/apache/usergrid/simulations/PushTargetDeviceSimulation.scala
----------------------------------------------------------------------
diff --git a/stack/loadtests/simulations/test/scala/org/apache/usergrid/simulations/PushTargetDeviceSimulation.scala b/stack/loadtests/simulations/test/scala/org/apache/usergrid/simulations/PushTargetDeviceSimulation.scala
deleted file mode 100755
index 66b3c5d..0000000
--- a/stack/loadtests/simulations/test/scala/org/apache/usergrid/simulations/PushTargetDeviceSimulation.scala
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.
- */
- package org.apache.usergrid
-
-import io.gatling.core.Predef._
-import io.gatling.http.Predef._
-import scala.concurrent.duration._
-
-/**
- *
- * Simple test for setting up multiple orgs and creating push notifications
- *
- */
-class PushNotificationTargetDeviceSimulation extends Simulation {
-
-  val numUsers:Int = Settings.numUsers
-  val numEntities:Int = Settings.numEntities
-  val rampTime:Int = Settings.rampTime
-  val throttle:Int = Settings.throttle
-  val duration:Int = Settings.duration  
-  val httpConf = Settings.httpConf
-    .acceptHeader("application/json")
-
-  val createNotifier = NotifierScenarios.createNotifier
-  val createDevice = DeviceScenarios.postDeviceWithNotifier
-  val sendNotification = NotificationScenarios.sendNotification
-
-  val deviceNameFeeder = FeederGenerator.generateEntityNameFeeder("device", numEntities).circular
-
-  val scnToRun = scenario("Create Push Notification")    
-    .during(duration.seconds) {
-      feed(deviceNameFeeder)
-      .exec(sendNotification)
-    }
-
-
-  setUp(scnToRun.inject(atOnceUsers(numUsers)).throttle(reachRps(throttle) in (rampTime.seconds)).protocols(httpConf))
-
-}