/* * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com * The software in this package is published under the terms of the CPAL v1.0 * license, a copy of which has been included with this distribution in the * LICENSE.txt file. */ package org.mule.runtime.core.util.store; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsCollectionContaining.hasItem; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.Mockito.withSettings; import static org.mule.runtime.core.api.config.MuleProperties.OBJECT_STORE_DEFAULT_IN_MEMORY_NAME; import static org.mule.runtime.core.api.config.MuleProperties.OBJECT_STORE_DEFAULT_PERSISTENT_NAME; import static org.mule.runtime.core.api.scheduler.SchedulerConfig.config; import static org.mule.runtime.api.store.ObjectStoreManager.UNBOUNDED; import static org.mule.tck.SerializationTestUtils.addJavaSerializerToMockMuleContext; import org.mule.runtime.api.exception.MuleException; import org.mule.runtime.api.lifecycle.Disposable; import org.mule.runtime.api.lifecycle.InitialisationException; import org.mule.runtime.core.api.MuleContext; import org.mule.runtime.core.api.config.MuleConfiguration; import org.mule.runtime.core.api.registry.MuleRegistry; import org.mule.runtime.api.store.ObjectStore; import org.mule.runtime.api.store.ObjectStoreException; import org.mule.runtime.core.api.store.PartitionableObjectStore; import org.mule.tck.SimpleUnitTestSupportSchedulerService; import org.mule.tck.junit4.AbstractMuleTestCase; import org.mule.tck.probe.PollingProber; import org.mule.tck.probe.Probe; import org.mule.tck.size.SmallTest; import java.io.Serializable; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @SmallTest public class MuleObjectStoreManagerTestCase extends AbstractMuleTestCase { public static final String TEST_PARTITION_NAME = "partition"; public static final int POLLING_TIMEOUT = 1000; public static final int POLLING_DELAY = 60; public static final String TEST_KEY = "Some Key"; public static final String TEST_VALUE = "Some Value"; private SimpleUnitTestSupportSchedulerService schedulerService; private MuleContext muleContext; private MuleObjectStoreManager storeManager; @Rule public TemporaryFolder tempWorkDir = new TemporaryFolder(); @Before public void setup() { schedulerService = new SimpleUnitTestSupportSchedulerService(); muleContext = mock(MuleContext.class); when(muleContext.getSchedulerService()).thenReturn(schedulerService); when(muleContext.getSchedulerBaseConfig()) .thenReturn(config().withPrefix(MuleObjectStoreManagerTestCase.class.getName() + "#" + name.getMethodName())); storeManager = new MuleObjectStoreManager(); storeManager.setMuleContext(muleContext); } @After public void after() throws MuleException { schedulerService.stop(); } @Test public void disposeDisposableStore() throws ObjectStoreException { @SuppressWarnings("unchecked") ObjectStore<Serializable> store = mock(ObjectStore.class, withSettings().extraInterfaces(Disposable.class)); this.storeManager.disposeStore(store); verify(store).clear(); verify((Disposable) store).dispose(); } @Test public void disposePartitionableStore() throws ObjectStoreException { @SuppressWarnings("unchecked") ObjectStorePartition<Serializable> store = mock(ObjectStorePartition.class, withSettings().extraInterfaces(Disposable.class).defaultAnswer(RETURNS_DEEP_STUBS)); when(store.getPartitionName()).thenReturn(TEST_PARTITION_NAME); storeManager.disposeStore(store); verify(store.getBaseStore()).disposePartition(TEST_PARTITION_NAME); verify(store, never()).clear(); verify((Disposable) store).dispose(); } @Test public void ensureTransientPartitionIsCleared() throws ObjectStoreException, InitialisationException { ensurePartitionIsCleared(false); } @Test public void ensurePersistentPartitionIsCleared() throws ObjectStoreException, InitialisationException { ensurePartitionIsCleared(true); } private void ensurePartitionIsCleared(boolean isPersistent) throws ObjectStoreException, InitialisationException { try { ObjectStorePartition<Serializable> store = createStorePartition(TEST_PARTITION_NAME, isPersistent); store.getBaseStore().store(TEST_KEY, TEST_VALUE, TEST_PARTITION_NAME); assertThat(store.allKeys().size(), is(1)); storeManager.disposeStore(store); assertThat(store.allKeys().size(), is(0)); } finally { storeManager.dispose(); } } @Test public void removeStoreAndMonitorOnTransientPartition() throws ObjectStoreException, InitialisationException { removeStoreAndMonitor(false); } @Test public void removeStoreAndMonitorOnPersistentPartition() throws ObjectStoreException, InitialisationException { removeStoreAndMonitor(true); } private void removeStoreAndMonitor(boolean isPersistent) throws ObjectStoreException, InitialisationException { try { ObjectStorePartition<Serializable> store = createStorePartition(TEST_PARTITION_NAME, isPersistent); assertMonitorsCount(1); storeManager.disposeStore(store); assertThat(storeManager.stores.keySet(), not(hasItem(TEST_PARTITION_NAME))); assertMonitorsCount(0); } finally { storeManager.dispose(); } } private void assertMonitorsCount(final int expectedValue) { new PollingProber(POLLING_TIMEOUT, POLLING_DELAY).check(new Probe() { @Override public boolean isSatisfied() { return assertMonitors(expectedValue); } private boolean assertMonitors(int expectedValue) { return storeManager.getMonitorsCount() == expectedValue; } @Override public String describeFailure() { return "Unexpected count of active monitors."; } }); } private ObjectStorePartition<Serializable> createStorePartition(String partitionName, boolean isPersistent) throws InitialisationException { addJavaSerializerToMockMuleContext(muleContext); createRegistryAndBaseStore(muleContext, isPersistent); storeManager.setMuleContext(muleContext); storeManager.initialise(); ObjectStorePartition<Serializable> store = storeManager.getObjectStore(partitionName, isPersistent, UNBOUNDED, 10000, 50); assertThat(storeManager.stores.keySet(), hasItem(partitionName)); return store; } private void createRegistryAndBaseStore(MuleContext muleContext, boolean isPersistent) { MuleRegistry muleRegistry = mock(MuleRegistry.class); if (isPersistent) { PartitionableObjectStore<?> store = createPersistentPartitionableObjectStore(muleContext); when(muleRegistry.lookupObject(OBJECT_STORE_DEFAULT_PERSISTENT_NAME)).thenReturn(store); } else { PartitionableObjectStore<?> store = createTransientPartitionableObjectStore(); when(muleRegistry.lookupObject(OBJECT_STORE_DEFAULT_IN_MEMORY_NAME)).thenReturn(store); } when(muleContext.getRegistry()).thenReturn(muleRegistry); } private PartitionableObjectStore<?> createTransientPartitionableObjectStore() { return new PartitionedInMemoryObjectStore<>(); } private PartitionableObjectStore<?> createPersistentPartitionableObjectStore(MuleContext muleContext) { MuleConfiguration muleConfiguration = mock(MuleConfiguration.class); when(muleConfiguration.getWorkingDirectory()).thenReturn(tempWorkDir.getRoot().getAbsolutePath()); when(muleContext.getConfiguration()).thenReturn(muleConfiguration); return new PartitionedPersistentObjectStore<>(muleContext); } @Test public void dontFailIfUnsupported() throws ObjectStoreException { @SuppressWarnings("unchecked") ObjectStore<Serializable> store = mock(ObjectStore.class, withSettings().extraInterfaces(Disposable.class)); doThrow(UnsupportedOperationException.class).when(store).clear(); storeManager.disposeStore(store); verify(store).clear(); verify((Disposable) store).dispose(); } }