/* * 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.internal.cache.wan.parallel; import org.apache.geode.CancelCriterion; import org.apache.geode.cache.*; import org.apache.geode.internal.cache.*; import org.apache.geode.internal.cache.lru.LRUAlgorithm; import org.apache.geode.internal.cache.partitioned.RegionAdvisor; import org.apache.geode.internal.cache.wan.AbstractGatewaySender; import org.apache.geode.internal.cache.wan.GatewaySenderEventImpl; import org.apache.geode.test.fake.Fakes; import org.apache.geode.test.junit.categories.UnitTest; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; import java.util.*; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import static org.junit.Assert.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @Category(UnitTest.class) public class ParallelQueueRemovalMessageJUnitTest { private GemFireCacheImpl cache; private PartitionedRegion queueRegion; private AbstractGatewaySender sender; private PartitionedRegion rootRegion; private BucketRegionQueue bucketRegionQueue; private BucketRegionQueueHelper bucketRegionQueueHelper; private static String GATEWAY_SENDER_ID = "ny"; private static int BUCKET_ID = 85; private static long KEY = 198l; @Before public void setUpGemFire() { createCache(); createQueueRegion(); createGatewaySender(); createRootRegion(); createBucketRegionQueue(); } private void createCache() { // Mock cache this.cache = Fakes.cache(); GemFireCacheImpl.setInstanceForTests(this.cache); } private void createQueueRegion() { // Mock queue region this.queueRegion = mock(PartitionedRegion.class); when(this.queueRegion.getFullPath()).thenReturn(getRegionQueueName()); when(this.queueRegion.getPrStats()).thenReturn(mock(PartitionedRegionStats.class)); when(this.queueRegion.getDataStore()).thenReturn(mock(PartitionedRegionDataStore.class)); when(this.queueRegion.getCache()).thenReturn(this.cache); EvictionAttributesImpl ea = (EvictionAttributesImpl) EvictionAttributes .createLRUMemoryAttributes(100, null, EvictionAction.OVERFLOW_TO_DISK); LRUAlgorithm algorithm = ea.createEvictionController(this.queueRegion, false); algorithm.getLRUHelper().initStats(this.queueRegion, this.cache.getDistributedSystem()); when(this.queueRegion.getEvictionController()).thenReturn(algorithm); } private void createGatewaySender() { // Mock gateway sender this.sender = mock(AbstractGatewaySender.class); when(this.queueRegion.getParallelGatewaySender()).thenReturn(this.sender); when(this.sender.getQueues()).thenReturn(null); when(this.sender.getDispatcherThreads()).thenReturn(1); when(this.sender.getCache()).thenReturn(this.cache); CancelCriterion cancelCriterion = mock(CancelCriterion.class); when(sender.getCancelCriterion()).thenReturn(cancelCriterion); } private void createRootRegion() { // Mock root region this.rootRegion = mock(PartitionedRegion.class); when(this.rootRegion.getFullPath()) .thenReturn(Region.SEPARATOR + PartitionedRegionHelper.PR_ROOT_REGION_NAME); when(this.cache.getRegion(PartitionedRegionHelper.PR_ROOT_REGION_NAME, true)) .thenReturn(this.rootRegion); when(this.cache.getRegion(getRegionQueueName(), false)).thenReturn(this.queueRegion); } private void createBucketRegionQueue() { // Create InternalRegionArguments InternalRegionArguments ira = new InternalRegionArguments(); ira.setPartitionedRegion(this.queueRegion); ira.setPartitionedRegionBucketRedundancy(1); BucketAdvisor ba = mock(BucketAdvisor.class); ira.setBucketAdvisor(ba); InternalRegionArguments pbrIra = new InternalRegionArguments(); RegionAdvisor ra = mock(RegionAdvisor.class); when(ra.getPartitionedRegion()).thenReturn(this.queueRegion); pbrIra.setPartitionedRegionAdvisor(ra); PartitionAttributes pa = mock(PartitionAttributes.class); when(this.queueRegion.getPartitionAttributes()).thenReturn(pa); when(this.queueRegion.getDataPolicy()).thenReturn(DataPolicy.PARTITION); when(pa.getColocatedWith()).thenReturn(null); ProxyBucketRegion pbr = new ProxyBucketRegion(BUCKET_ID, this.queueRegion, pbrIra); // final // classes // cannot be // mocked when(ba.getProxyBucketRegion()).thenReturn(pbr); // Create RegionAttributes AttributesFactory factory = new AttributesFactory(); factory.setScope(Scope.DISTRIBUTED_ACK); factory.setDataPolicy(DataPolicy.REPLICATE); factory.setEvictionAttributes( EvictionAttributes.createLRUMemoryAttributes(100, null, EvictionAction.OVERFLOW_TO_DISK)); RegionAttributes attributes = factory.create(); // Create BucketRegionQueue this.bucketRegionQueue = new BucketRegionQueue(this.queueRegion.getBucketName(BUCKET_ID), attributes, this.rootRegion, this.cache, ira); this.bucketRegionQueueHelper = new BucketRegionQueueHelper(this.cache, this.queueRegion, this.bucketRegionQueue); } @After public void tearDownGemFire() { GemFireCacheImpl.setInstanceForTests(null); } @Test public void validateFailedBatchRemovalMessageKeysInUninitializedBucketRegionQueue() throws Exception { // Validate initial BucketRegionQueue state assertFalse(this.bucketRegionQueue.isInitialized()); assertEquals(0, this.bucketRegionQueue.getFailedBatchRemovalMessageKeys().size()); // Create and process a ParallelQueueRemovalMessage (causes the failedBatchRemovalMessageKeys to // add a key) createAndProcessParallelQueueRemovalMessage(); // Validate BucketRegionQueue after processing ParallelQueueRemovalMessage assertEquals(1, this.bucketRegionQueue.getFailedBatchRemovalMessageKeys().size()); } @Test public void validateDestroyKeyFromBucketQueueInUninitializedBucketRegionQueue() throws Exception { // Validate initial BucketRegionQueue state assertEquals(0, this.bucketRegionQueue.size()); assertFalse(this.bucketRegionQueue.isInitialized()); // Add an event to the BucketRegionQueue and verify BucketRegionQueue state this.bucketRegionQueueHelper.addEvent(KEY); assertEquals(1, this.bucketRegionQueue.size()); // Create and process a ParallelQueueRemovalMessage (causes the value of the entry to be set to // DESTROYED) when(this.queueRegion.getKeyInfo(KEY, null, null)).thenReturn(new KeyInfo(KEY, null, null)); createAndProcessParallelQueueRemovalMessage(); // Clean up destroyed tokens and validate BucketRegionQueue this.bucketRegionQueueHelper.cleanUpDestroyedTokensAndMarkGIIComplete(); assertEquals(0, this.bucketRegionQueue.size()); } @Test public void validateDestroyFromTempQueueInUninitializedBucketRegionQueue() throws Exception { // Validate initial BucketRegionQueue state assertFalse(this.bucketRegionQueue.isInitialized()); // Create a real ConcurrentParallelGatewaySenderQueue ParallelGatewaySenderEventProcessor pgsep = createConcurrentParallelGatewaySenderQueue(); // Add a mock GatewaySenderEventImpl to the temp queue BlockingQueue<GatewaySenderEventImpl> tempQueue = createTempQueueAndAddEvent(pgsep, mock(GatewaySenderEventImpl.class)); assertEquals(1, tempQueue.size()); // Create and process a ParallelQueueRemovalMessage (causes the failedBatchRemovalMessageKeys to // add a key) createAndProcessParallelQueueRemovalMessage(); // Validate temp queue is empty after processing ParallelQueueRemovalMessage assertEquals(0, tempQueue.size()); } @Test public void validateDestroyFromBucketQueueAndTempQueueInUninitializedBucketRegionQueue() { // Validate initial BucketRegionQueue state assertFalse(this.bucketRegionQueue.isInitialized()); assertEquals(0, this.bucketRegionQueue.size()); // Create a real ConcurrentParallelGatewaySenderQueue ParallelGatewaySenderEventProcessor pgsep = createConcurrentParallelGatewaySenderQueue(); // Add an event to the BucketRegionQueue and verify BucketRegionQueue state GatewaySenderEventImpl gsei = this.bucketRegionQueueHelper.addEvent(KEY); assertEquals(1, this.bucketRegionQueue.size()); // Add a mock GatewaySenderEventImpl to the temp queue BlockingQueue<GatewaySenderEventImpl> tempQueue = createTempQueueAndAddEvent(pgsep, gsei); assertEquals(1, tempQueue.size()); // Create and process a ParallelQueueRemovalMessage (causes the value of the entry to be set to // DESTROYED) when(this.queueRegion.getKeyInfo(KEY, null, null)).thenReturn(new KeyInfo(KEY, null, null)); createAndProcessParallelQueueRemovalMessage(); // Validate temp queue is empty after processing ParallelQueueRemovalMessage assertEquals(0, tempQueue.size()); // Clean up destroyed tokens this.bucketRegionQueueHelper.cleanUpDestroyedTokensAndMarkGIIComplete(); // Validate BucketRegionQueue is empty after processing ParallelQueueRemovalMessage assertEquals(0, this.bucketRegionQueue.size()); } private void createAndProcessParallelQueueRemovalMessage() { ParallelQueueRemovalMessage pqrm = new ParallelQueueRemovalMessage(createRegionToDispatchedKeysMap()); pqrm.process(null); } private HashMap<String, Map<Integer, List<Long>>> createRegionToDispatchedKeysMap() { HashMap<String, Map<Integer, List<Long>>> regionToDispatchedKeys = new HashMap<>(); Map<Integer, List<Long>> bucketIdToDispatchedKeys = new HashMap<>(); List<Long> dispatchedKeys = new ArrayList<>(); dispatchedKeys.add(KEY); bucketIdToDispatchedKeys.put(BUCKET_ID, dispatchedKeys); regionToDispatchedKeys.put(getRegionQueueName(), bucketIdToDispatchedKeys); return regionToDispatchedKeys; } private ParallelGatewaySenderEventProcessor createConcurrentParallelGatewaySenderQueue() { ParallelGatewaySenderEventProcessor pgsep = new ParallelGatewaySenderEventProcessor(sender); ConcurrentParallelGatewaySenderQueue cpgsq = new ConcurrentParallelGatewaySenderQueue(sender, new ParallelGatewaySenderEventProcessor[] {pgsep}); Set<RegionQueue> queues = new HashSet<>(); queues.add(cpgsq); when(this.sender.getQueues()).thenReturn(queues); return pgsep; } private BlockingQueue<GatewaySenderEventImpl> createTempQueueAndAddEvent( ParallelGatewaySenderEventProcessor pgsep, GatewaySenderEventImpl gsei) { ParallelGatewaySenderQueue pgsq = (ParallelGatewaySenderQueue) pgsep.getQueue(); Map<Integer, BlockingQueue<GatewaySenderEventImpl>> tempQueueMap = pgsq.getBucketToTempQueueMap(); BlockingQueue<GatewaySenderEventImpl> tempQueue = new LinkedBlockingQueue(); when(gsei.getShadowKey()).thenReturn(KEY); tempQueue.add(gsei); tempQueueMap.put(BUCKET_ID, tempQueue); return tempQueue; } private String getRegionQueueName() { return Region.SEPARATOR + GATEWAY_SENDER_ID + ParallelGatewaySenderQueue.QSTRING; } }