blob: aefd62e6596c8779025ac1d947df5604995ba628 [file] [log] [blame]
/*
* 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.modules.util;
import static org.apache.geode.test.awaitility.GeodeAwaitility.await;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.io.Serializable;
import java.util.Collection;
import javax.servlet.http.HttpSession;
import org.apache.juli.logging.Log;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.RuleChain;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionAttributes;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.cache.Scope;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.client.ClientCacheFactory;
import org.apache.geode.cache.execute.FunctionException;
import org.apache.geode.cache.execute.FunctionService;
import org.apache.geode.cache.server.CacheServer;
import org.apache.geode.distributed.internal.DistributionManager;
import org.apache.geode.distributed.internal.MembershipListener;
import org.apache.geode.internal.cache.InternalCache;
import org.apache.geode.internal.cache.execute.FunctionStats;
import org.apache.geode.modules.session.catalina.ClientServerSessionCache;
import org.apache.geode.modules.session.catalina.SessionManager;
import org.apache.geode.test.dunit.DistributedTestUtils;
import org.apache.geode.test.dunit.VM;
import org.apache.geode.test.dunit.rules.CacheRule;
import org.apache.geode.test.dunit.rules.ClientCacheRule;
import org.apache.geode.test.dunit.rules.DistributedRule;
public class ClientServerSessionCacheDUnitTest implements Serializable {
private static final String SESSION_REGION_NAME = RegionHelper.NAME + "_sessions";
private CacheRule cacheRule = new CacheRule();
private DistributedRule distributedRule = new DistributedRule();
private ClientCacheRule clientCacheRule = new ClientCacheRule();
@Rule
public transient RuleChain ruleChain = RuleChain.outerRule(distributedRule)
.around(cacheRule)
.around(clientCacheRule);
@Test
public void multipleGeodeServersCreateSessionRegion() {
final VM server0 = VM.getVM(0);
final VM server1 = VM.getVM(1);
final VM client = VM.getVM(2);
server0.invoke(this::startCacheServer);
server1.invoke(this::startCacheServer);
client.invoke(this::startClientSessionCache);
server0.invoke(this::validateServer);
server1.invoke(this::validateServer);
}
@Test
public void addServerToExistingClusterCreatesSessionRegion() {
final VM server0 = VM.getVM(0);
final VM server1 = VM.getVM(1);
final VM client = VM.getVM(2);
server0.invoke(this::startCacheServer);
client.invoke(this::startClientSessionCache);
server0.invoke(this::validateServer);
server1.invoke(this::startCacheServer);
// Session region may be created asynchronously on the second server
server1.invoke(() -> await().untilAsserted(this::validateServer));
}
@Test
public void startingAClientWithoutServersFails() {
final VM client = VM.getVM(2);
assertThatThrownBy(() -> client.invoke(this::startClientSessionCache))
.hasCauseInstanceOf(FunctionException.class);
}
@Test
public void canPreCreateSessionRegionBeforeStartingClient() {
final VM server0 = VM.getVM(0);
final VM server1 = VM.getVM(1);
final VM client = VM.getVM(2);
server0.invoke(this::startCacheServer);
server1.invoke(this::startCacheServer);
server0.invoke(this::createSessionRegion);
server1.invoke(this::createSessionRegion);
client.invoke(this::startClientSessionCache);
server0.invoke(this::validateServer);
server1.invoke(this::validateServer);
}
@Test
public void preCreatedRegionIsNotCopiedToNewlyStartedServers() {
final VM server0 = VM.getVM(0);
final VM server1 = VM.getVM(1);
final VM client = VM.getVM(2);
server0.invoke(this::startCacheServer);
server0.invoke(this::createSessionRegion);
client.invoke(this::startClientSessionCache);
server1.invoke(this::startCacheServer);
server1.invoke(() -> await().untilAsserted(this::validateBootstrapped));
// server1 should not have created the session region
// If the user precreated the region, they must manually
// create it on all servers
server1.invoke(() -> {
Region<Object, Object> region = cacheRule.getCache().getRegion(SESSION_REGION_NAME);
assertThat(region).isNull();
});
}
@Test
public void cantPreCreateMismatchedSessionRegionBeforeStartingClient() {
final VM server0 = VM.getVM(0);
final VM server1 = VM.getVM(1);
final VM client = VM.getVM(2);
server0.invoke(this::startCacheServer);
server1.invoke(this::startCacheServer);
server0.invoke(this::createMismatchedSessionRegion);
server1.invoke(this::createMismatchedSessionRegion);
assertThatThrownBy(() -> client.invoke(this::startClientSessionCache))
.hasCauseInstanceOf(IllegalStateException.class);
}
@Test
public void sessionCacheSizeShouldNotInvokeFunctionsOnTheCluster() {
final VM server1 = VM.getVM(0);
final VM server2 = VM.getVM(1);
final VM client1 = VM.getVM(3);
server1.invoke(this::startCacheServer);
server2.invoke(this::startCacheServer);
server1.invoke(this::createSessionRegion);
server2.invoke(this::createSessionRegion);
client1.invoke(() -> {
final SessionManager sessionManager = mock(SessionManager.class);
final Log logger = mock(Log.class);
when(sessionManager.getLogger()).thenReturn(logger);
when(sessionManager.getRegionName()).thenReturn(RegionHelper.NAME + "_sessions");
when(sessionManager.getRegionAttributesId())
.thenReturn(RegionShortcut.PARTITION_REDUNDANT.toString());
final ClientCacheFactory clientCacheFactory = new ClientCacheFactory();
clientCacheFactory.addPoolLocator("localhost", DistributedTestUtils.getLocatorPort());
clientCacheFactory.setPoolSubscriptionEnabled(true);
clientCacheRule.createClientCache(clientCacheFactory);
final ClientCache clientCache = clientCacheRule.getClientCache();
ClientServerSessionCache clientServerSessionCache =
new ClientServerSessionCache(sessionManager, clientCache);
clientServerSessionCache.initialize();
assertThat(clientServerSessionCache.size()).isEqualTo(0);
});
// Verify defaults
server1.invoke(this::validateServer);
server2.invoke(this::validateServer);
// Verify that RegionSizeFunction was never executed .
server1.invoke(this::validateRegionSizeFunctionCalls);
server2.invoke(this::validateRegionSizeFunctionCalls);
}
private void createSessionRegion() {
Cache cache = cacheRule.getCache();
cache.<String, HttpSession>createRegionFactory(RegionShortcut.PARTITION_REDUNDANT)
.setCustomEntryIdleTimeout(new SessionCustomExpiry())
.create(SESSION_REGION_NAME);
}
private void createMismatchedSessionRegion() {
Cache cache = cacheRule.getCache();
cache.<String, HttpSession>createRegionFactory(RegionShortcut.PARTITION)
.setCustomEntryIdleTimeout(new SessionCustomExpiry())
.create(SESSION_REGION_NAME);
}
private void validateSessionRegion() {
final InternalCache cache = cacheRule.getCache();
final Region<String, HttpSession> region = cache.getRegion(SESSION_REGION_NAME);
assertThat(region).isNotNull();
final RegionAttributes<Object, Object> expectedAttributes =
cache.getRegionAttributes(RegionShortcut.PARTITION_REDUNDANT.toString());
final RegionAttributes attributes = region.getAttributes();
assertThat(attributes.getScope()).isEqualTo(expectedAttributes.getScope());
assertThat(attributes.getDataPolicy()).isEqualTo(expectedAttributes.getDataPolicy());
assertThat(attributes.getPartitionAttributes())
.isEqualTo(expectedAttributes.getPartitionAttributes());
assertThat(attributes.getCustomEntryIdleTimeout()).isInstanceOf(SessionCustomExpiry.class);
}
private void validateServer() {
validateBootstrapped();
validateSessionRegion();
}
private void validateBootstrapped() {
final InternalCache cache = cacheRule.getCache();
final DistributionManager distributionManager =
cache.getInternalDistributedSystem().getDistributionManager();
final Collection<MembershipListener> listeners =
distributionManager.getMembershipListeners();
assertThat(listeners)
.filteredOn(listener -> listener instanceof BootstrappingFunction)
.hasSize(1);
assertThat(FunctionService.getFunction(CreateRegionFunction.ID))
.isInstanceOf(CreateRegionFunction.class);
assertThat(FunctionService.getFunction(TouchPartitionedRegionEntriesFunction.ID))
.isInstanceOf(TouchPartitionedRegionEntriesFunction.class);
assertThat(FunctionService.getFunction(TouchReplicatedRegionEntriesFunction.ID))
.isInstanceOf(TouchReplicatedRegionEntriesFunction.class);
assertThat(FunctionService.getFunction(RegionSizeFunction.ID))
.isInstanceOf(RegionSizeFunction.class);
final Region<String, RegionConfiguration> region =
cache.getRegion(CreateRegionFunction.REGION_CONFIGURATION_METADATA_REGION);
assertThat(region).isNotNull();
final RegionAttributes<String, RegionConfiguration> attributes = region.getAttributes();
assertThat(attributes.getDataPolicy()).isEqualTo(DataPolicy.REPLICATE);
assertThat(attributes.getScope()).isEqualTo(Scope.DISTRIBUTED_ACK);
assertThat(attributes.getDataPolicy()).isEqualTo(DataPolicy.REPLICATE);
assertThat(attributes.getCacheListeners())
.filteredOn(listener -> listener instanceof RegionConfigurationCacheListener)
.hasSize(1);
}
private void validateRegionSizeFunctionCalls() {
FunctionStats functionStats = FunctionStats.getFunctionStats(RegionSizeFunction.ID);
assertThat(functionStats.getFunctionExecutionCalls())
.as("No function should be invoked to get the region size.")
.isEqualTo(0);
}
private void startClientSessionCache() {
final SessionManager sessionManager = mock(SessionManager.class);
final Log logger = mock(Log.class);
when(sessionManager.getLogger()).thenReturn(logger);
when(sessionManager.getRegionName()).thenReturn(RegionHelper.NAME + "_sessions");
when(sessionManager.getRegionAttributesId())
.thenReturn(RegionShortcut.PARTITION_REDUNDANT.toString());
final ClientCacheFactory clientCacheFactory = new ClientCacheFactory();
clientCacheFactory.addPoolLocator("localhost", DistributedTestUtils.getLocatorPort());
clientCacheFactory.setPoolSubscriptionEnabled(true);
clientCacheRule.createClientCache(clientCacheFactory);
final ClientCache clientCache = clientCacheRule.getClientCache();
new ClientServerSessionCache(sessionManager, clientCache).initialize();
}
private void startCacheServer() throws IOException {
final Cache cache = cacheRule.getOrCreateCache();
final CacheServer cacheServer = cache.addCacheServer();
cacheServer.setPort(0);
cacheServer.start();
}
}