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() {
      @Override
      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() {
      @Override
      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() {

      @Override
      public Object call() throws Exception {
        createClient(port0);
        return null;
      }
    });

    // create a client connected to the datastore
    vm3.invoke(new SerializableCallable() {

      @Override
      public Object call() throws Exception {
        createClient(port1);
        return null;
      }
    });


    // Disallow deserialization
    disallowDeserializationVM.invoke(new SerializableRunnable() {

      @Override
      public void run() {
        TestSerializable.throwExceptionOnDeserialization = true;
      }
    });


    // perform operations in the target VM
    try {

      operationVM.invoke(new SerializableRunnable() {

        @Override
        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() {

        @Override
        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() {
      @Override
      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);
  }
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.
geode-core/src/distributedTest/java/org/apache/geode/pdx/PdxDeserializationDUnitTest.java