/*
* 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.partitioned;
import static org.apache.geode.distributed.ConfigurationProperties.*;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.apache.geode.cache.CacheFactory;
import org.apache.geode.cache.PartitionAttributesFactory;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionFactory;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.cache.client.ClientCacheFactory;
import org.apache.geode.cache.client.ClientRegionFactory;
import org.apache.geode.cache.client.ClientRegionShortcut;
import org.apache.geode.internal.AvailablePort;
import org.apache.geode.internal.OSProcess;
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.internal.cache.RegionEntry;
import org.apache.geode.internal.i18n.LocalizedStrings;
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.VM;
import org.apache.geode.test.dunit.internal.JUnit4DistributedTestCase;
import org.apache.geode.test.junit.categories.DistributedTest;
/**
* TODO This doesn't really test the optimised RI behaviour but only that RI works. But there must
* be other tests doing the same.
*/
@Category(DistributedTest.class)
@SuppressWarnings("serial")
public class Bug43684DUnitTest extends JUnit4DistributedTestCase {
private static final String REGION_NAME = Bug43684DUnitTest.class.getSimpleName();
private static GemFireCacheImpl cache;
private Host host;
private static VM server1;
private static VM server2;
private static VM server3;
private static VM client1;
private static int numBuckets = 11;
@Override
public final void postSetUp() throws Exception {
host = Host.getHost(0);
server1 = host.getVM(0);
server2 = host.getVM(1);
server3 = host.getVM(2);
client1 = host.getVM(3);
IgnoredException.addIgnoredException("Connection refused: connect");
}
@Override
public final void preTearDown() throws Exception {
closeCache();
client1.invoke(() -> Bug43684DUnitTest.closeCache());
server1.invoke(() -> Bug43684DUnitTest.closeCache());
server2.invoke(() -> Bug43684DUnitTest.closeCache());
server3.invoke(() -> Bug43684DUnitTest.closeCache());
}
public static void closeCache() {
if (cache != null && !cache.isClosed()) {
cache.close();
}
disconnectFromDS();
}
@Test
public void testRIWithSingleKeyOnRR() throws Exception {
doRegisterInterest("KEY_1", null, numBuckets, true, false);
}
@Test
public void testRIWithAllKeysOnRR() throws Exception {
doRegisterInterest(null, null, numBuckets, true, false);
}
@Test
public void testRIWithKeyListOnRR() throws Exception {
ArrayList<String> riKeys = new ArrayList<String>();
riKeys.add("KEY_0");
riKeys.add("KEY_1");
riKeys.add("KEY_2");
riKeys.add("KEY_5");
riKeys.add("KEY_6");
riKeys.add("KEY_7");
riKeys.add("KEY_9");
doRegisterInterest(riKeys, null, numBuckets, true, false);
}
@Test
public void testRIWithRegularExpressionOnRR() throws Exception {
doRegisterInterest(null, "^[X][_].*", numBuckets, true, false);
}
@Test
public void testRIWithSingleKeyOnPR() throws Exception {
doRegisterInterest("KEY_1", null);
}
@Test
public void testRIWithAllKeysOnPR() throws Exception {
doRegisterInterest(null, null);
}
@Test
public void testRIWithKeyListOnPR() throws Exception {
ArrayList<String> riKeys = new ArrayList<String>();
riKeys.add("KEY_0");
riKeys.add("KEY_1");
riKeys.add("KEY_2");
riKeys.add("KEY_5");
riKeys.add("KEY_6");
riKeys.add("KEY_7");
riKeys.add("KEY_9");
doRegisterInterest(riKeys, null);
}
@Test
public void testRIWithRegularExpressionOnPR() throws Exception {
doRegisterInterest(null, "^[X][_].*");
}
@Test
public void testRIWithMoreEntriesOnPR() throws Exception {
doRegisterInterest(null, null, 5147, false, false);
}
@Test
public void testRIWithSingleKeyOnEmptyPrimaryOnPR() throws Exception {
doRegisterInterest("KEY_1", null, numBuckets, false, true);
}
@Test
public void testRIWithAllKeysOnEmptyPrimaryOnPR() throws Exception {
doRegisterInterest(null, null, numBuckets, false, true);
}
@Test
public void testRIWithKeyListOnEmptyPrimaryOnPR() throws Exception {
ArrayList<String> riKeys = new ArrayList<String>();
riKeys.add("KEY_0");
riKeys.add("KEY_1");
riKeys.add("KEY_2");
riKeys.add("KEY_5");
riKeys.add("KEY_6");
riKeys.add("KEY_7");
riKeys.add("KEY_9");
doRegisterInterest(riKeys, null, numBuckets, false, true);
}
@Test
public void testRIWithRegularExpressionOnEmptyPrimaryOnPR() throws Exception {
doRegisterInterest(null, "^[X][_].*", numBuckets, false, true);
}
@Test
public void testNativeClientIssueOnPR() throws Exception {
ArrayList<String> riKeys = new ArrayList<String>();
riKeys.add("OPKEY_0");
riKeys.add("OPKEY_1");
riKeys.add("OPKEY_2");
riKeys.add("OPKEY_3");
riKeys.add("OPKEY_4");
riKeys.add("OPKEY_5");
riKeys.add("OPKEY_6");
riKeys.add("OPKEY_7");
riKeys.add("OPKEY_8");
riKeys.add("OPKEY_9");
riKeys.add("OPKEY_10");
riKeys.add("OPKEY_11");
riKeys.add("OPKEY_12");
riKeys.add("OPKEY_13");
doRegisterInterest2(riKeys, false, false);
}
private void doRegisterInterest(Object keys, String regEx) throws Exception {
doRegisterInterest(keys, regEx, numBuckets, false, false);
}
@SuppressWarnings("rawtypes")
private void doRegisterInterest(Object keys, String regEx, Integer numOfPuts,
Boolean isReplicated, Boolean isPrimaryEmpty) throws Exception {
int port1 = (Integer) server1
.invoke(() -> Bug43684DUnitTest.createServerCache(isReplicated, isPrimaryEmpty));
server2.invoke(() -> Bug43684DUnitTest.createServerCache(isReplicated, false));
server3.invoke(() -> Bug43684DUnitTest.createServerCache(isReplicated, false));
int regexNum = 20;
server1.invoke(() -> Bug43684DUnitTest.doPuts(numOfPuts, regEx, regexNum));
client1.invoke(() -> Bug43684DUnitTest.createClientCache(host, port1));
client1.invoke(() -> Bug43684DUnitTest.registerInterest(keys, regEx));
server1.invoke(() -> Bug43684DUnitTest.closeCache());
int size = keys != null ? (keys instanceof List ? ((List) keys).size() : 1)
: regEx == null ? numOfPuts : regexNum;
client1.invoke(() -> Bug43684DUnitTest.verifyResponse(size));
}
@SuppressWarnings("rawtypes")
private void doRegisterInterest2(Object keys, Boolean isReplicated, Boolean isPrimaryEmpty)
throws Exception {
int port1 = (Integer) server1
.invoke(() -> Bug43684DUnitTest.createServerCache(isReplicated, isPrimaryEmpty));
server2.invoke(() -> Bug43684DUnitTest.createServerCache(isReplicated, false));
server3.invoke(() -> Bug43684DUnitTest.createServerCache(isReplicated, false));
client1.invoke(() -> Bug43684DUnitTest.createClientCache(host, port1));
createClientCache(host, port1);
doOps();
client1.invoke(() -> Bug43684DUnitTest.registerInterest(keys, null));
client1.invoke(() -> Bug43684DUnitTest.verifyResponse2());
}
public static Integer createServerCache() throws Exception {
return createServerCache(false, false);
}
@SuppressWarnings("rawtypes")
public static Integer createServerCache(Boolean isReplicated, Boolean isPrimaryEmpty)
throws Exception {
disconnectFromDS();
Properties props = new Properties();
props.setProperty(LOCATORS, "localhost[" + DistributedTestUtils.getDUnitLocatorPort() + "]");
props.setProperty(STATISTIC_ARCHIVE_FILE, "server_" + OSProcess.getId() + ".gfs");
props.setProperty(STATISTIC_SAMPLING_ENABLED, "true");
CacheFactory cf = new CacheFactory(props);
cache = (GemFireCacheImpl) cf.create();
RegionFactory rf;
if (isReplicated) {
RegionShortcut rs =
isPrimaryEmpty ? RegionShortcut.REPLICATE_PROXY : RegionShortcut.REPLICATE;
rf = cache.createRegionFactory(rs);
} else {
RegionShortcut rs =
isPrimaryEmpty ? RegionShortcut.PARTITION_PROXY : RegionShortcut.PARTITION;
rf = cache.createRegionFactory(rs);
rf.setPartitionAttributes(
new PartitionAttributesFactory().setTotalNumBuckets(numBuckets).create());
}
rf.create(REGION_NAME);
CacheServerImpl server = (CacheServerImpl) cache.addCacheServer();
server.setPort(AvailablePort.getRandomAvailablePort(AvailablePort.SOCKET));
server.start();
return server.getPort();
}
@SuppressWarnings({"unchecked", "rawtypes"})
public static void createClientCache(Host host, Integer port) {
disconnectFromDS();
Properties props = new Properties();
props.setProperty(STATISTIC_ARCHIVE_FILE, "client_" + OSProcess.getId() + ".gfs");
props.setProperty(STATISTIC_SAMPLING_ENABLED, "true");
ClientCacheFactory ccf = new ClientCacheFactory(props);
ccf.addPoolServer(host.getHostName(), port).setPoolSubscriptionEnabled(true);
cache = (GemFireCacheImpl) ccf.create();
ClientRegionFactory crf = cache.createClientRegionFactory(ClientRegionShortcut.CACHING_PROXY);
crf.create(REGION_NAME);
}
@SuppressWarnings({"unchecked", "rawtypes"})
public static void registerInterest(Object keys, String regEx) {
Region region = cache.getRegion(REGION_NAME);
if (keys == null && regEx == null) {
region.registerInterest("ALL_KEYS");
} else if (keys != null) {
region.registerInterest(keys);
region.registerInterest("UNKNOWN_KEY");
} else if (regEx != null) {
region.registerInterestRegex(regEx);
}
}
@SuppressWarnings({"rawtypes", "unchecked"})
public static void doPuts(Integer num, String regex, int regexNum) throws Exception {
Region r = cache.getRegion(REGION_NAME);
for (int i = 0; i < num; i++) {
r.create("KEY_" + i, "VALUE__" + i);
}
if (regex != null) {
for (int i = 0; i < regexNum; i++) {
r.create("X_KEY_" + i, "X_VALUE__" + i);
}
}
}
@SuppressWarnings({"rawtypes", "unchecked"})
public static void doOps() throws Exception {
Region r = cache.getRegion(REGION_NAME);
for (int i = 0; i < 14; i++) {
r.create("OPKEY_" + i, "OPVALUE__" + i);
}
for (int i = 7; i < 14; i++) {
r.destroy("OPKEY_" + i);
}
}
public static void verifyResponse2() throws Exception {
LocalRegion r = (LocalRegion) cache.getRegion(REGION_NAME);
for (int i = 0; i < 7; i++) {
assertTrue(r.containsKey("OPKEY_" + i));
}
for (int i = 7; i < 14; i++) {
assertFalse(r.containsKey("OPKEY_" + i));
assertTrue(r.containsTombstone("OPKEY_" + i));
}
}
public static void verifyResponse(Integer size) throws Exception {
LocalRegion r = (LocalRegion) cache.getRegion(REGION_NAME);
assertEquals(size.intValue(), r.size());
}
public static void getLocally() throws Exception {
LocalRegion r = (LocalRegion) cache.getRegion(REGION_NAME);
for (int i = 0; i < numBuckets; i++) {
RegionEntry e = r.getRegionEntry("KEY_" + i);
cache.getLoggerI18n().info(LocalizedStrings.DEBUG, e._getValue());
}
}
}