You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@usergrid.apache.org by ro...@apache.org on 2014/11/13 02:09:13 UTC
[5/8] incubator-usergrid git commit: organized rest IT
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/3993f081/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/groups/GroupResourceIT.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/groups/GroupResourceIT.java b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/groups/GroupResourceIT.java
new file mode 100644
index 0000000..0dd6dc8
--- /dev/null
+++ b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/groups/GroupResourceIT.java
@@ -0,0 +1,295 @@
+/*
+ * 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.rest.applications.collection.groups;
+
+
+import java.util.UUID;
+
+import javax.ws.rs.core.MediaType;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import java.io.IOException;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.usergrid.cassandra.Concurrent;
+import org.apache.usergrid.java.client.Client.Query;
+import org.apache.usergrid.java.client.response.ApiResponse;
+import org.apache.usergrid.rest.AbstractRestIT;
+import org.apache.usergrid.utils.UUIDUtils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+
+/** @author tnine */
+@Concurrent()
+public class GroupResourceIT extends AbstractRestIT {
+ private static Logger log = LoggerFactory.getLogger( GroupResourceIT.class );
+
+ private static final String GROUP = "testGroup";
+
+ private static final String USER = "edanuff";
+
+ private static boolean groupCreated = false;
+
+
+ public GroupResourceIT() throws Exception {
+
+ }
+
+
+ @Before
+ public void setupGroup() {
+ if ( groupCreated ) {
+ return;
+ }
+
+ try {
+ client.createGroup( GROUP );
+ groupCreated = true;
+ }
+ catch ( Exception e ) {
+ log.error( "Error creating group " + GROUP, e );
+ }
+ refreshIndex("test-organization", "test-app");
+
+ }
+
+
+ @Test
+ public void failGroupNameValidation() {
+
+ ApiResponse response = client.createGroup( "groupName/withslash" );
+ assertNull( response.getError() );
+
+ refreshIndex("test-organization", "test-app");
+
+ {
+ boolean failed = false;
+ try {
+ ApiResponse groupResponse = client.createGroup( "groupName withspace" );
+ failed = groupResponse.getError() != null;
+ } catch ( Exception e ) {
+ failed = true;
+ }
+ assertTrue( failed );
+ }
+ }
+
+
+ @Test
+ public void postGroupActivity() {
+
+ // don't populate the user, it will use the currently authenticated
+ // user.
+
+ UUID id = UUIDUtils.newTimeUUID();
+
+ String groupPath = "groupPath" + id;
+ String groupTitle = "groupTitle " + id;
+ String groupName = "groupName" + id;
+
+ ApiResponse response = client.createGroup( groupPath, groupTitle, groupName );
+
+ assertNull( "Error was: " + response.getErrorDescription(), response.getError() );
+
+ refreshIndex("test-organization", "test-app");
+
+ UUID newId = response.getEntities().get( 0 ).getUuid();
+
+ Query results = client.queryGroups( String.format( "name='%s'", groupName ) );
+
+ response = results.getResponse();
+
+ UUID entityId = response.getEntities().get( 0 ).getUuid();
+
+ assertEquals( newId, entityId );
+
+ results = client.queryGroups( String.format( "title='%s'", groupTitle ) );
+
+ response = results.getResponse();
+
+ entityId = response.getEntities().get( 0 ).getUuid();
+
+ assertEquals( newId, entityId );
+
+ results = client.queryGroups( String.format( "title contains '%s'", id ) );
+
+ response = results.getResponse();
+
+ entityId = response.getEntities().get( 0 ).getUuid();
+
+ assertEquals( newId, entityId );
+
+ results = client.queryGroups( String.format( "path='%s'", groupPath ) );
+
+ response = results.getResponse();
+
+ entityId = response.getEntities().get( 0 ).getUuid();
+
+ assertEquals( newId, entityId );
+ }
+
+
+ @Test
+ public void addRemovePermission() throws IOException {
+
+ UUID id = UUIDUtils.newTimeUUID();
+
+ String groupName = "groupname" + id;
+
+ ApiResponse response = client.createGroup( groupName );
+ assertNull( "Error was: " + response.getErrorDescription(), response.getError() );
+
+ refreshIndex("test-organization", "test-app");
+
+ UUID createdId = response.getEntities().get( 0 ).getUuid();
+
+ // add Permission
+
+ String json = "{\"permission\":\"delete:/test\"}";
+ JsonNode node = mapper.readTree( resource().path( "/test-organization/test-app/groups/" + createdId + "/permissions" )
+ .queryParam( "access_token", access_token ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class, json ));
+
+ // check it
+ assertNull( node.get( "errors" ) );
+ assertEquals( node.get( "data" ).get( 0 ).asText(), "delete:/test" );
+
+ refreshIndex("test-organization", "test-app");
+
+ node = mapper.readTree( resource().path( "/test-organization/test-app/groups/" + createdId + "/permissions" )
+ .queryParam( "access_token", access_token ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).get( String.class ));
+ assertNull( node.get( "errors" ) );
+ assertEquals( node.get( "data" ).get( 0 ).asText(), "delete:/test" );
+
+
+ // remove Permission
+
+ node = mapper.readTree( resource().path( "/test-organization/test-app/groups/" + createdId + "/permissions" )
+ .queryParam( "access_token", access_token ).queryParam( "permission", "delete%3A%2Ftest" )
+ .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE ).delete( String.class ));
+
+ // check it
+ assertNull( node.get( "errors" ) );
+ assertTrue( node.get( "data" ).size() == 0 );
+
+ refreshIndex("test-organization", "test-app");
+
+ node = mapper.readTree( resource().path( "/test-organization/test-app/groups/" + createdId + "/permissions" )
+ .queryParam( "access_token", access_token ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).get( String.class ));
+ assertNull( node.get( "errors" ) );
+ assertTrue( node.get( "data" ).size() == 0 );
+ }
+
+
+ @Test
+ public void addRemoveRole() throws IOException {
+
+ UUID id = UUIDUtils.newTimeUUID();
+
+ String groupName = "groupname" + id;
+ String roleName = "rolename" + id;
+
+ ApiResponse response = client.createGroup( groupName );
+ assertNull( "Error was: " + response.getErrorDescription(), response.getError() );
+
+ UUID createdId = response.getEntities().get( 0 ).getUuid();
+
+ refreshIndex("test-organization", "test-app");
+
+ // create Role
+
+ String json = "{\"title\":\"" + roleName + "\",\"name\":\"" + roleName + "\"}";
+ JsonNode node = mapper.readTree( resource().path( "/test-organization/test-app/roles" ).queryParam( "access_token", access_token )
+ .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE )
+ .post( String.class, json ));
+
+ // check it
+ assertNull( node.get( "errors" ) );
+
+
+ refreshIndex("test-organization", "test-app");
+
+ // add Role
+
+ node = mapper.readTree( resource().path( "/test-organization/test-app/groups/" + createdId + "/roles/" + roleName )
+ .queryParam( "access_token", access_token ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class ));
+
+ refreshIndex("test-organization", "test-app");
+
+ // check it
+ assertNull( node.get( "errors" ) );
+ assertEquals( node.get( "entities" ).get( 0 ).get( "name" ).asText(), roleName );
+
+ node = mapper.readTree( resource().path( "/test-organization/test-app/groups/" + createdId + "/roles" )
+ .queryParam( "access_token", access_token ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).get( String.class ));
+ assertNull( node.get( "errors" ) );
+ assertEquals( node.get( "entities" ).get( 0 ).get( "name" ).asText(), roleName );
+
+ // check root roles
+ node = mapper.readTree( resource().path( "/test-organization/test-app/roles" ).queryParam( "access_token", access_token )
+ .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE ).get( String.class ));
+ assertNull( node.get( "errors" ) );
+ assertTrue( node.get( "entities" ).findValuesAsText( "name" ).contains( roleName ) );
+
+ refreshIndex("test-organization", "test-app");
+
+ // remove Role
+
+ node = mapper.readTree( resource().path( "/test-organization/test-app/groups/" + createdId + "/roles/" + roleName )
+ .queryParam( "access_token", access_token ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).delete( String.class ));
+ assertNull( node.get( "errors" ) );
+
+ refreshIndex("test-organization", "test-app");
+
+ node = mapper.readTree( resource().path( "/test-organization/test-app/groups/" + createdId + "/roles" )
+ .queryParam( "access_token", access_token ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).get( String.class ));
+ assertNull( node.get( "errors" ) );
+ assertTrue( node.get( "entities" ).size() == 0 );
+
+ // check root roles - role should remain
+ node = mapper.readTree( resource().path( "/test-organization/test-app/roles" ).queryParam( "access_token", access_token )
+ .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE ).get( String.class ));
+ assertNull( node.get( "errors" ) );
+ assertTrue( node.get( "entities" ).findValuesAsText( "name" ).contains( roleName ) );
+
+ // now kill the root role
+ node = mapper.readTree( resource().path( "/test-organization/test-app/roles/" + roleName )
+ .queryParam( "access_token", access_token ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).delete( String.class ));
+ assertNull( node.get( "errors" ) );
+
+ refreshIndex("test-organization", "test-app");
+
+ // now it should be gone
+ node = mapper.readTree( resource().path( "/test-organization/test-app/roles" ).queryParam( "access_token", access_token )
+ .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE ).get( String.class ));
+ assertNull( node.get( "errors" ) );
+ assertFalse( node.get( "entities" ).findValuesAsText( "name" ).contains( roleName ) );
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/3993f081/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/paging/PagingEntitiesTest.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/paging/PagingEntitiesTest.java b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/paging/PagingEntitiesTest.java
new file mode 100644
index 0000000..93a061d
--- /dev/null
+++ b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/paging/PagingEntitiesTest.java
@@ -0,0 +1,141 @@
+/*
+ * 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.rest.applications.collection.paging;
+
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import java.io.IOException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.apache.usergrid.rest.AbstractRestIT;
+import org.apache.usergrid.rest.TestContextSetup;
+import org.apache.usergrid.rest.test.resource.CustomCollection;
+
+import org.apache.commons.lang.ArrayUtils;
+
+import static org.junit.Assert.assertEquals;
+import static org.apache.usergrid.utils.MapUtils.hashMap;
+
+
+/**
+ * // TODO: Document this
+ *
+ * @author ApigeeCorporation
+ * @since 4.0
+ */
+public class PagingEntitiesTest extends AbstractRestIT {
+
+ @Rule
+ public TestContextSetup context = new TestContextSetup( this );
+
+
+ @Test //USERGRID-266
+ public void pageThroughConnectedEntities() throws IOException {
+
+ CustomCollection activities = context.collection( "activities" );
+
+ long created = 0;
+ int maxSize = 100;
+ long[] verifyCreated = new long[maxSize];
+ Map actor = hashMap( "displayName", "Erin" );
+ Map props = new HashMap();
+
+
+ props.put( "actor", actor );
+ props.put( "verb", "go" );
+
+ for ( int i = 0; i < maxSize; i++ ) {
+
+ props.put( "ordinal", i );
+ JsonNode activity = activities.create( props );
+ verifyCreated[i] = activity.findValue( "created" ).longValue();
+ if ( i == 0 ) {
+ created = activity.findValue( "created" ).longValue();
+ }
+ }
+ ArrayUtils.reverse( verifyCreated );
+
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ String query = "select * where created >= " + created;
+
+
+ JsonNode node = activities.query( query, "limit", "2" ); //activities.query(query,"");
+ int index = 0;
+ while ( node.get( "entities" ).get( "created" ) != null ) {
+ assertEquals( 2, node.get( "entities" ).size() );
+
+ if ( node.get( "cursor" ) != null ) {
+ node = activities.query( query, "cursor", node.get( "cursor" ).toString() );
+ }
+
+ else {
+ break;
+ }
+ }
+ }
+
+
+ @Test //USERGRID-1253
+ public void pagingQueryReturnCorrectResults() throws Exception {
+
+ CustomCollection activities = context.collection( "activities" );
+
+ long created = 0;
+ int maxSize = 23;
+ long[] verifyCreated = new long[maxSize];
+ Map actor = hashMap( "displayName", "Erin" );
+ Map props = new HashMap();
+
+ props.put( "actor", actor );
+ props.put( "content", "bragh" );
+
+ for ( int i = 0; i < maxSize; i++ ) {
+
+ if ( i > 17 && i < 23 ) {
+ props.put( "verb", "stop" );
+ }
+ else {
+ props.put( "verb", "go" );
+ }
+ props.put( "ordinal", i );
+ JsonNode activity = activities.create( props );
+ verifyCreated[i] = activity.findValue( "created" ).longValue();
+ if ( i == 18 ) {
+ created = activity.findValue( "created" ).longValue();
+ }
+ }
+
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ String query = "select * where created >= " + created + " or verb = 'stop'";
+
+ JsonNode node = activities.withQuery( query ).get();
+
+ for ( int index = 0; index < 5; index++ ) {
+ assertEquals( verifyCreated[maxSize - 1 - index],
+ node.get( "entities" ).get( index ).get( "created" ).longValue() );
+ }
+
+ int totalEntitiesContained = activities.countEntities( query );
+
+ assertEquals( 5, totalEntitiesContained );
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/3993f081/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/paging/PagingResourceIT.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/paging/PagingResourceIT.java b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/paging/PagingResourceIT.java
new file mode 100644
index 0000000..397dd0f
--- /dev/null
+++ b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/paging/PagingResourceIT.java
@@ -0,0 +1,239 @@
+/*
+ * 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.rest.applications.collection.paging;
+
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import org.apache.usergrid.cassandra.Concurrent;
+import org.apache.usergrid.java.client.entities.Entity;
+import org.apache.usergrid.java.client.response.ApiResponse;
+import org.apache.usergrid.rest.AbstractRestIT;
+import org.apache.usergrid.rest.TestContextSetup;
+import org.apache.usergrid.rest.test.resource.CustomCollection;
+import org.apache.usergrid.rest.test.resource.EntityResource;
+import static org.apache.usergrid.utils.MapUtils.hashMap;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/** Simple tests to test querying at the REST tier */
+@Concurrent()
+public class PagingResourceIT extends AbstractRestIT {
+
+ private static final Logger logger = LoggerFactory.getLogger( PagingResourceIT.class );
+
+ @Rule
+ public TestContextSetup context = new TestContextSetup( this );
+
+
+ @Test
+ public void collectionPaging() throws Exception {
+
+ CustomCollection things = context.application().collection( "test1things" );
+
+ int size = 40;
+
+ List<Map<String, String>> created = new ArrayList<Map<String, String>>( size );
+
+ for ( int i = 0; i < size; i++ ) {
+ Map<String, String> entity = hashMap( "name", String.valueOf( i ) );
+ things.create( entity );
+
+ created.add( entity );
+ }
+
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ // now page them all
+ ApiResponse response = null;
+ Iterator<Map<String, String>> entityItr = created.iterator();
+
+ do {
+
+ response = parse( things.get() );
+
+ for ( Entity e : response.getEntities() ) {
+ assertTrue( entityItr.hasNext() );
+ assertEquals( entityItr.next().get( "name" ), e.getProperties().get( "name" ).asText() );
+ logger.debug("Got item value {}", e.getProperties().get( "name" ).asText());
+ }
+
+ logger.debug("response cursor: " + response.getCursor() );
+
+ things = things.withCursor( response.getCursor() );
+ }
+ while ( response != null && response.getCursor() != null );
+
+ assertFalse("Should have paged them all", entityItr.hasNext() );
+ }
+
+
+ @Test
+ @Ignore("ignored because currently startPaging is only be supported for queues and not for "
+ + "generic collections as this test assumes. "
+ + "see also: https://issues.apache.org/jira/browse/USERGRID-211 ")
+ public void startPaging() throws Exception {
+
+ CustomCollection things = context.application().collection( "test2things" );
+
+ int size = 40;
+
+ List<Map<String, String>> created = new ArrayList<Map<String, String>>( size );
+
+ for ( int i = 0; i < size; i++ ) {
+ Map<String, String> entity = hashMap( "name", String.valueOf( i ) );
+ things.create( entity );
+
+ created.add( entity );
+ }
+
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ // now page them all
+ ApiResponse response = null;
+
+ UUID start = null;
+ int index = 0;
+
+ do {
+
+ response = parse( things.get() );
+
+ for ( Entity e : response.getEntities() ) {
+ logger.debug("Getting item {} value {}", index, e.getProperties().get( "name" ).asText());
+ assertEquals( created.get( index ).get( "name" ), e.getProperties().get( "name" ).asText() );
+ index++;
+ }
+
+ // decrement since we'll get this one again
+ index--;
+
+ start = response.getEntities().get( response.getEntities().size() - 1 ).getUuid();
+
+ things = things.withStart( start );
+ }
+ while ( response != null && response.getEntities().size() > 1 );
+
+ // we paged them all
+ assertEquals( created.size() - 1, index );
+ }
+
+
+ @Test
+ public void collectionBatchDeleting() throws Exception {
+
+ CustomCollection things = context.application().collection( "test3things" );
+
+ int size = 40;
+
+ List<Map<String, String>> created = new ArrayList<Map<String, String>>( size );
+
+ for ( int i = 0; i < size; i++ ) {
+ Map<String, String> entity = hashMap( "name", String.valueOf( i ) );
+ things.create( entity );
+
+ created.add( entity );
+ }
+
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ ApiResponse response;
+ int deletePageSize = 10;
+
+ things = things.withLimit( deletePageSize );
+
+ for ( int i = 0; i < size / deletePageSize; i++ ) {
+ response = parse( things.delete() );
+
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ assertEquals( "Only 10 entities should have been deleted", 10, response.getEntityCount() );
+ }
+
+ response = parse( things.get() );
+
+ assertEquals( "All entities should have been removed", 0, response.getEntityCount() );
+
+ //now do 1 more delete, we should get any results
+
+ response = parse( things.delete() );
+
+ assertEquals( "No more entities deleted", 0, response.getEntityCount() );
+ }
+
+
+ @Test
+ public void emptyQlandLimitIgnored() throws Exception {
+
+ CustomCollection things = context.application().collection( "test4things" );
+
+ Map<String, String> data = hashMap( "name", "thing1" );
+ JsonNode response = things.create( data );
+
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ JsonNode entity = getEntity( response, 0 );
+
+ String uuid = entity.get( "uuid" ).asText();
+
+ EntityResource entityRequest = things.entity( "thing1" ).withParam( "ql", "" ).withParam( "limit", "" );
+
+ JsonNode returnedEntity = getEntity( entityRequest.get(), 0 );
+
+ assertEquals( entity, returnedEntity );
+
+ entityRequest = things.entity( uuid ).withParam( "ql", "" ).withParam( "limit", "" );
+
+ returnedEntity = getEntity( entityRequest.get(), 0 );
+
+ assertEquals( entity, returnedEntity );
+
+ // now do a delete
+ returnedEntity = getEntity( entityRequest.delete(), 0 );
+
+ assertEquals( entity, returnedEntity );
+
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ // verify it's gone
+ returnedEntity = getEntity( things.entity( uuid ).get(), 0 );
+
+ assertNull( returnedEntity );
+ }
+
+
+ private static ObjectMapper mapper = new ObjectMapper();
+
+
+ private static final ApiResponse parse( JsonNode response ) throws Exception {
+ String jsonResponseString = mapper.writeValueAsString( response );
+ return mapper.readValue( jsonResponseString, ApiResponse.class );
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/3993f081/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/ConnectionResourceTest.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/ConnectionResourceTest.java b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/ConnectionResourceTest.java
new file mode 100644
index 0000000..e034443
--- /dev/null
+++ b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/ConnectionResourceTest.java
@@ -0,0 +1,271 @@
+/*
+ * 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.rest.applications.collection.users;
+
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.ws.rs.core.MediaType;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.junit.Rule;
+import org.junit.Test;
+import org.apache.usergrid.rest.AbstractRestIT;
+import org.apache.usergrid.rest.TestContextSetup;
+import org.apache.usergrid.rest.test.resource.CustomCollection;
+
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.UniformInterfaceException;
+import java.io.IOException;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.apache.usergrid.utils.MapUtils.hashMap;
+
+
+/**
+ * // TODO: Document this
+ *
+ * @author ApigeeCorporation
+ * @since 4.0
+ */
+public class ConnectionResourceTest extends AbstractRestIT {
+ @Rule
+ public TestContextSetup context = new TestContextSetup( this );
+
+
+ @Test
+ public void connectionsQueryTest() throws IOException {
+
+
+ CustomCollection activities = context.collection( "peeps" );
+
+ Map stuff = hashMap( "type", "chicken" );
+
+ activities.create( stuff );
+
+
+ Map<String, Object> payload = new LinkedHashMap<String, Object>();
+ payload.put( "username", "todd" );
+
+ Map<String, Object> objectOfDesire = new LinkedHashMap<String, Object>();
+ objectOfDesire.put( "codingmunchies", "doritoes" );
+
+ resource().path( "/test-organization/test-app/users" ).queryParam( "access_token", access_token )
+ .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE )
+ .post( String.class, payload );
+
+ payload.put( "username", "scott" );
+
+
+ resource().path( "/test-organization/test-app/users" ).queryParam( "access_token", access_token )
+ .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE )
+ .post( String.class, payload );
+ /*finish setting up the two users */
+
+
+ refreshIndex("test-organization", "test-app");
+
+ ClientResponse toddWant = resource().path( "/test-organization/test-app/users/todd/likes/peeps" )
+ .queryParam( "access_token", access_token ).accept( MediaType.TEXT_HTML )
+ .type( MediaType.APPLICATION_JSON_TYPE ).post( ClientResponse.class, objectOfDesire );
+
+ assertEquals( 200, toddWant.getStatus() );
+
+ refreshIndex("test-organization", "test-app");
+
+ JsonNode node = mapper.readTree( resource().path( "/test-organization/test-app/peeps" ).queryParam( "access_token", access_token )
+ .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE )
+ .get( String.class ));
+
+ String uuid = node.get( "entities" ).get( 0 ).get( "uuid" ).textValue();
+
+
+ try {
+ node = mapper.readTree( resource().path( "/test-organization/test-app/users/scott/likes/" + uuid )
+ .queryParam( "access_token", access_token ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).get( String.class ));
+ assert ( false );
+ }
+ catch ( UniformInterfaceException uie ) {
+ assertEquals( 404, uie.getResponse().getClientResponseStatus().getStatusCode() );
+ }
+ }
+
+
+ @Test
+ public void connectionsLoopbackTest() throws IOException {
+
+ CustomCollection things = context.collection( "things" );
+
+ UUID thing1Id = getEntityId( things.create( hashMap( "name", "thing1" ) ), 0 );
+
+ UUID thing2Id = getEntityId( things.create( hashMap( "name", "thing2" ) ), 0 );
+
+
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ //create the connection
+ things.entity( thing1Id ).connection( "likes" ).entity( thing2Id ).post();
+
+
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ //test we have the "likes" in our connection meta data response
+
+ JsonNode response = things.entity( "thing1" ).get();
+
+ String url = getEntity( response, 0 ).get( "metadata" ).get( "connections" ).get( "likes" ).asText();
+
+
+ assertNotNull( "Connection url returned in entity", url );
+
+ //trim off the start /
+ url = url.substring( 1 );
+
+
+ //now that we know the URl is correct, follow it
+
+ response = context.collection( url ).get();
+
+ UUID returnedUUID = getEntityId( response, 0 );
+
+ assertEquals( thing2Id, returnedUUID );
+
+
+ //now follow the loopback, which should be pointers to the other entity
+
+ url = getEntity( response, 0 ).get( "metadata" ).get( "connecting" ).get( "likes" ).asText();
+
+ assertNotNull( "Incoming edge URL provited", url );
+
+ //trim off the start /
+ url = url.substring( 1 );
+
+ //now we should get thing1 from the loopback url
+
+ response = context.collection( url ).get();
+
+ UUID returned = getEntityId( response, 0 );
+
+ assertEquals( "Should point to thing1 as an incoming entity connection", thing1Id, returned );
+ }
+
+
+ @Test
+ public void connectionsUUIDTest() throws IOException {
+
+ CustomCollection things = context.collection( "things" );
+
+ UUID thing1Id = getEntityId( things.create( hashMap( "name", "thing1" ) ), 0 );
+
+ UUID thing2Id = getEntityId( things.create( hashMap( "name", "thing2" ) ), 0 );
+
+
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ //create the connection
+ things.entity( thing1Id ).connection( "likes" ).entity( thing2Id ).post();
+
+
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ //test we have the "likes" in our connection meta data response
+
+ JsonNode response = things.entity( "thing1" ).get();
+
+ String url = getEntity( response, 0 ).get( "metadata" ).get( "connections" ).get( "likes" ).asText();
+
+
+ assertNotNull( "Connection url returned in entity", url );
+
+ //trim off the start /
+ url = url.substring( 1 );
+
+
+ //now that we know the URl is correct, follow it
+
+ response = context.collection( url ).get();
+
+ UUID returnedUUID = getEntityId( response, 0 );
+
+ assertEquals( thing2Id, returnedUUID );
+
+ //get on the collection works, now get it directly by uuid
+
+ //now we should get thing1 from the loopback url
+
+ response = things.entity( thing1Id ).connection( "likes" ).entity( thing2Id ).get();
+
+ UUID returned = getEntityId( response, 0 );
+
+ assertEquals( "Should point to thing2 as an entity connection", thing2Id, returned );
+ }
+
+ @Test //USERGRID-3011
+ public void connectionsDeleteSecondEntityInConnectionTest() throws IOException {
+
+ CustomCollection things = context.collection( "things" );
+
+ UUID thing1Id = getEntityId( things.create( hashMap( "name", "thing1" ) ), 0 );
+
+ UUID thing2Id = getEntityId( things.create( hashMap( "name", "thing2" ) ), 0 );
+
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ //create the connection
+ things.entity( thing1Id ).connection( "likes" ).entity( thing2Id ).post();
+
+ JsonNode response = things.entity( "thing2" ).delete();
+
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ JsonNode node = things.entity ( "thing2" ).get();
+
+ assertNull(node);
+
+ }
+
+ @Test //USERGRID-3011
+ public void connectionsDeleteFirstEntityInConnectionTest() throws IOException {
+
+ CustomCollection things = context.collection( "things" );
+
+ UUID thing1Id = getEntityId( things.create( hashMap( "name", "thing1" ) ), 0 );
+
+ UUID thing2Id = getEntityId( things.create( hashMap( "name", "thing2" ) ), 0 );
+
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ //create the connection
+ things.entity( thing1Id ).connection( "likes" ).entity( thing2Id ).post();
+
+ JsonNode response = things.entity( "thing1" ).delete();
+
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ JsonNode node = things.entity ( "thing1" ).get();
+
+ assertNull(node);
+
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/3993f081/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/OwnershipResourceIT.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/OwnershipResourceIT.java b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/OwnershipResourceIT.java
new file mode 100644
index 0000000..a514781
--- /dev/null
+++ b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/OwnershipResourceIT.java
@@ -0,0 +1,379 @@
+/*
+ * 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.rest.applications.collection.users;
+
+
+import com.fasterxml.jackson.databind.JsonNode;
+import java.io.IOException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.apache.usergrid.cassandra.Concurrent;
+import org.apache.usergrid.rest.AbstractRestIT;
+import org.apache.usergrid.rest.TestContextSetup;
+import org.apache.usergrid.rest.test.resource.Connection;
+import org.apache.usergrid.rest.test.resource.CustomCollection;
+import org.apache.usergrid.rest.test.resource.app.queue.DevicesCollection;
+import org.apache.usergrid.rest.test.security.TestAppUser;
+import org.apache.usergrid.rest.test.security.TestUser;
+import org.apache.usergrid.utils.MapUtils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+
+/**
+ *
+ */
+@Concurrent()
+public class OwnershipResourceIT extends AbstractRestIT {
+
+ @Rule
+ public TestContextSetup context = new TestContextSetup( this );
+
+
+ @Test
+ public void meVerify() throws Exception {
+
+ context.clearUser();
+
+ String email = "testuser1@usergrid.org";
+ TestUser user1 = new TestAppUser( email, "password", email ).create( context );
+ refreshIndex(context.getOrgName(), context.getAppName());
+ user1.login( context ).makeActive( context );
+
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ String token = user1.getToken();
+ JsonNode userNode = context.application().users().user( "me" ).get();
+ assertNotNull( userNode );
+
+ String uuid = userNode.get( "entities" ).get( 0 ).get( "uuid" ).textValue();
+ assertNotNull( uuid );
+
+ setup.getMgmtSvc().revokeAccessTokenForAppUser( token );
+
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ try {
+ context.application().users().user( "me" ).get();
+ fail();
+ }
+ catch ( Exception ex ) {
+ ex.printStackTrace();
+ assertTrue( ex.getMessage().contains( "401" ) );
+ }
+ }
+
+
+ @Test
+ public void contextualPathOwnership() throws IOException {
+
+ // anonymous user
+ context.clearUser();
+
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ TestUser user1 = new TestAppUser( "testuser1@usergrid.org", "password", "testuser1@usergrid.org" ).create( context );
+ refreshIndex(context.getOrgName(), context.getAppName());
+ user1.login( context );
+ user1.makeActive( context );
+
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ // create device 1 on user1 devices
+ context.application().users().user( "me" ).devices()
+ .create( MapUtils.hashMap( "name", "device1" ).map( "number", "5551112222" ) );
+
+ // anonymous user
+ context.clearUser();
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ // create device 2 on user 2
+ TestUser user2 = new TestAppUser( "testuser2@usergrid.org", "password", "testuser2@usergrid.org" ).create( context );
+ refreshIndex(context.getOrgName(), context.getAppName());
+ user2.login( context );
+ user2.makeActive( context );
+
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ context.application().users().user( "me" ).devices()
+ .create( MapUtils.hashMap( "name", "device2" ).map( "number", "5552223333" ) );
+
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ // now query on user 1.
+
+ DevicesCollection devices = context.withUser( user1 ).application().users().user( "me" ).devices();
+
+ JsonNode data = devices.device( "device1" ).get();
+ assertNotNull( data );
+ assertEquals( "device1", getEntity( data, 0 ).get( "name" ).asText() );
+
+ // check we can't see device2
+ data = devices.device( "device2" ).get();
+ assertNull( data );
+
+ // do a collection load, make sure we're not loading device 2
+ data = devices.get();
+
+ assertEquals( "device1", getEntity( data, 0 ).get( "name" ).asText() );
+ assertNull( getEntity( data, 1 ) );
+
+ // log in as user 2 and check it
+ devices = context.withUser( user2 ).application().users().user( "me" ).devices();
+
+ data = devices.device( "device2" ).get();
+ assertNotNull( data );
+ assertEquals( "device2", getEntity( data, 0 ).get( "name" ).asText() );
+
+ // check we can't see device1
+ data = devices.device( "device1" ).get();
+ assertNull( data );
+
+ // do a collection load, make sure we're not loading device 1
+ data = devices.get();
+
+ assertEquals( "device2", getEntity( data, 0 ).get( "name" ).asText() );
+ assertNull( getEntity( data, 1 ) );
+
+ // we should see both devices when loaded from the root application
+
+ // test for user 1
+
+ devices = context.withUser( user1 ).application().devices();
+ data = devices.device( "device1" ).get();
+
+ assertNotNull( data );
+ assertEquals( "device1", getEntity( data, 0 ).get( "name" ).asText() );
+
+ data = devices.device( "device2" ).get();
+
+ assertNotNull( data );
+ assertEquals( "device2", getEntity( data, 0 ).get( "name" ).asText() );
+
+ // test for user 2
+ data = context.withUser( user2 ).application().devices().device( "device1" ).get();
+
+ assertNotNull( data );
+ assertEquals( "device1", getEntity( data, 0 ).get( "name" ).asText() );
+
+ data = devices.device( "device2" ).get();
+
+ assertNotNull( data );
+ assertEquals( "device2", getEntity( data, 0 ).get( "name" ).asText() );
+ }
+
+
+ @Test
+ public void contextualConnectionOwnership() throws IOException {
+
+ // anonymous user
+ context.clearUser();
+
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ String email = "testuser1@usergrid.org";
+ TestUser user1 = new TestAppUser( email, "password", email ).create( context );
+ refreshIndex(context.getOrgName(), context.getAppName());
+ user1.login( context ).makeActive( context );
+
+ // create a 4peaks restaurant
+ JsonNode data = context.application()
+ .collection( "restaurants" ).create( MapUtils.hashMap( "name", "4peaks" ) );
+
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ // create our connection
+ data = context.application().users().user( "me" )
+ .connection( "likes" ).collection( "restaurants" ).entity( "4peaks" ).post();
+
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ String peaksId = getEntity( data, 0 ).get( "uuid" ).asText();
+
+ // anonymous user
+ context.clearUser();
+
+ // create a restaurant and link it to user 2
+ email = "testuser2@usergrid.org";
+ TestUser user2 = new TestAppUser( email, "password", email ).create( context );
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ user2.login( context ).makeActive( context );
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ data = context.application().collection( "restaurants" )
+ .create( MapUtils.hashMap( "name", "arrogantbutcher" ) );
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ data = context.application().users().user( "me" ).connection( "likes" ).collection( "restaurants" )
+ .entity( "arrogantbutcher" ).post();
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ String arrogantButcherId = getEntity( data, 0 ).get( "uuid" ).asText();
+
+ // now query on user 1.
+
+ CustomCollection likeRestaurants =
+ context.withUser( user1 ).application().users().user( "me" ).connection( "likes" )
+ .collection( "restaurants" );
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ // check we can get it via id
+ data = likeRestaurants.entity( peaksId ).get();
+ assertNotNull( data );
+ assertEquals( "4peaks", getEntity( data, 0 ).get( "name" ).asText() );
+
+ // check we can get it by name
+ data = likeRestaurants.entity( "4peaks" ).get();
+ assertNotNull( data );
+ assertEquals( "4peaks", getEntity( data, 0 ).get( "name" ).asText() );
+
+ // check we can't see arrogantbutcher by name or id
+ data = likeRestaurants.entity( "arrogantbutcher" ).get();
+ assertNull( data );
+
+ data = likeRestaurants.entity( arrogantButcherId ).get();
+ assertNull( data );
+
+ // do a collection load, make sure we're not entities we shouldn't see
+ data = likeRestaurants.get();
+
+ assertEquals( "4peaks", getEntity( data, 0 ).get( "name" ).asText() );
+ assertNull( getEntity( data, 1 ) );
+
+ // log in as user 2 and check it
+ likeRestaurants = context.withUser( user2 ).application().users().user( "me" ).connection( "likes" )
+ .collection( "restaurants" );
+
+ data = likeRestaurants.entity( arrogantButcherId ).get();
+ assertNotNull( data );
+ assertEquals( "arrogantbutcher", getEntity( data, 0 ).get( "name" ).asText() );
+
+ data = likeRestaurants.entity( "arrogantbutcher" ).get();
+ assertNotNull( data );
+ assertEquals( "arrogantbutcher", getEntity( data, 0 ).get( "name" ).asText() );
+
+ // check we can't see 4peaks
+ data = likeRestaurants.entity( "4peaks" ).get();
+ assertNull( data );
+
+ data = likeRestaurants.entity( peaksId ).get();
+ assertNull( data );
+
+ // do a collection load, make sure we're not loading device 1
+ data = likeRestaurants.get();
+
+ assertEquals( "arrogantbutcher", getEntity( data, 0 ).get( "name" ).asText() );
+ assertNull( getEntity( data, 1 ) );
+
+ // we should see both devices when loaded from the root application
+
+ // test for user 1
+
+ CustomCollection restaurants = context.withUser( user1 ).application().collection( "restaurants" );
+ data = restaurants.entity( "4peaks" ).get();
+
+ assertNotNull( data );
+ assertEquals( "4peaks", getEntity( data, 0 ).get( "name" ).asText() );
+
+ data = restaurants.entity( "arrogantbutcher" ).get();
+
+ assertNotNull( data );
+ assertEquals( "arrogantbutcher", getEntity( data, 0 ).get( "name" ).asText() );
+
+ // test for user 2
+ restaurants = context.withUser( user1 ).application().collection( "restaurants" );
+ data = restaurants.entity( "4peaks" ).get();
+
+ assertNotNull( data );
+ assertEquals( "4peaks", getEntity( data, 0 ).get( "name" ).asText() );
+
+ data = restaurants.entity( "arrogantbutcher" ).get();
+
+ assertNotNull( data );
+ assertEquals( "arrogantbutcher", getEntity( data, 0 ).get( "name" ).asText() );
+ }
+
+
+ @Test
+ public void contextualConnectionOwnershipGuestAccess() throws IOException {
+
+ //set up full GET,PUT,POST,DELETE access for guests
+ context.application().collection( "roles" ).entity( "guest" ).collection( "permissions" )
+ .create( MapUtils.hashMap( "permission", "get,put,post,delete:/**" ) );
+
+
+ // anonymous user
+ context.clearUser();
+
+
+ JsonNode city = context.application().collection( "cities" ).create( MapUtils.hashMap( "name", "tempe" ) );
+
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ String cityId = getEntity( city, 0 ).get( "uuid" ).asText();
+
+ // create a 4peaks restaurant
+ JsonNode data = context.application().collection( "cities" ).entity( "tempe" ).connection( "likes" )
+ .collection( "restaurants" ).create( MapUtils.hashMap( "name", "4peaks" ) );
+
+ String peaksId = getEntity( data, 0 ).get( "uuid" ).asText();
+
+ data = context.application().collection( "cities" ).entity( "tempe" ).connection( "likes" )
+ .collection( "restaurants" ).create( MapUtils.hashMap( "name", "arrogantbutcher" ) );
+
+ String arrogantButcherId = getEntity( data, 0 ).get( "uuid" ).asText();
+
+ // now query on user 1.
+
+ Connection likeRestaurants =
+ context.application().collection( "cities" ).entity( "tempe" ).connection( "likes" );
+
+ refreshIndex(context.getOrgName(), context.getAppName());
+
+ // check we can get it via id with no collection name
+ data = likeRestaurants.entity( peaksId ).get();
+ assertNotNull( data );
+ assertEquals( "4peaks", getEntity( data, 0 ).get( "name" ).asText() );
+
+ data = likeRestaurants.entity( arrogantButcherId ).get();
+ assertEquals( "arrogantbutcher", getEntity( data, 0 ).get( "name" ).asText() );
+
+ // check we can get it via id with a collection name
+ data = likeRestaurants.collection( "restaurants" ).entity( peaksId ).get();
+ assertNotNull( data );
+ assertEquals( "4peaks", getEntity( data, 0 ).get( "name" ).asText() );
+
+ data = likeRestaurants.collection( "restaurants" ).entity( arrogantButcherId ).get();
+ assertEquals( "arrogantbutcher", getEntity( data, 0 ).get( "name" ).asText() );
+
+ // do a delete either token should work
+ data = likeRestaurants.collection( "restaurants" ).entity( peaksId ).delete();
+
+ assertNotNull( data );
+ assertEquals( "4peaks", getEntity( data, 0 ).get( "name" ).asText() );
+
+ data = likeRestaurants.collection( "restaurants" ).entity( arrogantButcherId ).delete();
+
+ assertNotNull( data );
+ assertEquals( "arrogantbutcher", getEntity( data, 0 ).get( "name" ).asText() );
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/3993f081/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/PermissionsResourceIT.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/PermissionsResourceIT.java b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/PermissionsResourceIT.java
new file mode 100644
index 0000000..a07622e
--- /dev/null
+++ b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/PermissionsResourceIT.java
@@ -0,0 +1,768 @@
+/*
+ * 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.rest.applications.collection.users;
+
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.ws.rs.core.MediaType;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.apache.usergrid.cassandra.Concurrent;
+import org.apache.usergrid.java.client.entities.Group;
+import org.apache.usergrid.management.ApplicationInfo;
+import org.apache.usergrid.management.OrganizationOwnerInfo;
+import org.apache.usergrid.rest.AbstractRestIT;
+import org.apache.usergrid.utils.UUIDUtils;
+
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.ClientResponse.Status;
+import com.sun.jersey.api.client.UniformInterfaceException;
+import java.io.IOException;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+import static org.apache.usergrid.utils.MapUtils.hashMap;
+
+
+/**
+ * Tests permissions of adding and removing users from roles as well as groups
+ *
+ * @author tnine
+ */
+@Concurrent()
+public class PermissionsResourceIT extends AbstractRestIT {
+
+ private static final String ROLE = "permtestrole";
+
+ private static final String USER = "edanuff";
+
+
+ public PermissionsResourceIT() throws Exception {
+
+ }
+
+
+ @Test
+ public void deleteUserFromRole() throws IOException {
+ Map<String, String> data = hashMap( "name", ROLE );
+
+ JsonNode node = mapper.readTree( resource().path( "/test-organization/test-app/roles" ).queryParam( "access_token", access_token )
+ .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE )
+ .post( String.class, data ));
+
+ assertNull( node.get( "error" ) );
+
+ assertEquals( ROLE, getEntity( node, 0 ).get( "name" ).asText() );
+
+ refreshIndex("test-organization", "test-app");
+
+ // add the user to the role
+ node = mapper.readTree( resource().path( "/test-organization/test-app/roles/" + ROLE + "/users/" + USER )
+ .queryParam( "access_token", access_token ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class ));
+
+ assertNull( node.get( "error" ) );
+
+ refreshIndex("test-organization", "test-app");
+
+ // now check the user has the role
+ node = mapper.readTree( resource().path( "/test-organization/test-app/users/" + USER + "/roles" )
+ .queryParam( "access_token", access_token ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).get( String.class ));
+
+ // check if the role was assigned
+ assertEquals( ROLE, getEntity( node, 0 ).get( "name" ).asText() );
+
+ // now delete the role
+ node = mapper.readTree( resource().path( "/test-organization/test-app/users/" + USER + "/roles/" + ROLE )
+ .queryParam( "access_token", access_token ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).delete( String.class ));
+
+ refreshIndex("test-organization", "test-app");
+
+ // check if the role was deleted
+
+ node = mapper.readTree( resource().path( "/test-organization/test-app/users/" + USER + "/roles" )
+ .queryParam( "access_token", access_token ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).get( String.class ));
+
+ // check if the role was assigned
+ assertNull( getEntity( node, 0 ) );
+ }
+
+
+ @Test
+ public void deleteUserGroup() throws IOException {
+
+ // don't populate the user, it will use the currently authenticated
+ // user.
+
+ UUID id = UUIDUtils.newTimeUUID();
+
+ String groupPath = "groupPath" + id;
+
+ Map<String, String> data = hashMap( "type", "group" ).map( "path", groupPath );
+
+ JsonNode node = mapper.readTree( resource().path( "/test-organization/test-app/groups" )
+ .queryParam( "access_token", access_token )
+ .accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE )
+ .post( String.class, data ));
+
+ assertNull( node.get( "error" ) );
+
+ refreshIndex("test-organization", "test-app");
+
+ node = mapper.readTree(
+ resource().path( "/test-organization/test-app/groups/" + groupPath + "/users/" + USER )
+ .queryParam( "access_token", access_token )
+ .accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE )
+ .post( String.class ));
+
+ assertNull( node.get( "error" ) );
+
+ refreshIndex("test-organization", "test-app");
+
+ Map<String, Group> groups = client.getGroupsForUser( USER );
+
+ assertNotNull( groups.get( groupPath ) );
+
+ // now delete the group
+
+ node = mapper.readTree(
+ resource().path( "/test-organization/test-app/groups/" + groupPath + "/users/" + USER )
+ .queryParam( "access_token", access_token )
+ .accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE )
+ .delete( String.class ));
+
+ assertNull( node.get( "error" ) );
+
+ refreshIndex("test-organization", "test-app");
+
+ groups = client.getGroupsForUser( USER );
+
+ assertNull( groups.get( groupPath ) );
+ }
+
+
+ /**
+ * For the record, you should NEVER allow the guest role to add roles. This is a gaping security hole and a VERY BAD
+ * IDEA! That being said, this should technically work, and needs testing.
+ */
+ @Test
+ public void dictionaryPermissions() throws Exception {
+ UUID id = UUIDUtils.newTimeUUID();
+
+ String applicationName = "testapp";
+ String orgname = "dictionaryPermissions";
+ String username = "permissionadmin" + id;
+ String password = "password";
+ String email = String.format( "email%s@usergrid.com", id );
+
+ OrganizationOwnerInfo orgs = setup.getMgmtSvc()
+ .createOwnerAndOrganization( orgname, username, "noname", email, password,
+ true, false );
+
+ // create the app
+ ApplicationInfo appInfo =
+ setup.getMgmtSvc().createApplication( orgs.getOrganization().getUuid(), applicationName );
+
+ String adminToken = setup.getMgmtSvc().getAccessTokenForAdminUser( orgs.getOwner().getUuid(), 0 );
+
+ // add the perms to the guest to allow users in the role to create roles
+ // themselves
+ addPermission( orgname, applicationName, adminToken, "guest", "get,put,post:/roles/**" );
+
+ Map<String, String> data = hashMap( "name", "usercreatedrole" );
+
+ // create a role as the user
+ JsonNode node = mapper.readTree( resource().path( String.format( "/%s/%s/roles", orgname, applicationName ) )
+ .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE )
+ .post( String.class, data ));
+
+ assertNull( getError( node ) );
+
+ refreshIndex(orgname, applicationName);
+
+ // now try to add permission as the user, this should work
+ addPermission( orgname, applicationName, "usercreatedrole", "get,put,post:/foo/**" );
+ }
+
+
+ /**
+ * Tests a real world example with the following steps. Creates an application.
+ * <p/>
+ * Creates a new role "reviewer"
+ * <p/>
+ * Grants a permission to GET, POST, and PUT the reviews url for the reviewer role
+ * <p/>
+ * Grants a permission GET on the reviewer for the
+ * <p/>
+ * Create a user reviewer1 and add them to the reviewer role
+ * <p/>
+ * Test access with reviewer1
+ * <p/>
+ * Create a group reviewergroup and add the "reviewer" group to it
+ * <p/>
+ * Create a user reviewer 2 and add them to the "reveiwergroup"
+ */
+ @Test
+ public void applicationPermissions() throws Exception {
+ UUID id = UUIDUtils.newTimeUUID();
+
+ String applicationName = "test";
+ String orgname = "applicationpermissions";
+ String username = "permissionadmin" + id;
+ String password = "password";
+ String email = String.format( "email%s@usergrid.com", id );
+
+ OrganizationOwnerInfo orgs = setup.getMgmtSvc()
+ .createOwnerAndOrganization( orgname, username, "noname", email, password,
+ true, false );
+
+ // create the app
+ ApplicationInfo appInfo =
+ setup.getMgmtSvc().createApplication( orgs.getOrganization().getUuid(), applicationName );
+
+ // now create the new role
+ Map<String, String> data = hashMap( "name", "reviewer" );
+
+ String adminToken = setup.getMgmtSvc().getAccessTokenForAdminUser( orgs.getOwner().getUuid(), 0 );
+
+ JsonNode node = mapper.readTree( resource().path( String.format( "/%s/%s/roles", orgname, applicationName ) )
+ .queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class, data ));
+
+ assertNull( getError( node ) );
+
+ // delete the default role to test permissions later
+ node = mapper.readTree( resource().path( String.format( "/%s/%s/roles/default", orgname, applicationName ) )
+ .queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).delete( String.class ));
+
+ assertNull( getError( node ) );
+ refreshIndex(orgname, applicationName);
+
+ // grant the perms to reviewer
+ addPermission( orgname, applicationName, adminToken, "reviewer", "get,put,post:/reviews/**" );
+
+ // grant get to guest
+ addPermission( orgname, applicationName, adminToken, "guest", "get:/reviews/**" );
+
+ UUID userId = createRoleUser( orgs.getOrganization().getUuid(), appInfo.getId(), adminToken, "reviewer1",
+ "reviewer1@usergrid.com" );
+
+ refreshIndex(orgname, applicationName);
+
+ // grant this user the "reviewer" role
+ node = mapper.readTree( resource().path( String.format( "/%s/%s/users/reviewer1/roles/reviewer", orgname, applicationName ) )
+ .queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class ));
+
+ assertNull( getError( node ) );
+
+ refreshIndex(orgname, applicationName);
+
+ String reviewer1Token = setup.getMgmtSvc().getAccessTokenForAppUser( appInfo.getId(), userId, 0 );
+
+ Map<String, String> review =
+ hashMap( "rating", "4" ).map( "name", "noca" ).map( "review", "Excellent service and food" );
+
+ // post a review as the reviewer1 user
+ resource().path( String.format( "/%s/%s/reviews", orgname, applicationName ) )
+ .queryParam( "access_token", reviewer1Token ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class, review );
+
+ review = hashMap( "rating", "4" ).map( "name", "4peaks" ).map( "review", "Huge beer selection" );
+
+ refreshIndex(orgname, applicationName);
+
+ // put a review as the reviewer1 user
+ resource().path( String.format( "/%s/%s/reviews", orgname, applicationName ) )
+ .queryParam( "access_token", reviewer1Token ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).put( String.class, review );
+
+ refreshIndex(orgname, applicationName);
+
+ // get the reviews
+
+ node = mapper.readTree( resource().path( String.format( "/%s/%s/reviews", orgname, applicationName ) )
+ .queryParam( "access_token", reviewer1Token ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).get( String.class ));
+
+ assertEquals( "noca", getEntity( node, 0 ).get( "name" ).asText() );
+ assertEquals( "4peaks", getEntity( node, 1 ).get( "name" ).asText() );
+
+ // can't delete, not in the grants
+
+ ClientResponse.Status status = null;
+
+ try {
+ resource().path( String.format( "/%s/%s/reviews/noca", orgname, applicationName ) )
+ .queryParam( "access_token", reviewer1Token ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).delete( String.class );
+ }
+ catch ( UniformInterfaceException uie ) {
+ status = uie.getResponse().getClientResponseStatus();
+ }
+
+ assertEquals( Status.UNAUTHORIZED, status );
+
+ refreshIndex(orgname, applicationName);
+
+ status = null;
+
+ try {
+ resource().path( String.format( "/%s/%s/reviews/4peaks", orgname, applicationName ) )
+ .queryParam( "access_token", reviewer1Token ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).delete( String.class );
+ }
+ catch ( UniformInterfaceException uie ) {
+ status = uie.getResponse().getClientResponseStatus();
+ }
+
+ assertEquals( Status.UNAUTHORIZED, status );
+
+ refreshIndex(orgname, applicationName);
+
+ // now test some groups
+ UUID secondUserId = createRoleUser( orgs.getOrganization().getUuid(), appInfo.getId(), adminToken, "reviewer2",
+ "reviewer2@usergrid.com" );
+
+ Map<String, String> group = hashMap( "path", "reviewergroup" );
+
+ // /now create the group
+ resource().path( String.format( "/%s/%s/groups", orgname, applicationName ) )
+ .queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class, group );
+
+ refreshIndex(orgname, applicationName);
+
+ // link the group to the role
+ resource().path( String.format( "/%s/%s/groups/reviewergroup/roles/reviewer", orgname, applicationName ) )
+ .queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class, group );
+
+ refreshIndex(orgname, applicationName);
+
+ // add the user to the group
+ resource().path( String.format( "/%s/%s/users/reviewer2/groups/reviewergroup", orgname, applicationName ) )
+ .queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class );
+
+ refreshIndex(orgname, applicationName);
+
+ // post 2 reviews. Should get permissions from the group
+
+ String secondUserToken = setup.getMgmtSvc().getAccessTokenForAppUser( appInfo.getId(), secondUserId, 0 );
+
+ review = hashMap( "rating", "4" ).map( "name", "cowboyciao" ).map( "review", "Great atmosphoere" );
+
+ // post a review as the reviewer2 user
+ resource().path( String.format( "/%s/%s/reviews", orgname, applicationName ) )
+ .queryParam( "access_token", secondUserToken ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class, review );
+
+ review = hashMap( "rating", "4" ).map( "name", "currycorner" ).map( "review", "Authentic" );
+
+ refreshIndex(orgname, applicationName);
+
+ // post a review as the reviewer2 user
+ resource().path( String.format( "/%s/%s/reviews", orgname, applicationName ) )
+ .queryParam( "access_token", secondUserToken ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class, review );
+
+ refreshIndex(orgname, applicationName);
+
+ // get all reviews as a user
+ node = mapper.readTree( resource().path( String.format( "/%s/%s/reviews", orgname, applicationName ) )
+ .queryParam( "access_token", secondUserToken ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).get( String.class ));
+
+ assertEquals( "noca", getEntity( node, 0 ).get( "name" ).asText() );
+ assertEquals( "4peaks", getEntity( node, 1 ).get( "name" ).asText() );
+ assertEquals( "cowboyciao", getEntity( node, 2 ).get( "name" ).asText() );
+ assertEquals( "currycorner", getEntity( node, 3 ).get( "name" ).asText() );
+
+ // issue a delete, it shouldn't work, no permissions
+
+ status = null;
+
+ try {
+ resource().path( String.format( "/%s/%s/reviews/cowboyciao", orgname, applicationName ) )
+ .queryParam( "access_token", secondUserToken ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).delete( String.class );
+ }
+ catch ( UniformInterfaceException uie ) {
+ status = uie.getResponse().getClientResponseStatus();
+ }
+
+ assertEquals( Status.UNAUTHORIZED, status );
+
+ refreshIndex(orgname, applicationName);
+
+ status = null;
+
+ try {
+ resource().path( String.format( "/%s/%s/reviews/currycorner", orgname, applicationName ) )
+ .queryParam( "access_token", secondUserToken ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).delete( String.class );
+ }
+ catch ( UniformInterfaceException uie ) {
+ status = uie.getResponse().getClientResponseStatus();
+ }
+
+ assertEquals( Status.UNAUTHORIZED, status );
+ }
+
+
+ /**
+ * Tests the scenario where we have roles declarations such as: <ul> <li>GET /users/[star]/reviews "any user can
+ * read any others book review"</li> <li>POST /users/[user1]/reviews "cannot post as user2 to user1's reviews"</li>
+ * <ii>POST /users/[star]/reviews/feedback/* "can post as user2 to user1's feedback/good or /bad</ii> </ul>
+ * <p/>
+ * Scenario is as follows: Create an application
+ * <p/>
+ * Add two application users - user1 - user2
+ * <p/>
+ * Create a book collection for user1
+ */
+ @Test
+ public void wildcardMiddlePermission() throws Exception {
+
+ Map<String, String> params = buildOrgAppParams();
+ String orgname =params.get( "orgName" ) ;
+ String applicationName = params.get( "appName" ) ;
+
+ OrganizationOwnerInfo orgs = setup.getMgmtSvc().createOwnerAndOrganization( params.get( "orgName" ),
+ params.get( "username" ), "noname", params.get( "email" ), params.get( "password" ), true, false );
+
+ // create the app
+ ApplicationInfo appInfo =
+ setup.getMgmtSvc().createApplication( orgs.getOrganization().getUuid(), params.get( "appName" ) );
+ assertNotNull( appInfo );
+
+ String adminToken = setup.getMgmtSvc().getAccessTokenForAdminUser( orgs.getOwner().getUuid(), 0 );
+
+ JsonNode node = mapper.readTree( resource()
+ .path( String.format( "/%s/%s/roles/default", params.get( "orgName" ), params.get( "appName" ) ) )
+ .queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).delete( String.class ));
+ Map<String, String> data = hashMap( "name", "reviewer" );
+
+ node = mapper.readTree( resource().path( String.format( "/%s/%s/roles", params.get( "orgName" ), params.get( "appName" ) ) )
+ .queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class, data ));
+ assertNull( getError( node ) );
+
+ refreshIndex(orgname, applicationName);
+
+ // allow access to reviews
+ addPermission( params.get( "orgName" ), params.get( "appName" ), adminToken, "reviewer",
+ "get,put,post:/reviews/**" );
+ // allow access to all user's connections
+ addPermission( params.get( "orgName" ), params.get( "appName" ), adminToken, "reviewer",
+ "get,put,post:/users/${user}/**" );
+ // allow access to the review relationship
+ addPermission( params.get( "orgName" ), params.get( "appName" ), adminToken, "reviewer",
+ "get,put,post:/books/*/review/*" );
+
+ assertNull( getError( node ) );
+ // create userOne
+ UUID userOneId =
+ createRoleUser( orgs.getOrganization().getUuid(), appInfo.getId(), adminToken, "wildcardpermuserone",
+ "wildcardpermuserone@apigee.com" );
+ assertNotNull( userOneId );
+
+ // create userTwo
+ UUID userTwoId =
+ createRoleUser( orgs.getOrganization().getUuid(), appInfo.getId(), adminToken, "wildcardpermusertwo",
+ "wildcardpermusertwo@apigee.com" );
+ assertNotNull( userTwoId );
+
+ refreshIndex(orgname, applicationName);
+
+ // assign userOne the reviewer role
+ node = mapper.readTree( resource().path( String
+ .format( "/%s/%s/users/%s/roles/reviewer", params.get( "orgName" ), params.get( "appName" ),
+ userOneId.toString() ) ).queryParam( "access_token", adminToken )
+ .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE ).post( String.class ));
+
+ refreshIndex(orgname, applicationName);
+
+ Map<String, String> book = hashMap( "title", "Ready Player One" ).map( "author", "Earnest Cline" );
+
+ // create a book as admin
+ node = mapper.readTree( resource().path( String.format( "/%s/%s/books", params.get( "orgName" ), params.get( "appName" ) ) )
+ .queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class, book ));
+
+ logNode( node );
+ assertEquals( "Ready Player One", getEntity( node, 0 ).get( "title" ).textValue() );
+ String bookId = getEntity( node, 0 ).get( "uuid" ).textValue();
+
+ refreshIndex(orgname, applicationName);
+
+ String userOneToken = setup.getMgmtSvc().getAccessTokenForAppUser( appInfo.getId(), userOneId, 0 );
+ // post a review of the book as user1
+ // POST https://api.usergrid.com/my-org/my-app/users/$user1/reviewed/books/$uuid
+ Map<String, String> review =
+ hashMap( "heading", "Loved It" ).map( "body", "80s Awesomeness set in the future" );
+ node = mapper.readTree( resource().path( String.format( "/%s/%s/reviews", params.get( "orgName" ), params.get( "appName" ) ) )
+ .queryParam( "access_token", userOneToken ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class, review ));
+ String reviewId = getEntity( node, 0 ).get( "uuid" ).textValue();
+
+ refreshIndex(orgname, applicationName);
+
+ // POST https://api.usergrid.com/my-org/my-app/users/me/wrote/review/${reviewId}
+ node = mapper.readTree( resource().path( String
+ .format( "/%s/%s/users/me/wrote/review/%s", params.get( "orgName" ), params.get( "appName" ),
+ reviewId ) ).queryParam( "access_token", userOneToken ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class ));
+
+ refreshIndex(orgname, applicationName);
+
+ node = mapper.readTree( resource().path( String
+ .format( "/%s/%s/users/me/reviewed/books/%s", params.get( "orgName" ), params.get( "appName" ),
+ bookId ) ).queryParam( "access_token", userOneToken ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class ));
+ logNode( node );
+
+ refreshIndex(orgname, applicationName);
+
+ // POST https://api.usergrid.com/my-org/my-app/books/${bookId}/review/${reviewId}
+ node = mapper.readTree( resource().path( String
+ .format( "/%s/%s/books/%s/review/%s", params.get( "orgName" ), params.get( "appName" ), bookId,
+ reviewId ) ).queryParam( "access_token", userOneToken ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class ));
+ logNode( node );
+
+ refreshIndex(orgname, applicationName);
+
+ // now try to post the same thing to books to verify as userOne the failure
+ Status status = null;
+ try {
+ node = mapper.readTree( resource().path( String.format( "/%s/%s/books", params.get( "orgName" ), params.get( "appName" ) ) )
+ .queryParam( "access_token", userOneToken ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class ));
+ logNode( node );
+ }
+ catch ( UniformInterfaceException uie ) {
+ status = uie.getResponse().getClientResponseStatus();
+ }
+ assertEquals( Status.UNAUTHORIZED, status );
+
+ refreshIndex(orgname, applicationName);
+
+ node = mapper.readTree( resource().path( String
+ .format( "/%s/%s/users/me/reviewed/books", params.get( "orgName" ), params.get( "appName" ) ) )
+ .queryParam( "access_token", userOneToken ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).get( String.class ));
+ logNode( node );
+
+ node = mapper.readTree( resource().path( String
+ .format( "/%s/%s/reviews/%s", params.get( "orgName" ), params.get( "appName" ), reviewId ) )
+ .queryParam( "access_token", userOneToken ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).get( String.class ));
+ logNode( node );
+
+ node = mapper.readTree( resource()
+ .path( String.format( "/%s/%s/users/me/wrote", params.get( "orgName" ), params.get( "appName" ) ) )
+ .queryParam( "access_token", userOneToken ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).get( String.class ));
+ logNode( node );
+ }
+
+
+ /**
+ * Tests the scenario where we have role declaration such as: <ul> <li>POST /users/[star]/following/users/${user}" a
+ * user can add himself to any other user following list"</li> </ul>
+ * <p/>
+ * Scenario is as follows: Create an application
+ * <p/>
+ * Add two application users - examplepatient - exampledoctor
+ * <p/>
+ * examplepatient add himself to exampledoctor following list
+ */
+ @Test
+ @Ignore("Why is this ignored?")
+ public void wildcardFollowingPermission() throws Exception {
+ UUID id = UUIDUtils.newTimeUUID();
+
+ String applicationName = "test";
+ String orgname = "followingpermissions";
+ String username = "permissionadmin" + id;
+ String password = "password";
+ String email = String.format( "email%s@usergrid.com", id );
+
+ OrganizationOwnerInfo orgs = setup.getMgmtSvc()
+ .createOwnerAndOrganization( orgname, username, "noname", email, password,
+ true, false );
+
+ // create the app
+ ApplicationInfo appInfo =
+ setup.getMgmtSvc().createApplication( orgs.getOrganization().getUuid(), applicationName );
+ assertNotNull( appInfo );
+
+ String adminToken = setup.getMgmtSvc().getAccessTokenForAdminUser( orgs.getOwner().getUuid(), 0 );
+
+ JsonNode node = mapper.readTree( resource().path( String.format( "/%s/%s/roles/default", orgname, applicationName ) )
+ .queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).delete( String.class ));
+ Map<String, String> data = hashMap( "name", "patient" );
+
+ node = mapper.readTree( resource().path( String.format( "/%s/%s/roles", orgname, applicationName ) )
+ .queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class, data ));
+ assertNull( getError( node ) );
+ //allow patients to add doctors as their followers
+ addPermission( orgname, applicationName, adminToken, "patient",
+ "delete,post:/users/*/following/users/${user}" );
+
+ assertNull( getError( node ) );
+ // create examplepatient
+ UUID patientId =
+ createRoleUser( orgs.getOrganization().getUuid(), appInfo.getId(), adminToken, "examplepatient",
+ "examplepatient@apigee.com" );
+ assertNotNull( patientId );
+
+ // create exampledoctor
+ UUID doctorId = createRoleUser( orgs.getOrganization().getUuid(), appInfo.getId(), adminToken, "exampledoctor",
+ "exampledoctor@apigee.com" );
+ assertNotNull( doctorId );
+
+
+ // assign examplepatient the patient role
+ node = mapper.readTree( resource().path( String
+ .format( "/%s/%s/users/%s/roles/patient", orgname, applicationName, patientId.toString() ) )
+ .queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).post( String.class ));
+
+ String patientToken = setup.getMgmtSvc().getAccessTokenForAppUser( appInfo.getId(), patientId, 0 );
+
+ node = mapper.readTree( resource().path( String
+ .format( "/%s/%s/users/%s/following/users/%s", orgname, applicationName, "exampledoctor",
+ "examplepatient" ) ).queryParam( "access_token", patientToken )
+ .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE ).post( String.class ));
+ logNode( node );
+ }
+
+
+ private Map<String, String> buildOrgAppParams() {
+ UUID id = UUIDUtils.newTimeUUID();
+ Map<String, String> props =
+ hashMap( "username", "wcpermadmin" ).map( "orgName", "orgnamewcperm" ).map( "appName", "test" )
+ .map( "password", "password" )
+ .map( "email", String.format( "email%s@apigee.com", id.toString() ) );
+
+ return props;
+ }
+
+
+ /**
+ * Create the user, check there are no errors
+ *
+ * @return the userid
+ */
+ private UUID createRoleUser( UUID orgId, UUID appId, String adminToken, String username, String email )
+ throws Exception {
+
+ Map<String, String> props = hashMap( "email", email ).map( "username", username ).map( "name", username )
+ .map( "password", "password" );
+
+ JsonNode node = mapper.readTree( resource().path( String.format( "/%s/%s/users", orgId, appId ) )
+ .queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).put( String.class, props ));
+
+ assertNull( getError( node ) );
+
+ UUID userId = UUID.fromString( getEntity( node, 0 ).get( "uuid" ).asText() );
+
+ // manually activate user
+ setup.getMgmtSvc().activateAppUser( appId, userId );
+
+ return userId;
+ }
+
+
+ /** Test adding the permission to the role */
+ private void addPermission( String orgname, String appname, String adminToken, String rolename, String grant ) throws IOException {
+ Map<String, String> props = hashMap( "permission", grant );
+
+ String rolePath = String.format( "/%s/%s/roles/%s/permissions", orgname, appname, rolename );
+
+ JsonNode node = mapper.readTree( resource().path( rolePath ).queryParam( "access_token", adminToken )
+ .accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE )
+ .put( String.class, props ));
+
+ assertNull( getError( node ) );
+
+ node = mapper.readTree( resource().path( rolePath ).queryParam( "access_token", adminToken ).accept( MediaType.APPLICATION_JSON )
+ .type( MediaType.APPLICATION_JSON_TYPE ).get( String.class ));
+
+ ArrayNode data = ( ArrayNode ) node.get( "data" );
+
+ Iterator<JsonNode> iterator = data.elements();
+
+ while ( iterator.hasNext() ) {
+ if ( grant.equals( iterator.next().asText() ) ) {
+ return;
+ }
+ }
+
+ fail( String.format( "didn't find grant %s in the results", grant ) );
+ }
+
+
+ /** Test adding the permission to the role */
+ private void addPermission( String orgname, String appname, String rolename, String grant ) throws IOException {
+ Map<String, String> props = hashMap( "permission", grant );
+
+ String rolePath = String.format( "/%s/%s/roles/%s/permissions", orgname, appname, rolename );
+
+ JsonNode node = mapper.readTree( resource().path( rolePath ).accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE )
+ .put( String.class, props ));
+
+ assertNull( getError( node ) );
+
+ node = mapper.readTree( resource().path( rolePath ).accept( MediaType.APPLICATION_JSON ).type( MediaType.APPLICATION_JSON_TYPE )
+ .get( String.class ));
+
+ ArrayNode data = ( ArrayNode ) node.get( "data" );
+
+ Iterator<JsonNode> iterator = data.elements();
+
+ while ( iterator.hasNext() ) {
+ if ( grant.equals( iterator.next().asText() ) ) {
+ return;
+ }
+ }
+
+ fail( String.format( "didn't find grant %s in the results", grant ) );
+ }
+}