/* * 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.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.UUID; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.usergrid.AbstractCoreIT; import org.apache.usergrid.utils.JsonUtils; import static me.prettyprint.hector.api.factory.HFactory.createMutator; import static org.junit.Assert.*; public class IndexIT extends AbstractCoreIT { private static final Logger logger = LoggerFactory.getLogger( IndexIT.class ); public static final String[] alphabet = { "Alpha", "Bravo", "Charlie", "Delta", "Echo", "Foxtrot", "Golf", "Hotel", "India", "Juliet", "Kilo", "Lima", "Mike", "November", "Oscar", "Papa", "Quebec", "Romeo", "Sierra", "Tango", "Uniform", "Victor", "Whiskey", "X-ray", "Yankee", "Zulu" }; @Test public void testCollectionOrdering() throws Exception { logger.info( "testCollectionOrdering" ); UUID applicationId = app.getId(); EntityManager em = setup.getEmf().getEntityManager( applicationId ); assertNotNull( em ); for ( int i = alphabet.length - 1; i >= 0; i-- ) { String name = alphabet[i]; Map<String, Object> properties = new LinkedHashMap<String, Object>(); properties.put( "name", name ); em.create( "item", properties ); } app.waitForQueueDrainAndRefreshIndex(); int i = 0; Query query = Query.fromQL( "order by name" ); Results r = em.searchCollection( em.getApplicationRef(), "items", query ); for ( Entity entity : r.getEntities() ) { assertEquals( alphabet[i], entity.getProperty( "name" ) ); i++; } query = Query.fromQL( "order by name" ).withCursor(r.getCursor()); r = em.searchCollection( em.getApplicationRef(), "items", query ); for ( Entity entity : r.getEntities() ) { assertEquals( alphabet[i], entity.getProperty( "name" ) ); i++; } query = Query.fromQL( "order by name" ).withCursor(r.getCursor()); r = em.searchCollection( em.getApplicationRef(), "items", query ); for ( Entity entity : r.getEntities() ) { assertEquals( alphabet[i], entity.getProperty( "name" ) ); i++; } assertEquals( alphabet.length, i ); i = alphabet.length; query = Query.fromQL( "order by name desc" ); r = em.searchCollection( em.getApplicationRef(), "items", query ); for ( Entity entity : r.getEntities() ) { i--; assertEquals( alphabet[i], entity.getProperty( "name" ) ); } query = Query.fromQL( "order by name desc" ).withCursor(r.getCursor()); r = em.searchCollection( em.getApplicationRef(), "items", query ); // logger.info(JsonUtils.mapToFormattedJsonString(r.getEntities())); for ( Entity entity : r.getEntities() ) { i--; assertEquals( alphabet[i], entity.getProperty( "name" ) ); } query = Query.fromQL( "order by name desc" ).withCursor( r.getCursor() ); r = em.searchCollection( em.getApplicationRef(), "items", query ); for ( Entity entity : r.getEntities() ) { i--; assertEquals( alphabet[i], entity.getProperty( "name" ) ); } assertEquals( 0, i ); } @Test public void testCollectionFilters() throws Exception { logger.info( "testCollectionFilters" ); UUID applicationId = app.getId(); assertNotNull( applicationId ); EntityManager em = setup.getEmf().getEntityManager( applicationId ); assertNotNull( em ); for ( int i = alphabet.length - 1; i >= 0; i-- ) { String name = alphabet[i]; Map<String, Object> properties = new LinkedHashMap<String, Object>(); properties.put( "name", name ); em.create( "item", properties ); } app.waitForQueueDrainAndRefreshIndex(); Query query = Query.fromQL( "name < 'delta' order by name asc" ); Results r = em.searchCollection( em.getApplicationRef(), "items", query ); logger.info( JsonUtils.mapToFormattedJsonString( r.getEntities() ) ); int i = 0; for ( Entity entity : r.getEntities() ) { assertEquals( alphabet[i], entity.getProperty( "name" ) ); i++; } assertEquals( 3, i ); query = Query.fromQL( "name <= 'delta' order by name asc" ); r = em.searchCollection( em.getApplicationRef(), "items", query ); logger.info( JsonUtils.mapToFormattedJsonString( r.getEntities() ) ); i = 0; for ( Entity entity : r.getEntities() ) { assertEquals( alphabet[i], entity.getProperty( "name" ) ); i++; } assertEquals( 4, i ); query = Query.fromQL( "name <= 'foxtrot' and name > 'bravo' order by name asc" ); r = em.searchCollection( em.getApplicationRef(), "items", query ); logger.info( JsonUtils.mapToFormattedJsonString( r.getEntities() ) ); i = 2; for ( Entity entity : r.getEntities() ) { assertEquals( alphabet[i], entity.getProperty( "name" ) ); i++; } assertEquals( 6, i ); query = Query.fromQL( "name < 'foxtrot' and name > 'bravo' order by name asc" ); r = em.searchCollection( em.getApplicationRef(), "items", query ); logger.info( JsonUtils.mapToFormattedJsonString( r.getEntities() ) ); i = 2; for ( Entity entity : r.getEntities() ) { assertEquals( alphabet[i], entity.getProperty( "name" ) ); i++; } assertEquals( 5, i ); query = Query.fromQL( "name < 'foxtrot' and name >= 'bravo' order by name asc" ); r = em.searchCollection( em.getApplicationRef(), "items", query ); logger.info( JsonUtils.mapToFormattedJsonString( r.getEntities() ) ); i = 1; for ( Entity entity : r.getEntities() ) { assertEquals( alphabet[i], entity.getProperty( "name" ) ); i++; } assertEquals( 5, i ); query = Query.fromQL( "name <= 'foxtrot' and name >= 'bravo' order by name asc" ); r = em.searchCollection( em.getApplicationRef(), "items", query ); logger.info( JsonUtils.mapToFormattedJsonString( r.getEntities() ) ); i = 1; for ( Entity entity : r.getEntities() ) { assertEquals( alphabet[i], entity.getProperty( "name" ) ); i++; } assertEquals( 6, i ); query = Query.fromQL( "name <= 'foxtrot' and name >= 'bravo' order by name desc" ); r = em.searchCollection( em.getApplicationRef(), "items", query ); logger.info( JsonUtils.mapToFormattedJsonString( r.getEntities() ) ); i = 6; for ( Entity entity : r.getEntities() ) { i--; assertEquals( alphabet[i], entity.getProperty( "name" ) ); } assertEquals( 1, i ); query = Query.fromQL( "name < 'foxtrot' and name > 'bravo' order by name desc" ); r = em.searchCollection( em.getApplicationRef(), "items", query ); logger.info( JsonUtils.mapToFormattedJsonString( r.getEntities() ) ); i = 5; for ( Entity entity : r.getEntities() ) { i--; assertEquals( alphabet[i], entity.getProperty( "name" ) ); } assertEquals( 2, i ); query = Query.fromQL( "name < 'foxtrot' and name >= 'bravo' order by name desc" ); r = em.searchCollection( em.getApplicationRef(), "items", query ); logger.info( JsonUtils.mapToFormattedJsonString( r.getEntities() ) ); i = 5; for ( Entity entity : r.getEntities() ) { i--; assertEquals( alphabet[i], entity.getProperty( "name" ) ); } assertEquals( 1, i ); query = Query.fromQL( "name = 'foxtrot'" ); r = em.searchCollection( em.getApplicationRef(), "items", query ); logger.info( JsonUtils.mapToFormattedJsonString( r.getEntities() ) ); assertEquals( 1, r.size() ); long created = r.getEntity().getCreated(); UUID entityId = r.getEntity().getUuid(); query = Query.fromQL( "created = " + created ); r = em.searchCollection( em.getApplicationRef(), "items", query ); logger.info( JsonUtils.mapToFormattedJsonString( r.getEntities() ) ); assertEquals( 1, r.size() ); assertEquals( entityId, r.getEntity().getUuid() ); } @Test public void testSecondarySorts() throws Exception { logger.info( "testSecondarySorts" ); UUID applicationId = app.getId(); assertNotNull( applicationId ); EntityManager em = setup.getEmf().getEntityManager( applicationId ); assertNotNull( em ); for ( int i = alphabet.length - 1; i >= 0; i-- ) { String name = alphabet[i]; Map<String, Object> properties = new LinkedHashMap<String, Object>(); properties.put( "name", name ); properties.put( "group", (long)(i / 3) ); properties.put( "reverse_name", alphabet[alphabet.length - 1 - i] ); em.create( "item", properties ); } app.waitForQueueDrainAndRefreshIndex(); Query query = Query.fromQL( "group = 1 order by name desc" ); Results r = em.searchCollection( em.getApplicationRef(), "items", query ); logger.info( JsonUtils.mapToFormattedJsonString( r.getEntities() ) ); int i = 6; for ( Entity entity : r.getEntities() ) { i--; assertEquals( 1L, entity.getProperty( "group" ) ); assertEquals( alphabet[i], entity.getProperty( "name" ) ); } assertEquals( 3, i ); } @Test public void testEntityReduction() throws Exception { UUID applicationId = app.getId(); EntityManager em = setup.getEmf().getEntityManager(applicationId); Map<String, Object> entity1 = new LinkedHashMap<String, Object>(); entity1.put("name", "name_1"); entity1.put("status", "pickled"); em.create("names", entity1); app.waitForQueueDrainAndRefreshIndex(); //should return valid values Query query = Query.fromQL("select status where status = 'pickled'"); Results r = em.searchCollection( em.getApplicationRef(), "names", query ); assertTrue(r.getEntities() != null && r.getEntities().size() > 0); Entity first = r.getEntities().get(0); assertTrue(first.getDynamicProperties().size() == 2); //should return valid values query = Query.fromQL("select uuid where status = 'pickled'"); r = em.searchCollection( em.getApplicationRef(), "names", query ); assertTrue(r.getEntities() != null && r.getEntities().size() > 0); first = r.getEntities().get(0); assertTrue(first.getDynamicProperties().size() == 1); //should return valid values query = Query.fromQL("select uuid:myid where status = 'pickled'"); r = em.searchCollection( em.getApplicationRef(), "names", query ); assertTrue(r.getEntities() != null && r.getEntities().size() > 0); first = r.getEntities().get(0); assertTrue(first.getDynamicProperties().size() == 1); } @Test public void testPropertyUpdateWithConnection() throws Exception { UUID applicationId = app.getId(); EntityManager em = setup.getEmf().getEntityManager( applicationId ); Map<String, Object> entity1 = new LinkedHashMap<String, Object>(); entity1.put( "name", "name_1" ); entity1.put( "status", "pickled" ); Map<String, Object> entity2 = new LinkedHashMap<String, Object>(); entity2.put( "name", "name_2" ); entity2.put( "status", "foo" ); Entity entity1Ref = em.create( "names", entity1 ); Entity entity2Ref = em.create( "names", entity2 ); em.createConnection( entity2Ref, "connecting", entity1Ref ); app.waitForQueueDrainAndRefreshIndex(); //should return valid values Query query = Query.fromQL( "select * where status = 'pickled'" ); Results r = em.searchCollection( em.getApplicationRef(), "names", query ); assertEquals( 1, r.size() ); assertEquals( entity1Ref.getUuid(), r.getEntity().getUuid() ); r = em.searchCollection( em.getApplicationRef(), "names", query ); assertEquals( 1, r.size() ); assertEquals( entity1Ref.getUuid(), r.getEntity().getUuid() ); //now update the first entity, this causes the failure after connections entity1Ref.setProperty( "status", "herring" ); em.update( entity1Ref ); app.waitForQueueDrainAndRefreshIndex(); //query and check the status has been updated, shouldn't return results query = Query.fromQL( "select * where status = 'pickled'" ); r = em.searchCollection( em.getApplicationRef(), "names", query ); assertEquals( 0, r.size() ); //search connections r = em.searchCollection( em.getApplicationRef(), "names", query ); assertEquals( 0, r.size() ); //should return results query = Query.fromQL( "select * where status = 'herring'" ); r = em.searchCollection( em.getApplicationRef(), "names", query ); assertEquals( 1, r.size() ); assertEquals( entity1Ref.getUuid(), r.getEntity().getUuid() ); //search connections r = em.searchCollection( em.getApplicationRef(), "names", query ); assertEquals( 1, r.size() ); assertEquals( entity1Ref.getUuid(), r.getEntity().getUuid() ); } /** Same as above, but verifies the data in our entity_index_entry CF after the operations have completed */ @Test public void testPropertyUpdateWithConnectionEntityIndexEntryAudit() throws Exception { UUID applicationId = app.getId(); EntityManager em = setup.getEmf().getEntityManager( applicationId ); Map<String, Object> entity1 = new LinkedHashMap<String, Object>(); entity1.put( "name", "name_1" ); entity1.put( "status", "pickled" ); Map<String, Object> entity2 = new LinkedHashMap<String, Object>(); entity2.put( "name", "name_2" ); entity2.put( "status", "foo" ); Entity entity1Ref = em.create( "names", entity1 ); Entity entity2Ref = em.create( "names", entity2 ); em.createConnection( entity2Ref, "connecting", entity1Ref ); app.waitForQueueDrainAndRefreshIndex(); //should return valid values Query query = Query.fromQL( "select * where status = 'pickled'" ); Results r = em.searchCollection( em.getApplicationRef(), "names", query ); assertEquals( 1, r.size() ); assertEquals( entity1Ref.getUuid(), r.getEntity().getUuid() ); r = em.searchCollection( em.getApplicationRef(), "names", query ); assertEquals( 1, r.size() ); assertEquals( entity1Ref.getUuid(), r.getEntity().getUuid() ); //now update the first entity, this causes the failure after connections entity1Ref.setProperty( "status", "herring" ); em.update( entity1Ref ); app.waitForQueueDrainAndRefreshIndex(); //query and check the status has been updated, shouldn't return results query = Query.fromQL( "select * where status = 'pickled'" ); r = em.searchCollection( em.getApplicationRef(), "names", query ); assertEquals( 0, r.size() ); //search connections r = em.searchCollection( em.getApplicationRef(), "names", query ); assertEquals( 0, r.size() ); //should return results query = Query.fromQL( "select * where status = 'herring'" ); r = em.searchCollection( em.getApplicationRef(), "names", query ); assertEquals( 1, r.size() ); assertEquals( entity1Ref.getUuid(), r.getEntity().getUuid() ); //search connections r = em.searchCollection( em.getApplicationRef(), "names", query ); assertEquals( 1, r.size() ); assertEquals( entity1Ref.getUuid(), r.getEntity().getUuid() ); } @Test public void testSelectMappings() throws Exception { UUID applicationId = app.getId(); EntityManager em = setup.getEmf().getEntityManager(applicationId); Map<String, Object> entity1 = new HashMap<String, Object>() {{ put("name","name_1"); put("status", "pickled"); put("data", new HashMap() {{ put("xfactor", 5.1); put("rando", "bar"); put("mondo", "2000"); put("frosting", "chocolate"); put("misc", new HashMap() {{ put("range", "open"); }}); }}); }}; em.create("names", entity1); Map<String, Object> entity2 = new HashMap<String, Object>() {{ put("name","name_2"); put("status", "pickled"); put("data", new HashMap() {{ put("xfactor", 5.1); put("rando", "bar"); put("mondo", "2001"); put("frosting", "orange"); put("misc", new HashMap() {{ put("range", "open"); }}); }}); }}; em.create("names", entity2); app.waitForQueueDrainAndRefreshIndex(); // simple single-field select mapping { Query query = Query.fromQL("select status where status = 'pickled'"); Results r = em.searchCollection( em.getApplicationRef(), "names", query ); assertTrue(r.getEntities() != null && r.getEntities().size() == 2); Entity first = r.getEntities().get(0); assertTrue(first.getDynamicProperties().size() == 2); } // simple single-field plus nested field select mapping { Query query = Query.fromQL( "select status, data.rando where data.rando = 'bar'" ); Results r = em.searchCollection( em.getApplicationRef(), "names", query ); assertTrue( r.getEntities() != null && r.getEntities().size() == 2 ); Entity first = r.getEntities().get( 0 ); assertNotNull( first.getProperty("status") ); assertEquals( first.getProperty("status"), "pickled" ); assertNotNull( first.getProperty("data") ); assertEquals( ((Map<String, Object>)first.getProperty("data")).get("rando"), "bar" ); assertTrue( first.getDynamicProperties().size() == 3 ); } // multiple nested fields with one doubly-nested field { Query query = Query.fromQL( "select data.rando, data.mondo, data.misc.range where status = 'pickled'" ); Results r = em.searchCollection( em.getApplicationRef(), "names", query ); assertTrue( r.getEntities() != null && r.getEntities().size() == 2 ); Entity first = r.getEntities().get( 0 ); Map<String, Object> data = ((Map<String, Object>)first.getProperty("data")); assertNotNull( data ); assertEquals( data.get("rando"), "bar" ); assertEquals( data.get("mondo"), "2001" ); assertNull( data.get("frosting") ); Map<String, Object> misc = (Map<String, Object>)data.get("misc"); assertEquals( misc.get("range"), "open" ); assertTrue( first.getDynamicProperties().size() == 2 ); } // query for one bogus field name should return empty entities { Query query = Query.fromQL( "select data.bogusfieldname where status = 'pickled'" ); Results r = em.searchCollection( em.getApplicationRef(), "names", query ); assertTrue( r.getEntities() != null && r.getEntities().size() == 2 ); Entity first = r.getEntities().get( 0 ); assertTrue( first.getDynamicProperties().size() == 1 ); } } }