/*
* 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.internal.cli.functions;
import static org.junit.Assert.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.lib.legacy.ClassImposteriser;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.execute.FunctionContext;
import org.apache.geode.cache.execute.ResultSender;
import org.apache.geode.cache.query.Index;
import org.apache.geode.cache.query.IndexStatistics;
import org.apache.geode.cache.query.IndexType;
import org.apache.geode.cache.query.QueryService;
import org.apache.geode.distributed.DistributedMember;
import org.apache.geode.distributed.DistributedSystem;
import org.apache.geode.internal.lang.Filter;
import org.apache.geode.internal.lang.ObjectUtils;
import org.apache.geode.internal.util.CollectionUtils;
import org.apache.geode.management.internal.cli.domain.IndexDetails;
import org.apache.geode.management.internal.cli.domain.IndexDetails.IndexStatisticsDetails;
import org.apache.geode.test.junit.categories.UnitTest;
/**
* The ListIndexFunctionJUnitTest class is test suite of test cases testing the contract and
* functionality of the ListIndexFunction GemFire function.
* </p>
* </p>
*
* @see org.apache.geode.management.internal.cli.functions.ListIndexFunction
* @see org.jmock.Expectations
* @see org.jmock.Mockery
* @see org.jmock.lib.legacy.ClassImposteriser
* @see org.junit.Assert
* @see org.junit.Test
* @since GemFire 7.0
*/
@Category(UnitTest.class)
public class ListIndexFunctionJUnitTest {
private Mockery mockContext;
private AtomicLong mockCounter;
@Before
public void setup() {
mockContext = new Mockery() {
{
setImposteriser(ClassImposteriser.INSTANCE);
}
};
mockCounter = new AtomicLong(0l);
}
@After
public void tearDown() {
mockContext.assertIsSatisfied();
mockContext = null;
}
private void assertIndexDetailsEquals(final IndexDetails expectedIndexDetails,
final IndexDetails actualIndexDetails) {
assertEquals(expectedIndexDetails.getFromClause(), actualIndexDetails.getFromClause());
assertEquals(expectedIndexDetails.getIndexedExpression(),
actualIndexDetails.getIndexedExpression());
assertEquals(expectedIndexDetails.getIndexName(), actualIndexDetails.getIndexName());
assertIndexStatisticsDetailsEquals(expectedIndexDetails.getIndexStatisticsDetails(),
actualIndexDetails.getIndexStatisticsDetails());
assertEquals(expectedIndexDetails.getIndexType(), actualIndexDetails.getIndexType());
assertEquals(expectedIndexDetails.getMemberId(), actualIndexDetails.getMemberId());
assertEquals(expectedIndexDetails.getMemberName(), actualIndexDetails.getMemberName());
assertEquals(expectedIndexDetails.getProjectionAttributes(),
actualIndexDetails.getProjectionAttributes());
assertEquals(expectedIndexDetails.getRegionName(), actualIndexDetails.getRegionName());
assertEquals(expectedIndexDetails.getRegionPath(), actualIndexDetails.getRegionPath());
}
private void assertIndexStatisticsDetailsEquals(
final IndexStatisticsDetails expectedIndexStatisticsDetails,
final IndexStatisticsDetails actualIndexStatisticsDetails) {
if (expectedIndexStatisticsDetails != null) {
assertNotNull(actualIndexStatisticsDetails);
assertEquals(expectedIndexStatisticsDetails.getNumberOfKeys(),
actualIndexStatisticsDetails.getNumberOfKeys());
assertEquals(expectedIndexStatisticsDetails.getNumberOfUpdates(),
actualIndexStatisticsDetails.getNumberOfUpdates());
assertEquals(expectedIndexStatisticsDetails.getNumberOfValues(),
actualIndexStatisticsDetails.getNumberOfValues());
assertEquals(expectedIndexStatisticsDetails.getTotalUpdateTime(),
actualIndexStatisticsDetails.getTotalUpdateTime());
assertEquals(expectedIndexStatisticsDetails.getTotalUses(),
actualIndexStatisticsDetails.getTotalUses());
} else {
assertNull(actualIndexStatisticsDetails);
}
}
private IndexDetails createIndexDetails(final String memberId, final String regionPath,
final String indexName, final IndexType indexType, final String fromClause,
final String indexedExpression, final String memberName, final String projectionAttributes,
final String regionName) {
final IndexDetails indexDetails = new IndexDetails(memberId, regionPath, indexName);
indexDetails.setFromClause(fromClause);
indexDetails.setIndexedExpression(indexedExpression);
indexDetails.setIndexType(indexType);
indexDetails.setMemberName(memberName);
indexDetails.setProjectionAttributes(projectionAttributes);
indexDetails.setRegionName(regionName);
return indexDetails;
}
private IndexStatisticsDetails createIndexStatisticsDetails(final Long numberOfKeys,
final Long numberOfUpdates, final Long numberOfValues, final Long totalUpdateTime,
final Long totalUses) {
final IndexStatisticsDetails indexStatisticsDetails = new IndexStatisticsDetails();
indexStatisticsDetails.setNumberOfKeys(numberOfKeys);
indexStatisticsDetails.setNumberOfUpdates(numberOfUpdates);
indexStatisticsDetails.setNumberOfValues(numberOfValues);
indexStatisticsDetails.setTotalUpdateTime(totalUpdateTime);
indexStatisticsDetails.setTotalUses(totalUses);
return indexStatisticsDetails;
}
private ListIndexFunction createListIndexFunction(final Cache cache) {
return new TestListIndexFunction(cache);
}
private Index createMockIndex(final IndexDetails indexDetails) {
final Index mockIndex = mockContext.mock(Index.class,
"Index " + indexDetails.getIndexName() + " " + mockCounter.getAndIncrement());
final Region mockRegion = mockContext.mock(Region.class,
"Region " + indexDetails.getRegionPath() + " " + mockCounter.getAndIncrement());
mockContext.checking(new Expectations() {
{
oneOf(mockIndex).getFromClause();
will(returnValue(indexDetails.getFromClause()));
oneOf(mockIndex).getIndexedExpression();
will(returnValue(indexDetails.getIndexedExpression()));
oneOf(mockIndex).getName();
will(returnValue(indexDetails.getIndexName()));
oneOf(mockIndex).getProjectionAttributes();
will(returnValue(indexDetails.getProjectionAttributes()));
exactly(2).of(mockIndex).getRegion();
will(returnValue(mockRegion));
oneOf(mockIndex).getType();
will(returnValue(getIndexType(indexDetails.getIndexType())));
oneOf(mockRegion).getName();
will(returnValue(indexDetails.getRegionName()));
oneOf(mockRegion).getFullPath();
will(returnValue(indexDetails.getRegionPath()));
}
});
if (indexDetails.getIndexStatisticsDetails() != null) {
final IndexStatistics mockIndexStatistics = mockContext.mock(IndexStatistics.class,
"IndexStatistics " + indexDetails.getIndexName() + " " + mockCounter.getAndIncrement());
mockContext.checking(new Expectations() {
{
exactly(2).of(mockIndex).getStatistics();
will(returnValue(mockIndexStatistics));
oneOf(mockIndexStatistics).getNumUpdates();
will(returnValue(indexDetails.getIndexStatisticsDetails().getNumberOfUpdates()));
oneOf(mockIndexStatistics).getNumberOfKeys();
will(returnValue(indexDetails.getIndexStatisticsDetails().getNumberOfKeys()));
oneOf(mockIndexStatistics).getNumberOfValues();
will(returnValue(indexDetails.getIndexStatisticsDetails().getNumberOfValues()));
oneOf(mockIndexStatistics).getTotalUpdateTime();
will(returnValue(indexDetails.getIndexStatisticsDetails().getTotalUpdateTime()));
oneOf(mockIndexStatistics).getTotalUses();
will(returnValue(indexDetails.getIndexStatisticsDetails().getTotalUses()));
}
});
} else {
mockContext.checking(new Expectations() {
{
oneOf(mockIndex).getStatistics();
will(returnValue(null));
}
});
}
return mockIndex;
}
private IndexType getIndexType(final IndexDetails.IndexType type) {
switch (type) {
case FUNCTIONAL:
return IndexType.FUNCTIONAL;
case PRIMARY_KEY:
return IndexType.PRIMARY_KEY;
default:
return null;
}
}
@Test
@SuppressWarnings("unchecked")
public void testExecute() throws Throwable {
final String memberId = "mockMemberId";
final String memberName = "mockMemberName";
final Cache mockCache = mockContext.mock(Cache.class, "Cache");
final DistributedSystem mockDistributedSystem =
mockContext.mock(DistributedSystem.class, "DistributedSystem");
final DistributedMember mockDistributedMember =
mockContext.mock(DistributedMember.class, "DistributedMember");
final IndexDetails indexDetailsOne =
createIndexDetails(memberId, "/Employees", "empIdIdx", IndexType.PRIMARY_KEY, "/Employees",
"id", memberName, "id, firstName, lastName", "Employees");
indexDetailsOne.setIndexStatisticsDetails(
createIndexStatisticsDetails(10124l, 4096l, 10124l, 1284100l, 280120l));
final IndexDetails indexDetailsTwo =
createIndexDetails(memberId, "/Employees", "empGivenNameIdx", IndexType.FUNCTIONAL,
"/Employees", "lastName", memberName, "id, firstName, lastName", "Employees");
final IndexDetails indexDetailsThree =
createIndexDetails(memberId, "/Contractors", "empIdIdx", IndexType.PRIMARY_KEY,
"/Contrators", "id", memberName, "id, firstName, lastName", "Contractors");
indexDetailsThree.setIndexStatisticsDetails(
createIndexStatisticsDetails(1024l, 256l, 20248l, 768001l, 24480l));
final IndexDetails indexDetailsFour =
createIndexDetails(memberId, "/Employees", "empIdIdx", IndexType.FUNCTIONAL, "/Employees",
"emp_id", memberName, "id, surname, givenname", "Employees");
final Set<IndexDetails> expectedIndexDetailsSet = new HashSet<IndexDetails>(3);
expectedIndexDetailsSet.add(indexDetailsOne);
expectedIndexDetailsSet.add(indexDetailsTwo);
expectedIndexDetailsSet.add(indexDetailsThree);
final QueryService mockQueryService = mockContext.mock(QueryService.class, "QueryService");
final FunctionContext mockFunctionContext =
mockContext.mock(FunctionContext.class, "FunctionContext");
final TestResultSender testResultSender = new TestResultSender();
mockContext.checking(new Expectations() {
{
oneOf(mockCache).getDistributedSystem();
will(returnValue(mockDistributedSystem));
oneOf(mockCache).getQueryService();
will(returnValue(mockQueryService));
oneOf(mockDistributedSystem).getDistributedMember();
will(returnValue(mockDistributedMember));
exactly(4).of(mockDistributedMember).getId();
will(returnValue(memberId));
exactly(4).of(mockDistributedMember).getName();
will(returnValue(memberName));
oneOf(mockQueryService).getIndexes();
will(returnValue(
Arrays.asList(createMockIndex(indexDetailsOne), createMockIndex(indexDetailsTwo),
createMockIndex(indexDetailsThree), createMockIndex(indexDetailsFour))));
oneOf(mockFunctionContext).getResultSender();
will(returnValue(testResultSender));
}
});
final ListIndexFunction function = createListIndexFunction(mockCache);
function.execute(mockFunctionContext);
final List<?> results = testResultSender.getResults();
assertNotNull(results);
assertEquals(1, results.size());
final Set<IndexDetails> actualIndexDetailsSet = (Set<IndexDetails>) results.get(0);
assertNotNull(actualIndexDetailsSet);
assertEquals(expectedIndexDetailsSet.size(), actualIndexDetailsSet.size());
for (final IndexDetails expectedIndexDetails : expectedIndexDetailsSet) {
final IndexDetails actualIndexDetails =
CollectionUtils.findBy(actualIndexDetailsSet, new Filter<IndexDetails>() {
@Override
public boolean accept(final IndexDetails indexDetails) {
return ObjectUtils.equals(expectedIndexDetails, indexDetails);
}
});
assertNotNull(actualIndexDetails);
assertIndexDetailsEquals(expectedIndexDetails, actualIndexDetails);
}
}
@Test
@SuppressWarnings("unchecked")
public void testExecuteWithNoIndexes() throws Throwable {
final Cache mockCache = mockContext.mock(Cache.class, "Cache");
final DistributedSystem mockDistributedSystem =
mockContext.mock(DistributedSystem.class, "DistributedSystem");
final DistributedMember mockDistributedMember =
mockContext.mock(DistributedMember.class, "DistributedMember");
final QueryService mockQueryService = mockContext.mock(QueryService.class, "QueryService");
final FunctionContext mockFunctionContext =
mockContext.mock(FunctionContext.class, "FunctionContext");
final TestResultSender testResultSender = new TestResultSender();
mockContext.checking(new Expectations() {
{
oneOf(mockCache).getDistributedSystem();
will(returnValue(mockDistributedSystem));
oneOf(mockCache).getQueryService();
will(returnValue(mockQueryService));
oneOf(mockDistributedSystem).getDistributedMember();
will(returnValue(mockDistributedMember));
oneOf(mockQueryService).getIndexes();
will(returnValue(Collections.emptyList()));
oneOf(mockFunctionContext).getResultSender();
will(returnValue(testResultSender));
}
});
final ListIndexFunction function = createListIndexFunction(mockCache);
function.execute(mockFunctionContext);
final List<?> results = testResultSender.getResults();
assertNotNull(results);
assertEquals(1, results.size());
final Set<IndexDetails> actualIndexDetailsSet = (Set<IndexDetails>) results.get(0);
assertNotNull(actualIndexDetailsSet);
assertTrue(actualIndexDetailsSet.isEmpty());
}
@Test(expected = RuntimeException.class)
public void testExecuteThrowsException() throws Throwable {
final Cache mockCache = mockContext.mock(Cache.class, "Cache");
final DistributedSystem mockDistributedSystem =
mockContext.mock(DistributedSystem.class, "DistributedSystem");
final DistributedMember mockDistributedMember =
mockContext.mock(DistributedMember.class, "DistributedMember");
final QueryService mockQueryService = mockContext.mock(QueryService.class, "QueryService");
final FunctionContext mockFunctionContext =
mockContext.mock(FunctionContext.class, "FunctionContext");
final TestResultSender testResultSender = new TestResultSender();
mockContext.checking(new Expectations() {
{
oneOf(mockCache).getDistributedSystem();
will(returnValue(mockDistributedSystem));
oneOf(mockCache).getQueryService();
will(returnValue(mockQueryService));
oneOf(mockDistributedSystem).getDistributedMember();
will(returnValue(mockDistributedMember));
oneOf(mockQueryService).getIndexes();
will(throwException(new RuntimeException("expected")));
oneOf(mockFunctionContext).getResultSender();
will(returnValue(testResultSender));
}
});
final ListIndexFunction function = createListIndexFunction(mockCache);
function.execute(mockFunctionContext);
try {
testResultSender.getResults();
} catch (Throwable t) {
assertTrue(t instanceof RuntimeException);
assertEquals("expected", t.getMessage());
throw t;
}
}
private static class TestListIndexFunction extends ListIndexFunction {
private final Cache cache;
protected TestListIndexFunction(final Cache cache) {
assert cache != null : "The Cache cannot be null!";
this.cache = cache;
}
@Override
protected Cache getCache() {
return this.cache;
}
}
private static class TestResultSender implements ResultSender {
private final List<Object> results = new LinkedList<Object>();
private Throwable t;
protected List<Object> getResults() throws Throwable {
if (t != null) {
throw t;
}
return Collections.unmodifiableList(results);
}
@Override
public void lastResult(final Object lastResult) {
results.add(lastResult);
}
@Override
public void sendResult(final Object oneResult) {
results.add(oneResult);
}
@Override
public void sendException(final Throwable t) {
this.t = t;
}
}
}