/*
* 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.tier.sockets;
import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS;
import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.apache.geode.GemFireConfigException;
import org.apache.geode.GemFireIOException;
import org.apache.geode.cache.AttributesFactory;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.CacheException;
import org.apache.geode.cache.CacheWriterException;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionAttributes;
import org.apache.geode.cache.Scope;
import org.apache.geode.cache.client.ClientCacheFactory;
import org.apache.geode.cache.client.NoAvailableServersException;
import org.apache.geode.cache.client.Pool;
import org.apache.geode.cache.client.PoolManager;
import org.apache.geode.cache.client.internal.Connection;
import org.apache.geode.cache.client.internal.Op;
import org.apache.geode.cache.client.internal.PoolImpl;
import org.apache.geode.cache.client.internal.RegisterInterestTracker;
import org.apache.geode.cache.server.CacheServer;
import org.apache.geode.cache30.CacheSerializableRunnable;
import org.apache.geode.distributed.DistributedSystem;
import org.apache.geode.distributed.DistributedSystemDisconnectedException;
import org.apache.geode.internal.AvailablePort;
import org.apache.geode.internal.cache.CacheServerImpl;
import org.apache.geode.internal.cache.GemFireCacheImpl;
import org.apache.geode.internal.cache.LocalRegion;
import org.apache.geode.test.dunit.Assert;
import org.apache.geode.test.dunit.DistributedTestUtils;
import org.apache.geode.test.dunit.Host;
import org.apache.geode.test.dunit.IgnoredException;
import org.apache.geode.test.dunit.LogWriterUtils;
import org.apache.geode.test.dunit.NetworkUtils;
import org.apache.geode.test.dunit.VM;
import org.apache.geode.test.dunit.Wait;
import org.apache.geode.test.dunit.WaitCriterion;
import org.apache.geode.test.dunit.cache.internal.JUnit4CacheTestCase;
import org.apache.geode.test.dunit.standalone.VersionManager;
import org.apache.geode.test.junit.categories.ClientServerTest;
import org.apache.geode.test.junit.categories.DistributedTest;
import org.apache.geode.test.junit.runners.CategoryWithParameterizedRunnerFactory;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Collection;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
/**
* Tests client server corner cases between Region and Pool
*/
@Category({DistributedTest.class, ClientServerTest.class})
public class ClientServerMiscDUnitTest extends JUnit4CacheTestCase {
protected static PoolImpl pool = null;
protected static Connection conn = null;
private static Cache static_cache;
private static int PORT1;
private static final String k1 = "k1";
private static final String k2 = "k2";
private static final String server_k1 = "server-k1";
private static final String server_k2 = "server-k2";
private static final String REGION_NAME1 = "ClientServerMiscDUnitTest_region1";
private static final String REGION_NAME2 = "ClientServerMiscDUnitTest_region2";
private static final String PR_REGION_NAME = "ClientServerMiscDUnitTest_PRregion";
private static Host host;
private static VM server1;
private static VM server2;
private static RegionAttributes attrs;
// variables for concurrent map API test
Properties props = new Properties();
final int putRange_1Start = 1;
final int putRange_1End = 5;
final int putRange_2Start = 6;
final int putRange_2End = 10;
final int putRange_3Start = 11;
final int putRange_3End = 15;
final int putRange_4Start = 16;
final int putRange_4End = 20;
final int removeRange_1Start = 2;
final int removeRange_1End = 4;
final int removeRange_2Start = 7;
final int removeRange_2End = 9;
protected String testVersion; // version for client caches for backward-compatibility
// testing
public ClientServerMiscDUnitTest() {
testVersion = VersionManager.CURRENT_VERSION;
}
@Override
public final void postSetUp() throws Exception {
host = Host.getHost(0);
server1 = host.getVM(2);
server2 = host.getVM(3);
}
private int initServerCache(boolean notifyBySub) {
Object[] args = new Object[] {notifyBySub, getMaxThreads()};
return ((Integer) server1.invoke(ClientServerMiscDUnitTest.class, "createServerCache", args))
.intValue();
}
private int initServerCache2(boolean notifyBySub) {
Object[] args = new Object[] {notifyBySub, getMaxThreads()};
return ((Integer) server2.invoke(ClientServerMiscDUnitTest.class, "createServerCache", args))
.intValue();
}
@Test
public void testConcurrentOperationsWithDRandPR() throws Exception {
int port1 = initServerCache(true); // vm0
int port2 = initServerCache2(true); // vm1
String serverName = NetworkUtils.getServerHostName(Host.getHost(0));
host.getVM(testVersion, 0).invoke(() -> this.createClientCacheV(serverName, port1));
host.getVM(testVersion, 1).invoke(() -> this.createClientCacheV(serverName, port2));
LogWriterUtils.getLogWriter()
.info("Testing concurrent map operations from a client with a distributed region");
concurrentMapTest(host.getVM(testVersion, 0), "/" + REGION_NAME1);
// TODO add verification in vm1
LogWriterUtils.getLogWriter()
.info("Testing concurrent map operations from a client with a partitioned region");
concurrentMapTest(host.getVM(testVersion, 0), "/" + PR_REGION_NAME);
// TODO add verification in vm1
}
@Test
public void testConcurrentOperationsWithDRandPRandEmptyClient() throws Exception {
int port1 = initServerCache(true); // vm0
int port2 = initServerCache2(true); // vm1
String serverName = NetworkUtils.getServerHostName(Host.getHost(0));
host.getVM(testVersion, 0).invoke(() -> this.createEmptyClientCache(serverName, port1));
host.getVM(testVersion, 1).invoke(() -> this.createClientCacheV(serverName, port2));
LogWriterUtils.getLogWriter()
.info("Testing concurrent map operations from a client with a distributed region");
concurrentMapTest(host.getVM(testVersion, 0), "/" + REGION_NAME1);
// TODO add verification in vm1
LogWriterUtils.getLogWriter()
.info("Testing concurrent map operations from a client with a partitioned region");
concurrentMapTest(host.getVM(testVersion, 0), "/" + PR_REGION_NAME);
// TODO add verification in vm1
}
/**
* Do putIfAbsent(), replace(Object, Object), replace(Object, Object, Object), remove(Object,
* Object) operations
*/
public void concurrentMapTest(final VM clientVM, final String rName) {
// String exceptionStr = "";
clientVM.invoke(new CacheSerializableRunnable("doConcurrentMapOperations") {
public void run2() throws CacheException {
Cache cache = getCache();
final Region pr = cache.getRegion(rName);
assertNotNull(rName + " not created", pr);
boolean isEmpty = pr.getAttributes().getDataPolicy() == DataPolicy.EMPTY;
// test successful putIfAbsent
for (int i = putRange_1Start; i <= putRange_1End; i++) {
Object putResult = pr.putIfAbsent(Integer.toString(i), Integer.toString(i));
assertNull("Expected null, but got " + putResult + " for key " + i, putResult);
}
int size;
if (!isEmpty) {
size = pr.size();
assertEquals("Size doesn't return expected value", putRange_1End, size);
assertFalse("isEmpty doesnt return proper state of the PartitionedRegion", pr.isEmpty());
}
// test unsuccessful putIfAbsent
for (int i = putRange_1Start; i <= putRange_1End; i++) {
Object putResult = pr.putIfAbsent(Integer.toString(i), Integer.toString(i + 1));
assertEquals("for i=" + i, Integer.toString(i), putResult);
assertEquals("for i=" + i, Integer.toString(i), pr.get(Integer.toString(i)));
}
if (!isEmpty) {
size = pr.size();
assertEquals("Size doesn't return expected value", putRange_1End, size);
assertFalse("isEmpty doesnt return proper state of the PartitionedRegion", pr.isEmpty());
}
// test successful replace(key, oldValue, newValue)
for (int i = putRange_1Start; i <= putRange_1End; i++) {
boolean replaceSucceeded =
pr.replace(Integer.toString(i), Integer.toString(i), "replaced" + i);
assertTrue("for i=" + i, replaceSucceeded);
assertEquals("for i=" + i, "replaced" + i, pr.get(Integer.toString(i)));
}
if (!isEmpty) {
size = pr.size();
assertEquals("Size doesn't return expected value", putRange_1End, size);
assertFalse("isEmpty doesnt return proper state of the PartitionedRegion", pr.isEmpty());
}
// test unsuccessful replace(key, oldValue, newValue)
for (int i = putRange_1Start; i <= putRange_2End; i++) {
boolean replaceSucceeded = pr.replace(Integer.toString(i), Integer.toString(i), // wrong
// expected
// old
// value
"not" + i);
assertFalse("for i=" + i, replaceSucceeded);
assertEquals("for i=" + i, i <= putRange_1End ? "replaced" + i : null,
pr.get(Integer.toString(i)));
}
if (!isEmpty) {
size = pr.size();
assertEquals("Size doesn't return expected value", putRange_1End, size);
assertFalse("isEmpty doesnt return proper state of the PartitionedRegion", pr.isEmpty());
}
// test successful replace(key, value)
for (int i = putRange_1Start; i <= putRange_1End; i++) {
Object replaceResult = pr.replace(Integer.toString(i), "twice replaced" + i);
assertEquals("for i=" + i, "replaced" + i, replaceResult);
assertEquals("for i=" + i, "twice replaced" + i, pr.get(Integer.toString(i)));
}
if (!isEmpty) {
size = pr.size();
assertEquals("Size doesn't return expected value", putRange_1End, size);
assertFalse("isEmpty doesnt return proper state of the PartitionedRegion", pr.isEmpty());
}
// test unsuccessful replace(key, value)
for (int i = putRange_2Start; i <= putRange_2End; i++) {
Object replaceResult = pr.replace(Integer.toString(i), "thrice replaced" + i);
assertNull("for i=" + i, replaceResult);
assertNull("for i=" + i, pr.get(Integer.toString(i)));
}
if (!isEmpty) {
size = pr.size();
assertEquals("Size doesn't return expected value", putRange_1End, size);
assertFalse("isEmpty doesnt return proper state of the PartitionedRegion", pr.isEmpty());
}
// test unsuccessful remove(key, value)
for (int i = putRange_1Start; i <= putRange_2End; i++) {
boolean removeResult = pr.remove(Integer.toString(i), Integer.toString(-i));
assertFalse("for i=" + i, removeResult);
assertEquals("for i=" + i, i <= putRange_1End ? "twice replaced" + i : null,
pr.get(Integer.toString(i)));
}
if (!isEmpty) {
size = pr.size();
assertEquals("Size doesn't return expected value", putRange_1End, size);
assertFalse("isEmpty doesnt return proper state of the PartitionedRegion", pr.isEmpty());
}
// test successful remove(key, value)
for (int i = putRange_1Start; i <= putRange_1End; i++) {
boolean removeResult = pr.remove(Integer.toString(i), "twice replaced" + i);
assertTrue("for i=" + i, removeResult);
assertEquals("for i=" + i, null, pr.get(Integer.toString(i)));
}
if (!isEmpty) {
size = pr.size();
assertEquals("Size doesn't return expected value", 0, size);
pr.localClear();
assertTrue("isEmpty doesnt return proper state of the PartitionedRegion", pr.isEmpty());
}
if (!isEmpty) {
// bug #42169 - entry not updated on server when locally destroyed on client
String key42169 = "key42169";
pr.put(key42169, "initialValue42169");
pr.localDestroy(key42169);
boolean success = pr.replace(key42169, "initialValue42169", "newValue42169");
assertTrue("expected replace to succeed", success);
pr.destroy(key42169);
pr.put(key42169, "secondRound");
pr.localDestroy(key42169);
Object result = pr.putIfAbsent(key42169, null);
assertEquals("expected putIfAbsent to fail", result, "secondRound");
pr.destroy(key42169);
}
if (isEmpty) {
String key41265 = "key41265";
boolean success = pr.remove(key41265, null);
assertFalse("expected remove to fail because key does not exist", success);
}
// test null values
// putIfAbsent with null value creates invalid entry
Object oldValue = pr.putIfAbsent("keyForNull", null);
assertNull(oldValue);
if (!isEmpty) {
assertTrue(pr.containsKey("keyForNull"));
assertTrue(!pr.containsValueForKey("keyForNull"));
}
// replace allows null value for oldValue, meaning invalidated entry
assertTrue(pr.replace("keyForNull", null, "no longer invalid"));
// replace does not allow null value for new value
try {
pr.replace("keyForNull", "no longer invalid", null);
fail("expected a NullPointerException");
} catch (NullPointerException expected) {
}
// other variant of replace does not allow null value for new value
try {
pr.replace("keyForNull", null);
fail("expected a NullPointerException");
} catch (NullPointerException expected) {
}
// replace with null oldvalue matches invalidated entry
pr.putIfAbsent("otherKeyForNull", null);
int puts = ((GemFireCacheImpl) pr.getCache()).getCachePerfStats().getPuts();
boolean success = pr.replace("otherKeyForNull", null, "no longer invalid");
assertTrue(success);
int newputs = ((GemFireCacheImpl) pr.getCache()).getCachePerfStats().getPuts();
assertTrue("stats not updated properly or replace malfunctioned", newputs == puts + 1);
}
});
}
/**
* Test two regions: notify by subscription is true. For region1 the interest list is empty , for
* region 2 the intetest list is all keys. If an update/create is made on region1 , the client
* should not receive any. If the create/update is on region2 , the client should receive the
* update.
*/
@Test
public void testForTwoRegionHavingDifferentInterestList() throws Exception {
// start server first
PORT1 = initServerCache(true);
createClientCache(NetworkUtils.getServerHostName(Host.getHost(0)), PORT1);
populateCache();
registerInterest();
server1.invoke(() -> ClientServerMiscDUnitTest.put());
// pause(5000 + 5000 + 10000);
/*
* final int maxWaitTime = Integer.getInteger(WAIT_PROPERTY, WAIT_DEFAULT).intValue(); try {
* Thread.yield(); Thread.sleep(maxWaitTime); } catch (InterruptedException e) {
* fail("interrupted"); }
*/
verifyUpdates();
}
/**
* Test two regions: notify by subscription is true. Both the regions have registered interest in
* all the keys. Now close region1 on the client. The region1 should get removed from the interest
* list on CCP at server. Any update on region1 on server should not get pushed to the client.
* Ensure that the message related is not added to the client's queue at all ( which is diferent
* from not receiving a callbak on the client). If an update on region2 is made on the server ,
* then client should receive the calback
*/
@Test
public void testForTwoRegionHavingALLKEYSInterest() throws Exception {
// start server first
PORT1 = initServerCache(true);
createClientCache(NetworkUtils.getServerHostName(Host.getHost(0)), PORT1);
populateCache();
registerInterestInBothTheRegions();
closeRegion1();
Wait.pause(6000);
server1.invoke(() -> ClientServerMiscDUnitTest.verifyInterestListOnServer());
server1.invoke(() -> ClientServerMiscDUnitTest.put());
// pause(5000);
verifyUpdatesOnRegion2();
}
/**
* Test two regions: notify by subscription is true. Both the regions have registered interest in
* all the keys. Close both the regions. When the last region is closed , it should close the
* ConnectionProxy on the client , close all the server connection threads on the server & remove
* the CacheClientProxy from the CacheClient notifier
*/
@Test
public void testRegionClose() throws Exception {
// start server first
PORT1 = initServerCache(true);
pool = (PoolImpl) createClientCache(NetworkUtils.getServerHostName(Host.getHost(0)), PORT1);
populateCache();
registerInterestInBothTheRegions();
closeBothRegions();
// pause(5000);
assertEquals(false, pool.isDestroyed());
pool.destroy();
assertEquals(true, pool.isDestroyed());
server1.invoke(() -> ClientServerMiscDUnitTest.verifyNoCacheClientProxyOnServer());
}
/**
* Test two regions: notify by subscription is true. Both the regions have registered interest in
* all the keys. Destroy region1 on the client. It should reach the server , kill the region on
* the server , propagate it to the interested clients , but it should keep CacheClient Proxy
* alive. Destroy Region2 . It should reach server , close conenction proxy , destroy the region2
* on the server , remove the cache client proxy from the cache client notifier & propagate it to
* the clients. Then create third region and verify that no CacheClientProxy is created on server
*/
@Test
public void testCCPDestroyOnLastDestroyRegion() throws Exception {
PORT1 = initServerCache(true);
PoolImpl pool =
(PoolImpl) createClientCache(NetworkUtils.getServerHostName(Host.getHost(0)), PORT1);
destroyRegion1();
// pause(5000);
server1.invoke(
() -> ClientServerMiscDUnitTest.verifyCacheClientProxyOnServer(new String(REGION_NAME1)));
Connection conn = pool.acquireConnection();
assertNotNull(conn);
assertEquals(1, pool.getConnectedServerCount());
assertEquals(false, pool.isDestroyed());
destroyRegion2();
assertEquals(false, pool.isDestroyed());
destroyPRRegion();
assertEquals(false, pool.isDestroyed());
pool.destroy();
assertEquals(true, pool.isDestroyed());
// pause(5000);
server1.invoke(() -> ClientServerMiscDUnitTest.verifyNoCacheClientProxyOnServer());
try {
getCache().createRegion(REGION_NAME2, attrs);
fail("expected IllegalStateException");
} catch (IllegalStateException expected) {
}
}
/**
* Test two regions:If notify by subscription is false , both the regions should receive
* invalidates for the updates on server in their respective regions
*
*/
@Test
public void testInvalidatesPropagateOnTwoRegions() throws Exception {
// start server first
PORT1 = initServerCache(false);
createClientCache(NetworkUtils.getServerHostName(Host.getHost(0)), PORT1);
registerInterestForInvalidatesInBothTheRegions();
populateCache();
server1.invoke(() -> ClientServerMiscDUnitTest.put());
// pause(5000);
verifyInvalidatesOnBothRegions();
}
/**
* Test for bug 43407, where LRU in the client caused an entry to be evicted with DESTROY(), then
* the client invalidated the entry and did a get(). After the get() the entry was not seen to be
* in the client's cache. This turned out to be expected behavior, but we now have this test to
* guarantee that the product behaves as expected.
*/
@Test
public void testGetInClientCreatesEntry() throws Exception {
// start server first
PORT1 = initServerCache(false);
createClientCache(NetworkUtils.getServerHostName(Host.getHost(0)), PORT1);
registerInterestForInvalidatesInBothTheRegions();
Region region = static_cache.getRegion(REGION_NAME1);
populateCache();
region.put("invalidationKey", "invalidationValue");
region.localDestroy("invalidationKey");
if (region.containsKey("invalidationKey")) {
fail("region still contains invalidationKey");
}
region.invalidate("invalidationKey");
if (region.containsKey("invalidationKey")) {
fail(
"this test expects the entry is not created on invalidate() if not there before the operation");
}
Object value = region.get("invalidationKey");
if (value != null) {
fail("this test expected a null response to get('invalidationKey')");
}
if (!region.containsKeyOnServer("invalidationKey")) {
fail("expected an entry on the server after invalidation");
}
// bug 43407 asserts that there should be an entry, but the product does not
// do this. This verifies that the product does not behave as asserted in that bug
if (region.containsKey("invalidationKey")) {
fail("expected no entry after invalidation when entry was not in client but was on server");
}
}
/**
* GEODE-478 - large payloads are rejected by client->server
*/
@Test
public void testLargeMessageIsRejected() throws Exception {
PORT1 = initServerCache(false);
createClientCache(NetworkUtils.getServerHostName(Host.getHost(0)), PORT1);
Region region = static_cache.getRegion(REGION_NAME1);
Op operation = new Op() {
@Override
public Object attempt(Connection cnx) throws Exception {
throw new MessageTooLargeException("message is too big");
}
@Override
public boolean useThreadLocalConnection() {
return false;
}
};
try {
((LocalRegion) region).getServerProxy().getPool().execute(operation);
} catch (GemFireIOException e) {
assertTrue(e.getCause() instanceof MessageTooLargeException);
return;
}
fail("expected an exception to be thrown");
}
/**
* Create cache, create pool, notify-by-subscription=false, create a region and on client and on
* server. Do not attach pool to region , populate some entries on region both on client and
* server. Update the entries on server the client. The client should not have entry invalidate.
*/
@Test
public void testInvalidatesPropagateOnRegionHavingNoPool() throws Exception {
// start server first
PORT1 = initServerCache(false);
Properties props = new Properties();
props.setProperty(MCAST_PORT, "0");
props.setProperty(LOCATORS, "");
new ClientServerMiscDUnitTest().createCache(props);
String host = NetworkUtils.getServerHostName(server1.getHost());
PoolImpl p =
(PoolImpl) PoolManager.createFactory().addServer(host, PORT1).setSubscriptionEnabled(true)
.setThreadLocalConnections(true).setReadTimeout(1000).setSocketBufferSize(32768)
.setMinConnections(3).setSubscriptionRedundancy(-1).setPingInterval(2000)
// .setRetryAttempts(5)
// .setRetryInterval(2000)
.create("testInvalidatesPropagateOnRegionHavingNoPool");
AttributesFactory factory = new AttributesFactory();
factory.setScope(Scope.DISTRIBUTED_ACK);
// factory.setPoolName(p.getName());
attrs = factory.create();
final Region region1 = getCache().createRegion(REGION_NAME1, attrs);
final Region region2 = getCache().createRegion(REGION_NAME2, attrs);
assertNotNull(region1);
assertNotNull(region2);
pool = p;
conn = pool.acquireConnection();
assertNotNull(conn);
populateCache();
server1.invoke(() -> ClientServerMiscDUnitTest.put());
// pause(5000);
WaitCriterion wc = new WaitCriterion() {
String excuse;
public boolean done() {
Object val = region1.getEntry(k1).getValue();
return k1.equals(val);
}
public String description() {
return excuse;
}
};
Wait.waitForCriterion(wc, 60 * 1000, 1000, true);
// assertIndexDetailsEquals(region1.getEntry(k1).getValue(), k1);
wc = new WaitCriterion() {
String excuse;
public boolean done() {
Object val = region1.getEntry(k2).getValue();
return k2.equals(val);
}
public String description() {
return excuse;
}
};
Wait.waitForCriterion(wc, 60 * 1000, 1000, true);
wc = new WaitCriterion() {
String excuse;
public boolean done() {
Object val = region2.getEntry(k1).getValue();
return k1.equals(val);
}
public String description() {
return excuse;
}
};
Wait.waitForCriterion(wc, 60 * 1000, 1000, true);
// assertIndexDetailsEquals(region1.getEntry(k2).getValue(), k2);
// assertIndexDetailsEquals(region2.getEntry(k1).getValue(), k1);
wc = new WaitCriterion() {
String excuse;
public boolean done() {
Object val = region2.getEntry(k2).getValue();
return k2.equals(val);
}
public String description() {
return excuse;
}
};
Wait.waitForCriterion(wc, 60 * 1000, 1000, true);
// assertIndexDetailsEquals(region2.getEntry(k2).getValue(), k2);
}
/**
* Create proxy before cache creation, create cache, create two regions, attach same bridge writer
* to both of the regions Region interests AL_KEYS on both the regions,
* notify-by-subscription=true . The CCP should have both the regions in interest list.
*
* @throws Exception
*/
@Test
public void testProxyCreationBeforeCacheCreation() throws Exception {
Properties props = new Properties();
props.setProperty(MCAST_PORT, "0");
props.setProperty(LOCATORS, "");
DistributedSystem ds = getSystem(props);
assertNotNull(ds);
ds.disconnect();
ds = getSystem(props);
PORT1 = initServerCache(true);
String host = NetworkUtils.getServerHostName(server1.getHost());
Pool p = PoolManager.createFactory().addServer(host, PORT1).setSubscriptionEnabled(true)
.setSubscriptionRedundancy(-1)
// .setRetryAttempts(5)
.create("testProxyCreationBeforeCacheCreationPool");
Cache cache = getCache();
assertNotNull(cache);
AttributesFactory factory = new AttributesFactory();
factory.setScope(Scope.DISTRIBUTED_ACK);
factory.setPoolName(p.getName());
RegionAttributes myAttrs = factory.create();
Region region1 = cache.createRegion(REGION_NAME1, myAttrs);
Region region2 = cache.createRegion(REGION_NAME2, myAttrs);
assertNotNull(region1);
assertNotNull(region2);
// region1.registerInterest(CacheClientProxy.ALL_KEYS);
region2.registerInterest("ALL_KEYS");
Wait.pause(6000);
server1.invoke(() -> ClientServerMiscDUnitTest.verifyInterestListOnServer());
}
/**
*
* bug 35380: Cycling a DistributedSystem with an initialized pool causes interest registration
* NPE
*
* Test Scenario:
*
* Create a DistributedSystem (DS1). Create a pool, initialize (creates a proxy with DS1 memberid)
* Disconnect DS1. Create a DistributedSystem (DS2). Create a Region with pool, it attempts to
* register interest using DS2 memberid, gets NPE.
*
* @throws Exception
*/
@Test
public void testSystemCanBeCycledWithAnInitializedPool() throws Exception {
// work around GEODE-477
IgnoredException.addIgnoredException("Connection reset");
Properties props = new Properties();
props.setProperty(MCAST_PORT, "0");
props.setProperty(LOCATORS, "");
DistributedSystem ds = getSystem(props);
assertNotNull(ds);
PORT1 = initServerCache(true);
String host = NetworkUtils.getServerHostName(server1.getHost());
Pool p = PoolManager.createFactory().addServer(host, PORT1).setSubscriptionEnabled(true)
.setSubscriptionRedundancy(-1)
// .setRetryAttempts(5)
.create("testBug35380Pool");
Cache cache = getCache();
AttributesFactory factory = new AttributesFactory();
factory.setScope(Scope.DISTRIBUTED_ACK);
factory.setPoolName(p.getName());
RegionAttributes myAttrs = factory.create();
Region region1 = cache.createRegion(REGION_NAME1, myAttrs);
Region region2 = cache.createRegion(REGION_NAME2, myAttrs);
assertNotNull(region1);
assertNotNull(region2);
region2.registerInterest("ALL_KEYS");
ds.disconnect();
Properties prop = new Properties();
prop.setProperty(MCAST_PORT, "0");
prop.setProperty(LOCATORS, "");
ds = getSystem(prop);
cache = getCache();
assertNotNull(cache);
AttributesFactory factory1 = new AttributesFactory();
factory1.setScope(Scope.DISTRIBUTED_ACK);
// reuse writer from prev DS
factory1.setPoolName(p.getName());
RegionAttributes attrs1 = factory1.create();
try {
cache.createRegion(REGION_NAME1, attrs1);
fail("expected ShutdownException");
} catch (IllegalStateException expected) {
} catch (DistributedSystemDisconnectedException expected) {
}
}
@Test(expected = GemFireConfigException.class)
public void clientIsPreventedFromConnectingToLocatorAsServer() throws Exception {
IgnoredException.addIgnoredException("Improperly configured client detected");
ClientCacheFactory clientCacheFactory = new ClientCacheFactory();
clientCacheFactory.addPoolServer("localhost", DistributedTestUtils.getDUnitLocatorPort());
clientCacheFactory.setPoolSubscriptionEnabled(true);
getClientCache(clientCacheFactory);
}
private void createCache(Properties props) throws Exception {
createCacheV(props);
}
private Cache createCacheV(Properties props) throws Exception {
DistributedSystem ds = getSystem(props);
assertNotNull(ds);
ds.disconnect();
ds = getSystem(props);
Cache cache = getCache();
assertNotNull(cache);
return cache;
}
public static void createClientCacheV(String h, int port) throws Exception {
_createClientCache(h, port, false);
}
public static void createEmptyClientCache(String h, int port) throws Exception {
_createClientCache(h, port, true);
}
public static Pool createClientCache(String h, int port) throws Exception {
return _createClientCache(h, port, false);
}
public static Pool _createClientCache(String h, int port, boolean empty) throws Exception {
Properties props = new Properties();
props.setProperty(MCAST_PORT, "0");
props.setProperty(LOCATORS, "");
Cache cache = new ClientServerMiscDUnitTest().createCacheV(props);
ClientServerMiscDUnitTest.static_cache = cache;
PoolImpl p =
(PoolImpl) PoolManager.createFactory().addServer(h, port).setSubscriptionEnabled(true)
.setThreadLocalConnections(true).setReadTimeout(1000).setSocketBufferSize(32768)
.setMinConnections(3).setSubscriptionRedundancy(-1).setPingInterval(2000)
// .setRetryAttempts(5)
// .setRetryInterval(2000)
.create("ClientServerMiscDUnitTestPool");
AttributesFactory factory = new AttributesFactory();
factory.setScope(Scope.DISTRIBUTED_ACK);
if (empty) {
factory.setDataPolicy(DataPolicy.EMPTY);
}
factory.setPoolName(p.getName());
attrs = factory.create();
Region region1 = cache.createRegion(REGION_NAME1, attrs);
Region region2 = cache.createRegion(REGION_NAME2, attrs);
Region prRegion = cache.createRegion(PR_REGION_NAME, attrs);
assertNotNull(region1);
assertNotNull(region2);
assertNotNull(prRegion);
pool = p;
// conn = pool.acquireConnection();
// assertNotNull(conn);
// TODO does this WaitCriterion actually help?
WaitCriterion wc = new WaitCriterion() {
String excuse;
public boolean done() {
try {
conn = pool.acquireConnection();
if (conn == null) {
excuse = "acquireConnection returned null?";
return false;
}
return true;
} catch (NoAvailableServersException e) {
excuse = "Cannot find a server: " + e;
return false;
}
}
public String description() {
return excuse;
}
};
Wait.waitForCriterion(wc, 60 * 1000, 1000, true);
return p;
}
public static Integer createServerCache(Boolean notifyBySubscription, Integer maxThreads)
throws Exception {
Cache cache = new ClientServerMiscDUnitTest().createCacheV(new Properties());
unsetSlowDispatcherFlag();
AttributesFactory factory = new AttributesFactory();
factory.setScope(Scope.DISTRIBUTED_ACK);
factory.setEnableConflation(true);
factory.setDataPolicy(DataPolicy.REPLICATE);
RegionAttributes myAttrs = factory.create();
Region r1 = cache.createRegion(REGION_NAME1, myAttrs);
Region r2 = cache.createRegion(REGION_NAME2, myAttrs);
factory = new AttributesFactory();
factory.setDataPolicy(DataPolicy.PARTITION);
RegionAttributes prAttrs = factory.create();
Region pr = cache.createRegion(PR_REGION_NAME, prAttrs);
assertNotNull(r1);
assertNotNull(r2);
assertNotNull(pr);
CacheServer server = cache.addCacheServer();
int port = AvailablePort.getRandomAvailablePort(AvailablePort.SOCKET);
r1.getCache().getDistributedSystem().getLogWriter().info("Starting server on port " + port);
server.setPort(port);
server.setMaxThreads(maxThreads.intValue());
server.setNotifyBySubscription(notifyBySubscription.booleanValue());
server.start();
r1.getCache().getDistributedSystem().getLogWriter()
.info("Started server on port " + server.getPort());
return new Integer(server.getPort());
}
protected int getMaxThreads() {
return 0;
}
public static void registerInterest() {
try {
Cache cache = new ClientServerMiscDUnitTest().getCache();
Region r = cache.getRegion(Region.SEPARATOR + REGION_NAME2);
assertNotNull(r);
// r.registerInterestRegex(CacheClientProxy.ALL_KEYS);
r.registerInterest("ALL_KEYS");
} catch (CacheWriterException e) {
e.printStackTrace();
Assert.fail("Test failed due to CacheWriterException during registerInterest", e);
}
}
public static void registerInterestForInvalidatesInBothTheRegions() {
try {
Cache cache = new ClientServerMiscDUnitTest().getCache();
Region r1 = cache.getRegion(Region.SEPARATOR + REGION_NAME1);
assertNotNull(r1);
Region r2 = cache.getRegion(Region.SEPARATOR + REGION_NAME2);
assertNotNull(r2);
r1.registerInterest("ALL_KEYS", false, false);
r2.registerInterest("ALL_KEYS", false, false);
} catch (CacheWriterException e) {
e.printStackTrace();
Assert.fail("Test failed due to CacheWriterException during registerInterestnBothRegions", e);
}
}
public static void registerInterestInBothTheRegions() {
try {
Cache cache = new ClientServerMiscDUnitTest().getCache();
Region r1 = cache.getRegion(Region.SEPARATOR + REGION_NAME1);
assertNotNull(r1);
Region r2 = cache.getRegion(Region.SEPARATOR + REGION_NAME2);
assertNotNull(r2);
r1.registerInterest("ALL_KEYS");
r2.registerInterest("ALL_KEYS");
} catch (CacheWriterException e) {
e.printStackTrace();
Assert.fail("Test failed due to CacheWriterException during registerInterestnBothRegions", e);
}
}
public static void closeRegion1() {
try {
Cache cache = new ClientServerMiscDUnitTest().getCache();
Region r1 = cache.getRegion(Region.SEPARATOR + REGION_NAME1);
assertNotNull(r1);
r1.close();
} catch (Exception e) {
e.printStackTrace();
Assert.fail("Test failed due to Exception during closeRegion1", e);
}
}
public static void closeBothRegions() {
try {
Cache cache = new ClientServerMiscDUnitTest().getCache();
Region r1 = cache.getRegion(Region.SEPARATOR + REGION_NAME1);
Region r2 = cache.getRegion(Region.SEPARATOR + REGION_NAME2);
Region pr = cache.getRegion(Region.SEPARATOR + PR_REGION_NAME);
assertNotNull(r1);
assertNotNull(r2);
assertNotNull(pr);
r1.close();
r2.close();
pr.close();
} catch (Exception e) {
e.printStackTrace();
Assert.fail("Test failed due to Exception during closeBothRegions", e);
}
}
public static void destroyRegion1() {
try {
Cache cache = new ClientServerMiscDUnitTest().getCache();
Region r1 = cache.getRegion(Region.SEPARATOR + REGION_NAME1);
assertNotNull(r1);
r1.destroyRegion();
} catch (Exception e) {
e.printStackTrace();
Assert.fail("Test failed due to Exception during closeBothRegions", e);
}
}
public static void destroyRegion2() {
try {
Cache cache = new ClientServerMiscDUnitTest().getCache();
Region r2 = cache.getRegion(Region.SEPARATOR + REGION_NAME2);
assertNotNull(r2);
r2.destroyRegion();
} catch (Exception e) {
e.printStackTrace();
Assert.fail("Test failed due to Exception during closeBothRegions", e);
}
}
public static void destroyPRRegion() {
try {
Cache cache = new ClientServerMiscDUnitTest().getCache();
Region r2 = cache.getRegion(Region.SEPARATOR + PR_REGION_NAME);
assertNotNull(r2);
r2.destroyRegion();
} catch (Exception e) {
// e.printStackTrace();
Assert.fail("Test failed due to Exception during closeBothRegions", e);
}
}
public static void verifyInterestListOnServer() {
try {
Cache cache = new ClientServerMiscDUnitTest().getCache();
assertEquals("More than one BridgeServer", 1, cache.getCacheServers().size());
CacheServerImpl bs = (CacheServerImpl) cache.getCacheServers().iterator().next();
assertNotNull(bs);
assertNotNull(bs.getAcceptor());
assertNotNull(bs.getAcceptor().getCacheClientNotifier());
Iterator iter_prox = bs.getAcceptor().getCacheClientNotifier().getClientProxies().iterator();
while (iter_prox.hasNext()) {
CacheClientProxy ccp = (CacheClientProxy) iter_prox.next();
// CCP should not contain region1
Set akr = ccp.cils[RegisterInterestTracker.interestListIndex].regions;
assertNotNull(akr);
assertTrue(!akr.contains(Region.SEPARATOR + REGION_NAME1));
// CCP should contain region2
assertTrue(akr.contains(Region.SEPARATOR + REGION_NAME2));
assertEquals(1, akr.size());
}
} catch (Exception ex) {
ex.printStackTrace();
fail("while setting verifyInterestListOnServer " + ex);
}
}
public static void verifyNoCacheClientProxyOnServer() {
try {
Cache cache = new ClientServerMiscDUnitTest().getCache();
assertEquals("More than one BridgeServer", 1, cache.getCacheServers().size());
CacheServerImpl bs = (CacheServerImpl) cache.getCacheServers().iterator().next();
assertNotNull(bs);
assertNotNull(bs.getAcceptor());
final CacheClientNotifier ccn = bs.getAcceptor().getCacheClientNotifier();
assertNotNull(ccn);
WaitCriterion wc = new WaitCriterion() {
String excuse;
public boolean done() {
return ccn.getClientProxies().size() == 0;
}
public String description() {
return excuse;
}
};
Wait.waitForCriterion(wc, 40 * 1000, 1000, true);
} catch (Exception ex) {
ex.printStackTrace();
fail("while setting verifyNoCacheClientProxyOnServer " + ex);
}
}
public static void verifyCacheClientProxyOnServer(String regionName) {
try {
Cache cache = new ClientServerMiscDUnitTest().getCache();
assertNull(cache.getRegion(Region.SEPARATOR + regionName));
verifyCacheClientProxyOnServer();
// assertIndexDetailsEquals(1,
// bs.getAcceptor().getCacheClientNotifier().getClientProxies().size());
} catch (Exception ex) {
ex.printStackTrace();
fail("while setting verifyNoCacheClientProxyOnServer " + ex);
}
}
public static void verifyCacheClientProxyOnServer() {
try {
Cache cache = new ClientServerMiscDUnitTest().getCache();
assertEquals("More than one BridgeServer", 1, cache.getCacheServers().size());
CacheServerImpl bs = (CacheServerImpl) cache.getCacheServers().iterator().next();
assertNotNull(bs);
assertNotNull(bs.getAcceptor());
final CacheClientNotifier ccn = bs.getAcceptor().getCacheClientNotifier();
assertNotNull(ccn);
WaitCriterion wc = new WaitCriterion() {
String excuse;
public boolean done() {
return ccn.getClientProxies().size() == 1;
}
public String description() {
return excuse;
}
};
Wait.waitForCriterion(wc, 40 * 1000, 1000, true);
} catch (Exception ex) {
ex.printStackTrace();
fail("while setting verifyNoCacheClientProxyOnServer " + ex);
}
}
public static void populateCache() {
try {
Cache cache = new ClientServerMiscDUnitTest().getCache();
Region r1 = cache.getRegion(Region.SEPARATOR + REGION_NAME1);
Region r2 = cache.getRegion(Region.SEPARATOR + REGION_NAME2);
assertNotNull(r1);
assertNotNull(r2);
if (!r1.containsKey(k1))
r1.create(k1, k1);
if (!r1.containsKey(k2))
r1.create(k2, k2);
if (!r2.containsKey(k1))
r2.create(k1, k1);
if (!r2.containsKey(k2))
r2.create(k2, k2);
assertEquals(r1.getEntry(k1).getValue(), k1);
assertEquals(r1.getEntry(k2).getValue(), k2);
assertEquals(r2.getEntry(k1).getValue(), k1);
assertEquals(r2.getEntry(k2).getValue(), k2);
} catch (Exception ex) {
Assert.fail("failed while createEntries()", ex);
}
}
public static void put() {
try {
Cache cache = new ClientServerMiscDUnitTest().getCache();
Region r1 = cache.getRegion(Region.SEPARATOR + REGION_NAME1);
Region r2 = cache.getRegion(Region.SEPARATOR + REGION_NAME2);
assertNotNull(r1);
assertNotNull(r2);
r1.put(k1, server_k1);
r1.put(k2, server_k2);
r2.put(k1, server_k1);
r2.put(k2, server_k2);
assertEquals(r1.getEntry(k1).getValue(), server_k1);
assertEquals(r1.getEntry(k2).getValue(), server_k2);
assertEquals(r2.getEntry(k1).getValue(), server_k1);
assertEquals(r2.getEntry(k2).getValue(), server_k2);
} catch (Exception ex) {
Assert.fail("failed while put()", ex);
}
}
public static void verifyUpdates() {
try {
Cache cache = new ClientServerMiscDUnitTest().getCache();
final Region r1 = cache.getRegion(Region.SEPARATOR + REGION_NAME1);
final Region r2 = cache.getRegion(Region.SEPARATOR + REGION_NAME2);
assertNotNull(r1);
assertNotNull(r2);
// verify updates
WaitCriterion wc = new WaitCriterion() {
String excuse;
public boolean done() {
Object val = r1.getEntry(k1).getValue();
return k1.equals(val);
}
public String description() {
return excuse;
}
};
Wait.waitForCriterion(wc, 60 * 1000, 1000, true);
// assertIndexDetailsEquals(k1, r1.getEntry(k1).getValue());
wc = new WaitCriterion() {
String excuse;
public boolean done() {
Object val = r1.getEntry(k2).getValue();
return k2.equals(val);
}
public String description() {
return excuse;
}
};
Wait.waitForCriterion(wc, 60 * 1000, 1000, true);
// assertIndexDetailsEquals(k2, r1.getEntry(k2).getValue());
wc = new WaitCriterion() {
String excuse;
public boolean done() {
Object val = r2.getEntry(k1).getValue();
return server_k1.equals(val);
}
public String description() {
return excuse;
}
};
Wait.waitForCriterion(wc, 60 * 1000, 1000, true);
// assertIndexDetailsEquals(server_k1, r2.getEntry(k1).getValue());
wc = new WaitCriterion() {
String excuse;
public boolean done() {
Object val = r2.getEntry(k2).getValue();
return server_k2.equals(val);
}
public String description() {
return excuse;
}
};
Wait.waitForCriterion(wc, 60 * 1000, 1000, true);
// assertIndexDetailsEquals(server_k2, r2.getEntry(k2).getValue());
} catch (Exception ex) {
Assert.fail("failed while verifyUpdates()", ex);
}
}
public static void verifyInvalidatesOnBothRegions() {
try {
Cache cache = new ClientServerMiscDUnitTest().getCache();
final Region r1 = cache.getRegion(Region.SEPARATOR + REGION_NAME1);
final Region r2 = cache.getRegion(Region.SEPARATOR + REGION_NAME2);
assertNotNull(r1);
assertNotNull(r2);
WaitCriterion wc = new WaitCriterion() {
String excuse;
public boolean done() {
Object val = r1.getEntry(k1).getValue();
return val == null;
}
public String description() {
return excuse;
}
};
Wait.waitForCriterion(wc, 90 * 1000, 1000, true);
// assertNull(r1.getEntry(k1).getValue());
wc = new WaitCriterion() {
String excuse;
public boolean done() {
Object val = r1.getEntry(k1).getValue();
return val == null;
}
public String description() {
return excuse;
}
};
Wait.waitForCriterion(wc, 90 * 1000, 1000, true);
// assertNull(r1.getEntry(k2).getValue());
wc = new WaitCriterion() {
String excuse;
public boolean done() {
Object val = r1.getEntry(k2).getValue();
return val == null;
}
public String description() {
return excuse;
}
};
Wait.waitForCriterion(wc, 90 * 1000, 1000, true);
// assertNull(r2.getEntry(k1).getValue());
wc = new WaitCriterion() {
String excuse;
public boolean done() {
Object val = r2.getEntry(k1).getValue();
return val == null;
}
public String description() {
return excuse;
}
};
Wait.waitForCriterion(wc, 90 * 1000, 1000, true);
// assertNull(r2.getEntry(k2).getValue());
wc = new WaitCriterion() {
String excuse;
public boolean done() {
Object val = r2.getEntry(k2).getValue();
return val == null;
}
public String description() {
return excuse;
}
};
Wait.waitForCriterion(wc, 90 * 1000, 1000, true);
} catch (Exception ex) {
Assert.fail("failed while verifyInvalidatesOnBothRegions()", ex);
}
}
public static void verifyUpdatesOnRegion2() {
try {
Cache cache = new ClientServerMiscDUnitTest().getCache();
final Region r2 = cache.getRegion(Region.SEPARATOR + REGION_NAME2);
assertNotNull(r2);
WaitCriterion wc = new WaitCriterion() {
String excuse;
public boolean done() {
Object val = r2.getEntry(k1).getValue();
return server_k1.equals(val);
}
public String description() {
return excuse;
}
};
Wait.waitForCriterion(wc, 60 * 1000, 1000, true);
// assertIndexDetailsEquals(server_k1, r2.getEntry(k1).getValue());
wc = new WaitCriterion() {
String excuse;
public boolean done() {
Object val = r2.getEntry(k2).getValue();
return server_k2.equals(val);
}
public String description() {
return excuse;
}
};
Wait.waitForCriterion(wc, 60 * 1000, 1000, true);
// assertIndexDetailsEquals(server_k2, r2.getEntry(k2).getValue());
} catch (Exception ex) {
Assert.fail("failed while verifyUpdatesOnRegion2()", ex);
}
}
/**
* set the boolean for starting the dispatcher thread a bit later to FALSE. This is just a
* precaution in case any test set it to true and did not unset it on completion.
*
*/
public static void unsetSlowDispatcherFlag() {
CacheClientProxy.isSlowStartForTesting = false;
}
}