blob: 24a571c8cdd1edb00bf2a8f433c2b00baf64e33b [file] [log] [blame]
/*
* 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.geode.management;
import static org.apache.geode.cache.Region.SEPARATOR;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.ArrayList;
import java.util.Collection;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.cache.query.data.Portfolio;
import org.apache.geode.internal.cache.InternalCache;
import org.apache.geode.management.internal.ManagementConstants;
import org.apache.geode.management.internal.SystemManagementService;
import org.apache.geode.management.internal.beans.DataQueryEngine;
import org.apache.geode.management.internal.beans.QueryDataFunction;
import org.apache.geode.management.model.EmptyObject;
import org.apache.geode.management.model.Item;
import org.apache.geode.management.model.Order;
import org.apache.geode.management.model.SubOrder;
import org.apache.geode.pdx.PdxInstance;
import org.apache.geode.pdx.PdxInstanceFactory;
import org.apache.geode.pdx.internal.PdxInstanceFactoryImpl;
import org.apache.geode.test.junit.categories.GfshTest;
import org.apache.geode.test.junit.rules.ServerStarterRule;
/**
* Functional integration tests for {@link DataQueryEngine}.
*/
@Category(GfshTest.class)
public class DataQueryEngineIntegrationTest {
private static final String REGION_NAME = "exampleRegion";
private static final String QUERY_1 = "SELECT * FROM " + SEPARATOR + "exampleRegion";
/**
* Number of rows queryData operation will return. By default it will be 1000
*/
private static final int queryResultSetLimit = ManagementConstants.DEFAULT_QUERY_LIMIT;
/**
* Number of elements to be shown in queryData operation if query results contain collections like
* Map, List etc.
*/
private static final int queryCollectionsDepth =
QueryDataFunction.DEFAULT_COLLECTION_ELEMENT_LIMIT;
@Rule
public ServerStarterRule server = new ServerStarterRule().withNoCacheServer()
.withJMXManager().withRegion(RegionShortcut.REPLICATE, REGION_NAME).withAutoStart();
private Region<Object, Object> region;
private DataQueryEngine queryEngine;
@Before
public void setUp() throws Exception {
region = server.getCache().getRegion(REGION_NAME);
queryEngine = new DataQueryEngine((SystemManagementService) server.getManagementService(),
server.getCache());
}
/**
* Tests a model where Objects have a circular reference with object reference. e.g. Order1--
* Has--> Items each Item --Has --> OrderN where (OrderN == Order1)
* <p>
*
* RegressionTest for TRAC #51048: Disk Read/ Write shows negative at cluster level JMX
*/
@Test
public void testCyclicWithNestedObjectReference() throws Exception {
Order order = new Order();
order.setId("test");
for (int subOrderIndex = 1; subOrderIndex <= 5; subOrderIndex++) {
Item item = new Item(order, "ID_" + subOrderIndex, "Book");
order.addItem(item);
}
region.put("order1", order);
String expectedResult =
"{\"result\":[[\"org.apache.geode.management.model.Order\",{\"id\":[\"java.lang.String\",\"test\"],\"items\":[\"java.util.ArrayList\",{\"0\":[\"org.apache.geode.management.model.Item\",{\"itemDescription\":[\"java.lang.String\",\"Book\"],\"itemId\":[\"java.lang.String\",\"ID_1\"],\"order\":\"duplicate org.apache.geode.management.model.Order\"}],\"1\":[\"org.apache.geode.management.model.Item\",{\"itemDescription\":[\"java.lang.String\",\"Book\"],\"itemId\":[\"java.lang.String\",\"ID_2\"],\"order\":\"duplicate org.apache.geode.management.model.Order\"}],\"2\":[\"org.apache.geode.management.model.Item\",{\"itemDescription\":[\"java.lang.String\",\"Book\"],\"itemId\":[\"java.lang.String\",\"ID_3\"],\"order\":\"duplicate org.apache.geode.management.model.Order\"}],\"3\":[\"org.apache.geode.management.model.Item\",{\"itemDescription\":[\"java.lang.String\",\"Book\"],\"itemId\":[\"java.lang.String\",\"ID_4\"],\"order\":\"duplicate org.apache.geode.management.model.Order\"}],\"4\":[\"org.apache.geode.management.model.Item\",{\"itemDescription\":[\"java.lang.String\",\"Book\"],\"itemId\":[\"java.lang.String\",\"ID_5\"],\"order\":\"duplicate org.apache.geode.management.model.Order\"}]}]}]]}";
String queryResult =
queryEngine.queryForJsonResult(QUERY_1, 0, queryResultSetLimit, queryCollectionsDepth);
assertThat(queryResult).isEqualToIgnoringWhitespace(expectedResult);
// If not correct JSON format this will throw a JSONException
new ObjectMapper().readTree(queryResult);
}
/**
* Tests a model where Objects have a circular reference with their class types. e.g. Order1--
* Has--> Items each Item --Has --> OrderN where (OrderN != Order1)
*/
@Test
public void testCyclicWithNestedClasses() throws Exception {
Order order = new Order();
order.setId("test");
for (int subOrderIndex = 1; subOrderIndex <= 5; subOrderIndex++) {
Order subOrder = new Order();
subOrder.setId("ORDER_ID_" + subOrderIndex);
Item item = new Item(subOrder, "ID_" + subOrderIndex, "Book");
order.addItem(item);
}
region.put("order1", order);
String queryResult = queryEngine.queryForJsonResult(QUERY_1, 0, queryResultSetLimit,
queryCollectionsDepth);
String expectedResult =
"{\"result\":[[\"org.apache.geode.management.model.Order\",{\"id\":[\"java.lang.String\",\"test\"],\"items\":[\"java.util.ArrayList\",{\"0\":[\"org.apache.geode.management.model.Item\",{\"itemDescription\":[\"java.lang.String\",\"Book\"],\"itemId\":[\"java.lang.String\",\"ID_1\"],\"order\":[\"org.apache.geode.management.model.Order\",{\"id\":[\"java.lang.String\",\"ORDER_ID_1\"],\"items\":[\"java.util.ArrayList\",{}]}]}],\"1\":[\"org.apache.geode.management.model.Item\",{\"itemDescription\":[\"java.lang.String\",\"Book\"],\"itemId\":[\"java.lang.String\",\"ID_2\"],\"order\":[\"org.apache.geode.management.model.Order\",{\"id\":[\"java.lang.String\",\"ORDER_ID_2\"],\"items\":[\"java.util.ArrayList\",{}]}]}],\"2\":[\"org.apache.geode.management.model.Item\",{\"itemDescription\":[\"java.lang.String\",\"Book\"],\"itemId\":[\"java.lang.String\",\"ID_3\"],\"order\":[\"org.apache.geode.management.model.Order\",{\"id\":[\"java.lang.String\",\"ORDER_ID_3\"],\"items\":[\"java.util.ArrayList\",{}]}]}],\"3\":[\"org.apache.geode.management.model.Item\",{\"itemDescription\":[\"java.lang.String\",\"Book\"],\"itemId\":[\"java.lang.String\",\"ID_4\"],\"order\":[\"org.apache.geode.management.model.Order\",{\"id\":[\"java.lang.String\",\"ORDER_ID_4\"],\"items\":[\"java.util.ArrayList\",{}]}]}],\"4\":[\"org.apache.geode.management.model.Item\",{\"itemDescription\":[\"java.lang.String\",\"Book\"],\"itemId\":[\"java.lang.String\",\"ID_5\"],\"order\":[\"org.apache.geode.management.model.Order\",{\"id\":[\"java.lang.String\",\"ORDER_ID_5\"],\"items\":[\"java.util.ArrayList\",{}]}]}]}]}]]}";
assertThat(queryResult).isEqualToIgnoringWhitespace(expectedResult);
// If not correct JSON format this will throw a JSONException
new ObjectMapper().readTree(queryResult);
}
/**
* Tests a model where Objects have a circular reference with their class types. e.g. Order1--
* Has--> Items each Item --Has --> OrderN where (OrderN != Order1)
*/
@Test
public void testCyclicWithNestedRefernce2ndLayer() throws Exception {
Collection<Item> items = new ArrayList<>();
Order order = new Order("ORDER_TEST", items);
for (int subOrderIndex = 1; subOrderIndex <= 5; subOrderIndex++) {
Order subOrder = new Order();
subOrder.setId("ORDER_ID_" + subOrderIndex);
subOrder.setItems(items);
Item item = new Item(subOrder, "ID_" + subOrderIndex, "Book");
order.addItem(item);
}
region.put("order1", order);
String queryResult = queryEngine.queryForJsonResult(QUERY_1, 0, queryResultSetLimit,
queryCollectionsDepth);
String expectedResult =
"{\"result\":[[\"org.apache.geode.management.model.Order\",{\"id\":[\"java.lang.String\",\"ORDER_TEST\"],\"items\":[\"java.util.ArrayList\",{\"0\":[\"org.apache.geode.management.model.Item\",{\"itemDescription\":[\"java.lang.String\",\"Book\"],\"itemId\":[\"java.lang.String\",\"ID_1\"],\"order\":[\"org.apache.geode.management.model.Order\",{\"id\":[\"java.lang.String\",\"ORDER_ID_1\"],\"items\":[\"java.util.ArrayList\",{\"0\":\"duplicate org.apache.geode.management.model.Item\",\"1\":[\"org.apache.geode.management.model.Item\",{\"itemDescription\":[\"java.lang.String\",\"Book\"],\"itemId\":[\"java.lang.String\",\"ID_2\"],\"order\":[\"org.apache.geode.management.model.Order\",{\"id\":[\"java.lang.String\",\"ORDER_ID_2\"],\"items\":[\"java.util.ArrayList\",{\"0\":\"duplicate org.apache.geode.management.model.Item\",\"1\":\"duplicate org.apache.geode.management.model.Item\",\"2\":[\"org.apache.geode.management.model.Item\",{\"itemDescription\":[\"java.lang.String\",\"Book\"],\"itemId\":[\"java.lang.String\",\"ID_3\"],\"order\":[\"org.apache.geode.management.model.Order\",{\"id\":[\"java.lang.String\",\"ORDER_ID_3\"],\"items\":[\"java.util.ArrayList\",{\"0\":\"duplicate org.apache.geode.management.model.Item\",\"1\":\"duplicate org.apache.geode.management.model.Item\",\"2\":\"duplicate org.apache.geode.management.model.Item\",\"3\":[\"org.apache.geode.management.model.Item\",{\"itemDescription\":[\"java.lang.String\",\"Book\"],\"itemId\":[\"java.lang.String\",\"ID_4\"],\"order\":[\"org.apache.geode.management.model.Order\",{\"id\":[\"java.lang.String\",\"ORDER_ID_4\"],\"items\":[\"java.util.ArrayList\",{\"0\":\"duplicate org.apache.geode.management.model.Item\",\"1\":\"duplicate org.apache.geode.management.model.Item\",\"2\":\"duplicate org.apache.geode.management.model.Item\",\"3\":\"duplicate org.apache.geode.management.model.Item\",\"4\":[\"org.apache.geode.management.model.Item\",{\"itemDescription\":[\"java.lang.String\",\"Book\"],\"itemId\":[\"java.lang.String\",\"ID_5\"],\"order\":[\"org.apache.geode.management.model.Order\",{\"id\":[\"java.lang.String\",\"ORDER_ID_5\"],\"items\":[\"java.util.ArrayList\",{\"0\":\"duplicate org.apache.geode.management.model.Item\",\"1\":\"duplicate org.apache.geode.management.model.Item\",\"2\":\"duplicate org.apache.geode.management.model.Item\",\"3\":\"duplicate org.apache.geode.management.model.Item\",\"4\":\"duplicate org.apache.geode.management.model.Item\"}]}]}]}]}]}],\"4\":\"duplicate org.apache.geode.management.model.Item\"}]}]}],\"3\":\"duplicate org.apache.geode.management.model.Item\",\"4\":\"duplicate org.apache.geode.management.model.Item\"}]}]}],\"2\":\"duplicate org.apache.geode.management.model.Item\",\"3\":\"duplicate org.apache.geode.management.model.Item\",\"4\":\"duplicate org.apache.geode.management.model.Item\"}]}]}],\"1\":\"duplicate org.apache.geode.management.model.Item\",\"2\":\"duplicate org.apache.geode.management.model.Item\",\"3\":\"duplicate org.apache.geode.management.model.Item\",\"4\":\"duplicate org.apache.geode.management.model.Item\"}]}]]}";
assertThat(queryResult).isEqualToIgnoringWhitespace(expectedResult);
// If not correct JSON format this will throw a JSONException
new ObjectMapper().readTree(queryResult);
}
@Test
public void testCyclicWithCollection1stLayer() throws Exception {
Collection<Item> items = new ArrayList<>();
Order order = new Order("ORDER_TEST", items);
for (int subOrderIndex = 1; subOrderIndex <= 5; subOrderIndex++) {
Order subOrder = new Order();
subOrder.setId("ORDER_ID_" + subOrderIndex);
subOrder.setItems(items);
Item item = new Item(subOrder, "ID_" + subOrderIndex, "Book");
order.addItem(item);
}
region.put("items", items);
String queryResult = queryEngine.queryForJsonResult(QUERY_1, 0, queryResultSetLimit,
queryCollectionsDepth);
System.out.println("Query Result: " + queryResult);
// If not correct JSON format this will throw a JSONException
new ObjectMapper().readTree(queryResult);
}
@Test
public void testCyclicCollectionWithMultipleObjects() throws Exception {
for (int orderIndex = 1; orderIndex <= 5; orderIndex++) {
Collection<Item> items = new ArrayList<>();
Order order = new Order("ORDER_TEST_" + orderIndex, items);
for (int subOrderIndex = 1; subOrderIndex <= 5; subOrderIndex++) {
Order subOrder = new Order();
subOrder.setId("ORDER_ID_" + subOrderIndex);
subOrder.setItems(items);
Item item = new Item(subOrder, "ID_" + subOrderIndex, "Book");
order.addItem(item);
}
region.put("items_" + orderIndex, items);
}
String queryResult = queryEngine.queryForJsonResult(QUERY_1, 0, queryResultSetLimit,
queryCollectionsDepth);
System.out.println("Query Result: " + queryResult);
// If not correct JSON format this will throw a JSONException
new ObjectMapper().readTree(queryResult);
}
@Test
public void testCyclicArrayMultipleObjects() throws Exception {
for (int orderIndex = 1; orderIndex <= 5; orderIndex++) {
Collection<Item> items = new ArrayList<>();
Order order = new Order("ORDER_TEST_" + orderIndex, items);
for (int subOrderIndex = 1; subOrderIndex <= 5; subOrderIndex++) {
Order subOrder = new Order();
subOrder.setId("ORDER_ID_" + subOrderIndex);
subOrder.setItems(items);
Item item = new Item(subOrder, "ID_" + subOrderIndex, "Book");
order.addItem(item);
}
region.put("items_" + orderIndex, items);
}
String queryResult = queryEngine.queryForJsonResult(QUERY_1, 0, queryResultSetLimit,
queryCollectionsDepth);
System.out.println("Query Result: " + queryResult);
// If not correct JSON format this will throw a JSONException
new ObjectMapper().readTree(queryResult);
}
@Test
public void testCyclicArrayMultipleObjectsMemberWise() throws Exception {
region.put(1, new Portfolio(0));
String queryResult = queryEngine.queryForJsonResult(QUERY_1, "server", 0, queryResultSetLimit,
queryCollectionsDepth);
System.out.println(queryResult);
// If not correct JSON format this will throw a JSONException
new ObjectMapper().readTree(queryResult);
}
@Test
public void testEmptyObject() throws Exception {
EmptyObject emptyObject = new EmptyObject();
region.put("port", emptyObject);
String queryResult = queryEngine.queryForJsonResult(QUERY_1, 0, queryResultSetLimit,
queryCollectionsDepth);
String expectedResult = "{\"result\":[[\"org.apache.geode.management.model.EmptyObject\",{}]]}";
assertThat(queryResult).isEqualToIgnoringWhitespace(expectedResult);
// If not correct JSON format this will throw a JSONException
new ObjectMapper().readTree(queryResult);
}
@Test
public void testSubClassOverridingMethods() throws Exception {
SubOrder subOrder = new SubOrder();
region.put("port", subOrder);
String queryResult = queryEngine.queryForJsonResult(QUERY_1, 0, queryResultSetLimit,
queryCollectionsDepth);
String expectedResult =
"{\"result\":[[\"org.apache.geode.management.model.SubOrder\",{\"id\":[\"java.lang.String\",\"null1\"],\"items\":[\"java.util.ArrayList\",{}]}]]}";
assertThat(queryResult).isEqualToIgnoringWhitespace(expectedResult);
// If not correct JSON format this will throw a JSONException
new ObjectMapper().readTree(queryResult);
}
@Test
public void testNestedPDXObject() throws Exception {
PdxInstanceFactory factory = PdxInstanceFactoryImpl.newCreator("Portfolio", false,
(InternalCache) region.getRegionService());
factory.writeInt("ID", 111);
factory.writeString("status", "active");
factory.writeString("secId", "IBM");
PdxInstance pdxInstance = factory.create();
region.put("port", pdxInstance);
String queryResult = queryEngine.queryForJsonResult(QUERY_1, 0, queryResultSetLimit,
queryCollectionsDepth);
String expectedResult =
"{\"result\":[[\"org.apache.geode.pdx.PdxInstance\",{\"ID\":[\"java.lang.Integer\",111],\"status\":[\"java.lang.String\",\"active\"],\"secId\":[\"java.lang.String\",\"IBM\"]}]]}";
assertThat(queryResult).isEqualToIgnoringWhitespace(expectedResult);
// If not correct JSON format this will throw a JSONException
new ObjectMapper().readTree(queryResult);
}
@Test
public void testArrayWithNullValues() throws Exception {
SubOrder[] subOrderArray = new SubOrder[2];
subOrderArray[0] = new SubOrder();
subOrderArray[1] = null;
region.put("p1", subOrderArray);
String queryResult = queryEngine.queryForJsonResult(QUERY_1, 0, queryResultSetLimit,
queryCollectionsDepth);
String expectedResult =
"{\"result\":[[\"org.apache.geode.management.model.SubOrder[]\",[{\"id\":[\"java.lang.String\",\"null1\"],\"items\":[\"java.util.ArrayList\",{}]},null]]]}";
assertThat(queryResult).isEqualToIgnoringWhitespace(expectedResult);
// If not correct JSON format this will throw a JSONException
new ObjectMapper().readTree(queryResult);
}
@Test
public void testWithSqlDate() throws Exception {
SubOrder[] subOrderArray = new SubOrder[2];
subOrderArray[0] = new SubOrder();
subOrderArray[1] = null;
region.put("p1", subOrderArray);
String queryResult = queryEngine.queryForJsonResult(QUERY_1, 0, queryResultSetLimit,
queryCollectionsDepth);
String expectedResult =
"{\"result\":[[\"org.apache.geode.management.model.SubOrder[]\",[{\"id\":[\"java.lang.String\",\"null1\"],\"items\":[\"java.util.ArrayList\",{}]},null]]]}";
assertThat(queryResult).isEqualToIgnoringWhitespace(expectedResult);
// If not correct JSON format this will throw a JSONException
new ObjectMapper().readTree(queryResult);
}
@Test
public void testWithUnknownRegion() throws Exception {
String queryResult =
queryEngine.queryForJsonResult("select * from " + SEPARATOR + "unknonwn", 1, 1, 1);
assertThat(queryResult)
.isEqualTo("{\"message\":\"Cannot find regions " + SEPARATOR
+ "unknonwn in any of the members\"}");
}
public static class Root {
public Root getRoot() {
return this;
}
public Child getChild() { // getter that returns unique instances
return new Child();
}
}
public static class Child {
public Child getChild() {
return this;
}
}
}