/*
* Copyright to the original author or authors.
*
* Licensed 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.rioproject.test.deploy;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.rioproject.cybernode.Cybernode;
import org.rioproject.deploy.ServiceBeanInstance;
import org.rioproject.exec.ExecDescriptor;
import org.rioproject.impl.exec.VirtualMachineHelper;
import org.rioproject.impl.jmx.JMXConnectionUtil;
import org.rioproject.impl.jmx.JMXUtil;
import org.rioproject.opstring.OperationalString;
import org.rioproject.opstring.OperationalStringManager;
import org.rioproject.opstring.ServiceElement;
import org.rioproject.test.RioTestRunner;
import org.rioproject.test.SetTestManager;
import org.rioproject.test.TestManager;
import org.rioproject.test.simple.Fork;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.management.MBeanServerConnection;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
/**
* Tests simple deploy scenario that forks a service
*/
@RunWith (RioTestRunner.class)
public class SimpleForkTest {
@SetTestManager
static TestManager testManager;
Cybernode cybernode;
static Logger logger = LoggerFactory.getLogger(RioTestRunner.class.getName());
@Before
public void setup() {
cybernode = testManager.waitForService(Cybernode.class);
}
@Test
public void testFork() throws Exception {
Assert.assertNotNull(testManager);
Assert.assertNotNull(cybernode);
OperationalStringManager mgr = testManager.getOperationalStringManager();
Assert.assertNotNull("Expected non-null OperationalStringManager", mgr);
OperationalString opstring = mgr.getOperationalString();
Assert.assertNotNull(opstring);
Assert.assertEquals(1, opstring.getServices().length);
ServiceElement elem = opstring.getServices()[0];
Assert.assertNotNull("Expected a non-null ExecDescriptor", elem.getExecDescriptor());
testManager.waitForDeployment(mgr);
String jvmVersion = System.getProperty("java.version");
if(jvmVersion.contains("1.5")) {
logger.info("The JMX Attach APIs require Java 6 or above. You are running Java "+jvmVersion);
} else {
RuntimeMXBean runtime = attach("T62___W_FL___SK_-1");
Assert.assertNotNull("Expected a RuntimeMXBean", runtime);
verifyJVMArgs(runtime, elem.getExecDescriptor());
}
ServiceBeanInstance[] instances = cybernode.getServiceBeanInstances(opstring.getServices()[0]);
Assert.assertEquals(1, instances.length);
Fork fork = (Fork)instances[0].getService();
Assert.assertTrue("Expected verify() to return true, check service log for details", fork.verify());
//logger.info("Wait for 5 minutes, make sure that only one service remains....");
//Thread.sleep(TimeUnit.MINUTES.toMillis(5));
//testManager.undeploy(opstring.getName());
/*testManager.stopCybernode(cybernode);
System.out.println("\nService Bean Exec JVMs\n============");
String listing = null;
long t0 = System.currentTimeMillis();
for(int i=0; i<180; i++) {
listing = list();
if(listing.length()==0 || (System.currentTimeMillis()-t0)>15000)
break;
if(i % 5 == 0)
System.out.println(listing);
Thread.sleep(500);
}
System.out.println("Time to exit: "+(System.currentTimeMillis()-t0));
Assert.assertTrue(listing.length()==0);*/
}
private void verifyJVMArgs(RuntimeMXBean runtime, ExecDescriptor exDesc) {
String[] declaredArgs = toArray(exDesc.getInputArgs());
List<String> jvmArgs = runtime.getInputArguments();
logger.info("Runtime JVM Args ["+flatten(jvmArgs)+"]");
for(String arg : declaredArgs) {
boolean matched = false;
for(String jvmArg : jvmArgs) {
if(arg.equals(jvmArg)) {
matched = true;
break;
}
}
Assert.assertTrue("Expected to match ["+arg+"]", matched);
}
}
private RuntimeMXBean attach(final String matchName) throws Exception {
String[] managedVMs = VirtualMachineHelper.listManagedVMs();
for(String managedVM : managedVMs) {
if(managedVM.contains("start-service-bean-exec")) {
String pid = managedVM.substring(0, managedVM.indexOf(" "));
long forkedPID = Long.valueOf(pid);
if(forkedPID!=-1) {
logger.info("PID of exec'd process obtained: "+forkedPID);
try {
MBeanServerConnection mbsc = JMXConnectionUtil.attach(Long.toString(forkedPID));
logger.info("JMX Attach succeeded to exec'd JVM with pid: "+forkedPID);
RuntimeMXBean runtime = JMXUtil.getPlatformMXBeanProxy(mbsc,
ManagementFactory.RUNTIME_MXBEAN_NAME,
RuntimeMXBean.class);
for(Map.Entry<String,String> entry : runtime.getSystemProperties().entrySet()) {
if(entry.getKey().equals("org.rioproject.service") && entry.getValue().equals(matchName)) {
return runtime;
}
}
} catch(Exception e) {
logger.warn("Could not attach to the exec'd JVM with pid: "+forkedPID+", continue service execution",
e);
}
} else {
logger.warn("Could not obtain actual pid of exec'd process, " +
"process cpu and java memory utilization are not available [{}]", managedVM);
}
}
}
return null;
}
private String[] toArray(String s) {
StringTokenizer tok = new StringTokenizer(s);
String[] array = new String[tok.countTokens()];
int i=0;
while(tok.hasMoreTokens()) {
array[i] = tok.nextToken();
i++;
}
return(array);
}
private String flatten(List<String> l) {
StringBuilder sb = new StringBuilder();
for (String s : l) {
sb.append(s).append(" ");
}
return sb.toString();
}
}