package org.infinispan.client.hotrod.query; import static org.infinispan.client.hotrod.test.HotRodClientTestingUtil.killRemoteCacheManager; import static org.infinispan.client.hotrod.test.HotRodClientTestingUtil.killServers; import static org.infinispan.query.dsl.Expression.avg; import static org.infinispan.query.dsl.Expression.count; import static org.infinispan.query.dsl.Expression.max; import static org.infinispan.query.dsl.Expression.min; import static org.infinispan.query.dsl.Expression.param; import static org.infinispan.query.dsl.Expression.sum; import static org.infinispan.server.hotrod.test.HotRodTestingUtil.hotRodCacheConfiguration; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertFalse; import static org.testng.AssertJUnit.assertNotNull; import static org.testng.AssertJUnit.assertTrue; import java.io.IOException; import java.util.List; import org.hibernate.search.spi.SearchIntegrator; import org.infinispan.Cache; import org.infinispan.client.hotrod.RemoteCache; import org.infinispan.client.hotrod.RemoteCacheManager; import org.infinispan.client.hotrod.Search; import org.infinispan.client.hotrod.exceptions.HotRodClientException; import org.infinispan.client.hotrod.impl.query.RemoteQueryFactory; import org.infinispan.client.hotrod.marshall.ProtoStreamMarshaller; import org.infinispan.client.hotrod.query.testdomain.protobuf.AnalyzerTestEntity; import org.infinispan.client.hotrod.query.testdomain.protobuf.ModelFactoryPB; import org.infinispan.client.hotrod.query.testdomain.protobuf.marshallers.AnalyzerTestEntityMarshaller; import org.infinispan.client.hotrod.query.testdomain.protobuf.marshallers.MarshallerRegistration; import org.infinispan.client.hotrod.query.testdomain.protobuf.marshallers.NotIndexedMarshaller; import org.infinispan.client.hotrod.test.HotRodClientTestingUtil; import org.infinispan.commons.util.Util; import org.infinispan.configuration.cache.ConfigurationBuilder; import org.infinispan.configuration.cache.Index; import org.infinispan.protostream.FileDescriptorSource; import org.infinispan.protostream.SerializationContext; import org.infinispan.query.dsl.Query; import org.infinispan.query.dsl.QueryFactory; import org.infinispan.query.dsl.SortOrder; import org.infinispan.query.dsl.embedded.QueryDslConditionsTest; import org.infinispan.query.dsl.embedded.testdomain.Account; import org.infinispan.query.dsl.embedded.testdomain.ModelFactory; import org.infinispan.query.remote.client.ProtobufMetadataManagerConstants; import org.infinispan.query.remote.impl.indexing.ProtobufValueWrapper; import org.infinispan.server.hotrod.HotRodServer; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; /** * Test for query conditions (filtering). Exercises the whole query DSL on the sample domain model. * * @author anistor@redhat.com * @since 6.0 */ @Test(groups = "functional", testName = "client.hotrod.query.RemoteQueryDslConditionsTest") public class RemoteQueryDslConditionsTest extends QueryDslConditionsTest { private static final String NOT_INDEXED_PROTO_SCHEMA = "package sample_bank_account;\n" + "/* @Indexed(false) */\n" + "message NotIndexed {\n" + "\toptional string notIndexedField = 1;\n" + "}\n"; private static final String CUSTOM_ANALYZER_PROTO_SCHEMA = "package sample_bank_account;\n" + "/* @Indexed */\n" + "message AnalyzerTestEntity {\n" + "\t/* @Field(store = Store.YES, analyze = Analyze.YES, analyzer = @Analyzer(definition = \"stemmer\")) */\n" + "\toptional string f1 = 1;\n" + "\t/* @Field(store = Store.YES, analyze = Analyze.NO, indexNullAs = \"-1\") */\n" + "\toptional int32 f2 = 2;\n" + "}\n"; protected HotRodServer hotRodServer; protected RemoteCacheManager remoteCacheManager; protected RemoteCache<Object, Object> remoteCache; protected Cache<Object, Object> cache; @BeforeClass @Override protected void populateCache() throws Exception { super.populateCache(); getCacheForWrite().put("analyzed1", new AnalyzerTestEntity("testing 123", 3)); getCacheForWrite().put("analyzed2", new AnalyzerTestEntity("xyz", null)); } @Override protected QueryFactory getQueryFactory() { return Search.getQueryFactory(remoteCache); } @Override protected ModelFactory getModelFactory() { return ModelFactoryPB.INSTANCE; } @Override protected RemoteCache<Object, Object> getCacheForQuery() { return remoteCache; } protected Cache<Object, Object> getEmbeddedCache() { return cache; } @Override protected void createCacheManagers() throws Throwable { ConfigurationBuilder cfg = getConfigurationBuilder(); createClusteredCaches(1, cfg); cache = manager(0).getCache(); hotRodServer = HotRodClientTestingUtil.startHotRodServer(manager(0)); org.infinispan.client.hotrod.configuration.ConfigurationBuilder clientBuilder = new org.infinispan.client.hotrod.configuration.ConfigurationBuilder(); clientBuilder.addServer().host("127.0.0.1").port(hotRodServer.getPort()); clientBuilder.marshaller(new ProtoStreamMarshaller()); remoteCacheManager = new RemoteCacheManager(clientBuilder.build()); remoteCache = remoteCacheManager.getCache(); initProtoSchema(remoteCacheManager); } protected void initProtoSchema(RemoteCacheManager remoteCacheManager) throws IOException { //initialize server-side serialization context RemoteCache<String, String> metadataCache = remoteCacheManager.getCache(ProtobufMetadataManagerConstants.PROTOBUF_METADATA_CACHE_NAME); metadataCache.put("sample_bank_account/bank.proto", Util.read(Util.getResourceAsStream("/sample_bank_account/bank.proto", getClass().getClassLoader()))); metadataCache.put("not_indexed.proto", NOT_INDEXED_PROTO_SCHEMA); metadataCache.put("custom_analyzer.proto", CUSTOM_ANALYZER_PROTO_SCHEMA); assertFalse(metadataCache.containsKey(ProtobufMetadataManagerConstants.ERRORS_KEY_SUFFIX)); //initialize client-side serialization context SerializationContext serCtx = ProtoStreamMarshaller.getSerializationContext(remoteCacheManager); MarshallerRegistration.registerMarshallers(serCtx); serCtx.registerProtoFiles(FileDescriptorSource.fromString("not_indexed.proto", NOT_INDEXED_PROTO_SCHEMA)); serCtx.registerProtoFiles(FileDescriptorSource.fromString("custom_analyzer.proto", CUSTOM_ANALYZER_PROTO_SCHEMA)); serCtx.registerMarshaller(new NotIndexedMarshaller()); serCtx.registerMarshaller(new AnalyzerTestEntityMarshaller()); } protected ConfigurationBuilder getConfigurationBuilder() { ConfigurationBuilder builder = hotRodCacheConfiguration(); builder.indexing().index(Index.ALL) .addProperty("default.directory_provider", "ram") .addProperty("lucene_version", "LUCENE_CURRENT"); return builder; } @AfterClass(alwaysRun = true) public void release() { killRemoteCacheManager(remoteCacheManager); killServers(hotRodServer); } @Override public void testIndexPresence() { SearchIntegrator searchIntegrator = org.infinispan.query.Search.getSearchManager(cache).unwrap(SearchIntegrator.class); assertTrue(searchIntegrator.getIndexedTypes().contains(ProtobufValueWrapper.class)); assertNotNull(searchIntegrator.getIndexManager(ProtobufValueWrapper.class.getName())); } @Override public void testQueryFactoryType() { assertEquals(RemoteQueryFactory.class, getQueryFactory().getClass()); } @Test(expectedExceptions = HotRodClientException.class, expectedExceptionsMessageRegExp = ".*ISPN028503:.*") @Override public void testInvalidEmbeddedAttributeQuery() throws Exception { // the original exception gets wrapped in HotRodClientException super.testInvalidEmbeddedAttributeQuery(); } @Test(expectedExceptions = HotRodClientException.class, expectedExceptionsMessageRegExp = "org.infinispan.objectfilter.ParsingException: ISPN014027: The property path 'addresses.postCode' cannot be projected because it is multi-valued") @Override public void testRejectProjectionOfRepeatedProperty() { // the original exception gets wrapped in HotRodClientException super.testRejectProjectionOfRepeatedProperty(); } /** * This test is overridden because dates need special handling for protobuf (being actually emulated as long * timestamps). */ @Override public void testSampleDomainQuery9() throws Exception { QueryFactory qf = getQueryFactory(); // all the transactions that happened in January 2013, projected by date field only Query q = qf.from(getModelFactory().getTransactionImplClass()) .select("date") .having("date").between(makeDate("2013-01-01"), makeDate("2013-01-31")) .build(); List<Object[]> list = q.list(); assertEquals(4, list.size()); assertEquals(1, list.get(0).length); assertEquals(1, list.get(1).length); assertEquals(1, list.get(2).length); assertEquals(1, list.get(3).length); for (int i = 0; i < 4; i++) { Long d = (Long) list.get(i)[0]; assertTrue(d.compareTo(makeDate("2013-01-31").getTime()) <= 0); assertTrue(d.compareTo(makeDate("2013-01-01").getTime()) >= 0); } } public void testDefaultValue() throws Exception { QueryFactory qf = getQueryFactory(); Query q = qf.from(getModelFactory().getAccountImplClass()).orderBy("description", SortOrder.ASC).build(); List<Account> list = q.list(); assertEquals(3, list.size()); assertEquals("Checking account", list.get(0).getDescription()); } @Override @Test(expectedExceptions = HotRodClientException.class, expectedExceptionsMessageRegExp = "org.infinispan.objectfilter.ParsingException: ISPN014026: The expression 'surname' must be part of an aggregate function or it should be included in the GROUP BY clause") public void testGroupBy3() { // the original exception gets wrapped in HotRodClientException super.testGroupBy3(); } @Test(expectedExceptions = HotRodClientException.class, expectedExceptionsMessageRegExp = "org.infinispan.objectfilter.ParsingException: ISPN014021: Queries containing grouping and aggregation functions must use projections.") @Override public void testGroupBy5() { // the original exception gets wrapped in HotRodClientException super.testGroupBy5(); } @Test(expectedExceptions = HotRodClientException.class, expectedExceptionsMessageRegExp = "java.lang.IllegalStateException: Aggregation SUM cannot be applied to property of type java.lang.String") public void testGroupBy6() { // the original exception gets wrapped in HotRodClientException super.testGroupBy6(); } @Test(expectedExceptions = HotRodClientException.class, expectedExceptionsMessageRegExp = "org.infinispan.objectfilter.ParsingException: ISPN028515: Cannot have aggregate functions in the WHERE clause : SUM.") public void testGroupBy7() { // the original exception gets wrapped in HotRodClientException super.testGroupBy7(); } /** * This test is overridden because dates need special handling for protobuf (being actually emulated as long * timestamps). */ @Override public void testDateGrouping1() throws Exception { QueryFactory qf = getQueryFactory(); Query q = qf.from(getModelFactory().getTransactionImplClass()) .select("date") .having("date").between(makeDate("2013-02-15"), makeDate("2013-03-15")) .groupBy("date") .build(); List<Object[]> list = q.list(); assertEquals(1, list.size()); assertEquals(1, list.get(0).length); assertEquals(makeDate("2013-02-27").getTime(), list.get(0)[0]); } /** * This test is overridden because dates need special handling for protobuf (being actually emulated as long * timestamps). */ @Override public void testDateGrouping2() throws Exception { QueryFactory qf = getQueryFactory(); Query q = qf.from(getModelFactory().getTransactionImplClass()) .select(count("date"), min("date")) .having("description").eq("Hotel") .groupBy("id") .build(); List<Object[]> list = q.list(); assertEquals(1, list.size()); assertEquals(2, list.get(0).length); assertEquals(1L, list.get(0)[0]); assertEquals(makeDate("2013-02-27").getTime(), list.get(0)[1]); } /** * This test is overridden because dates need special handling for protobuf (being actually emulated as long * timestamps). */ @Override public void testDateGrouping3() throws Exception { QueryFactory qf = getQueryFactory(); Query q = qf.from(getModelFactory().getTransactionImplClass()) .select(min("date"), count("date")) .having("description").eq("Hotel") .groupBy("id") .build(); List<Object[]> list = q.list(); assertEquals(1, list.size()); assertEquals(2, list.get(0).length); assertEquals(makeDate("2013-02-27").getTime(), list.get(0)[0]); assertEquals(1L, list.get(0)[1]); } /** * This test is overridden because dates need special handling for protobuf (being actually emulated as long * timestamps). */ @Override public void testDuplicateDateProjection() throws Exception { QueryFactory qf = getQueryFactory(); Query q = qf.from(getModelFactory().getTransactionImplClass()) .select("id", "date", "date") .having("description").eq("Hotel") .build(); List<Object[]> list = q.list(); assertEquals(1, list.size()); assertEquals(3, list.get(0).length); assertEquals(3, list.get(0)[0]); assertEquals(makeDate("2013-02-27").getTime(), list.get(0)[1]); assertEquals(makeDate("2013-02-27").getTime(), list.get(0)[2]); } @Test(expectedExceptions = IllegalStateException.class, expectedExceptionsMessageRegExp = "ISPN014825: Query parameter 'param2' was not set") @Override public void testMissingParamWithParameterMap() throws Exception { // exception message code is different because it is generated by a different logger super.testMissingParamWithParameterMap(); } @Test(expectedExceptions = IllegalStateException.class, expectedExceptionsMessageRegExp = "ISPN014825: Query parameter 'param2' was not set") @Override public void testMissingParam() throws Exception { // exception message code is different because it is generated by a different logger super.testMissingParam(); } /** * This test is overridden because dates need special handling for protobuf (being actually emulated as long * timestamps). */ @Override public void testComplexQuery() throws Exception { QueryFactory qf = getQueryFactory(); Query q = qf.from(getModelFactory().getTransactionImplClass()) .select(avg("amount"), sum("amount"), count("date"), min("date"), max("accountId")) .having("isDebit").eq(param("param")) .orderBy(avg("amount"), SortOrder.DESC).orderBy(count("date"), SortOrder.DESC) .orderBy(max("amount"), SortOrder.ASC) .build(); q.setParameter("param", true); List<Object[]> list = q.list(); assertEquals(1, list.size()); assertEquals(5, list.get(0).length); assertEquals(143.50909d, (Double) list.get(0)[0], 0.0001d); assertEquals(7893d, (Double) list.get(0)[1], 0.0001d); assertEquals(55L, list.get(0)[2]); assertEquals(Long.class, list.get(0)[3].getClass()); assertEquals(makeDate("2013-01-01").getTime(), list.get(0)[3]); assertEquals(2, list.get(0)[4]); } /** * This test is overridden because dates need special handling for protobuf (being actually emulated as long * timestamps). */ @Override public void testDateFilteringWithGroupBy() throws Exception { QueryFactory qf = getQueryFactory(); Query q = qf.from(getModelFactory().getTransactionImplClass()) .select("date") .having("date").between(makeDate("2013-02-15"), makeDate("2013-03-15")) .groupBy("date") .build(); List<Object[]> list = q.list(); assertEquals(1, list.size()); assertEquals(1, list.get(0).length); assertEquals(Long.class, list.get(0)[0].getClass()); assertEquals(makeDate("2013-02-27").getTime(), list.get(0)[0]); } /** * This test is overridden because dates need special handling for protobuf (being actually emulated as long * timestamps). */ @Override public void testAggregateDate() throws Exception { QueryFactory qf = getQueryFactory(); Query q = qf.from(getModelFactory().getTransactionImplClass()) .select(count("date"), min("date")) .having("description").eq("Hotel") .groupBy("id") .build(); List<Object[]> list = q.list(); assertEquals(1, list.size()); assertEquals(2, list.get(0).length); assertEquals(1L, list.get(0)[0]); assertEquals(Long.class, list.get(0)[1].getClass()); assertEquals(makeDate("2013-02-27").getTime(), list.get(0)[1]); } @Test(expectedExceptions = HotRodClientException.class, expectedExceptionsMessageRegExp = "org.infinispan.objectfilter.ParsingException: ISPN014023: Using the multi-valued property path 'addresses.street' in the GROUP BY clause is not currently supported") @Override public void testGroupByMustNotAcceptRepeatedProperty() { // the original exception gets wrapped in HotRodClientException super.testGroupByMustNotAcceptRepeatedProperty(); } @Test(expectedExceptions = HotRodClientException.class, expectedExceptionsMessageRegExp = "org.infinispan.objectfilter.ParsingException: ISPN014024: The property path 'addresses.street' cannot be used in the ORDER BY clause because it is multi-valued") @Override public void testOrderByMustNotAcceptRepeatedProperty() { // the original exception gets wrapped in HotRodClientException super.testOrderByMustNotAcceptRepeatedProperty(); } @Test(expectedExceptions = HotRodClientException.class, expectedExceptionsMessageRegExp = "org.infinispan.objectfilter.ParsingException: ISPN028515: Cannot have aggregate functions in the WHERE clause : MIN.") @Override public void testRejectAggregationsInWhereClause() { // the original exception gets wrapped in HotRodClientException super.testRejectAggregationsInWhereClause(); } }