/* // This software is subject to the terms of the Eclipse Public License v1.0 // Agreement, available at the following URL: // http://www.eclipse.org/legal/epl-v10.html. // You must accept the terms of that agreement to use this software. // // Copyright (C) 2006-2015 Pentaho and others // All Rights Reserved. */ package mondrian.rolap; import mondrian.rolap.sql.MemberChildrenConstraint; import junit.framework.TestCase; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class MemberCacheHelperTest extends TestCase { @Mock private RolapMember parentMember; @Mock private ChildByNameConstraint childByNameConstraint; @Mock private MemberKey memberKey; private MemberChildrenConstraint defMemChildrenConstraint = DefaultMemberChildrenConstraint.instance(); private List<RolapMember> children = new ArrayList<RolapMember>(); private MemberCacheHelper cacheHelper = new MemberCacheHelper(null); @Override public void setUp() { MockitoAnnotations.initMocks(this); } public void testRoundtripChildrenUsingChildByNameConstraint() { List<String> childNames = fillChildren(children, 3); when(childByNameConstraint.getChildNames()).thenReturn(childNames); cacheHelper.putChildren(parentMember, childByNameConstraint, children); List<RolapMember> retrievedChildren = cacheHelper.getChildrenFromCache( parentMember, childByNameConstraint); assertEquals(children, retrievedChildren); } public void testCachedByDefaultConstraint() { List<String> childNames = fillChildren(children, 5); when(childByNameConstraint.getChildNames()).thenReturn(childNames); // cached under default constraint, but subsequent // retrieval with childByName should work since all children present. cacheHelper.putChildren( parentMember, defMemChildrenConstraint, children); List<RolapMember> retrievedChildren = cacheHelper.getChildrenFromCache( parentMember, childByNameConstraint); assertEquals(children, retrievedChildren); } public void testOnlyRequestedChildrenRetrieved() { // tests retrieval of a subset of children from // the cache with keyed with DefaultMemberChildrenConstraint List<String> childNames = fillChildren(children, 5); int FROM = 2; int TO = 5; // childByName constraint defined with member names in sublist when(childByNameConstraint.getChildNames()).thenReturn( childNames.subList(FROM, TO)); // cached under default constraint, but subsequent // retrieval with childByName should work since all children present. cacheHelper.putChildren( parentMember, defMemChildrenConstraint, children); List<RolapMember> retrievedChildren = cacheHelper.getChildrenFromCache( parentMember, childByNameConstraint); assertEquals( "Expected children were not retrieved from cache.", children.subList(FROM, TO), retrievedChildren); } public void testMissingChildrenNotRetrievedDefaultConst() { runMissingChildrenNotRetrievedTest(defMemChildrenConstraint); } public void testMissingChildrenNotRetrievedChildByName() { runMissingChildrenNotRetrievedTest(childByNameConstraint); } public void runMissingChildrenNotRetrievedTest( MemberChildrenConstraint constraint) { fillChildren(children, 5); when(childByNameConstraint.getChildNames()).thenReturn( Arrays.asList(new String[]{ "Other Name", "Other Name2" })); cacheHelper.putChildren( parentMember, constraint, children); List<RolapMember> retrievedChildren = cacheHelper.getChildrenFromCache( parentMember, childByNameConstraint); assertEquals( "Not expecting to retrieve anything from cache", null, retrievedChildren); } public void testRemoveChildMemberPresentInNamedChildrenMap() { List<String> childNames = fillChildren(children, 3); when(childByNameConstraint.getChildNames()).thenReturn( childNames.subList(1, 3)); List<MemberKey> childKeys = new ArrayList<MemberKey>(); for (RolapMember member : children) { when(member.getParentMember()).thenReturn(parentMember); MemberKey key = mockMemberKey(); childKeys.add(key); cacheHelper.putMember(key, member); } cacheHelper.putMember(memberKey, parentMember); cacheHelper.putChildren(parentMember, childByNameConstraint, children); cacheHelper.removeMember(childKeys.get(0)); List<RolapMember> members = cacheHelper.getChildrenFromCache( parentMember, childByNameConstraint); assertEquals( "Retrieved children should not include the removed member", children.subList(1, 3), members); } private MemberKey mockMemberKey() { MemberKey mock = mock(MemberKey.class); when(mock.getLevel()).thenReturn(mock(RolapLevel.class)); return mock; } private List<String> fillChildren(List<RolapMember> children, int count) { List<String> names = new ArrayList<String>(); for (int i = 0; i < count; i++) { RolapMember member = mock(RolapMember.class); String name = "Member-" + i; names.add(name); when(member.getName()).thenReturn(name); // there's a bug in mockito which causes mock objects // .compareTo to always return 1 // https://code.google.com/p/mockito/issues/detail?id=467 // here's a workaround. when(member.compareTo(any(RolapMember.class))).thenAnswer( new Answer<Object>() { public Object answer(InvocationOnMock invocation) throws Throwable { return ((RolapMember)invocation.getMock()).getName() .compareTo( ((RolapMember) invocation.getArguments()[0]) .getName()); } } ); children.add(member); } return names; } } // End MemberCacheHelperTest.java