/*
* 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.distributed.internal;
import static org.apache.geode.distributed.ConfigurationProperties.*;
import static org.junit.Assert.*;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Set;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.apache.geode.SystemFailure;
import org.apache.geode.cache.AttributesFactory;
import org.apache.geode.cache.CacheException;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionAttributes;
import org.apache.geode.cache.Scope;
import org.apache.geode.distributed.DistributedLockService;
import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
import org.apache.geode.internal.Config;
import org.apache.geode.internal.admin.Alert;
import org.apache.geode.internal.admin.AlertListener;
import org.apache.geode.internal.admin.ApplicationVM;
import org.apache.geode.internal.admin.DLockInfo;
import org.apache.geode.internal.admin.EntryValueNode;
import org.apache.geode.internal.admin.GemFireVM;
import org.apache.geode.internal.admin.GfManagerAgent;
import org.apache.geode.internal.admin.GfManagerAgentConfig;
import org.apache.geode.internal.admin.GfManagerAgentFactory;
import org.apache.geode.internal.admin.StatResource;
import org.apache.geode.internal.admin.remote.RemoteTransportConfig;
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.SerializableRunnable;
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.junit.categories.DistributedTest;
import org.apache.geode.test.junit.categories.FlakyTest;
/**
* This class tests the functionality of the {@linkplain org.apache.geode.internal.admin internal
* admin} API.
*/
@Category(DistributedTest.class)
public class ConsoleDistributionManagerDUnitTest extends JUnit4CacheTestCase
implements AlertListener {
protected GfManagerAgent agent = null;
private static boolean firstTime = true;
public void alert(Alert alert) {
LogWriterUtils.getLogWriter().info("DEBUG: alert=" + alert);
}
@Override
public final void postSetUp() throws Exception {
boolean finishedSetup = false;
IgnoredException.addIgnoredException("Error occurred while reading system log");
try {
if (firstTime) {
disconnectFromDS(); // make sure there's no ldm lying around
try {
Thread.sleep(5 * 1000);
} catch (InterruptedException ie) {
fail("interrupted");
}
firstTime = false;
}
DistributionManager.isDedicatedAdminVM = true;
populateCache();
RemoteTransportConfig transport = null;
{
boolean created = !isConnectedToDS();
InternalDistributedSystem ds = getSystem();
transport =
new RemoteTransportConfig(ds.getConfig(), DistributionManager.ADMIN_ONLY_DM_TYPE);
if (created) {
disconnectFromDS();
}
}
// create a GfManagerAgent in the master vm.
this.agent = GfManagerAgentFactory.getManagerAgent(new GfManagerAgentConfig(null, transport,
LogWriterUtils.getLogWriter(), Alert.SEVERE, this, null));
if (!agent.isConnected()) {
WaitCriterion ev = new WaitCriterion() {
public boolean done() {
return agent.isConnected();
}
public String description() {
return null;
}
};
Wait.waitForCriterion(ev, 60 * 1000, 200, true);
}
finishedSetup = true;
} finally {
if (!finishedSetup) {
try {
this.agent.disconnect();
} catch (VirtualMachineError e) {
SystemFailure.initiateFailure(e);
throw e;
} catch (Throwable ignore) {
}
try {
super.preTearDown();
} catch (VirtualMachineError e) {
SystemFailure.initiateFailure(e);
throw e;
} catch (Throwable ignore) {
}
try {
disconnectFromDS();
} catch (VirtualMachineError e) {
SystemFailure.initiateFailure(e);
throw e;
} catch (Throwable ignore) {
}
DistributionManager.isDedicatedAdminVM = false;
}
}
}
@Override
public final void preTearDownCacheTestCase() throws Exception {
this.agent.disconnect();
}
@Override
public final void postTearDownCacheTestCase() throws Exception {
try {
disconnectFromDS(); // make sure there's no ldm lying around
} finally {
DistributionManager.isDedicatedAdminVM = false;
}
}
@Test
public void testGetDistributionVMType() {
DM dm = this.agent.getDM();
InternalDistributedMember ipaddr = dm.getId();
assertEquals(DistributionManager.ADMIN_ONLY_DM_TYPE, ipaddr.getVmKind());
}
@Test
public void testAgent() {
assertEquals("expected empty peer array", 0, agent.listPeers().length);
int systemCount = 0;
for (int h = 0; h < Host.getHostCount(); h++) {
Host host = Host.getHost(h);
systemCount += host.getSystemCount();
}
// note that JoinLeaveListener is not tested since it would require
// this test to start and stop systems.
agent.disconnect();
assertTrue("agent should have been disconnected", !agent.isConnected());
}
@Category(FlakyTest.class) // GEODE-1688
@Test
public void testApplications() throws Exception {
{
WaitCriterion ev = new WaitCriterion() {
public boolean done() {
ApplicationVM[] apps = agent.listApplications();
return apps.length >= 4;
}
public String description() {
return null;
}
};
Wait.waitForCriterion(ev, 60 * 1000, 200, true);
}
// final Serializable controllerId = getSystem().getDistributionManager().getId(); //can't do
// this...
ApplicationVM[] apps = agent.listApplications();
for (int i = 0; i < apps.length; i++) {
// if (apps[i].getId().equals(controllerId)) {
// continue; // skip this one; its the locator vm
// }
InetAddress host = apps[i].getHost();
String appHostName = host.getHostName();
try {
InetAddress appHost = InetAddress.getByName(appHostName);
assertEquals(appHost, host);
} catch (UnknownHostException ex) {
fail("Lookup of address for host " + appHostName + " failed because " + ex);
}
StatResource[] stats = apps[i].getStats(null);
assertTrue(stats.length > 0);
Config conf = apps[i].getConfig();
String[] attNames = conf.getAttributeNames();
boolean foundIt = false;
for (int j = 0; j < attNames.length; j++) {
if (attNames[j].equals(STATISTIC_SAMPLING_ENABLED)) {
foundIt = true;
assertEquals(conf.getAttribute(attNames[j]), "true");
break;
}
}
assertTrue(foundIt);
String[] logs = apps[i].getSystemLogs();
assertTrue(logs.length > 0);
// assertTrue(logs[0].length() > 0);
{
VM vm = findVMForAdminObject(apps[i]);
// getLogWriter().info("DEBUG: found VM " + vm +
// " which corresponds to ApplicationVM "
// + apps[i] + " in testApplications");
assertNotNull(vm);
String lockName = "cdm_testlock" + i;
assertTrue(acquireDistLock(vm, lockName));
DLockInfo[] locks = apps[i].getDistributedLockInfo();
assertTrue(locks.length > 0);
boolean foundLock = false;
for (int j = 0; j < locks.length; j++) {
if (locks[j].getLockName().equals(lockName)) {
foundLock = true;
assertTrue(locks[j].isAcquired());
}
}
assertTrue(foundLock);
}
Region[] roots = apps[i].getRootRegions();
if (roots.length == 0) {
LogWriterUtils.getLogWriter().info(
"DEBUG: testApplications: apps[" + i + "]=" + apps[i] + " did not have a root region");
} else {
Region root = roots[0];
assertNotNull(root);
assertEquals("root", root.getName());
assertEquals("/root", root.getFullPath());
RegionAttributes attributes = root.getAttributes();
assertNotNull(attributes);
if (attributes.getStatisticsEnabled()) {
assertNotNull(root.getStatistics());
}
final Set subregions = root.subregions(false);
assertEquals(3, subregions.size());
assertEquals(2, root.keys().size());
Region.Entry entry = root.getEntry("cacheObj1");
assertNotNull(entry);
if (attributes.getStatisticsEnabled()) {
assertNotNull(entry.getStatistics());
}
assertTrue(entry.getValue().equals("null"));
/// test lightweight inspection;
entry = root.getEntry("cacheObj2");
assertNotNull(entry);
Object val = entry.getValue();
assertTrue(val instanceof String);
assertTrue(((String) val).indexOf("java.lang.StringBuffer") != -1);
/// test physical inspection
// getLogWriter().info("DEBUG: Starting test of physical cache value inspection");
apps[i].setCacheInspectionMode(GemFireVM.PHYSICAL_CACHE_VALUE);
entry = root.getEntry("cacheObj2");
assertNotNull(entry);
val = entry.getValue();
assertTrue(val instanceof EntryValueNode);
EntryValueNode node = (EntryValueNode) val;
String type = node.getType();
assertTrue(type.indexOf("java.lang.StringBuffer") != -1);
assertTrue(!node.isPrimitiveOrString());
EntryValueNode[] fields = node.getChildren();
assertNotNull(fields);
LogWriterUtils.getLogWriter().warning(
"The tests use StringBuffers for values which might be implmented differently in jdk 1.5");
// assertTrue(fields.length > 0);
/// test destruction in the last valid app
int lastIdx = apps.length - 1;
/*
* if (i == lastIdx || (i == lastIdx-1 && apps[lastIdx].getId().equals(controllerId))) {
*/
if (i == lastIdx) {
// getLogWriter().info("DEBUG: starting region destroy from admin apis");
final int expectedSize = subregions.size() - 1;
final Region r = (Region) subregions.iterator().next();
final Region rr = root;
r.destroyRegion();
WaitCriterion ev = new WaitCriterion() {
public boolean done() {
Set s = rr.subregions(false);
return s.size() == expectedSize;
}
public String description() {
return "Waited 20 seconds for region " + r.getFullPath() + "to be destroyed.";
}
};
Wait.waitForCriterion(ev, 20 * 1000, 200, true);
}
}
}
}
private void populateCache() {
AttributesFactory fact = new AttributesFactory();
fact.setScope(Scope.DISTRIBUTED_NO_ACK);
final RegionAttributes rAttr = fact.create();
final SerializableRunnable populator = new SerializableRunnable() {
public void run() {
try {
createRegion("cdm-testSubRegion1", rAttr);
createRegion("cdm-testSubRegion2", rAttr);
createRegion("cdm-testSubRegion3", rAttr);
remoteCreateEntry("", "cacheObj1", null);
StringBuffer val = new StringBuffer("userDefValue1");
remoteCreateEntry("", "cacheObj2", val);
} catch (CacheException ce) {
fail("Exception while populating cache:\n" + ce);
}
}
};
for (int h = 0; h < Host.getHostCount(); h++) {
Host host = Host.getHost(h);
for (int v = 0; v < host.getVMCount(); v++) {
VM vm = host.getVM(v);
vm.invoke(populator);
}
}
}
/**
* Puts (or creates) a value in a region named <code>regionName</code> named
* <code>entryName</code>.
*/
protected void remoteCreateEntry(String regionName, String entryName, Object value)
throws CacheException {
Region root = getRootRegion();
Region region = root.getSubregion(regionName);
region.create(entryName, value);
LogWriterUtils.getLogWriter().info("Put value " + value + " in entry " + entryName
+ " in region '" + region.getFullPath() + "'");
}
// private long getConId(VM vm) {
// return vm.invoke(() -> this.remoteGetConId());
// }
/**
* Accessed via reflection. DO NOT REMOVE
*
* @return
*/
protected static long remoteGetConId() {
return InternalDistributedSystem.getAnyInstance().getId();
}
private boolean acquireDistLock(VM vm, String lockName) {
return vm.invoke(() -> remoteAcquireDistLock(lockName));
}
/**
* Accessed via reflection. DO NOT REMOVE
*
* @param lockName
* @return
*/
protected static boolean remoteAcquireDistLock(String lockName) {
String serviceName = "cdmtest_service";
DistributedLockService service = DistributedLockService.getServiceNamed(serviceName);
if (service == null) {
service =
DistributedLockService.create(serviceName, InternalDistributedSystem.getAnyInstance());
}
assertNotNull(service);
try {
return service.lock(lockName, 1000, 3000);
} catch (Exception e) {
throw new RuntimeException("DEBUG: remoteAcquireDistLock", e);
// return false;
}
}
private VM findVMForAdminObject(GemFireVM adminObj) {
for (int i = 0; i < Host.getHostCount(); i++) {
Host host = Host.getHost(i);
for (int j = 0; j < host.getVMCount(); j++) {
VM vm = host.getVM(j);
InternalDistributedMember id = getJavaGroupsIdForVM(vm);
if (adminObj.getId().equals(id)) {
return vm;
}
}
}
return null;
}
private InternalDistributedMember getJavaGroupsIdForVM(VM vm) {
return (InternalDistributedMember) vm.invoke(() -> remoteGetJavaGroupsIdForVM());
}
/**
* INVOKED VIA REFLECTION
*
* @return
*/
protected static InternalDistributedMember remoteGetJavaGroupsIdForVM() {
InternalDistributedSystem sys = InternalDistributedSystem.getAnyInstance();
return sys.getDistributionManager().getDistributionManagerId();
}
}