/* * 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.cache.lucene.internal; import static org.junit.Assert.*; import static org.mockito.Matchers.*; import static org.mockito.Mockito.when; import java.io.IOException; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.index.IndexWriter; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.apache.geode.cache.lucene.internal.directory.RegionDirectory; import org.apache.geode.cache.lucene.internal.filesystem.FileSystemStats; import org.apache.geode.cache.lucene.internal.repository.IndexRepository; import org.apache.geode.cache.lucene.internal.repository.IndexRepositoryImpl; import org.apache.geode.cache.lucene.internal.repository.serializer.HeterogeneousLuceneSerializer; import org.apache.geode.cache.lucene.internal.repository.serializer.LuceneSerializer; import org.apache.geode.internal.cache.BucketNotFoundException; import org.apache.geode.internal.cache.BucketRegion; import org.apache.geode.internal.cache.GemFireCacheImpl; import org.apache.geode.internal.cache.PartitionedRegion; import org.apache.geode.internal.cache.PartitionedRegion.RetryTimeKeeper; import org.apache.geode.internal.cache.PartitionedRegionDataStore; import org.apache.geode.internal.cache.execute.InternalRegionFunctionContext; import org.apache.geode.test.fake.Fakes; import org.apache.geode.test.junit.categories.UnitTest; @Category(UnitTest.class) public class PartitionedRepositoryManagerJUnitTest { protected PartitionedRegion userRegion; protected PartitionedRegion fileRegion; protected PartitionedRegion chunkRegion; protected LuceneSerializer serializer; protected PartitionedRegionDataStore userDataStore; protected PartitionedRegionDataStore fileDataStore; protected PartitionedRegionDataStore chunkDataStore; protected Map<Integer, BucketRegion> fileBuckets = new HashMap<Integer, BucketRegion>(); protected Map<Integer, BucketRegion> chunkBuckets = new HashMap<Integer, BucketRegion>(); protected Map<Integer, BucketRegion> dataBuckets = new HashMap<Integer, BucketRegion>(); protected LuceneIndexStats indexStats; protected FileSystemStats fileSystemStats; protected LuceneIndexImpl indexForPR; protected AbstractPartitionedRepositoryManager repoManager; protected GemFireCacheImpl cache; @Before public void setUp() { cache = Fakes.cache(); userRegion = Mockito.mock(PartitionedRegion.class); userDataStore = Mockito.mock(PartitionedRegionDataStore.class); when(userRegion.getDataStore()).thenReturn(userDataStore); when(cache.getRegion("/testRegion")).thenReturn(userRegion); serializer = new HeterogeneousLuceneSerializer(new String[] {"a", "b"}); createIndexAndRepoManager(); } protected void createIndexAndRepoManager() { fileRegion = Mockito.mock(PartitionedRegion.class); fileDataStore = Mockito.mock(PartitionedRegionDataStore.class); when(fileRegion.getDataStore()).thenReturn(fileDataStore); chunkRegion = Mockito.mock(PartitionedRegion.class); chunkDataStore = Mockito.mock(PartitionedRegionDataStore.class); when(chunkRegion.getDataStore()).thenReturn(chunkDataStore); indexStats = Mockito.mock(LuceneIndexStats.class); fileSystemStats = Mockito.mock(FileSystemStats.class); indexForPR = Mockito.mock(LuceneIndexForPartitionedRegion.class); when(((LuceneIndexForPartitionedRegion) indexForPR).getFileRegion()).thenReturn(fileRegion); when(((LuceneIndexForPartitionedRegion) indexForPR).getChunkRegion()).thenReturn(chunkRegion); when(((LuceneIndexForPartitionedRegion) indexForPR).getFileSystemStats()) .thenReturn(fileSystemStats); when(indexForPR.getIndexStats()).thenReturn(indexStats); when(indexForPR.getAnalyzer()).thenReturn(new StandardAnalyzer()); when(indexForPR.getCache()).thenReturn(cache); when(indexForPR.getRegionPath()).thenReturn("/testRegion"); repoManager = new PartitionedRepositoryManager(indexForPR, serializer); } @Test public void getByKey() throws BucketNotFoundException, IOException { setUpMockBucket(0); setUpMockBucket(1); IndexRepositoryImpl repo0 = (IndexRepositoryImpl) repoManager.getRepository(userRegion, 0, null); IndexRepositoryImpl repo1 = (IndexRepositoryImpl) repoManager.getRepository(userRegion, 1, null); IndexRepositoryImpl repo113 = (IndexRepositoryImpl) repoManager.getRepository(userRegion, 113, null); assertNotNull(repo0); assertNotNull(repo1); assertNotNull(repo113); assertEquals(repo0, repo113); assertNotEquals(repo0, repo1); checkRepository(repo0, 0); checkRepository(repo1, 1); } /** * Test what happens when a bucket is destroyed. */ @Test public void destroyBucketShouldCreateNewIndexRepository() throws BucketNotFoundException, IOException { setUpMockBucket(0); IndexRepositoryImpl repo0 = (IndexRepositoryImpl) repoManager.getRepository(userRegion, 0, null); assertNotNull(repo0); checkRepository(repo0, 0); BucketRegion fileBucket0 = fileBuckets.get(0); BucketRegion dataBucket0 = dataBuckets.get(0); // Simulate rebalancing of a bucket by marking the old bucket is destroyed // and creating a new bucket when(dataBucket0.isDestroyed()).thenReturn(true); setUpMockBucket(0); IndexRepositoryImpl newRepo0 = (IndexRepositoryImpl) repoManager.getRepository(userRegion, 0, null); assertNotEquals(repo0, newRepo0); checkRepository(newRepo0, 0); assertTrue(repo0.isClosed()); assertFalse(repo0.getWriter().isOpen()); } /** * Test that we get the expected exception when a user bucket is missing */ @Test(expected = BucketNotFoundException.class) public void getMissingBucketByKey() throws BucketNotFoundException { repoManager.getRepository(userRegion, 0, null); } @Test public void createMissingBucket() throws BucketNotFoundException { setUpMockBucket(0); when(fileDataStore.getLocalBucketById(eq(0))).thenReturn(null); when(fileRegion.getOrCreateNodeForBucketWrite(eq(0), (RetryTimeKeeper) any())) .then(new Answer() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { when(fileDataStore.getLocalBucketById(eq(0))).thenReturn(fileBuckets.get(0)); return null; } }); assertNotNull(repoManager.getRepository(userRegion, 0, null)); } @Test public void getByRegion() throws BucketNotFoundException { setUpMockBucket(0); setUpMockBucket(1); Set<Integer> buckets = new LinkedHashSet<Integer>(Arrays.asList(0, 1)); InternalRegionFunctionContext ctx = Mockito.mock(InternalRegionFunctionContext.class); when(ctx.getLocalBucketSet((any()))).thenReturn(buckets); Collection<IndexRepository> repos = repoManager.getRepositories(ctx); assertEquals(2, repos.size()); Iterator<IndexRepository> itr = repos.iterator(); IndexRepositoryImpl repo0 = (IndexRepositoryImpl) itr.next(); IndexRepositoryImpl repo1 = (IndexRepositoryImpl) itr.next(); assertNotNull(repo0); assertNotNull(repo1); assertNotEquals(repo0, repo1); checkRepository(repo0, 0); checkRepository(repo1, 1); } /** * Test that we get the expected exception when a user bucket is missing */ @Test(expected = BucketNotFoundException.class) public void getMissingBucketByRegion() throws BucketNotFoundException { setUpMockBucket(0); Set<Integer> buckets = new LinkedHashSet<Integer>(Arrays.asList(0, 1)); InternalRegionFunctionContext ctx = Mockito.mock(InternalRegionFunctionContext.class); when(ctx.getLocalBucketSet((any()))).thenReturn(buckets); repoManager.getRepositories(ctx); } protected void checkRepository(IndexRepositoryImpl repo0, int bucketId) { IndexWriter writer0 = repo0.getWriter(); RegionDirectory dir0 = (RegionDirectory) writer0.getDirectory(); assertEquals(fileBuckets.get(bucketId), dir0.getFileSystem().getFileRegion()); assertEquals(chunkBuckets.get(bucketId), dir0.getFileSystem().getChunkRegion()); assertEquals(serializer, repo0.getSerializer()); } protected BucketRegion setUpMockBucket(int id) { BucketRegion mockBucket = Mockito.mock(BucketRegion.class); BucketRegion fileBucket = Mockito.mock(BucketRegion.class); // Allowing the fileBucket to behave like a map so that the IndexWriter operations don't fail Fakes.addMapBehavior(fileBucket); BucketRegion chunkBucket = Mockito.mock(BucketRegion.class); when(mockBucket.getId()).thenReturn(id); when(userRegion.getBucketRegion(eq(id), eq(null))).thenReturn(mockBucket); when(userDataStore.getLocalBucketById(eq(id))).thenReturn(mockBucket); when(userRegion.getBucketRegion(eq(id + 113), eq(null))).thenReturn(mockBucket); when(userDataStore.getLocalBucketById(eq(id + 113))).thenReturn(mockBucket); when(fileDataStore.getLocalBucketById(eq(id))).thenReturn(fileBucket); when(chunkDataStore.getLocalBucketById(eq(id))).thenReturn(chunkBucket); fileBuckets.put(id, fileBucket); chunkBuckets.put(id, chunkBucket); dataBuckets.put(id, mockBucket); return mockBucket; } }