blob: b31b761d2527895888b64347596ad7db91260092 [file] [log] [blame]
/*=========================================================================
* Copyright (c) 2011-2014 Pivotal Software, Inc. All Rights Reserved.
* This product is protected by U.S. and international copyright
* and intellectual property laws. Pivotal products are covered by
* more patents listed at http://www.pivotal.io/patents.
*=========================================================================
*/
package com.gemstone.gemfire.pdx;
import java.io.IOException;
import com.gemstone.gemfire.SerializationException;
import com.gemstone.gemfire.cache.Cache;
import com.gemstone.gemfire.cache.CacheLoader;
import com.gemstone.gemfire.cache.CacheLoaderException;
import com.gemstone.gemfire.cache.EvictionAction;
import com.gemstone.gemfire.cache.EvictionAttributes;
import com.gemstone.gemfire.cache.InterestResultPolicy;
import com.gemstone.gemfire.cache.LoaderHelper;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.RegionShortcut;
import com.gemstone.gemfire.cache.client.ClientCache;
import com.gemstone.gemfire.cache.client.ClientCacheFactory;
import com.gemstone.gemfire.cache.client.ClientRegionShortcut;
import com.gemstone.gemfire.cache.query.SelectResults;
import com.gemstone.gemfire.cache.server.CacheServer;
import com.gemstone.gemfire.cache30.CacheTestCase;
import com.gemstone.gemfire.internal.AvailablePortHelper;
import com.gemstone.gemfire.pdx.PdxReader;
import com.gemstone.gemfire.pdx.PdxSerializable;
import com.gemstone.gemfire.pdx.PdxWriter;
import dunit.Host;
import dunit.SerializableCallable;
import dunit.SerializableRunnable;
import dunit.VM;
/**
* A test to ensure that we do not deserialize PDX objects
* when we shouldn't
*
* This test is trying to cover all of the possible access paths.
*
* @author dsmith
*
*/
public class PdxDeserializationDUnitTest extends CacheTestCase {
public PdxDeserializationDUnitTest(String name) {
super(name);
}
/**
* Test that we don't deserialize objects on a remote peer
* when performing operations.
*/
public void testP2P() {
Host host = Host.getHost(0);
VM vm0 = host.getVM(0);
VM vm1 = host.getVM(1);
VM vm2 = host.getVM(2);
doTest(vm0, vm1);
}
/**
* Test to make sure we don't deserialize
* objects on a server that is a datastore
*/
public void testClientToDataStore() {
Host host = Host.getHost(0);
VM vm1 = host.getVM(1);
VM vm2 = host.getVM(2);
doTest(vm2, vm1);
}
/**
* Test to make sure we don't deserialize
* objects on a server that is an accessor.
*/
public void testClientToAccessor() {
Host host = Host.getHost(0);
VM vm1 = host.getVM(1);
VM vm3 = host.getVM(3);
doTest(vm3, vm1);
}
/**
* Test to make sure we don't deserialize
* objects on a client that has registered interest.
*/
public void testAccessorToClient() {
Host host = Host.getHost(0);
VM vm1 = host.getVM(1);
VM vm3 = host.getVM(2);
doTest(vm1, vm3);
}
/**
* This test creates the following topology
*
* vm0 a peer accessor for both a PR and a replicate region
* vm1 a peer data store for a replicate region and a PR
* vm2 a client of vm0
* vm3 a client vm1
*
* The test then performs all region operations
* in operationVM, while deserialization is
* prevented in disallowDeserializationVM.
*
* If an operation causes a deserialization in the
* disallow VM, this test will fail.
*
* @param operationVM
* @param disallowDeserializationVM
*/
private void doTest(VM operationVM, VM disallowDeserializationVM) {
Host host = Host.getHost(0);
VM vm0 = host.getVM(0);
VM vm1 = host.getVM(1);
VM vm2 = host.getVM(2);
VM vm3 = host.getVM(3);
//Create an accessor
final int port0 = (Integer) vm0.invoke(new SerializableCallable() {
public Object call() {
Cache cache = getCache();
CacheServer server = createCacheServer(cache);
cache.createRegionFactory(RegionShortcut.REPLICATE_PROXY).create("replicate");
cache.createRegionFactory(RegionShortcut.PARTITION_PROXY).create("pr");
cache.createRegionFactory(RegionShortcut.REPLICATE_PROXY).create("overflow_replicate");
cache.createRegionFactory(RegionShortcut.PARTITION_PROXY).create("overflow_pr");
return server.getPort();
}
});
//Create a datastore
final int port1 = (Integer) vm1.invoke(new SerializableCallable() {
public Object call() {
Cache cache = getCache();
CacheServer server = createCacheServer(cache);
cache.createRegionFactory(RegionShortcut.REPLICATE)
.setCacheLoader(new TestCacheLoader())
.create("replicate");
cache.createRegionFactory(RegionShortcut.PARTITION)
.setCacheLoader(new TestCacheLoader())
.create("pr");
cache.createDiskStoreFactory()
.setDiskDirs(getDiskDirs())
.setMaxOplogSize(1)
.create("store");
//these regions will test that faulting in an object
//from disk doesn't cause an issue.
cache.createRegionFactory(RegionShortcut.REPLICATE_OVERFLOW)
.setEvictionAttributes(EvictionAttributes.createLRUEntryAttributes(1, EvictionAction.OVERFLOW_TO_DISK))
.setDiskStoreName("store")
.setCacheLoader(new TestCacheLoader())
.create("overflow_replicate");
cache.createRegionFactory(RegionShortcut.PARTITION_OVERFLOW)
.setEvictionAttributes(EvictionAttributes.createLRUEntryAttributes(1, EvictionAction.OVERFLOW_TO_DISK))
.setDiskStoreName("store")
.setCacheLoader(new TestCacheLoader())
.create("overflow_pr");
return server.getPort();
}
});
//create a client connected to the accessor
vm2.invoke(new SerializableCallable() {
public Object call() throws Exception {
createClient(port0);
return null;
}
});
//create a client connected to the datastore
vm3.invoke(new SerializableCallable() {
public Object call() throws Exception {
createClient(port1);
return null;
}
});
//Disallow deserialization
disallowDeserializationVM.invoke(new SerializableRunnable() {
public void run() {
TestSerializable.throwExceptionOnDeserialization = true;
}
});
//perform operations in the target VM
try {
operationVM.invoke(new SerializableRunnable() {
public void run() {
Cache cache = getCache();
doOperations(cache.getRegion("replicate"));
doOperations(cache.getRegion("pr"));
doOperations(cache.getRegion("overflow_replicate"));
doOperations(cache.getRegion("overflow_pr"));
}
});
} finally {
//Ok, now allow deserialization.
disallowDeserializationVM.invoke(new SerializableRunnable() {
public void run() {
TestSerializable.throwExceptionOnDeserialization = false;
}
});
}
//Sanity Check to make sure the values not in some weird form
//on the actual datastore.
vm1.invoke(new SerializableRunnable() {
public void run() {
Cache cache = getCache();
checkValues(cache.getRegion("replicate"));
checkValues(cache.getRegion("pr"));
checkValues(cache.getRegion("overflow_replicate"));
checkValues(cache.getRegion("overflow_pr"));
}
});
//Make sure the clients receive keys they have registered interest in
checkRegisterInterestValues(vm2);
checkRegisterInterestValues(vm3);
}
private void checkRegisterInterestValues(VM vm2) {
vm2.invoke(new SerializableRunnable() {
public void run() {
Cache cache = getCache();
checkClientValue(cache.getRegion("replicate"));
checkClientValue(cache.getRegion("pr"));
checkClientValue(cache.getRegion("overflow_replicate"));
checkClientValue(cache.getRegion("overflow_pr"));
}
});
}
protected void checkClientValue(final Region<Object, Object> region) {
//Because register interest is asynchronous, we need to wait for the value to arrive.
waitForCriterion(new WaitCriterion() {
public boolean done() {
return region.get("A") != null;
}
public String description() {
return "Client region never received value for key A";
}
}, 30000, 100, true);
assertEquals(TestSerializable.class, region.get("A").getClass());
//do a register interest which will download the value
region.registerInterest("B", InterestResultPolicy.KEYS_VALUES);
assertEquals(TestSerializable.class, region.get("B").getClass());
}
private void doOperations(Region<Object, Object> region) {
//Do a put and a get
region.put("A", new TestSerializable());
assertEquals(TestSerializable.class, region.get("A").getClass());
//Do a cache load
assertEquals(TestSerializable.class, region.get("B").getClass());
//Make sure the cache load is in the right object form
assertEquals(TestSerializable.class, region.get("B").getClass());
//If we're a client region, try a register interest
if(region.getAttributes().getPoolName() != null) {
region.registerInterest(".*", InterestResultPolicy.KEYS_VALUES);
}
//Do a query
try {
SelectResults queryResults = (SelectResults) getCache().getQueryService().newQuery("select * from " + region.getFullPath()).execute();
for(Object result : queryResults.asList()) {
assertEquals(TestSerializable.class, result.getClass());
}
} catch (Exception e) {
fail("got exception from query", e);
}
//TODO Transactions don't work
// CacheTransactionManager txManager = getCache().getCacheTransactionManager();
// //Test puts and get in a transaction
// txManager.begin();
// region.put("C", new TestSerializable());
// assertEquals(TestSerializable.class, region.get("C").getClass());
// txManager.commit();
//
// txManager.begin();
// assertEquals(TestSerializable.class, region.get("C").getClass());
// txManager.commit();
//
//
// //Test cache load in a transaction
// txManager.begin();
// assertEquals(TestSerializable.class, region.get("D").getClass());
// txManager.commit();
//
// txManager.begin();
// assertEquals(TestSerializable.class, region.get("D").getClass());
// txManager.commit();
}
private void checkValues(Region<Object, Object> region) {
assertEquals(TestSerializable.class, region.get("A").getClass());
assertEquals(TestSerializable.class, region.get("B").getClass());
//TODO Transactions don't work
// assertEquals(TestSerializable.class, region.get("C").getClass());
// assertEquals(TestSerializable.class, region.get("D").getClass());
}
private CacheServer createCacheServer(Cache cache) {
CacheServer server = cache.addCacheServer();
server.setPort(AvailablePortHelper.getRandomAvailableTCPPort());
try {
server.start();
} catch (IOException e) {
fail("got exception", e);
}
return server;
}
private void createClient(final int port0) {
ClientCacheFactory cf = new ClientCacheFactory();
cf.addPoolServer("localhost", port0);
cf.setPoolSubscriptionEnabled(true);
ClientCache cache = getClientCache(cf);
Region replicate = cache.createClientRegionFactory(ClientRegionShortcut.CACHING_PROXY).create("replicate");
Region pr = cache.createClientRegionFactory(ClientRegionShortcut.CACHING_PROXY).create("pr");
cache.createClientRegionFactory(ClientRegionShortcut.CACHING_PROXY).create("overflow_replicate");
cache.createClientRegionFactory(ClientRegionShortcut.CACHING_PROXY).create("overflow_pr");
//Register interest in a key
replicate.registerInterest("A", InterestResultPolicy.KEYS_VALUES);
pr.registerInterest("A", InterestResultPolicy.KEYS_VALUES);
}
public static class TestCacheLoader implements CacheLoader {
public void close() {
// TODO Auto-generated method stub
}
public Object load(LoaderHelper helper)
throws CacheLoaderException {
return new TestSerializable();
}
}
/** Test PDX object. This object will fail to be
* deserialized in the target VM.
*/
public static class TestSerializable implements PdxSerializable {
private static boolean throwExceptionOnDeserialization =false;
public void toData(PdxWriter writer) {
// TODO Auto-generated method stub
}
public void fromData(PdxReader reader) {
if(throwExceptionOnDeserialization) {
throw new SerializationException("Deserialization should not be happening in this VM");
}
}
}
}