/*
* 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;
import static org.junit.Assert.*;
import java.util.Properties;
import org.apache.geode.test.junit.categories.ClientServerTest;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.apache.geode.cache.AttributesFactory;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.CacheFactory;
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.server.CacheServer;
import org.apache.geode.distributed.DistributedSystem;
import org.apache.geode.internal.AvailablePort;
import org.apache.geode.internal.cache.tier.sockets.DeltaEOFException;
import org.apache.geode.internal.cache.tier.sockets.FaultyDelta;
import org.apache.geode.test.dunit.Host;
import org.apache.geode.test.dunit.Invoke;
import org.apache.geode.test.dunit.SerializableRunnable;
import org.apache.geode.test.dunit.VM;
import org.apache.geode.test.dunit.internal.JUnit4DistributedTestCase;
import org.apache.geode.test.junit.categories.DistributedTest;
/**
* Test delta propagation for faulty delta implementation
*
* @since GemFire 6.1
*/
@Category({DistributedTest.class, ClientServerTest.class})
public class Bug40396DUnitTest extends JUnit4DistributedTestCase {
private static Cache cache;
private static final String REGION_NAME = "Bug40396DUnitTest_region";
private static final String END_OF_FILE_EX = "eofe";
private static final String ARRAY_INDEX_OUT_BOUND_EX = "aiob";
private static int counter;
private VM server;
private VM server2;
private static final int PUT_COUNT = 10;
public Bug40396DUnitTest() {
super();
}
@Override
public final void postSetUp() throws Exception {
disconnectAllFromDS();
final Host host = Host.getHost(0);
server = host.getVM(0);
server2 = host.getVM(2);
}
/*
* create server cache
*/
public static Integer createServerCache() throws Exception {
new Bug40396DUnitTest().createCache(new Properties());
AttributesFactory factory = new AttributesFactory();
factory.setScope(Scope.DISTRIBUTED_ACK);
factory.setDataPolicy(DataPolicy.REPLICATE);
RegionAttributes attrs = factory.create();
Region region = cache.createRegion(REGION_NAME, attrs);
region.getAttributesMutator().setCloningEnabled(false);
CacheServer server = cache.addCacheServer();
addExceptions();
int port = AvailablePort.getRandomAvailablePort(AvailablePort.SOCKET);
server.setPort(port);
// ensures updates to be sent instead of invalidations
server.setNotifyBySubscription(true);
server.start();
return new Integer(server.getPort());
}
public static void addExceptions() throws Exception {
if (cache != null && !cache.isClosed()) {
cache.getLogger()
.info("<ExpectedException action=add>" + "java.io.EOFException" + "</ExpectedException>");
cache.getLogger().info("<ExpectedException action=add>"
+ "java.lang.ArrayIndexOutOfBoundsException" + "</ExpectedException>");
}
}
public static void removeExceptions() {
if (cache != null && !cache.isClosed()) {
cache.getLogger().info(
"<ExpectedException action=remove>" + "java.io.EOFException" + "</ExpectedException>");
cache.getLogger().info("<ExpectedException action=remove>"
+ "java.lang.ArrayIndexOutOfBoundsException" + "</ExpectedException>");
}
}
/*
* create cache with properties
*/
private void createCache(Properties props) throws Exception {
DistributedSystem ds = getSystem(props);
cache = CacheFactory.create(ds);
assertNotNull(cache);
}
public static void closeCache() {
if (cache != null && !cache.isClosed()) {
cache.close();
cache.getDistributedSystem().disconnect();
}
}
public static Exception putDelta(String regName, String type) {
Region reg = cache.getRegion(Region.SEPARATOR + regName);
try {
if (type.equals(END_OF_FILE_EX)) {
DeltaEOFException obj = new DeltaEOFException();
for (int i = 0; i < PUT_COUNT; i++) {
obj.setIntVal(i);
obj.setBigObj(new byte[] {(byte) (i + 3), (byte) (i + 3)});
reg.put("key", obj);
}
} else if (type.equals(ARRAY_INDEX_OUT_BOUND_EX)) {
FaultyDelta obj = new FaultyDelta();
for (int i = 0; i < PUT_COUNT; i++) {
obj.setIntVal(i);
obj.setBigObj(new byte[] {(byte) (i + 3), (byte) (i + 3)});
reg.put("key", obj);
}
}
} catch (Exception ex) {
return ex;
}
// this make tests fail
return new Exception();
}
/**
* This test does the following 1)send faulty implementation (Reading more in fromDelta then what
* sent by toDelta) of delta raises EOF exception<br>
*/
@Test
public void testForFaultyDeltaImplementationForEOFEX() {
boolean matched = false;
((Integer) server.invoke(() -> Bug40396DUnitTest.createServerCache())).intValue();
((Integer) server2.invoke(() -> Bug40396DUnitTest.createServerCache())).intValue();
Exception xp =
(Exception) server.invoke(() -> Bug40396DUnitTest.putDelta(REGION_NAME, END_OF_FILE_EX));
StackTraceElement[] st = xp.getCause().getStackTrace();
matched = getMatched(st);
assertTrue("pattern not found", matched);
}
private boolean getMatched(StackTraceElement[] ste) {
boolean mched = false;
for (int i = 0; i < ste.length; i++) {
if (mched)
break;
if (ste[i].toString().indexOf("fromDelta") != -1)
mched = true;
}
return mched;
}
/**
* This test does the following 1)send faulty implementation when reading incorrect order from
* toDelta, raises delta raises array index out of bound exception<br>
*/
@Test
public void testForFaultyDeltaImplementationForAIOBEX() {
boolean matched = false;
((Integer) server.invoke(() -> Bug40396DUnitTest.createServerCache())).intValue();
((Integer) server2.invoke(() -> Bug40396DUnitTest.createServerCache())).intValue();
Exception xp = (Exception) server
.invoke(() -> Bug40396DUnitTest.putDelta(REGION_NAME, ARRAY_INDEX_OUT_BOUND_EX));
StackTraceElement[] st = xp.getStackTrace();
matched = getMatched(st);
assertTrue("pattern not found", matched);
}
@Override
public final void preTearDown() throws Exception {
// then close the servers
server.invoke(() -> Bug40396DUnitTest.removeExceptions());
server.invoke(() -> Bug40396DUnitTest.closeCache());
server2.invoke(() -> Bug40396DUnitTest.closeCache());
cache = null;
Invoke.invokeInEveryVM(new SerializableRunnable() {
public void run() {
cache = null;
}
});
}
}