/*
* 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;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.junit.Test;
import org.apache.usergrid.AbstractCoreIT;
import org.apache.usergrid.persistence.Query.Level;
import org.apache.usergrid.persistence.model.util.UUIDGenerator;
import static org.junit.Assert.assertEquals;
public class PathQueryIT extends AbstractCoreIT {
@Test
public void testUserDevicePathQuery() throws Exception {
UUID applicationId = setup.createApplication(
"testOrganization"+ UUIDGenerator.newTimeUUID(), "testUserDevicePathQuery" + UUIDGenerator.newTimeUUID() );
EntityManager em = setup.getEmf().getEntityManager( applicationId );
List<Entity> users = new ArrayList<Entity>();
for ( int i = 0; i < 15; i++ ) {
Map<String, Object> properties = new LinkedHashMap<String, Object>();
properties.put( "index", i );
properties.put( "username", "user " + i );
Entity created = em.create( "user", properties );
users.add( created );
}
List<EntityRef> deviceRefs = new ArrayList<EntityRef>();
for ( Entity user : users ) {
for ( int i = 0; i < 5; i++ ) {
Map<String, Object> properties = new LinkedHashMap<String, Object>();
properties.put( "index", i );
Entity created = em.create( "device", properties );
deviceRefs.add( created );
em.addToCollection( user, "devices", created );
}
}
app.waitForQueueDrainAndRefreshIndex();
Thread.sleep(1000);
// pick an arbitrary user, ensure it has 5 devices
Results devices = em.getCollection( users.get( 10 ), "devices", null, 20, Level.IDS, false );
assertEquals( 5, devices.size() );
int pageSize = 10; // shouldn't affect these tests
Query userQuery = Query.fromQL( "select * where index >= 2 AND index <= 13" );
userQuery.setCollection( "users" );
userQuery.setLimit( pageSize );
int expectedUserQuerySize = 12;
// query the users, ignoring page boundaries
Results results = em.searchCollection( em.getApplicationRef(), "users", userQuery );
PagingResultsIterator pri = new PagingResultsIterator( results );
int count = 13;
while ( pri.hasNext() ) {
Entity e = ( Entity ) pri.next();
assertEquals( count --, e.getProperty( "index" ) );
}
assertEquals( count, 1 );
// query devices as a sub-query of the users, ignoring page boundaries
Query deviceQuery = Query.fromQL( "select * where index >= 2 " );
deviceQuery.setCollection( "devices" );
deviceQuery.setLimit( pageSize );
int expectedDeviceQuerySize = 3;
PathQuery<EntityRef> usersPQ = new PathQuery<EntityRef>(
new SimpleEntityRef( em.getApplicationRef()), userQuery );
PathQuery<Entity> devicesPQ = usersPQ.chain( deviceQuery );
HashSet set = new HashSet( expectedUserQuerySize * expectedDeviceQuerySize );
Iterator<Entity> i = devicesPQ.iterator( em );
while ( i.hasNext() ) {
set.add( i.next() );
}
assertEquals( expectedUserQuerySize * expectedDeviceQuerySize, set.size() );
}
@Test
public void testGroupUserDevicePathQuery() throws Exception {
UUID applicationId = setup.createApplication(
"testOrganization"+ UUIDGenerator.newTimeUUID(), "testGroupUserDevicePathQuery" + UUIDGenerator.newTimeUUID() );
EntityManager em = setup.getEmf().getEntityManager( applicationId );
List<Entity> groups = new ArrayList<Entity>();
for ( int i = 0; i < 4; i++ ) {
Map<String, Object> properties = new LinkedHashMap<String, Object>();
properties.put( "index", i );
properties.put( "path", "group_" + i );
Entity created = em.create( "group", properties );
groups.add( created );
}
List<Entity> users = new ArrayList<Entity>();
for ( Entity group : groups ) {
for ( int i = 0; i < 7; i++ ) {
Map<String, Object> properties = new LinkedHashMap<String, Object>();
properties.put( "index", i );
properties.put( "username", group.getProperty( "path" ) + " user " + i );
Entity created = em.create( "user", properties );
em.addToCollection( group, "users", created );
users.add( created );
}
}
app.waitForQueueDrainAndRefreshIndex();
// pick an arbitrary group, ensure it has 7 users
Results ru = em.getCollection( groups.get( 2 ), "users", null, 20, Level.IDS, false );
assertEquals( 7, ru.size() );
List<EntityRef> devices = new ArrayList<EntityRef>();
for ( Entity user : users ) {
for ( int i = 0; i < 7; i++ ) {
Map<String, Object> properties = new LinkedHashMap<String, Object>();
properties.put( "index", i );
Entity created = em.create( "device", properties );
devices.add( created );
em.addToCollection( user, "devices", created );
}
}
app.waitForQueueDrainAndRefreshIndex();
// pick an arbitrary user, ensure it has 7 devices
Results rd = em.getCollection( users.get( 6 ), "devices", null, 20, Level.IDS, false );
assertEquals( 7, rd.size() );
int pageSize = 3; // ensure we're crossing page boundaries
Query groupQuery = Query.fromQL( "select * where index <= 7 " );
groupQuery.setCollection( "groups" );
groupQuery.setLimit( pageSize );
int expectedGroupQuerySize = 4;
Query userQuery = Query.fromQL( "select * where index >= 2 AND index <= 6" );
userQuery.setCollection( "users" );
userQuery.setLimit( pageSize );
int expectedUserQuerySize = 5;
Query deviceQuery = Query.fromQL( "select * where index >= 4 " );
deviceQuery.setCollection( "devices" );
deviceQuery.setLimit( pageSize );
int expectedDeviceQuerySize = 3;
final PathQuery groupsPQ = new PathQuery(new SimpleEntityRef( em.getApplicationRef() ), groupQuery );
//test 1 level deep
HashSet groupSet = new HashSet( expectedGroupQuerySize );
Iterator<Entity> groupsIterator = groupsPQ.iterator( em );
while ( groupsIterator.hasNext() ) {
groupSet.add( groupsIterator.next() );
}
assertEquals( expectedGroupQuerySize, groupSet.size() );
//test 2 levels
final PathQuery groupsPQ1 = new PathQuery(new SimpleEntityRef( em.getApplicationRef() ), groupQuery );
PathQuery usersPQ1 = groupsPQ1.chain( userQuery );
final Iterator<Entity> userIterator = usersPQ1.iterator( em );
final HashSet userSet = new HashSet( expectedGroupQuerySize * expectedUserQuerySize );
while ( userIterator.hasNext() ) {
userSet.add( userIterator.next() );
}
assertEquals( expectedGroupQuerySize * expectedUserQuerySize, userSet.size() );
Thread.sleep(1000);
// ORIGINAL TEST, restore
PathQuery groupsPQ2 = new PathQuery(new SimpleEntityRef( em.getApplicationRef() ), groupQuery );
PathQuery usersPQ2 = groupsPQ2.chain( userQuery );
PathQuery<Entity> devicesPQ2 = usersPQ2.chain( deviceQuery );
final HashSet deviceSet = new HashSet( expectedGroupQuerySize * expectedUserQuerySize * expectedDeviceQuerySize );
Iterator<Entity> i = devicesPQ2.iterator( em );
while ( i.hasNext() ) {
deviceSet.add( i.next() );
}
assertEquals( expectedGroupQuerySize * expectedUserQuerySize * expectedDeviceQuerySize, deviceSet.size() );
}
}