Repository: usergrid
Updated Branches:
  refs/heads/master f9aab9125 -> 2ef1f322e


Updated to latest GCM library and support "priority" in push notification 
entities.  Enhanced QueueListener thread naming and shutdown logic.  Fixed all 
GCM push notification tests.  Fixed matrix queries in notifications service.


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

Branch: refs/heads/master
Commit: 741d336bcd6e4fb09da08cb016480c4f29abcd83
Parents: 29bf682
Author: Michael Russo <[email protected]>
Authored: Wed Jan 6 20:58:05 2016 -0800
Committer: Michael Russo <[email protected]>
Committed: Wed Jan 6 20:58:05 2016 -0800

----------------------------------------------------------------------
 .../persistence/entities/Notification.java      | 145 ++++++++------
 .../usergrid/persistence/entities/Notifier.java |  51 +++--
 .../persistence/queue/LocalQueueManager.java    |   5 +
 stack/pom.xml                                   |   5 +-
 stack/services/pom.xml                          |   3 +-
 .../notifications/NotificationsService.java     |  24 ++-
 .../services/notifications/ProviderAdapter.java |   5 +-
 .../services/notifications/QueueListener.java   |  15 +-
 .../services/notifications/TestAdapter.java     |   8 +-
 .../notifications/apns/APNsAdapter.java         |   9 +-
 .../services/notifications/gcm/GCMAdapter.java  |  92 +++++++--
 .../impl/ApplicationQueueManagerImpl.java       |   4 +-
 .../services/notifications/wns/WNSAdapter.java  |   4 +-
 .../AbstractServiceNotificationIT.java          |   2 +-
 .../apns/MockSuccessfulProviderAdapter.java     |   4 +-
 .../apns/NotificationsServiceIT.java            |  22 +--
 .../gcm/MockSuccessfulProviderAdapter.java      |   7 +-
 .../gcm/NotificationsServiceIT.java             | 197 ++++++++++++++-----
 .../notifications/wns/WNSAdapterTest.java       |   5 -
 19 files changed, 398 insertions(+), 209 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/741d336b/stack/core/src/main/java/org/apache/usergrid/persistence/entities/Notification.java
----------------------------------------------------------------------
diff --git 
a/stack/core/src/main/java/org/apache/usergrid/persistence/entities/Notification.java
 
b/stack/core/src/main/java/org/apache/usergrid/persistence/entities/Notification.java
index 096706b..f10e0c2 100644
--- 
a/stack/core/src/main/java/org/apache/usergrid/persistence/entities/Notification.java
+++ 
b/stack/core/src/main/java/org/apache/usergrid/persistence/entities/Notification.java
@@ -25,11 +25,8 @@ import 
com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import org.apache.usergrid.persistence.*;
 import org.apache.usergrid.persistence.annotations.EntityCollection;
 import org.apache.usergrid.persistence.annotations.EntityProperty;
-import org.apache.usergrid.persistence.entities.Device;
 import org.apache.usergrid.persistence.index.query.Identifier;
 
-import static org.apache.usergrid.utils.InflectionUtils.pluralize;
-
 /**
  * The entity class for representing Notifications.
  */
@@ -40,13 +37,13 @@ public class Notification extends TypedEntity {
 
     public static final String RECEIPTS_COLLECTION = "receipts";
 
-    /** Total count */
+    /** Total count of notifications sent based on the API path/query */
     @EntityProperty
     protected int expectedCount;
 
+    /** The pathQuery/query that Usergrid used to idenitfy the devices to send 
the notification to */
     @EntityProperty
-    private PathTokens pathTokens;
-    private String pathQuery;
+    private PathTokens pathQuery;
 
     public static enum State {
         CREATED, FAILED, SCHEDULED, STARTED, FINISHED, CANCELED, EXPIRED
@@ -56,27 +53,23 @@ public class Notification extends TypedEntity {
     @EntityProperty
     protected Map<String, Object> payloads;
 
-    /** Time processed */
+    /** Timestamp (ms) when the notification was processed */
     @EntityProperty
     protected Long queued;
 
-    /** Debug logging is on  */
-    @EntityProperty
-    protected boolean debug;
-
-    /** Time send started */
+    /** Timestamp (ms) when send notification started */
     @EntityProperty
     protected Long started;
 
-    /** Time processed */
+    /** Timestamp (ms) when send notification finished */
     @EntityProperty
     protected Long finished;
 
-    /** Time to deliver to provider */
+    /** Timestamp (ms) to deliver to provider */
     @EntityProperty
     protected Long deliver;
 
-    /** Time to expire the notification */
+    /** Timestamp (ms) to expire the notification*/
     @EntityProperty
     protected Long expire;
 
@@ -84,29 +77,42 @@ public class Notification extends TypedEntity {
     @EntityProperty
     protected Boolean canceled;
 
-    /** Error message */
+    /** Flag to enable/disable verbose logging of states  */
+    @EntityProperty
+    protected boolean debug;
+
+    /** Flag to set the notification priority. Valid values "normal" and 
"high"  */
+    @EntityProperty
+    protected String priority;
+
+    /** Error messages that may have been encounted by Usergrid when trying to 
process the notification */
     @EntityProperty
     protected String errorMessage;
 
     @EntityCollection(type = "receipt")
     protected List<UUID> receipts;
 
-    /** stats (sent & errors) */
+    /** Map containing a count for "sent" and "errors" */
     @EntityProperty
     protected Map<String, Long> statistics;
 
 
     public Notification() {
-        pathTokens = new PathTokens();
+        pathQuery = new PathTokens();
     }
 
-    @JsonIgnore
-    public List<UUID> getReceipts() {
-        return receipts;
+    @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+    public int getExpectedCount() {  return expectedCount;  }
+
+    public void setExpectedCount(int expectedCount) {  this.expectedCount = 
expectedCount;  }
+
+    @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+    public PathTokens getPathQuery(){
+        return pathQuery;
     }
 
-    public void setReceipts(List<UUID> receipts) {
-        this.receipts = receipts;
+    public void setPathQuery(PathTokens pathQuery){
+        this.pathQuery = pathQuery;
     }
 
     @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
@@ -119,6 +125,15 @@ public class Notification extends TypedEntity {
     }
 
     @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+    public Long getQueued() {
+        return queued;
+    }
+
+    public void setQueued(Long queued) {
+        this.queued = queued;
+    }
+
+    @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
     public Long getFinished() {
         return finished;
     }
@@ -145,11 +160,6 @@ public class Notification extends TypedEntity {
         this.expire = expire;
     }
 
-    @JsonIgnore
-    public boolean isExpired() {
-        return expire != null && expire < System.currentTimeMillis();
-    }
-
     @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
     public Boolean getCanceled() {
         return canceled;
@@ -169,6 +179,15 @@ public class Notification extends TypedEntity {
     }
 
     @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+    public String getPriority() {
+        return priority;
+    }
+
+    public void setPriority(String priority) {
+        this.priority = priority;
+    }
+
+    @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
     public Long getStarted() {
         return started;
     }
@@ -207,11 +226,6 @@ public class Notification extends TypedEntity {
         }
     }
 
-    /** don't bother, I will ignore you */
-    public void setState(State ignored) {
-        // does nothing - state is derived
-    }
-
     @EntityProperty(mutable = true, indexed = true)
     public State getState() {
         if (getErrorMessage() != null) {
@@ -230,6 +244,11 @@ public class Notification extends TypedEntity {
         return State.CREATED;
     }
 
+    /** don't bother, I will ignore you */
+    public void setState(State ignored) {
+        // does nothing - state is derived
+    }
+
     @JsonIgnore
     public long getExpireTimeMillis() {
         return getExpire() != null ? getExpire() : 0;
@@ -241,35 +260,18 @@ public class Notification extends TypedEntity {
         return ttlSeconds > 0 ? ttlSeconds : 0;
     }
 
-    @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
-    public Long getQueued() {
-        return queued;
-    }
-
-    public void setQueued(Long queued) {
-        this.queued = queued;
-    }
-
-    public void setExpectedCount(int expectedCount) {  this.expectedCount = 
expectedCount;  }
-
-    @org.codehaus.jackson.map.annotate.JsonSerialize(include = 
org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion.NON_NULL)
-    public int getExpectedCount() {  return expectedCount;  }
-
-    @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
-    public PathTokens getPathTokens(){
-        return pathTokens;
-    }
-
-    public void setPathTokens(PathTokens pathTokens){
-        this.pathTokens = pathTokens;
+    @JsonIgnore
+    public boolean isExpired() {
+        return expire != null && expire < System.currentTimeMillis();
     }
 
     @JsonIgnore
-    public String getPathQuery(){
-        return pathQuery;
+    public List<UUID> getReceipts() {
+        return receipts;
     }
-    public void setPathQuery(String query){
-        pathQuery = query;
+
+    public void setReceipts(List<UUID> receipts) {
+        this.receipts = receipts;
     }
 
     public static class PathTokens{
@@ -282,6 +284,7 @@ public class Notification extends TypedEntity {
         public PathTokens(final SimpleEntityRef applicationRef, final 
List<PathToken> pathTokens){
             this.applicationRef = applicationRef;
             this.pathTokens = pathTokens;
+
         }
 
         public void setPathTokens(final List<PathToken> pathTokens){
@@ -298,12 +301,17 @@ public class Notification extends TypedEntity {
         }
 
         @JsonIgnore
-        public PathQuery<Device> getPathQuery() {
+        public PathQuery<Device> buildPathQuery() {
             PathQuery pathQuery = null;
             for (PathToken pathToken : getPathTokens()) {
                 String collection = pathToken.getCollection();
                 Query query = new Query();
-                if (pathToken.getIdentifier()!=null) {
+                if(pathToken.getQl() != null){
+
+                    // if a query is already present, use it's QL
+                    query.setQl(pathToken.getQl());
+
+                }else if (pathToken.getIdentifier()!=null) {
 
                     // users collection is special case and uses "username" 
instaed of "name"
                     // build a query using QL with "username" as 
Identifier.Type.USERNAME doesn't exist
@@ -331,6 +339,7 @@ public class Notification extends TypedEntity {
     public static class PathToken{
         private  String collection;
         private  Identifier identifier;
+        private String ql;
 
         public PathToken(){
 
@@ -338,8 +347,15 @@ public class Notification extends TypedEntity {
 
         public PathToken( final String collection, final Identifier 
identifier){
             this.collection = collection;
-
             this.identifier = identifier;
+            this.ql = null;
+
+        }
+
+        public PathToken( final String collection, final String ql){
+            this.collection = collection;
+            this.ql = ql;
+            this.identifier = null;
 
         }
 
@@ -357,6 +373,13 @@ public class Notification extends TypedEntity {
             this.identifier = identifier;
         }
 
+        public String getQl() {
+            return ql;
+        }
+        public void setQl(String ql){
+            this.ql = ql;
+        }
+
 
     }
 }

http://git-wip-us.apache.org/repos/asf/usergrid/blob/741d336b/stack/core/src/main/java/org/apache/usergrid/persistence/entities/Notifier.java
----------------------------------------------------------------------
diff --git 
a/stack/core/src/main/java/org/apache/usergrid/persistence/entities/Notifier.java
 
b/stack/core/src/main/java/org/apache/usergrid/persistence/entities/Notifier.java
index 2f23249..f1a9ef2 100644
--- 
a/stack/core/src/main/java/org/apache/usergrid/persistence/entities/Notifier.java
+++ 
b/stack/core/src/main/java/org/apache/usergrid/persistence/entities/Notifier.java
@@ -24,6 +24,7 @@ import 
org.apache.usergrid.persistence.annotations.EntityProperty;
 import javax.xml.bind.annotation.XmlRootElement;
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
+import java.util.Map;
 import java.util.UUID;
 
 /**
@@ -66,22 +67,31 @@ public class Notifier extends TypedEntity {
     @EntityProperty(indexed = false, includedInExport = false, encrypted = 
true)
     protected String sid;
 
-    @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
-    public String getSid() {
-        return sid;
-    }
-
-    public void setSid(String sid) {  this.sid = sid; }
-
     //Windows WNS logging
     @EntityProperty(indexed = false, includedInExport = false, encrypted = 
true)
     protected boolean logging = true;
 
+    /** This contains info like {"certInfo" : {"name": "test.p12", 
"attributes":{"cn":"api.usergrid.com"}} */
+    @EntityProperty
+    protected Map<String, Object> certInfo;
+
+
     @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
-    public boolean getLogging() {  return logging;  }
+    public String getProvider() {
+        return provider;
+    }
 
-    public void setLogging(boolean logging) {
-        this.logging = logging;
+    public void setProvider(String provider) {
+        this.provider = provider;
+    }
+
+    @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+    public String getEnvironment() {
+        return environment;
+    }
+
+    public void setEnvironment(String environment) {
+        this.environment = environment;
     }
 
     @Override
@@ -95,21 +105,24 @@ public class Notifier extends TypedEntity {
     }
 
     @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
-    public String getProvider() {
-        return provider;
+    public String getSid() {
+        return sid;
     }
 
-    public void setProvider(String provider) {
-        this.provider = provider;
-    }
+    public void setSid(String sid) {  this.sid = sid; }
 
     @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
-    public String getEnvironment() {
-        return environment;
+    public boolean getLogging() {  return logging;  }
+
+    public void setLogging(boolean logging) {
+        this.logging = logging;
     }
 
-    public void setEnvironment(String environment) {
-        this.environment = environment;
+     @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+    public Map getCertInfo() {  return certInfo;  }
+
+    public void setCertInfo(Map<String, Object> certInfo) {
+        this.certInfo = certInfo;
     }
 
     @JsonIgnore

http://git-wip-us.apache.org/repos/asf/usergrid/blob/741d336b/stack/corepersistence/queue/src/main/java/org/apache/usergrid/persistence/queue/LocalQueueManager.java
----------------------------------------------------------------------
diff --git 
a/stack/corepersistence/queue/src/main/java/org/apache/usergrid/persistence/queue/LocalQueueManager.java
 
b/stack/corepersistence/queue/src/main/java/org/apache/usergrid/persistence/queue/LocalQueueManager.java
index d5f6858..4d26100 100644
--- 
a/stack/corepersistence/queue/src/main/java/org/apache/usergrid/persistence/queue/LocalQueueManager.java
+++ 
b/stack/corepersistence/queue/src/main/java/org/apache/usergrid/persistence/queue/LocalQueueManager.java
@@ -20,6 +20,8 @@
 
 package org.apache.usergrid.persistence.queue;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import rx.Observable;
 
 import java.io.IOException;
@@ -37,6 +39,9 @@ import java.util.concurrent.TimeUnit;
  * Default queue manager implementation, uses in memory linked queue
  */
 public class LocalQueueManager implements QueueManager {
+
+    private static final Logger logger = 
LoggerFactory.getLogger(LocalQueueManager.class);
+
     public ArrayBlockingQueue<QueueMessage> queue = new 
ArrayBlockingQueue<>(10000);
 
     @Override

http://git-wip-us.apache.org/repos/asf/usergrid/blob/741d336b/stack/pom.xml
----------------------------------------------------------------------
diff --git a/stack/pom.xml b/stack/pom.xml
index 1f5cdba..e086295 100644
--- a/stack/pom.xml
+++ b/stack/pom.xml
@@ -120,6 +120,7 @@
         <antlr.version>3.4</antlr.version>
         <tika.version>1.4</tika.version>
         <mockito.version>1.10.8</mockito.version>
+        <io.apigee.gcm.version>1.0.0</io.apigee.gcm.version>
 
         <!-- only use half the cores on the machine for testing -->
         <usergrid.it.parallel>methods</usergrid.it.parallel>
@@ -1280,9 +1281,9 @@
             </dependency>
 
             <dependency>
-                <groupId>com.ganyo</groupId>
+                <groupId>io.apigee.gcm</groupId>
                 <artifactId>gcm-server</artifactId>
-                <version>1.0.2</version>
+                <version>${io.apigee.gcm.version}</version>
             </dependency>
 
         </dependencies>

http://git-wip-us.apache.org/repos/asf/usergrid/blob/741d336b/stack/services/pom.xml
----------------------------------------------------------------------
diff --git a/stack/services/pom.xml b/stack/services/pom.xml
index bfd2f3b..9660894 100644
--- a/stack/services/pom.xml
+++ b/stack/services/pom.xml
@@ -436,9 +436,8 @@
     </dependency>
 
     <dependency>
-      <groupId>com.ganyo</groupId>
+      <groupId>io.apigee.gcm</groupId>
       <artifactId>gcm-server</artifactId>
-      <version>1.0.2</version>
     </dependency>
 
     <dependency>

http://git-wip-us.apache.org/repos/asf/usergrid/blob/741d336b/stack/services/src/main/java/org/apache/usergrid/services/notifications/NotificationsService.java
----------------------------------------------------------------------
diff --git 
a/stack/services/src/main/java/org/apache/usergrid/services/notifications/NotificationsService.java
 
b/stack/services/src/main/java/org/apache/usergrid/services/notifications/NotificationsService.java
index 202971d..63375cd 100644
--- 
a/stack/services/src/main/java/org/apache/usergrid/services/notifications/NotificationsService.java
+++ 
b/stack/services/src/main/java/org/apache/usergrid/services/notifications/NotificationsService.java
@@ -136,7 +136,7 @@ public class NotificationsService extends 
AbstractCollectionService {
             validate(null, context.getPayload());
             Notification.PathTokens pathTokens = 
getPathTokens(context.getRequest().getOriginalParameters());
             context.getProperties().put("state", Notification.State.CREATED);
-            context.getProperties().put("pathTokens", pathTokens);
+            context.getProperties().put("pathQuery", pathTokens);
             context.setOwner(sm.getApplication());
             ServiceResults results = super.postCollection(context);
             Notification notification = (Notification) results.getEntity();
@@ -166,18 +166,30 @@ public class NotificationsService extends 
AbstractCollectionService {
     }
 
     private Notification.PathTokens getPathTokens(List<ServiceParameter> 
parameters){
+
         Notification.PathTokens pathTokens = new Notification.PathTokens();
         pathTokens.setApplicationRef((SimpleEntityRef)em.getApplicationRef());
-        for (int i = 0; i < parameters.size() - 1; i += 2) {
+
+        // first parameter is always collection name, start parsing after that
+        for (int i = 0; i < parameters.size() - 1; i += 2 ) {
             String collection = pluralize(parameters.get(i).getName());
             Identifier identifier = null;
+            String ql = null;
             ServiceParameter sp = parameters.get(i + 1);
-                if(collection.equals("devices") && sp.isName() && 
sp.getName().equals("notifications")) {
-                    //look for queries to /devices;ql=/notifications
-                }else{
+
+            // if the next param is a query, add a token with the query
+            if(sp.isQuery()){
+                ql = sp.getQuery().getQl().get();
+                pathTokens.getPathTokens().add(new Notification.PathToken( 
collection, ql));
+            }else{
+                // if the next param is "notifications", it's the end let 
identifier be null
+                if(sp.isName() && 
!sp.getName().equalsIgnoreCase("notifications") || sp.isId()){
                     identifier = sp.getIdentifier();
                 }
-            pathTokens.getPathTokens().add(new Notification.PathToken( 
collection, identifier));
+                pathTokens.getPathTokens().add(new Notification.PathToken( 
collection, identifier));
+            }
+
+
         }
         return pathTokens;
     }

http://git-wip-us.apache.org/repos/asf/usergrid/blob/741d336b/stack/services/src/main/java/org/apache/usergrid/services/notifications/ProviderAdapter.java
----------------------------------------------------------------------
diff --git 
a/stack/services/src/main/java/org/apache/usergrid/services/notifications/ProviderAdapter.java
 
b/stack/services/src/main/java/org/apache/usergrid/services/notifications/ProviderAdapter.java
index 1783882..6b6307b 100644
--- 
a/stack/services/src/main/java/org/apache/usergrid/services/notifications/ProviderAdapter.java
+++ 
b/stack/services/src/main/java/org/apache/usergrid/services/notifications/ProviderAdapter.java
@@ -16,9 +16,6 @@
  */
 package org.apache.usergrid.services.notifications;
 
-import java.util.Date;
-import java.util.Map;
-import org.apache.usergrid.persistence.EntityManager;
 import org.apache.usergrid.persistence.entities.Notification;
 import org.apache.usergrid.persistence.entities.Notifier;
 import org.apache.usergrid.services.ServicePayload;
@@ -38,7 +35,7 @@ public interface ProviderAdapter {
      * test the connection
      * @throws ConnectionException
      */
-    public void testConnection() throws ConnectionException;
+    public void testConnection() throws Exception;
 
     /**
      * send a notification

http://git-wip-us.apache.org/repos/asf/usergrid/blob/741d336b/stack/services/src/main/java/org/apache/usergrid/services/notifications/QueueListener.java
----------------------------------------------------------------------
diff --git 
a/stack/services/src/main/java/org/apache/usergrid/services/notifications/QueueListener.java
 
b/stack/services/src/main/java/org/apache/usergrid/services/notifications/QueueListener.java
index bcf7b49..8ce4e17 100644
--- 
a/stack/services/src/main/java/org/apache/usergrid/services/notifications/QueueListener.java
+++ 
b/stack/services/src/main/java/org/apache/usergrid/services/notifications/QueueListener.java
@@ -114,29 +114,34 @@ public class QueueListener  {
 
                 while (threadCount++ < maxThreads) {
                     LOG.info("QueueListener: Starting thread {}.", 
threadCount);
+                    final int threadNumber = threadCount;
                     Runnable task = new Runnable() {
                         @Override
                         public void run() {
                             try {
-                                execute();
+                                execute(threadNumber);
                             } catch (Exception e) {
-                                LOG.error("failed to start push", e);
+                                if(pool.isShutdown()){
+                                    LOG.warn("QueueListener: push listener 
pool already shut down.");
+                                }else{
+                                    LOG.error("QueueListener: threads 
interrupted", e);
+                                }
                             }
                         }
                     };
                     futures.add( pool.submit(task));
                 }
             } catch (Exception e) {
-                LOG.error("QueueListener: failed to start:", e);
+                LOG.error("QueueListener: failed to start", e);
             }
             LOG.info("QueueListener: done starting.");
     }
 
-    private void execute(){
+    private void execute(int threadNumber){
         if(Thread.currentThread().isDaemon()) {
             Thread.currentThread().setDaemon(true);
         }
-        
Thread.currentThread().setName("Notifications_Processor"+UUID.randomUUID());
+        
Thread.currentThread().setName(getClass().getSimpleName()+"_PushNotifications-"+threadNumber);
 
         final AtomicInteger consecutiveExceptions = new AtomicInteger();
         LOG.info("QueueListener: Starting execute process.");

http://git-wip-us.apache.org/repos/asf/usergrid/blob/741d336b/stack/services/src/main/java/org/apache/usergrid/services/notifications/TestAdapter.java
----------------------------------------------------------------------
diff --git 
a/stack/services/src/main/java/org/apache/usergrid/services/notifications/TestAdapter.java
 
b/stack/services/src/main/java/org/apache/usergrid/services/notifications/TestAdapter.java
index 1007dc6..1f1b6d9 100644
--- 
a/stack/services/src/main/java/org/apache/usergrid/services/notifications/TestAdapter.java
+++ 
b/stack/services/src/main/java/org/apache/usergrid/services/notifications/TestAdapter.java
@@ -22,11 +22,9 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 
-import java.util.Date;
-import java.util.Map;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
-import org.apache.usergrid.persistence.EntityManager;
+
 import org.apache.usergrid.services.ServicePayload;
 import org.apache.usergrid.services.notifications.apns.APNsAdapter;
 import org.apache.usergrid.services.notifications.apns.APNsNotification;
@@ -51,12 +49,12 @@ public class TestAdapter implements ProviderAdapter {
     }
 
     @Override
-    public void testConnection() throws ConnectionException {
+    public void testConnection() throws Exception {
     }
 
     @Override
     public void sendNotification(
-            String providerId, 
+            String providerId,
             final Object payload,
             Notification notification,
             TaskTracker tracker)

http://git-wip-us.apache.org/repos/asf/usergrid/blob/741d336b/stack/services/src/main/java/org/apache/usergrid/services/notifications/apns/APNsAdapter.java
----------------------------------------------------------------------
diff --git 
a/stack/services/src/main/java/org/apache/usergrid/services/notifications/apns/APNsAdapter.java
 
b/stack/services/src/main/java/org/apache/usergrid/services/notifications/apns/APNsAdapter.java
index 8e97f4c..51024ed 100644
--- 
a/stack/services/src/main/java/org/apache/usergrid/services/notifications/apns/APNsAdapter.java
+++ 
b/stack/services/src/main/java/org/apache/usergrid/services/notifications/apns/APNsAdapter.java
@@ -16,20 +16,15 @@
  */
 package org.apache.usergrid.services.notifications.apns;
 
-import com.google.common.cache.*;
-
 import com.relayrides.pushy.apns.*;
 import com.relayrides.pushy.apns.util.*;
 
-import io.netty.channel.nio.NioEventLoopGroup;
 import org.apache.usergrid.persistence.entities.Notification;
 import org.apache.usergrid.persistence.entities.Notifier;
 import org.mortbay.util.ajax.JSON;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.InputStream;
-import java.security.*;
 import java.util.*;
 import java.util.concurrent.*;
 
@@ -40,8 +35,6 @@ import 
org.apache.usergrid.services.notifications.ConnectionException;
 import org.apache.usergrid.services.notifications.ProviderAdapter;
 import org.apache.usergrid.services.notifications.TaskTracker;
 
-import javax.net.ssl.SSLContext;
-
 /**
  * Adapter for Apple push notifications
  */
@@ -72,7 +65,7 @@ public class APNsAdapter implements ProviderAdapter {
     }
 
     @Override
-    public void testConnection() throws ConnectionException {
+    public void testConnection() throws Exception {
         TestAPNsNotification notification =  
TestAPNsNotification.create(TEST_TOKEN, TEST_PAYLOAD);
         try {
             CountDownLatch latch = new CountDownLatch(1);

http://git-wip-us.apache.org/repos/asf/usergrid/blob/741d336b/stack/services/src/main/java/org/apache/usergrid/services/notifications/gcm/GCMAdapter.java
----------------------------------------------------------------------
diff --git 
a/stack/services/src/main/java/org/apache/usergrid/services/notifications/gcm/GCMAdapter.java
 
b/stack/services/src/main/java/org/apache/usergrid/services/notifications/gcm/GCMAdapter.java
index ba404e8..089d660 100644
--- 
a/stack/services/src/main/java/org/apache/usergrid/services/notifications/gcm/GCMAdapter.java
+++ 
b/stack/services/src/main/java/org/apache/usergrid/services/notifications/gcm/GCMAdapter.java
@@ -47,20 +47,35 @@ public class GCMAdapter implements ProviderAdapter {
 
     private ConcurrentHashMap<Long,Batch> batches;
 
+    private static final String ttlKey = "time_to_live";
+    private static final String priorityKey = "priority";
+    private static final String dataKey = "data";
+
+
     public GCMAdapter(EntityManager entityManager,Notifier notifier){
         this.notifier = notifier;
         this.entityManager = entityManager;
         batches = new ConcurrentHashMap<>();
     }
     @Override
-    public void testConnection() throws ConnectionException {
+    public void testConnection() throws Exception {
         Sender sender = new Sender(notifier.getApiKey());
-        Message message = new Message.Builder().build();
+        Message message = new Message.Builder().addData("registration_id", 
"").build();
+        List<String> ids = new ArrayList<String>();
+        ids.add("device_token");
         try {
-            Result result = sender.send(message, "device_token", 1);
+            MulticastResult result = sender.send(message, ids, 1);
             LOG.debug("testConnection result: {}", result);
-        } catch (IOException e) {
-            throw new ConnectionException(e.getMessage(), e);
+        } catch (InvalidRequestException e){
+            // do nothing, we don't have a valid device token to test with
+            LOG.debug("here for testing only");
+        }
+        catch (IOException e) {
+            if(isInvalidRequestException(e)){
+                throw new InvalidRequestException(401, 
Constants.ERROR_INVALID_REGISTRATION);
+            }else {
+                throw new ConnectionException(e.getMessage(), e);
+            }
         }
     }
 
@@ -68,13 +83,15 @@ public class GCMAdapter implements ProviderAdapter {
     public void sendNotification(String providerId, Object payload, 
Notification notification, TaskTracker tracker)
             throws Exception {
         Map<String,Object> map = (Map<String, Object>) payload;
-        final String expiresKey = "time_to_live";
-        if(!map.containsKey(expiresKey) && notification.getExpire() != null){
+        if(!map.containsKey(ttlKey) && notification.getExpire() != null){
             // ttl provided to GCM is in seconds.  calculate the difference 
from now
             long ttlSeconds = notification.getExpireTTLSeconds();
             // max ttl for gcm is 4 weeks - 
https://developers.google.com/cloud-messaging/http-server-ref
             ttlSeconds = ttlSeconds <= 2419200 ? ttlSeconds : 2419200;
-            map.put(expiresKey, (int)ttlSeconds);//needs to be int
+            map.put(ttlKey, (int)ttlSeconds);//needs to be int
+        }
+        if(!map.containsKey(priorityKey) && notification.getPriority() != 
null){
+            map.put(priorityKey, notification.getPriority());
         }
         Batch batch = getBatch( map);
         batch.add(providerId, tracker);
@@ -119,7 +136,7 @@ public class GCMAdapter implements ProviderAdapter {
         if (payload instanceof Map) {
             mapPayload = (Map<String, Object>) payload;
         } else if (payload instanceof String) {
-            mapPayload.put("data", payload);
+            mapPayload.put(dataKey, payload);
         } else {
             throw new IllegalArgumentException(
                     "GCM Payload must be either a Map or a String");
@@ -156,6 +173,12 @@ public class GCMAdapter implements ProviderAdapter {
         return notifier;
     }
 
+    // this is a hack because Google library can't parse exceptions properly 
when you have a bad API key
+    private boolean isInvalidRequestException(IOException ie){
+        String message = ie.getMessage();
+        return message.contains("Could not post JSON requests to GCM");
+    }
+
     private class Batch {
         private Notifier notifier;
         private Map payload;
@@ -191,27 +214,56 @@ public class GCMAdapter implements ProviderAdapter {
             }
         }
 
-        // Message.Builder requires the payload to be Map<String,String> for no
-        // good reason, so I just blind cast it.
-        // What actually happens is: "JSONValue.toJSONString(payload);" so
-        // anything that JSONValue can handle is fine.
-        // (What is necessary here is that the Map needs to have a nested
-        // structure.)
+
         void send() throws Exception {
             synchronized (this) {
                 if (ids.size() == 0)
                     return;
                 Sender sender = new Sender(notifier.getApiKey());
                 Message.Builder builder = new Message.Builder();
-                builder.setData(payload);
-                if(payload.containsKey("time_to_live")){
-                    int ttl = (int)payload.get("time_to_live");
-                    builder.timeToLive(ttl);
+                if(payload.containsKey(ttlKey)){
+                    builder.timeToLive((int)payload.get(ttlKey));
+                    payload.remove(ttlKey);
                 }
+                if(payload.containsKey(priorityKey)){
+
+                    try{
+                        
builder.priority(Message.Priority.valueOf(payload.get(priorityKey).toString().toUpperCase()));
+                    }catch(Exception e){
+                        // couldn't determine the priority from the 
notification, default to "normal"
+                        builder.priority(Message.Priority.NORMAL);
+                    }
+                    payload.remove(priorityKey);
+
+                }
+
+                // add our source notification payload data into the Message 
Builder
+                // Message.Builder requires the payload to be 
Map<String,String> so blindly cast
+                Map<String,String> dataMap = (Map<String,String>) payload;
+                dataMap.forEach( (key, value) -> builder.addData(key, value));
+
                 Message message = builder.build();
+                MulticastResult multicastResult;
+                try{
+
+                    multicastResult = sender.send(message, ids, SEND_RETRIES);
+
+                }catch (IOException e) {
+                    if(isInvalidRequestException(e)){
+                        String error = Constants.ERROR_INVALID_REGISTRATION;
+                        for(int i=0; i < ids.size(); i++){
+                            trackers.get(i).failed(error, error);
+                        }
+                        this.ids.clear();
+                        this.trackers.clear();
+                        return;
+                        //throw new InvalidRequestException(401, 
Constants.ERROR_INVALID_REGISTRATION);
+                    }else {
+                        throw new ConnectionException(e.getMessage(), e);
+                    }
+                }
 
 
-                MulticastResult multicastResult = sender.send(message, ids, 
SEND_RETRIES);
                 LOG.debug("sendNotification result: {}", multicastResult);
 
                 for (int i = 0; i < multicastResult.getResults().size(); i++) {

http://git-wip-us.apache.org/repos/asf/usergrid/blob/741d336b/stack/services/src/main/java/org/apache/usergrid/services/notifications/impl/ApplicationQueueManagerImpl.java
----------------------------------------------------------------------
diff --git 
a/stack/services/src/main/java/org/apache/usergrid/services/notifications/impl/ApplicationQueueManagerImpl.java
 
b/stack/services/src/main/java/org/apache/usergrid/services/notifications/impl/ApplicationQueueManagerImpl.java
index 37ced91..f3b7cee 100644
--- 
a/stack/services/src/main/java/org/apache/usergrid/services/notifications/impl/ApplicationQueueManagerImpl.java
+++ 
b/stack/services/src/main/java/org/apache/usergrid/services/notifications/impl/ApplicationQueueManagerImpl.java
@@ -34,9 +34,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import rx.Observable;
 import rx.Subscriber;
-import rx.functions.Action1;
 import rx.functions.Func1;
-import rx.schedulers.Schedulers;
 
 import java.util.*;
 import java.util.concurrent.*;
@@ -94,7 +92,7 @@ public class ApplicationQueueManagerImpl implements 
ApplicationQueueManager {
 
         LOG.info("notification {} start queuing", notification.getUuid());
 
-        final PathQuery<Device> pathQuery = 
notification.getPathTokens().getPathQuery() ; //devices query
+        final PathQuery<Device> pathQuery = 
notification.getPathQuery().buildPathQuery() ; //devices query
         final AtomicInteger deviceCount = new AtomicInteger(); //count devices 
so you can make a judgement on batching
         final ConcurrentLinkedQueue<String> errorMessages = new 
ConcurrentLinkedQueue<String>(); //build up list of issues
 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/741d336b/stack/services/src/main/java/org/apache/usergrid/services/notifications/wns/WNSAdapter.java
----------------------------------------------------------------------
diff --git 
a/stack/services/src/main/java/org/apache/usergrid/services/notifications/wns/WNSAdapter.java
 
b/stack/services/src/main/java/org/apache/usergrid/services/notifications/wns/WNSAdapter.java
index f2946df..98dffa4 100644
--- 
a/stack/services/src/main/java/org/apache/usergrid/services/notifications/wns/WNSAdapter.java
+++ 
b/stack/services/src/main/java/org/apache/usergrid/services/notifications/wns/WNSAdapter.java
@@ -30,13 +30,11 @@ import org.apache.usergrid.persistence.EntityManager;
 import org.apache.usergrid.persistence.entities.Notification;
 import org.apache.usergrid.persistence.entities.Notifier;
 import org.apache.usergrid.services.ServicePayload;
-import org.apache.usergrid.services.notifications.ConnectionException;
 import org.apache.usergrid.services.notifications.ProviderAdapter;
 import org.apache.usergrid.services.notifications.TaskTracker;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.*;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -59,7 +57,7 @@ public class WNSAdapter implements ProviderAdapter {
     }
 
     @Override
-    public void testConnection() throws ConnectionException {
+    public void testConnection() throws Exception {
         WnsToast toast = new 
WnsToastBuilder().bindingTemplateToastText01("test").build();
         try{
             //this fails every time due to jax error which is ok

http://git-wip-us.apache.org/repos/asf/usergrid/blob/741d336b/stack/services/src/test/java/org/apache/usergrid/services/notifications/AbstractServiceNotificationIT.java
----------------------------------------------------------------------
diff --git 
a/stack/services/src/test/java/org/apache/usergrid/services/notifications/AbstractServiceNotificationIT.java
 
b/stack/services/src/test/java/org/apache/usergrid/services/notifications/AbstractServiceNotificationIT.java
index d0d2c29..91b94b2 100644
--- 
a/stack/services/src/test/java/org/apache/usergrid/services/notifications/AbstractServiceNotificationIT.java
+++ 
b/stack/services/src/test/java/org/apache/usergrid/services/notifications/AbstractServiceNotificationIT.java
@@ -48,7 +48,7 @@ public abstract class AbstractServiceNotificationIT extends 
AbstractServiceIT {
         return ns;
     }
 
-    protected Notification scheduleNotificationAndWait(Notification 
notification)
+    protected Notification notificationWaitForComplete(Notification 
notification)
             throws Exception {
         long timeout = System.currentTimeMillis() + 60000;
         while (System.currentTimeMillis() < timeout) {

http://git-wip-us.apache.org/repos/asf/usergrid/blob/741d336b/stack/services/src/test/java/org/apache/usergrid/services/notifications/apns/MockSuccessfulProviderAdapter.java
----------------------------------------------------------------------
diff --git 
a/stack/services/src/test/java/org/apache/usergrid/services/notifications/apns/MockSuccessfulProviderAdapter.java
 
b/stack/services/src/test/java/org/apache/usergrid/services/notifications/apns/MockSuccessfulProviderAdapter.java
index b3096b7..6be4375 100644
--- 
a/stack/services/src/test/java/org/apache/usergrid/services/notifications/apns/MockSuccessfulProviderAdapter.java
+++ 
b/stack/services/src/test/java/org/apache/usergrid/services/notifications/apns/MockSuccessfulProviderAdapter.java
@@ -18,8 +18,6 @@ package org.apache.usergrid.services.notifications.apns;
 
 import org.apache.usergrid.persistence.entities.Notification;
 import org.apache.usergrid.persistence.entities.Notifier;
-import org.apache.usergrid.services.notifications.ConnectionException;
-import org.apache.usergrid.services.notifications.NotificationsService;
 import org.apache.usergrid.services.notifications.ProviderAdapter;
 import org.apache.usergrid.services.notifications.TaskTracker;
 
@@ -46,7 +44,7 @@ public class MockSuccessfulProviderAdapter implements 
ProviderAdapter {
     }
 
     @Override
-    public void testConnection() throws ConnectionException {
+    public void testConnection() throws Exception {
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/usergrid/blob/741d336b/stack/services/src/test/java/org/apache/usergrid/services/notifications/apns/NotificationsServiceIT.java
----------------------------------------------------------------------
diff --git 
a/stack/services/src/test/java/org/apache/usergrid/services/notifications/apns/NotificationsServiceIT.java
 
b/stack/services/src/test/java/org/apache/usergrid/services/notifications/apns/NotificationsServiceIT.java
index daf73d6..e18cdb2 100644
--- 
a/stack/services/src/test/java/org/apache/usergrid/services/notifications/apns/NotificationsServiceIT.java
+++ 
b/stack/services/src/test/java/org/apache/usergrid/services/notifications/apns/NotificationsServiceIT.java
@@ -178,7 +178,7 @@ public class NotificationsServiceIT extends 
AbstractServiceNotificationIT {
 
         // perform push //
 
-        notification = scheduleNotificationAndWait(notification);
+        notification = notificationWaitForComplete(notification);
 
                 setup.getEntityIndex().refresh(app.getId());
 
@@ -249,7 +249,7 @@ public class NotificationsServiceIT extends 
AbstractServiceNotificationIT {
         Entity entity = results.getEntitiesMap().get(notification.getUuid());
         assertNotNull(entity);
 
-        scheduleNotificationAndWait(notification);
+        notificationWaitForComplete(notification);
 
         // perform push //
 
@@ -413,7 +413,7 @@ public class NotificationsServiceIT extends 
AbstractServiceNotificationIT {
         ns.addDevice(notification, device1);
 
         // perform push //
-        notification = scheduleNotificationAndWait(notification);
+        notification = notificationWaitForComplete(notification);
         checkStatistics(notification, 0, 1);
 
         notification = (Notification) app.getEntityManager().get(notification)
@@ -444,7 +444,7 @@ public class NotificationsServiceIT extends 
AbstractServiceNotificationIT {
 
 
         // perform push //
-        notification = scheduleNotificationAndWait(notification);
+        notification = notificationWaitForComplete(notification);
 
         checkReceipts(notification, 2);
     }
@@ -503,7 +503,7 @@ public class NotificationsServiceIT extends 
AbstractServiceNotificationIT {
         assertEquals(notification.getPayloads().get(notifierName), payload);
 
         // perform push //
-        notification = scheduleNotificationAndWait(notification);
+        notification = notificationWaitForComplete(notification);
 
                 setup.getEntityIndex().refresh(app.getId());
 
@@ -570,7 +570,7 @@ public class NotificationsServiceIT extends 
AbstractServiceNotificationIT {
                 setup.getEntityIndex().refresh(app.getId());
 
         // perform push //
-        notification = scheduleNotificationAndWait(notification);
+        notification = notificationWaitForComplete(notification);
 
                 setup.getEntityIndex().refresh(app.getId());
 
@@ -636,7 +636,7 @@ public class NotificationsServiceIT extends 
AbstractServiceNotificationIT {
         // perform push //
 
         try {
-            scheduleNotificationAndWait(notification);
+            notificationWaitForComplete(notification);
             fail("testConnection() should have failed");
         } catch (Exception ex) {
             // good, there should be an error
@@ -685,7 +685,7 @@ public class NotificationsServiceIT extends 
AbstractServiceNotificationIT {
                 + NOTIFIER_ID_POSTFIX));
 
         // perform push //
-        scheduleNotificationAndWait(notification);
+        notificationWaitForComplete(notification);
 
         // check provider IDs //
 
@@ -747,7 +747,7 @@ public class NotificationsServiceIT extends 
AbstractServiceNotificationIT {
 
         // perform push //
 
-        notification = scheduleNotificationAndWait(notification);
+        notification = notificationWaitForComplete(notification);
 
                 setup.getEntityIndex().refresh(app.getId());
 
@@ -807,7 +807,7 @@ public class NotificationsServiceIT extends 
AbstractServiceNotificationIT {
         final Notification notification = (Notification) 
entity.toTypedEntity();
 
         try {
-            scheduleNotificationAndWait(notification);
+            notificationWaitForComplete(notification);
         } finally {
             listener.setBatchSize( oldBatchSize);
         }
@@ -852,7 +852,7 @@ public class NotificationsServiceIT extends 
AbstractServiceNotificationIT {
             Notification.class);
 
         // perform push //
-        notification = scheduleNotificationAndWait(notification);
+        notification = notificationWaitForComplete(notification);
         setup.getEntityIndex().refresh(app.getId());
 
         try {

http://git-wip-us.apache.org/repos/asf/usergrid/blob/741d336b/stack/services/src/test/java/org/apache/usergrid/services/notifications/gcm/MockSuccessfulProviderAdapter.java
----------------------------------------------------------------------
diff --git 
a/stack/services/src/test/java/org/apache/usergrid/services/notifications/gcm/MockSuccessfulProviderAdapter.java
 
b/stack/services/src/test/java/org/apache/usergrid/services/notifications/gcm/MockSuccessfulProviderAdapter.java
index c41e5ab..47bf538 100644
--- 
a/stack/services/src/test/java/org/apache/usergrid/services/notifications/gcm/MockSuccessfulProviderAdapter.java
+++ 
b/stack/services/src/test/java/org/apache/usergrid/services/notifications/gcm/MockSuccessfulProviderAdapter.java
@@ -18,14 +18,9 @@ package org.apache.usergrid.services.notifications.gcm;
 
 import org.apache.usergrid.persistence.entities.Notification;
 import org.apache.usergrid.persistence.entities.Notifier;
-import org.apache.usergrid.services.notifications.ConnectionException;
-import org.apache.usergrid.services.notifications.NotificationsService;
 import org.apache.usergrid.services.notifications.ProviderAdapter;
 import org.apache.usergrid.services.notifications.TaskTracker;
 
-import java.util.Date;
-import java.util.Map;
-import org.apache.usergrid.persistence.EntityManager;
 import org.apache.usergrid.services.ServicePayload;
 
 public class MockSuccessfulProviderAdapter implements ProviderAdapter {
@@ -38,7 +33,7 @@ public class MockSuccessfulProviderAdapter implements 
ProviderAdapter {
     }
 
     @Override
-    public void testConnection() throws ConnectionException {
+    public void testConnection() throws Exception {
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/usergrid/blob/741d336b/stack/services/src/test/java/org/apache/usergrid/services/notifications/gcm/NotificationsServiceIT.java
----------------------------------------------------------------------
diff --git 
a/stack/services/src/test/java/org/apache/usergrid/services/notifications/gcm/NotificationsServiceIT.java
 
b/stack/services/src/test/java/org/apache/usergrid/services/notifications/gcm/NotificationsServiceIT.java
index 282055c..52a3541 100644
--- 
a/stack/services/src/test/java/org/apache/usergrid/services/notifications/gcm/NotificationsServiceIT.java
+++ 
b/stack/services/src/test/java/org/apache/usergrid/services/notifications/gcm/NotificationsServiceIT.java
@@ -16,6 +16,8 @@
  */
 package org.apache.usergrid.services.notifications.gcm;
 
+import com.google.android.gcm.server.Constants;
+import com.google.android.gcm.server.InvalidRequestException;
 import org.apache.usergrid.persistence.*;
 import org.apache.usergrid.persistence.entities.*;
 import org.apache.usergrid.services.notifications.*;
@@ -41,7 +43,7 @@ public class NotificationsServiceIT extends 
AbstractServiceNotificationIT {
      * set to true to run tests against actual GCM servers - but they may not
      * all run correctly
      */
-    private static final boolean USE_REAL_CONNECTIONS = false;
+    private static final boolean USE_REAL_CONNECTIONS = true;
     private static final String PROVIDER = USE_REAL_CONNECTIONS ? "google" : 
"noop";
 
     private static final String API_KEY = 
"AIzaSyCIH_7WC0mOqBGMOXyQnFgrBpOePgHvQJM";
@@ -137,12 +139,11 @@ public class NotificationsServiceIT extends 
AbstractServiceNotificationIT {
                 Notification.class);
 
         // perform push //
-        notification = scheduleNotificationAndWait(notification);
+        notification = notificationWaitForComplete(notification);
         checkReceipts(notification, 0);
     }
 
     @Test
-    @Ignore("Pending https://issues.apache.org/jira/browse/USERGRID-1113. ")
     public void singlePushNotification() throws Exception {
 
         app.clear();
@@ -163,12 +164,91 @@ public class NotificationsServiceIT extends 
AbstractServiceNotificationIT {
                 payload);
 
         // perform push //
-        notification = scheduleNotificationAndWait(notification);
+        notification = notificationWaitForComplete(notification);
+        checkReceipts(notification, 1);
+    }
+
+
+    @Test
+    public void singlePushNotificationHighPriority() throws Exception {
+
+        app.clear();
+        String payload = "Hello, World!";
+        Map<String, String> payloads = new HashMap<String, String>(1);
+        payloads.put(notifier.getUuid().toString(), payload);
+        app.put("payloads", payloads);
+        app.put("queued", System.currentTimeMillis());
+        app.put("debug",true);
+        app.put("expire", System.currentTimeMillis() + 300000); // add 5 
minutes to current time
+        app.put("priority", "high");
+
+        Entity e = app.testRequest(ServiceAction.POST, 1, 
"devices",device1.getUuid(),"notifications").getEntity();
+        app.testRequest(ServiceAction.GET, 1, "notifications", e.getUuid());
+
+        Notification notification = app.getEntityManager().get(e.getUuid(), 
Notification.class);
+        assertEquals(
+            notification.getPayloads().get(notifier.getUuid().toString()),
+            payload);
+
+        // perform push //
+        notification = notificationWaitForComplete(notification);
+        assertEquals("high", notification.getPriority());
+        checkReceipts(notification, 1);
+    }
+
+    @Test
+    public void singlePushNotificationWithInvalidPriority() throws Exception {
+
+        app.clear();
+        String payload = "Hello, World!";
+        Map<String, String> payloads = new HashMap<String, String>(1);
+        payloads.put(notifier.getUuid().toString(), payload);
+        app.put("payloads", payloads);
+        app.put("queued", System.currentTimeMillis());
+        app.put("debug",true);
+        app.put("expire", System.currentTimeMillis() + 300000); // add 5 
minutes to current time
+        app.put("priority", "not_a_priority");
+
+        Entity e = app.testRequest(ServiceAction.POST, 1, 
"devices",device1.getUuid(),"notifications").getEntity();
+        app.testRequest(ServiceAction.GET, 1, "notifications", e.getUuid());
+
+        Notification notification = app.getEntityManager().get(e.getUuid(), 
Notification.class);
+        assertEquals(
+            notification.getPayloads().get(notifier.getUuid().toString()),
+            payload);
+
+        // perform push //
+        notification = notificationWaitForComplete(notification);
+        assertEquals("high", notification.getPriority());
+        checkReceipts(notification, 1);
+    }
+
+    @Test
+    public void singlePushNotificationMultipleDevices() throws Exception {
+
+        app.clear();
+        String payload = "Hello, World!";
+        Map<String, String> payloads = new HashMap<String, String>(1);
+        payloads.put(notifier.getUuid().toString(), payload);
+        app.put("payloads", payloads);
+        app.put("queued", System.currentTimeMillis());
+        app.put("debug",true);
+        app.put("expire", System.currentTimeMillis() + 300000); // add 5 
minutes to current time
+
+        Entity e = app.testRequest(ServiceAction.POST, 1, 
"devices","*","notifications").getEntity();
+        app.testRequest(ServiceAction.GET, 1, "notifications", e.getUuid());
+
+        Notification notification = app.getEntityManager().get(e.getUuid(), 
Notification.class);
+        assertEquals(
+            notification.getPayloads().get(notifier.getUuid().toString()),
+            payload);
+
+        // perform push //
+        notification = notificationWaitForComplete(notification);
         checkReceipts(notification, 2);
     }
 
     @Test
-    @Ignore("Pending https://issues.apache.org/jira/browse/USERGRID-1113. ")
     public void singlePushNotificationViaUser() throws Exception {
 
         app.clear();
@@ -193,13 +273,10 @@ public class NotificationsServiceIT extends 
AbstractServiceNotificationIT {
         Entity e = app.testRequest(ServiceAction.POST, 
1,"users",user.getUuid(), "notifications").getEntity();
         app.testRequest(ServiceAction.GET, 1, "notifications", e.getUuid());
 
-        setup.getEntityIndex().refresh(app.getId());
 
         // perform push //
         Notification notification = app.getEntityManager().get(e.getUuid(), 
Notification.class);
-        notification = scheduleNotificationAndWait(notification);
-
-        setup.getEntityIndex().refresh(app.getId());
+        notification = notificationWaitForComplete(notification);
 
         checkReceipts(notification, 1);
     }
@@ -231,7 +308,7 @@ public class NotificationsServiceIT extends 
AbstractServiceNotificationIT {
             field.setInt(GCMAdapter.class, 1);
 
             // perform push //
-            notification = scheduleNotificationAndWait(notification);
+            notification = notificationWaitForComplete(notification);
 
             checkReceipts(notification, 2);
         } finally {
@@ -303,13 +380,15 @@ public class NotificationsServiceIT extends 
AbstractServiceNotificationIT {
         }
     }
 
-    @Ignore("Pending https://issues.apache.org/jira/browse/USERGRID-1113. 
todo: how can I mock this?")
     @Test
     public void badToken() throws Exception {
 
+        // create device w/ bad token
+        app.put(notifier.getName() + NOTIFIER_ID_POSTFIX, PUSH_TOKEN + "x");
+        Entity badDeviceEntity = app.testRequest(ServiceAction.POST, 1, 
"devices").getEntity();
+        Device badDevice = 
app.getEntityManager().get(badDeviceEntity.getUuid(), Device.class);
 
-        // create push notification //
-
+        // create notification payload
         app.clear();
         String payload = "Hello, World!";
         Map<String, String> payloads = new HashMap<String, String>(1);
@@ -318,40 +397,63 @@ public class NotificationsServiceIT extends 
AbstractServiceNotificationIT {
         app.put("queued", System.currentTimeMillis());
         app.put("debug",true);
 
-        Entity e = app.testRequest(ServiceAction.POST, 1, 
"devices",device1.getUuid(),"notifications")
-                .getEntity();
-        app.testRequest(ServiceAction.GET, 1, "notifications", e.getUuid());
+        // create push notification
+        Entity e = app.testRequest(ServiceAction.POST, 1, 
"devices",badDevice.getUuid(),"notifications")
+            .getEntity();
 
-        Notification notification = app.getEntityManager().get(e.getUuid(),
-                Notification.class);
+        // validate notification  was created successfully
+        app.testRequest(ServiceAction.GET, 1, "notifications", e.getUuid());
+        Notification notification = app.getEntityManager().get(e.getUuid(), 
Notification.class);
         assertEquals(
-                notification.getPayloads().get(notifier.getUuid().toString()),
-                payload);
-
-        // device w/ bad token
-        app.clear();
-        app.put(notifier.getName() + NOTIFIER_ID_POSTFIX, PUSH_TOKEN + "x");
+            notification.getPayloads().get(notifier.getUuid().toString()),
+            payload);
 
-        e = app.testRequest(ServiceAction.POST, 1, "devices").getEntity();
-        device1 = app.getEntityManager().get(e.getUuid(), Device.class);
-
-        ns.addDevice(notification, device1);
-
-        // perform push //
-        notification = scheduleNotificationAndWait(notification);
+        // wait for notification to be marked finished
+        notification = notificationWaitForComplete(notification);
 
+        // get the receipts entity IDs
         List<EntityRef> receipts = getNotificationReceipts(notification);
         assertEquals(1, receipts.size());
+
+        // Validate the error is the correct type InvalidRegistration
         Receipt receipt = app.getEntityManager().get(receipts.get(0), 
Receipt.class);
         assertEquals("InvalidRegistration", receipt.getErrorCode());
     }
 
-    @Ignore("Pending https://issues.apache.org/jira/browse/USERGRID-1113. 
todo: how can I mock this?")
     @Test
-    public void badAPIKey() throws Exception {
+    public void createGoogleNotifierWithBadAPIKey() throws Exception {
+
+        final String badKey = API_KEY+"bad";
+
+        // create notifier with bad API key
+        app.clear();
+        app.put("name", "gcm_bad_key");
+        app.put("provider", PROVIDER);
+        app.put("environment", "development");
+        app.put("apiKey", badKey);
+
+        try{
+            notifier = (Notifier) app
+                .testRequest(ServiceAction.POST, 1, "notifiers").getEntity()
+                .toTypedEntity();
+        }catch(InvalidRequestException e){
+            assertEquals(Constants.ERROR_INVALID_REGISTRATION, 
e.getDescription());
+        }
+
+    }
+
+    @Test
+    public void sendNotificationWithBadAPIKey() throws Exception{
+        final String badKey = API_KEY+"bad";
 
-        // create push notification //
+        // update an existing notifier with a bad API key
+        app.clear();
+        app.put("apiKey", badKey);
+        notifier = (Notifier) app
+            .testRequest(ServiceAction.PUT, 1, 
"notifiers",notifier.getUuid()).getEntity()
+            .toTypedEntity();
 
+        // create notification payload
         app.clear();
         String payload = "Hello, World!";
         Map<String, String> payloads = new HashMap<String, String>(1);
@@ -360,25 +462,30 @@ public class NotificationsServiceIT extends 
AbstractServiceNotificationIT {
         app.put("queued", System.currentTimeMillis());
         app.put("debug",true);
 
+        // create notification
         Entity e = app.testRequest(ServiceAction.POST, 
1,"devices",device1.getUuid(), "notifications")
                 .getEntity();
-        app.testRequest(ServiceAction.GET, 1, "notifications", e.getUuid());
 
-        Notification notification = app.getEntityManager().get(e.getUuid(),
-                Notification.class);
+
+        // validate notification  was created successfully
+        app.testRequest(ServiceAction.GET, 1, "notifications", e.getUuid());
+        Notification notification = app.getEntityManager().get(e.getUuid(), 
Notification.class);
         assertEquals(
-                notification.getPayloads().get(notifier.getUuid().toString()),
-                payload);
+            notification.getPayloads().get(notifier.getUuid().toString()),
+            payload);
 
-        ns.addDevice(notification, device1);
+        // wait for notification to be marked finished and retrieve it back
+        notification = notificationWaitForComplete(notification);
+        app.testRequest(ServiceAction.GET, 1, "notifications", e.getUuid());
 
-        // save bad API key
-        app.getEntityManager().setProperty(notifier, "apiKey", API_KEY + "x");
+        // get the receipts entity IDs
+        List<EntityRef> receipts = getNotificationReceipts(notification);
+        assertEquals(1, receipts.size());
 
-        // perform push //
+        // Validate the error is the correct type InvalidRegistration
+        Receipt receipt = app.getEntityManager().get(receipts.get(0), 
Receipt.class);
+        assertEquals("InvalidRegistration", receipt.getErrorCode());
 
-        // ns.getQueueManager().processBatchAndReschedule(notification, null);
-        fail("Should have received a ConnectionException");
     }
 
 }

http://git-wip-us.apache.org/repos/asf/usergrid/blob/741d336b/stack/services/src/test/java/org/apache/usergrid/services/notifications/wns/WNSAdapterTest.java
----------------------------------------------------------------------
diff --git 
a/stack/services/src/test/java/org/apache/usergrid/services/notifications/wns/WNSAdapterTest.java
 
b/stack/services/src/test/java/org/apache/usergrid/services/notifications/wns/WNSAdapterTest.java
index 35f3180..07886e4 100644
--- 
a/stack/services/src/test/java/org/apache/usergrid/services/notifications/wns/WNSAdapterTest.java
+++ 
b/stack/services/src/test/java/org/apache/usergrid/services/notifications/wns/WNSAdapterTest.java
@@ -19,16 +19,11 @@
  */
 package org.apache.usergrid.services.notifications.wns;
 
-import org.apache.usergrid.corepersistence.util.CpNamingUtils;
-import org.apache.usergrid.management.OrganizationInfo;
-import org.apache.usergrid.management.OrganizationOwnerInfo;
 import org.apache.usergrid.persistence.EntityManager;
 import org.apache.usergrid.persistence.entities.Notifier;
 import org.apache.usergrid.services.AbstractServiceIT;
 import org.junit.Test;
 
-import java.util.UUID;
-
 /**
  * test windows phone.
  */

Reply via email to