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. */
