You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@usergrid.apache.org by to...@apache.org on 2014/09/29 22:52:55 UTC

[16/52] [abbrv] git commit: Improvements to tests only in Rest and QueryIndex modules.

Improvements to tests only in Rest and QueryIndex modules.


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

Branch: refs/heads/eventsystem
Commit: b01b2a70ba73892aac5445152ccc65a837ed555d
Parents: 824ec55
Author: Dave Johnson <dm...@apigee.com>
Authored: Thu Sep 25 10:48:15 2014 -0400
Committer: Dave Johnson <dm...@apigee.com>
Committed: Thu Sep 25 10:48:15 2014 -0400

----------------------------------------------------------------------
 .../index/impl/ElasticSearchTest.java           | 274 -------------------
 .../impl/EntityConnectionIndexImplTest.java     |   2 -
 .../index/impl/EntityIndexMapUtils.java         |  12 +-
 .../persistence/index/impl/EntityIndexTest.java |  77 +++++-
 .../apache/usergrid/rest/AbstractRestIT.java    |   6 +-
 .../apache/usergrid/rest/NotificationsIT.java   | 162 +++++++----
 .../collection/PagingResourceIT.java            |  20 +-
 7 files changed, 209 insertions(+), 344 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/b01b2a70/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/ElasticSearchTest.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/ElasticSearchTest.java b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/ElasticSearchTest.java
deleted file mode 100644
index 5019b18..0000000
--- a/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/ElasticSearchTest.java
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.usergrid.persistence.index.impl;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.elasticsearch.ElasticsearchException;
-import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse;
-import org.elasticsearch.action.get.GetResponse;
-import org.elasticsearch.action.index.IndexResponse;
-import org.elasticsearch.action.search.SearchResponse;
-import org.elasticsearch.client.AdminClient;
-import org.elasticsearch.client.Client;
-import org.elasticsearch.common.xcontent.XContentBuilder;
-import org.elasticsearch.index.query.QueryBuilder;
-import org.elasticsearch.index.query.QueryBuilders;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.apache.commons.lang3.RandomStringUtils;
-
-import org.apache.usergrid.persistence.core.cassandra.CassandraRule;
-
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-
-/**
- * Elastic search experiments in the form of a test.
- */
-public class ElasticSearchTest extends BaseIT {
-    private static final Logger log = LoggerFactory.getLogger( ElasticSearchTest.class );
-
-    @ClassRule
-    public static ElasticSearchRule es = new ElasticSearchRule();
-
-    @ClassRule
-    public static CassandraRule cass = new CassandraRule();
-    
-    @Test 
-    public void testSimpleCrud() {
-
-        String indexName = RandomStringUtils.randomAlphanumeric(20 ).toLowerCase();
-        String collectionName = "testtype1";
-        String id = RandomStringUtils.randomAlphanumeric(20 );
-
-        Client client = es.getClient();
-
-        Map<String, Object> json = new HashMap<String, Object>();
-        json.put( "user", "edward" );
-        json.put( "postDate", new Date() );
-        json.put( "message", "who knows if the moon's a baloon" );
-
-
-        // create
-        IndexResponse indexResponse = client.prepareIndex(indexName, collectionName, id)
-                .setSource( json ).execute().actionGet();
-        assertTrue( indexResponse.isCreated() );
-
-        // retrieve
-        GetResponse getResponse = client.prepareGet( indexName, collectionName, id).get();
-        assertEquals( "edward", getResponse.getSource().get( "user" ) );
-
-        // update
-        json.put( "message", "If freckles were lovely, and day was night");
-        client.prepareUpdate( indexName, collectionName, id).setDoc( json ).execute().actionGet();
-        getResponse = client.prepareGet( indexName, collectionName, id).get();
-        assertEquals("If freckles were lovely, and day was night", 
-            getResponse.getSource().get( "message" ) );
-
-        // update via script
-//        client.prepareUpdate( indexName, collectionName, id)
-//            .setScript( "ctx._source.message = \"coming out of a keen city in the sky\"" )
-//            .execute().actionGet();
-//        getResponse = client.prepareGet( indexName, collectionName, id).get();
-//        assertEquals("coming out of a keen city in the sky", 
-//            getResponse.getSource().get( "message" ) );
-
-        // delete
-        client.prepareDelete(indexName, collectionName, id).execute().actionGet();
-        getResponse = client.prepareGet( indexName, collectionName, id).get();
-        assertFalse( getResponse.isExists() );
-    } 
-
-
-    @Test
-    public void testStringDoubleIndexDynamicMapping() throws IOException {
-
-        Client client = es.getClient();
-
-        AdminClient admin = client.admin();
-
-        String index = RandomStringUtils.randomAlphanumeric(20).toLowerCase();
-        String type = "testtype";
-        admin.indices().prepareCreate( index ).execute().actionGet();
-
-        // add dynamic string-double index mapping
-        XContentBuilder mxcb = EsEntityIndexImpl
-            .createDoubleStringIndexMapping( jsonBuilder(), type );
-        PutMappingResponse pmr = admin.indices().preparePutMapping(index)
-            .setType( type ).setSource( mxcb ).execute().actionGet();
-
-        indexSampleData( type, client, index );
-
-        testQuery( client, index, type, 
-            QueryBuilders.termQuery( "name", "Orr Byers"), 1 );
-
-        testQuery( client, index, type, 
-            QueryBuilders.termQuery( "name", "orr byers" ), 0 );
-
-        // term query is exact match
-        testQuery( client, index, type, 
-            QueryBuilders.termQuery("name", "Byers" ), 0 );
-
-        // match query allows partial match 
-        testQuery( client, index, type, 
-            QueryBuilders.matchQuery( "name_ug_analyzed", "Byers" ), 1 );
-
-        testQuery( client, index, type, 
-            QueryBuilders.termQuery( "company", "Geologix" ), 1 );
-
-        testQuery( client, index, type, 
-            QueryBuilders.rangeQuery("company").gt( "Geologix" ), 2 );
-
-        testQuery( client, index, type, 
-            QueryBuilders.termQuery( "gender", "female" ), 3 );
-
-        // query of nested object fields supported
-        testQuery( client, index, type, 
-            QueryBuilders.termQuery( "contact.email", "orrbyers@bittor.com" ), 1 );
-
-    }
-
-    
-    private void indexSampleData( String type, Client client, String index ) 
-            throws ElasticsearchException, IOException {
-        
-        InputStream is = this.getClass().getResourceAsStream( "/sample-small.json" );
-        ObjectMapper mapper = new ObjectMapper();
-        List<Object> contacts = mapper.readValue( is, new TypeReference<List<Object>>() {} );
-
-        for ( Object o : contacts ) {
-            Map<String, Object> item = (Map<String, Object>)o;
-            String id = item.get( "id" ).toString();
-
-            XContentBuilder dxcb = ElasticSearchTest
-                .prepareContentForIndexing( jsonBuilder(), type, item );
-
-            IndexResponse ir = client.prepareIndex(index, type, id )
-                .setSource( dxcb ).setRefresh( true ).execute().actionGet();
-        }
-    }
-
-    
-    private void testQuery( Client client, String index, String type, QueryBuilder qb, int num ) {
-        SearchResponse sr = client.prepareSearch( index ).setTypes( type )
-            .setQuery( qb ).setFrom( 0 ).setSize( 20 ).execute().actionGet();
-        assertEquals( num, sr.getHits().getTotalHits() );
-    }
-
-    
-   public static XContentBuilder prepareContentForIndexing( String name, XContentBuilder builder, 
-        String type, Map<String, Object> data ) throws IOException {
-
-        if ( name != null ) {
-            builder = builder.startObject( name );
-        } else {
-            builder = builder.startObject();
-        }
-        for ( String key : data.keySet() ) {
-            Object value = data.get( key );
-            try {
-
-                if ( value instanceof Map ) {
-                    builder = prepareContentForIndexing(
-                        key, builder, type, (Map<String, Object>)data.get(key));
-
-                } else if ( value instanceof List ) {
-                    builder = prepareContentForIndexing(key, builder, type, (List)value);
-
-                } else if ( value instanceof String ) {
-                    builder = builder
-                        .field( key + "_ug_analyzed", value )
-                        .field( key, value );
-
-                } else {
-                    builder = builder
-                        .field( key, value );
-
-                }
-            } catch ( Exception e ) {
-                log.error( "Error processing {} : {}", key, value );
-                throw new RuntimeException(e);
-            }
-        }
-        builder = builder.endObject();
-        return builder;
-    }
-    
-   
-    public static XContentBuilder prepareContentForIndexing( XContentBuilder builder, 
-        String type, Map<String, Object> dataMap ) throws IOException {
-        return prepareContentForIndexing( null, builder, type, dataMap );
-    }
-
-    
-    public static XContentBuilder prepareContentForIndexing( String name, XContentBuilder builder, 
-        String type, List dataList ) throws IOException {
-
-        if ( name != null ) {
-            builder = builder.startArray( name );
-        } else {
-            builder = builder.startArray();
-        }
-        for ( Object o : dataList ) {
-
-            if ( o instanceof Map ) {
-                builder = prepareContentForIndexing( builder, type, (Map<String, Object>)o );
-
-            } else if ( o instanceof List ) {
-                builder = prepareContentForIndexing( builder, type, (List)o);
-
-            } else {
-                builder = builder.value( o );
-
-            }
-        }
-        builder = builder.endArray();
-        return builder;
-    }
-
-
-    public static XContentBuilder prepareContentForIndexing( XContentBuilder builder, 
-        String type, List dataList ) throws IOException {
-        return prepareContentForIndexing( null, builder, type, dataList );
-    }
-
-    void log( GetResponse getResponse ) {
-        log.info( "-------------------------------------------------------------------------" );
-        log.info( "id:      " + getResponse.getId() );
-        log.info( "type:    " + getResponse.getType() );
-        log.info( "version: " + getResponse.getVersion() );
-        log.info( "index:   " + getResponse.getIndex() );
-        log.info( "source:  " + getResponse.getSourceAsString() );
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/b01b2a70/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityConnectionIndexImplTest.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityConnectionIndexImplTest.java b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityConnectionIndexImplTest.java
index 529ee0d..f8df2a2 100644
--- a/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityConnectionIndexImplTest.java
+++ b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityConnectionIndexImplTest.java
@@ -71,8 +71,6 @@ public class EntityConnectionIndexImplTest extends BaseIT {
     @Inject
     public EntityIndexFactory ecif;
 
-
-
     @Test
     public void testBasicOperation() throws IOException {
 

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/b01b2a70/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityIndexMapUtils.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityIndexMapUtils.java b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityIndexMapUtils.java
index 261809c..71f5e91 100644
--- a/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityIndexMapUtils.java
+++ b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityIndexMapUtils.java
@@ -51,10 +51,10 @@ import org.apache.usergrid.persistence.model.field.value.Location;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 
-import static org.apache.usergrid.persistence.index.impl.EsEntityIndexImpl.ANALYZED_SUFFIX;
-import static org.apache.usergrid.persistence.index.impl.EsEntityIndexImpl.GEO_SUFFIX;
-
 
+/**
+ * Test utility for creating entities from maps and vice versa.
+ */
 class EntityIndexMapUtils {
 
     static ObjectMapper objectMapper = new ObjectMapper(  );
@@ -239,10 +239,6 @@ class EntityIndexMapUtils {
                 EntityObject eo = (EntityObject) field.getValue();
                 entityMap.put(field.getName(), toMap(eo)); // recursion
 
-            } else if (f instanceof StringField) {
-                entityMap.put(field.getName(), ((String) field.getValue()).toLowerCase());
-                entityMap.put(field.getName() + ANALYZED_SUFFIX, field.getValue());
-
             } else if (f instanceof LocationField) {
                 LocationField locField = (LocationField) f;
                 Map<String, Object> locMap = new HashMap<String, Object>();
@@ -250,7 +246,7 @@ class EntityIndexMapUtils {
                 // field names lat and lon trigger ElasticSearch geo location 
                 locMap.put("lat", locField.getValue().getLatitude());
                 locMap.put("lon", locField.getValue().getLongtitude());
-                entityMap.put(field.getName() + GEO_SUFFIX, locMap);
+                entityMap.put( field.getName(), locMap);
 
             } else if (f instanceof ByteArrayField) {
                 ByteArrayField ba = ( ByteArrayField ) f;

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/b01b2a70/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityIndexTest.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityIndexTest.java b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityIndexTest.java
index 5d3e50c..d4b8d5b 100644
--- a/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityIndexTest.java
+++ b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityIndexTest.java
@@ -58,6 +58,7 @@ import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.common.collect.Maps;
 import com.google.inject.Inject;
+import java.util.ArrayList;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -225,8 +226,11 @@ public class EntityIndexTest extends BaseIT {
     }
 
 
+    /**
+     * Tests that Entity-to-map and Map-to-entity round trip works.
+     */
     @Test
-    public void testEntityToMap() throws IOException {
+    public void testEntityIndexMapUtils() throws IOException {
 
         InputStream is = this.getClass().getResourceAsStream( "/sample-small.json" );
         ObjectMapper mapper = new ObjectMapper();
@@ -237,15 +241,14 @@ public class EntityIndexTest extends BaseIT {
             Map<String, Object> map1 = ( Map<String, Object> ) o;
 
             // convert map to entity
-
             Entity entity1 = EntityIndexMapUtils.fromMap( map1 );
 
             // convert entity back to map
             Map map2 = EntityIndexMapUtils.toMap( entity1 );
 
-            // the two maps should be the same except for six new system properties
+            // the two maps should be the same 
             Map diff = Maps.difference( map1, map2 ).entriesDiffering();
-            assertEquals( 6, diff.size() );
+            assertEquals( 0, diff.size() );
         }
     }
 
@@ -325,7 +328,6 @@ public class EntityIndexTest extends BaseIT {
         Query query = new Query();
         query.addEqualityFilter( "username", "edanuff" );
         CandidateResults r = ei.search( query );
-
         assertEquals( user.getId(), r.get( 0 ).getId() );
 
         ei.deindex( user.getId(), user.getVersion() );
@@ -339,6 +341,71 @@ public class EntityIndexTest extends BaseIT {
 
         assertFalse( r.iterator().hasNext() );
     }
+
+    @Test 
+    public void multiValuedTypes() {
+
+        Id appId = new SimpleId( "entityindextest" );
+        Id ownerId = new SimpleId( "multivaluedtype" );
+        IndexScope appScope = new IndexScopeImpl( appId, ownerId, "user" );
+
+        EntityIndex ei = cif.createEntityIndex( appScope );
+
+        // Bill has favorites as string, age as string and retirement goal as number
+        Map billMap = new HashMap() {{
+            put( "username", "bill" );
+            put( "email", "bill@example.com" );
+            put( "age", "thirtysomething");
+            put( "favorites", "scallops, croquet, wine");
+            put( "retirementGoal", 100000);
+        }};
+        Entity bill = EntityIndexMapUtils.fromMap( billMap );
+        EntityUtils.setId( bill, new SimpleId( UUIDGenerator.newTimeUUID(), "user"  ) );
+        EntityUtils.setVersion( bill, UUIDGenerator.newTimeUUID() );
+        ei.index( bill );
+
+        // Fred has age as int, favorites as object and retirement goal as object
+        Map fredMap = new HashMap() {{
+            put( "username", "fred" );
+            put( "email", "fred@example.com" );
+            put( "age", 41 );
+            put( "favorites", new HashMap<String, Object>() {{
+                put("food", "cheezewiz"); 
+                put("sport", "nascar"); 
+                put("beer", "budwizer"); 
+            }});
+            put( "retirementGoal", new HashMap<String, Object>() {{
+                put("car", "Firebird"); 
+                put("home", "Mobile"); 
+            }});
+        }};
+        Entity fred = EntityIndexMapUtils.fromMap( fredMap );
+        EntityUtils.setId( fred, new SimpleId( UUIDGenerator.newTimeUUID(), "user"  ) );
+        EntityUtils.setVersion( fred, UUIDGenerator.newTimeUUID() );
+        ei.index( fred );
+
+        ei.refresh();
+
+        Query query = new Query();
+        query.addEqualityFilter( "username", "bill" );
+        CandidateResults r = ei.search( query );
+        assertEquals( bill.getId(), r.get( 0 ).getId() );
+
+        query = new Query();
+        query.addEqualityFilter( "username", "fred" );
+        r = ei.search( query );
+        assertEquals( fred.getId(), r.get( 0 ).getId() );
+
+        query = new Query();
+        query.addEqualityFilter( "age", 41 );
+        r = ei.search( query );
+        assertEquals( fred.getId(), r.get( 0 ).getId() );
+
+        query = new Query();
+        query.addEqualityFilter( "age", "thirtysomething" );
+        r = ei.search( query );
+        assertEquals( bill.getId(), r.get( 0 ).getId() );
+    }
 }
 
 

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/b01b2a70/stack/rest/src/test/java/org/apache/usergrid/rest/AbstractRestIT.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/AbstractRestIT.java b/stack/rest/src/test/java/org/apache/usergrid/rest/AbstractRestIT.java
index 66f377a..e835c33 100644
--- a/stack/rest/src/test/java/org/apache/usergrid/rest/AbstractRestIT.java
+++ b/stack/rest/src/test/java/org/apache/usergrid/rest/AbstractRestIT.java
@@ -166,7 +166,8 @@ public abstract class AbstractRestIT extends JerseyTest {
         client = new Client( "test-organization", "test-app" ).withApiUrl(
                 UriBuilder.fromUri( "http://localhost/" ).port( setup.getTomcatPort() ).build().toString() );
 
-        org.apache.usergrid.java.client.response.ApiResponse response = client.authorizeAppUser( "ed@anuff.com", "sesame" );
+        org.apache.usergrid.java.client.response.ApiResponse response = 
+                client.authorizeAppUser( "ed@anuff.com", "sesame" );
 
         assertTrue( response != null && response.getError() == null );
     }
@@ -257,7 +258,8 @@ public abstract class AbstractRestIT extends JerseyTest {
         adminToken();
 
         // change the password as admin. The old password isn't required
-        JsonNode node = mapper.readTree( resource().path( String.format( "/test-organization/test-app/users/%s/password", username ) )
+        JsonNode node = mapper.readTree( resource().path( 
+                String.format( "/test-organization/test-app/users/%s/password", username ) )
                 .queryParam( "access_token", adminAccessToken ).accept( MediaType.APPLICATION_JSON )
                 .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class, data ));
 

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/b01b2a70/stack/rest/src/test/java/org/apache/usergrid/rest/NotificationsIT.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/NotificationsIT.java b/stack/rest/src/test/java/org/apache/usergrid/rest/NotificationsIT.java
index cdc3755..b3af838 100644
--- a/stack/rest/src/test/java/org/apache/usergrid/rest/NotificationsIT.java
+++ b/stack/rest/src/test/java/org/apache/usergrid/rest/NotificationsIT.java
@@ -15,34 +15,70 @@
  */
 package org.apache.usergrid.rest;
 
+import com.codahale.metrics.Meter;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.Slf4jReporter;
 import com.fasterxml.jackson.databind.JsonNode;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 import javax.ws.rs.core.MediaType;
 import org.apache.commons.lang3.time.StopWatch;
+import org.junit.After;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import org.junit.Before;
 import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+
 /**
- * Test Notification end-points.
+ * Test creating, sending and paging through Notifications via the REST API. 
  */
 public class NotificationsIT extends AbstractRestIT {
     private static final Logger logger = LoggerFactory.getLogger( NotificationsIT.class );
-  
+
+    private static final MetricRegistry registry = new MetricRegistry();
+
+    final String org = "test-organization";
+    final String app = "test-app";
+    final String orgapp = org + "/" + app;
+    String token;
+
+    private static final long writeDelayMs = 15;
+    private static final long readDelayMs = 15;
+
+    private Slf4jReporter reporter;
+
+    @Before
+    public void startReporting() {
+
+        reporter = Slf4jReporter.forRegistry( registry ).outputTo( logger )
+                .convertRatesTo( TimeUnit.SECONDS )
+                .convertDurationsTo( TimeUnit.MILLISECONDS ).build();
+
+        reporter.start( 10, TimeUnit.SECONDS );
+    }
+
+
+    @After
+    public void printReport() {
+        reporter.report();
+        reporter.stop();
+    }
+
+
     @Test
-    public void testBasicOperation() throws Exception {
+    public void testPaging() throws Exception {
 
         int numDevices = 10;
         int numNotifications = 100; // to send to each device
 
-        String token = userToken( "ed@anuff.com", "sesame" );
-        String org = "test-organization";
-        String app = "test-app";
-        String orgapp = org + "/" + app;
+        token = userToken( "ed@anuff.com", "sesame" );
 
         // create notifier
         Map<String, Object> notifier = new HashMap<String, Object>() {{
@@ -54,14 +90,12 @@ public class NotificationsIT extends AbstractRestIT {
             .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON )
             .post(String.class, notifier ) );
 
-        logger.debug("Notifier is: " + notifierNode.toString());
+        //logger.debug("Notifier is: " + notifierNode.toString());
         assertEquals( "noop", notifierNode.withArray("entities").get(0).get("provider").asText()); 
         
         refreshIndex( org, app );
 
         // create devices
-        StopWatch sw = new StopWatch();
-        sw.start();
         int devicesCount = 0;
         List<String> deviceIds = new ArrayList();
         for (int i=0; i<numDevices; i++) {
@@ -81,24 +115,22 @@ public class NotificationsIT extends AbstractRestIT {
                 .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON )
                 .post(String.class, device ) );
 
-            logger.debug("Device is: " + deviceNode.toString());
+            //logger.debug("Device is: " + deviceNode.toString());
             assertEquals( "device"+i, deviceNode.withArray("entities").get(0).get("name").asText()); 
 
             deviceIds.add(deviceNode.withArray("entities").get(0).get("uuid").asText());
             devicesCount++;
         }
-        sw.stop();
-        logger.info("Created {} devices in {}ms", devicesCount, sw.getTime());
 
         refreshIndex( org, app );
 
-        StopWatch allSw = new StopWatch();
-        allSw.start();
+        String postMeterName = getClass().getSimpleName() + ".postNotifications";
+        Meter postMeter = registry.meter( postMeterName );
 
         // send notifications 
-        sw.reset();
-        sw.start();
         int notificationCount = 0;
+        List<String> notificationUuids = new ArrayList<String>();
+
         for (int i=0; i<numNotifications; i++) {
 
             // send a notificaton to each device
@@ -116,66 +148,92 @@ public class NotificationsIT extends AbstractRestIT {
                     .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON )
                     .post( String.class, notification ) );
 
-                logger.debug("Notification is: " + notificationNode.toString());
+                postMeter.mark();
+
+                Thread.sleep( writeDelayMs );
+
+                //logger.debug("Notification is: " + notificationNode.toString());
+                notificationUuids.add( notificationNode.withArray("entities").get(0).get("uuid").asText());
             }
+
             notificationCount++;
+
+            if ( notificationCount % 100 == 0 ) {
+                logger.debug("Created {} notifications", notificationCount);
+            }
         }
-        sw.stop();
-        logger.info("Created {} notifications in {}ms", notificationCount, sw.getTime());
-        logger.info("Post Notification throughput = {} TPS", 
-                ((float)notificationCount) / (sw.getTime()/1000));
+        registry.remove( postMeterName );
 
         refreshIndex( org, app );
 
         logger.info("Waiting for all notifications to be sent");
-        sw.reset();
+        StopWatch sw = new StopWatch();
         sw.start();
         boolean allSent = false;
         while (!allSent) {
 
-            Thread.sleep(1000); 
+            Thread.sleep(100);
+            int finished = pageThroughAllNotifications("FINISHED");
+            if ( finished == (numDevices * numNotifications) ) {
+                allSent = true;
+            }
+        }
+        sw.stop();
+        int nc = numDevices * numNotifications; 
+        logger.info("Processed {} notifications in {}ms", nc, sw.getTime());
+        logger.info("Processing Notifications throughput = {} TPS", ((float)nc) / (sw.getTime()/1000));
+
+        logger.info( "Successfully Paged through {} notifications", 
+            pageThroughAllNotifications("FINISHED"));
+    }
+
+
+    private int pageThroughAllNotifications( String state ) throws IOException, InterruptedException {
 
-            JsonNode finishedNode = mapper.readTree( resource().path(orgapp + "/notifications")
-                .queryParam("ql", "select * where state='FINISHED'")
+        JsonNode initialNode = mapper.readTree( resource().path(orgapp + "/notifications")
+                .queryParam("ql", "select * where state='" + state + "'")
                 .queryParam("access_token", token)
                 .accept(MediaType.APPLICATION_JSON)
                 .get(String.class));
 
-            int finished = finishedNode.get("count").asInt();
-            if ( finishedNode.get("cursor") != null ) {
-                String cursor = finishedNode.get("cursor").asText();
-                while ( cursor != null ) {
+        int count = initialNode.get("count").asInt();
 
-                    JsonNode moreNode = mapper.readTree( resource().path(orgapp + "/notifications")
-                        .queryParam("ql", "select * where state='FINISHED'")
+        if (initialNode.get("cursor") != null) {
+
+            String cursor = initialNode.get("cursor").asText();
+           
+            // since we have a cursor, we should have gotten the limit, which defaults to 10 
+            // or we should get back 0 which indicates no more data
+            assertTrue( count == 10 || count == 0 );
+
+            while (cursor != null) {
+
+                JsonNode anotherNode = mapper.readTree(resource().path(orgapp + "/notifications")
+                        .queryParam("ql", "select * where state='" + state + "'")
                         .queryParam("access_token", token)
                         .queryParam("cursor", cursor)
                         .accept(MediaType.APPLICATION_JSON)
                         .get(String.class));
 
-                    int returnCount = moreNode.get("count").asInt(); 
+                int returnCount = anotherNode.get("count").asInt();
 
-                    // if there is a cursor then we should have gotten the limit, i.e. 10
-                    //assertEquals( 10, returnCount );
-        
-                    finished += returnCount;
-
-                    if ( moreNode.get("cursor") != null ) {
-                        cursor = moreNode.get("cursor").asText();
-                    } else {
-                        cursor = null;
-                    }
-                } 
-            }
+                count += returnCount;
 
-            if ( finished == (numDevices * numNotifications) ) {
-                allSent = true;
+                if (anotherNode.get("cursor") != null) {
+
+                    // since we have a cursor, we should have gotten the limit, which defaults to 10 
+                    // or we should get back 0 which indicates no more data
+                    assertTrue( returnCount == 10 || returnCount == 0 );
+
+                    cursor = anotherNode.get("cursor").asText();
+
+                    Thread.sleep( readDelayMs );
+
+                } else {
+                    cursor = null;
+                }
             }
         }
-        notificationCount = numDevices * numNotifications; 
-        allSw.stop();
-        logger.info("Finished {} notifications in {}ms", notificationCount, allSw.getTime());
-        logger.info("Finished Notification throughput = {} TPS", 
-            ((float)notificationCount) / (allSw.getTime()/1000));
+        return count;
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/b01b2a70/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/PagingResourceIT.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/PagingResourceIT.java b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/PagingResourceIT.java
index 7008f3e..b74b314 100644
--- a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/PagingResourceIT.java
+++ b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/PagingResourceIT.java
@@ -19,6 +19,7 @@ package org.apache.usergrid.rest.applications.collection;
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
@@ -278,6 +279,23 @@ public class PagingResourceIT extends AbstractRestIT {
                 .get(String.class));
         assertEquals(trinketsSize, trinketsNode.get("count").asInt()); // get back all 
         assertNull(trinketsNode.get("cursor")); // and no cursor
-
     }
+
+
+//    @Test
+//    public void testPagingWithUpdates() throws IOException {
+//
+//        // create 500 widgets
+//        int widgetsSize = 500;
+//        List<String> widgetIds = new ArrayList<String>();
+//        CustomCollection widgets = context.application().collection("widgets");
+//        for (int i = 0; i < widgetsSize; i++) {
+//            Map<String, String> entity = hashMap("name", String.valueOf(i));
+//            JsonNode widgetNode = widgets.create(entity);
+//            logger.info("widgetNode: " + widgetNode.toString());
+//        }
+//
+//        refreshIndex(context.getOrgName(), context.getAppName());
+//    }
+
 }