package org.infinispan.query.continuous;
import static org.infinispan.query.dsl.Expression.max;
import static org.infinispan.query.dsl.Expression.param;
import static org.testng.AssertJUnit.assertEquals;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.objectfilter.ParsingException;
import org.infinispan.query.Search;
import org.infinispan.query.api.continuous.ContinuousQuery;
import org.infinispan.query.dsl.Query;
import org.infinispan.query.dsl.QueryFactory;
import org.infinispan.query.test.Person;
import org.infinispan.test.SingleCacheManagerTest;
import org.infinispan.test.TestingUtil;
import org.infinispan.test.fwk.TestCacheManagerFactory;
import org.infinispan.util.ControlledTimeService;
import org.infinispan.util.TimeService;
import org.testng.annotations.Test;
/**
* @author anistor@redhat.com
* @since 8.0
*/
@Test(groups = "functional", testName = "query.continuous.ContinuousQueryTest")
public class ContinuousQueryTest extends SingleCacheManagerTest {
protected ControlledTimeService timeService = new ControlledTimeService();
@Override
protected EmbeddedCacheManager createCacheManager() throws Exception {
ConfigurationBuilder cacheConfiguration = TestCacheManagerFactory.getDefaultCacheConfiguration(true);
//cacheConfiguration.transaction().lockingMode(LockingMode.PESSIMISTIC);
EmbeddedCacheManager cm = TestCacheManagerFactory.createCacheManager(cacheConfiguration);
TestingUtil.replaceComponent(cm, TimeService.class, timeService, true);
return cm;
}
/**
* Fulltext continuous queries are not allowed.
*/
@Test(expectedExceptions = ParsingException.class, expectedExceptionsMessageRegExp = ".*ISPN028521:.*")
public void testDisallowFullTextQuery() {
Query query = Search.getQueryFactory(cache()).create("from org.infinispan.query.test.Person where name : 'john'");
ContinuousQuery<Object, Object> cq = Search.getContinuousQuery(cache());
cq.addContinuousQueryListener(query, new CallCountingCQResultListener<>());
}
/**
* Using grouping and aggregation with continuous query is not allowed.
*/
@Test(expectedExceptions = ParsingException.class, expectedExceptionsMessageRegExp = ".*ISPN028509:.*")
public void testDisallowGroupingAndAggregation() {
Query query = Search.getQueryFactory(cache()).from(Person.class)
.select(max("age"))
.having("age").gte(20)
.build();
ContinuousQuery<Object, Object> cq = Search.getContinuousQuery(cache());
cq.addContinuousQueryListener(query, new CallCountingCQResultListener<>());
}
public void testContinuousQuery() {
for (int i = 0; i < 2; i++) {
Person value = new Person();
value.setName("John");
value.setAge(30 + i);
cache().put(i, value);
}
QueryFactory qf = Search.getQueryFactory(cache());
ContinuousQuery<Object, Object> cq = Search.getContinuousQuery(cache());
Query query = qf.from(Person.class)
.select("age")
.having("age").lte(param("ageParam"))
.build().setParameter("ageParam", 30);
CallCountingCQResultListener<Object, Object> listener = new CallCountingCQResultListener<>();
cq.addContinuousQueryListener(query, listener);
final Map<Object, Integer> joined = listener.getJoined();
final Map<Object, Integer> updated = listener.getUpdated();
final Map<Object, Integer> left = listener.getLeft();
assertEquals(1, joined.size());
assertEquals(0, updated.size());
assertEquals(0, left.size());
joined.clear();
for (int i = 0; i < 10; i++) {
Person value = new Person();
value.setName("John");
value.setAge(i + 25);
cache().put(i, value);
}
assertEquals(5, joined.size());
assertEquals(1, updated.size());
assertEquals(0, left.size());
joined.clear();
for (int i = 0; i < 2; i++) {
Person value = new Person();
value.setName("John");
value.setAge(i + 40);
cache().put(i, value);
}
assertEquals(0, joined.size());
assertEquals(1, updated.size());
assertEquals(2, left.size());
left.clear();
for (int i = 4; i < 20; i++) {
cache().remove(i);
}
assertEquals(0, joined.size());
assertEquals(1, updated.size());
assertEquals(2, left.size());
left.clear();
cache().clear(); //todo [anistor] Does this generate MODIFY instead of REMOVE ???
assertEquals(0, joined.size());
assertEquals(1, updated.size());
assertEquals(2, left.size());
left.clear();
for (int i = 0; i < 2; i++) {
Person value = new Person();
value.setName("John");
value.setAge(i + 20);
cache().put(i, value, 5, TimeUnit.MILLISECONDS);
}
assertEquals(2, joined.size());
assertEquals(1, updated.size());
assertEquals(0, left.size());
joined.clear();
timeService.advance(6);
cache.getAdvancedCache().getExpirationManager().processExpiration();
assertEquals(0, cache().size());
assertEquals(0, joined.size());
assertEquals(1, updated.size());
assertEquals(2, left.size());
left.clear();
cq.removeContinuousQueryListener(listener);
for (int i = 0; i < 3; i++) {
Person value = new Person();
value.setName("John");
value.setAge(i + 20);
cache().put(i, value);
}
assertEquals(0, joined.size());
assertEquals(1, updated.size());
assertEquals(0, left.size());
}
public void testContinuousQueryChangingParameter() {
for (int i = 0; i < 2; i++) {
Person value = new Person();
value.setName("John");
value.setAge(30 + i);
cache().put(i, value);
}
QueryFactory qf = Search.getQueryFactory(cache());
ContinuousQuery<Object, Object> cq = Search.getContinuousQuery(cache());
Query query = qf.from(Person.class)
.select("age")
.having("age").lte(param("ageParam"))
.build();
query.setParameter("ageParam", 30);
CallCountingCQResultListener<Object, Object> listener = new CallCountingCQResultListener<>();
cq.addContinuousQueryListener(query, listener);
Map<Object, Integer> joined = listener.getJoined();
Map<Object, Integer> updated = listener.getUpdated();
Map<Object, Integer> left = listener.getLeft();
assertEquals(1, joined.size());
assertEquals(0, updated.size());
assertEquals(0, left.size());
joined.clear();
cq.removeContinuousQueryListener(listener);
query.setParameter("ageParam", 32);
listener = new CallCountingCQResultListener<>();
cq.addContinuousQueryListener(query, listener);
joined = listener.getJoined();
left = listener.getLeft();
assertEquals(2, joined.size());
assertEquals(0, updated.size());
assertEquals(0, left.size());
cq.removeContinuousQueryListener(listener);
}
public void testTwoSimilarCQ() {
QueryFactory qf = Search.getQueryFactory(cache());
CallCountingCQResultListener<Object, Object> listener = new CallCountingCQResultListener<>();
Query query1 = qf.from(Person.class)
.having("age").lte(30)
.and().having("name").eq("John").or().having("name").eq("Johny")
.build();
ContinuousQuery<Object, Object> cq1 = Search.getContinuousQuery(cache());
cq1.addContinuousQueryListener(query1, listener);
Query query2 = qf.from(Person.class)
.having("age").lte(30).or().having("name").eq("Joe")
.build();
ContinuousQuery<Object, Object> cq2 = Search.getContinuousQuery(cache());
cq2.addContinuousQueryListener(query2, listener);
final Map<Object, Integer> joined = listener.getJoined();
final Map<Object, Integer> updated = listener.getUpdated();
final Map<Object, Integer> left = listener.getLeft();
assertEquals(0, joined.size());
assertEquals(0, updated.size());
assertEquals(0, left.size());
Person value = new Person();
value.setName("John");
value.setAge(20);
cache().put(1, value);
assertEquals(1, joined.size());
assertEquals(2, joined.get(1).intValue());
assertEquals(0, updated.size());
assertEquals(0, left.size());
joined.clear();
value = new Person();
value.setName("Joe");
cache().replace(1, value);
assertEquals(0, joined.size());
assertEquals(1, updated.size());
assertEquals(1, left.size());
joined.clear();
left.clear();
value = new Person();
value.setName("Joe");
value.setAge(31);
cache().replace(1, value);
assertEquals(0, joined.size());
assertEquals(1, updated.size());
assertEquals(0, left.size());
joined.clear();
left.clear();
value = new Person();
value.setName("John");
value.setAge(29);
cache().put(1, value);
assertEquals(1, joined.size());
assertEquals(1, joined.get(1).intValue());
assertEquals(1, updated.size());
assertEquals(0, left.size());
joined.clear();
left.clear();
value = new Person();
value.setName("Johny");
value.setAge(29);
cache().put(1, value);
assertEquals(0, joined.size());
assertEquals(1, updated.size());
assertEquals(0, left.size());
joined.clear();
left.clear();
cache().clear();
assertEquals(0, joined.size());
assertEquals(1, left.size());
assertEquals(2, left.get(1).intValue());
assertEquals(1, updated.size());
}
}