http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/dfba327e/gemfire-core/src/test/java/dunit/standalone/ProcessManager.java ---------------------------------------------------------------------- diff --git a/gemfire-core/src/test/java/dunit/standalone/ProcessManager.java b/gemfire-core/src/test/java/dunit/standalone/ProcessManager.java new file mode 100644 index 0000000..7fc762f --- /dev/null +++ b/gemfire-core/src/test/java/dunit/standalone/ProcessManager.java @@ -0,0 +1,261 @@ +/* + * 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 dunit.standalone; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.rmi.AccessException; +import java.rmi.NotBoundException; +import java.rmi.RemoteException; +import java.rmi.registry.Registry; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.io.FileUtils; + +import com.gemstone.gemfire.internal.FileUtil; +import com.gemstone.gemfire.internal.logging.LogService; + +import dunit.RemoteDUnitVMIF; + +/** + * @author dsmith + * + */ +public class ProcessManager { + private int namingPort; + private Map<Integer, ProcessHolder> processes = new HashMap<Integer, ProcessHolder>(); + private File log4jConfig; + private int pendingVMs; + private Registry registry; + private int debugPort = Integer.getInteger("dunit.debug.basePort", 0); + private int suspendVM = Integer.getInteger("dunit.debug.suspendVM", -100); + + public ProcessManager(int namingPort, Registry registry) { + this.namingPort = namingPort; + this.registry = registry; + } + + public void launchVMs() throws IOException, NotBoundException { + log4jConfig = LogService.findLog4jConfigInCurrentDir(); + } + + public synchronized void launchVM(int vmNum) throws IOException { + if(processes.containsKey(vmNum)) { + throw new IllegalStateException("VM " + vmNum + " is already running."); + } + + String[] cmd = buildJavaCommand(vmNum, namingPort); + System.out.println("Executing " + Arrays.asList(cmd)); + File workingDir = getVMDir(vmNum); + try { + FileUtil.delete(workingDir); + } catch(IOException e) { + //This delete is occasionally failing on some platforms, maybe due to a lingering + //process. Allow the process to be launched anyway. + System.err.println("Unable to delete " + workingDir + ". Currently contains " + + Arrays.asList(workingDir.list())); + } + workingDir.mkdirs(); + if (log4jConfig != null) { + FileUtils.copyFileToDirectory(log4jConfig, workingDir); + } + + //TODO - delete directory contents, preferably with commons io FileUtils + Process process = Runtime.getRuntime().exec(cmd, null, workingDir); + pendingVMs++; + ProcessHolder holder = new ProcessHolder(process); + processes.put(vmNum, holder); + linkStreams(vmNum, holder, process.getErrorStream(), System.err); + linkStreams(vmNum, holder, process.getInputStream(), System.out); + } + + public static File getVMDir(int vmNum) { + return new File(DUnitLauncher.DUNIT_DIR, "vm" + vmNum); + } + + public synchronized void killVMs() { + for(ProcessHolder process : processes.values()) { + if(process != null) { + process.kill(); + } + } + } + + public synchronized boolean hasLiveVMs() { + for(ProcessHolder process : processes.values()) { + if(process != null && process.isAlive()) { + return true; + } + } + return false; + } + + public synchronized void bounce(int vmNum) { + if(!processes.containsKey(vmNum)) { + throw new IllegalStateException("No such process " + vmNum); + } + try { + ProcessHolder holder = processes.remove(vmNum); + holder.kill(); + holder.getProcess().waitFor(); + launchVM(vmNum); + } catch (InterruptedException | IOException e) { + throw new RuntimeException("Unable to restart VM " + vmNum, e); + } + } + + private void linkStreams(final int vmNum, final ProcessHolder holder, final InputStream in, final PrintStream out) { + Thread ioTransport = new Thread() { + public void run() { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + String vmName = (vmNum==-2)? "[locator]" : "[vm_"+vmNum+"]"; + try { + String line = reader.readLine(); + while(line != null) { + if (line.length() == 0) { + out.println(); + } else { + out.print(vmName); + out.println(line); + } + line = reader.readLine(); + } + } catch(Exception e) { + if(!holder.isKilled()) { + out.println("Error transporting IO from child process"); + e.printStackTrace(out); + } + } + } + }; + + ioTransport.setDaemon(true); + ioTransport.start(); + } + + private String[] buildJavaCommand(int vmNum, int namingPort) { + String cmd = System.getProperty( "java.home" ) + File.separator + "bin" + File.separator + "java"; + String classPath = System.getProperty("java.class.path"); + //String tmpDir = System.getProperty("java.io.tmpdir"); + String agent = getAgentString(); + + String jdkDebug = ""; + if (debugPort > 0) { + jdkDebug += ",address=" + debugPort; + debugPort++; + } + + String jdkSuspend = vmNum == suspendVM ? "y" : "n"; + + return new String[] { + cmd, "-classpath", classPath, + "-D" + DUnitLauncher.RMI_PORT_PARAM + "=" + namingPort, + "-D" + DUnitLauncher.VM_NUM_PARAM + "=" + vmNum, + "-D" + DUnitLauncher.WORKSPACE_DIR_PARAM + "=" + new File(".").getAbsolutePath(), + "-DlogLevel=" + DUnitLauncher.LOG_LEVEL, + "-Djava.library.path=" + System.getProperty("java.library.path"), + "-Xrunjdwp:transport=dt_socket,server=y,suspend=" + jdkSuspend + jdkDebug, + "-XX:+HeapDumpOnOutOfMemoryError", + "-Xmx512m", + "-Dgemfire.DEFAULT_MAX_OPLOG_SIZE=10", + "-Dgemfire.disallowMcastDefaults=true", + "-ea", + agent, + "dunit.standalone.ChildVM" + }; + } + + /** + * Get the java agent passed to this process and pass it to the child VMs. + * This was added to support jacoco code coverage reports + */ + private String getAgentString() { + RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean(); + if (runtimeBean != null) { + for(String arg: runtimeBean.getInputArguments()) { + if(arg.contains("-javaagent:")) { + //HACK for gradle bug GRADLE-2859. Jacoco is passing a relative path + //That won't work when we pass this to dunit VMs in a different + //directory + arg = arg.replace("-javaagent:..", "-javaagent:" + System.getProperty("user.dir") + File.separator + ".."); + arg = arg.replace("destfile=..", "destfile=" + System.getProperty("user.dir") + File.separator + ".."); + return arg; + } + } + } + + return "-DdummyArg=true"; + } + + synchronized void signalVMReady() { + pendingVMs--; + this.notifyAll(); + } + + public synchronized boolean waitForVMs(long timeout) throws InterruptedException { + long end = System.currentTimeMillis() + timeout; + while(pendingVMs > 0) { + long remaining = end - System.currentTimeMillis(); + if(remaining <= 0) { + return false; + } + this.wait(remaining); + } + + return true; + } + + private static class ProcessHolder { + private final Process process; + private volatile boolean killed = false; + + public ProcessHolder(Process process) { + this.process = process; + } + + public void kill() { + this.killed = true; + process.destroy(); + + } + + public Process getProcess() { + return process; + } + + public boolean isKilled() { + return killed; + } + + public boolean isAlive() { + return !killed && process.isAlive(); + } + } + + public RemoteDUnitVMIF getStub(int i) throws AccessException, RemoteException, NotBoundException, InterruptedException { + waitForVMs(DUnitLauncher.STARTUP_TIMEOUT); + return (RemoteDUnitVMIF) registry.lookup("vm" + i); + } +}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/dfba327e/gemfire-core/src/test/java/dunit/standalone/RemoteDUnitVM.java ---------------------------------------------------------------------- diff --git a/gemfire-core/src/test/java/dunit/standalone/RemoteDUnitVM.java b/gemfire-core/src/test/java/dunit/standalone/RemoteDUnitVM.java new file mode 100644 index 0000000..742dc55 --- /dev/null +++ b/gemfire-core/src/test/java/dunit/standalone/RemoteDUnitVM.java @@ -0,0 +1,144 @@ +/* + * 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 dunit.standalone; + +import hydra.MethExecutor; +import hydra.MethExecutorResult; + +import java.rmi.RemoteException; +import java.rmi.server.UnicastRemoteObject; + +import org.apache.logging.log4j.Logger; + +import com.gemstone.gemfire.internal.logging.LogService; + +import dunit.RemoteDUnitVMIF; + +/** + * @author dsmith + * + */ +public class RemoteDUnitVM extends UnicastRemoteObject implements RemoteDUnitVMIF { + + private static final Logger logger = LogService.getLogger(); + + public RemoteDUnitVM() throws RemoteException { + super(); + } + + /** + * Called remotely by the master controller to cause the client to execute + * the instance method on the object. Does this synchronously (does not spawn + * a thread). This method is used by the unit test framework, dunit. + * + * @param obj the object to execute the method on + * @param methodName the name of the method to execute + * @return the result of method execution + */ + public MethExecutorResult executeMethodOnObject( Object obj, String methodName ) { + String name = obj.getClass().getName() + "." + methodName + + " on object: " + obj; + logger.info("Received method: " + name); + long start = System.currentTimeMillis(); + MethExecutorResult result = MethExecutor.executeObject( obj, methodName ); + long delta = System.currentTimeMillis() - start; + logger.info( "Got result: " + result.toString().trim() + " from " + + name + " (took " + delta + " ms)"); + return result; + } + + /** + * Executes a given instance method on a given object with the given + * arguments. + */ + public MethExecutorResult executeMethodOnObject(Object obj, + String methodName, + Object[] args) { + String name = obj.getClass().getName() + "." + methodName + + (args != null ? " with " + args.length + " args": "") + + " on object: " + obj; + logger.info("Received method: " + name); + long start = System.currentTimeMillis(); + MethExecutorResult result = + MethExecutor.executeObject(obj, methodName, args); + long delta = System.currentTimeMillis() - start; + logger.info( "Got result: " + result.toString() + " from " + name + + " (took " + delta + " ms)"); + return result; + } + + /** + * Called remotely by the master controller to cause the client to execute + * the method on the class. Does this synchronously (does not spawn a thread). + * This method is used by the unit test framework, dunit. + * + * @param className the name of the class execute + * @param methodName the name of the method to execute + * @return the result of method execution + */ + public MethExecutorResult executeMethodOnClass( String className, String methodName ) { + String name = className + "." + methodName; + logger.info("Received method: " + name); + long start = System.currentTimeMillis(); + MethExecutorResult result = MethExecutor.execute( className, methodName ); + long delta = System.currentTimeMillis() - start; + logger.info( "Got result: " + result.toString() + " from " + name + + " (took " + delta + " ms)"); + + return result; + } + + /** + * Executes a given static method in a given class with the given + * arguments. + */ + public MethExecutorResult executeMethodOnClass(String className, + String methodName, + Object[] args) { + String name = className + "." + methodName + + (args != null ? " with " + args.length + " args": ""); + logger.info("Received method: " + name); + long start = System.currentTimeMillis(); + MethExecutorResult result = + MethExecutor.execute(className, methodName, args); + long delta = System.currentTimeMillis() - start; + logger.info( "Got result: " + result.toString() + " from " + name + + " (took " + delta + " ms)"); + return result; + } + + public void executeTask(int tsid, int type, int index) throws RemoteException { + throw new UnsupportedOperationException(); + + } + + public void runShutdownHook() throws RemoteException { + + } + + public void notifyDynamicActionComplete(int actionId) throws RemoteException { + throw new UnsupportedOperationException(); + + } + + public void shutDownVM() throws RemoteException { + ChildVM.stopVM(); + } + + public void disconnectVM() throws RemoteException { + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/dfba327e/gemfire-core/src/test/java/dunit/standalone/StandAloneDUnitEnv.java ---------------------------------------------------------------------- diff --git a/gemfire-core/src/test/java/dunit/standalone/StandAloneDUnitEnv.java b/gemfire-core/src/test/java/dunit/standalone/StandAloneDUnitEnv.java new file mode 100644 index 0000000..085035d --- /dev/null +++ b/gemfire-core/src/test/java/dunit/standalone/StandAloneDUnitEnv.java @@ -0,0 +1,75 @@ +/* + * 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 dunit.standalone; + +import java.io.File; +import java.rmi.RemoteException; +import java.util.Properties; + +import dunit.BounceResult; +import dunit.DUnitEnv; +import dunit.standalone.DUnitLauncher.MasterRemote; + +public class StandAloneDUnitEnv extends DUnitEnv { + + private MasterRemote master; + + public StandAloneDUnitEnv(MasterRemote master) { + this.master = master; + } + + @Override + public String getLocatorString() { + return DUnitLauncher.getLocatorString(); + } + + @Override + public String getLocatorAddress() { + return "localhost"; + } + + @Override + public int getLocatorPort() { + return DUnitLauncher.locatorPort; + } + + @Override + public Properties getDistributedSystemProperties() { + return DUnitLauncher.getDistributedSystemProperties(); + } + + @Override + public int getPid() { + return Integer.getInteger(DUnitLauncher.VM_NUM_PARAM, -1).intValue(); + } + + @Override + public int getVMID() { + return getPid(); + } + + @Override + public BounceResult bounce(int pid) throws RemoteException { + return master.bounce(pid); + } + + @Override + public File getWorkingDirectory(int pid) { + return ProcessManager.getVMDir(pid); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/dfba327e/gemfire-core/src/test/java/dunit/tests/BasicDUnitTest.java ---------------------------------------------------------------------- diff --git a/gemfire-core/src/test/java/dunit/tests/BasicDUnitTest.java b/gemfire-core/src/test/java/dunit/tests/BasicDUnitTest.java new file mode 100644 index 0000000..c284b3a --- /dev/null +++ b/gemfire-core/src/test/java/dunit/tests/BasicDUnitTest.java @@ -0,0 +1,132 @@ +/* + * 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 dunit.tests; + +import java.util.Properties; + +import dunit.AsyncInvocation; +import dunit.DistributedTestCase; +import dunit.Host; +import dunit.RMIException; +import dunit.VM; + +/** + * This class tests the basic functionality of the distributed unit + * test framework. + */ +public class BasicDUnitTest extends DistributedTestCase { + + public BasicDUnitTest(String name) { + super(name); + } + + //////// Test Methods + + /** + * Tests how the Hydra framework handles an error + */ + public void _testDontCatchRemoteException() { + Host host = Host.getHost(0); + VM vm = host.getVM(0); + vm.invoke(this.getClass(), "remoteThrowException"); + } + + public void testRemoteInvocationWithException() { + Host host = Host.getHost(0); + VM vm = host.getVM(0); + try { + vm.invoke(this.getClass(), "remoteThrowException"); + fail("Should have thrown a BasicTestException"); + + } catch (RMIException ex) { + assertTrue(ex.getCause() instanceof BasicTestException); + } + } + + static class BasicTestException extends RuntimeException { + BasicTestException() { + this("Test exception. Please ignore."); + } + + BasicTestException(String s) { + super(s); + } + } + + /** + * Accessed via reflection. DO NOT REMOVE + * + */ + protected static void remoteThrowException() { + String s = "Test exception. Please ignore."; + throw new BasicTestException(s); + } + + public void _testRemoteInvocationBoolean() { + + } + + public void testRemoteInvokeAsync() throws InterruptedException { + Host host = Host.getHost(0); + VM vm = host.getVM(0); + String name = this.getUniqueName(); + String value = "Hello"; + + AsyncInvocation ai = + vm.invokeAsync(this.getClass(), "remoteBind", + new Object[] { name, value }); + ai.join(); + // TODO shouldn't we call fail() here? + if (ai.exceptionOccurred()) { + fail("remoteBind failed", ai.getException()); + } + + ai = vm.invokeAsync(this.getClass(), "remoteValidateBind", + new Object[] {name, value }); + ai.join(); + if (ai.exceptionOccurred()) { + fail("remoteValidateBind failed", ai.getException()); + } + } + + private static Properties bindings = new Properties(); + private static void remoteBind(String name, String s) { + new BasicDUnitTest("bogus").getSystem(); // forces connection + bindings.setProperty(name, s); + } + + private static void remoteValidateBind(String name, String expected) + { + assertEquals(expected, bindings.getProperty(name)); + } + + public void testRemoteInvokeAsyncWithException() + throws InterruptedException { + + Host host = Host.getHost(0); + VM vm = host.getVM(0); +// String name = this.getUniqueName(); +// String value = "Hello"; + + AsyncInvocation ai = + vm.invokeAsync(this.getClass(), "remoteThrowException"); + ai.join(); + assertTrue(ai.exceptionOccurred()); + Throwable ex = ai.getException(); + assertTrue(ex instanceof BasicTestException); + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/dfba327e/gemfire-core/src/test/java/dunit/tests/TestFailure.java ---------------------------------------------------------------------- diff --git a/gemfire-core/src/test/java/dunit/tests/TestFailure.java b/gemfire-core/src/test/java/dunit/tests/TestFailure.java new file mode 100644 index 0000000..17a39fa --- /dev/null +++ b/gemfire-core/src/test/java/dunit/tests/TestFailure.java @@ -0,0 +1,50 @@ +/* + * 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 dunit.tests; + +import dunit.*; + +/** + * The tests in this class always fail. It is used when developing + * DUnit to give us an idea of how test failure are logged, etc. + * + * @author David Whitlock + * + * @since 3.0 + */ +public class TestFailure extends DistributedTestCase { + + public TestFailure(String name) { + super(name); + } + + //////// Test Methods + + public void testFailure() { + assertTrue("Test Failure", false); + } + + public void testError() { + String s = "Test Error"; + throw new Error(s); + } + + public void testHang() throws InterruptedException { + Thread.sleep(100000 * 1000); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/dfba327e/gemfire-core/src/test/java/dunit/tests/VMDUnitTest.java ---------------------------------------------------------------------- diff --git a/gemfire-core/src/test/java/dunit/tests/VMDUnitTest.java b/gemfire-core/src/test/java/dunit/tests/VMDUnitTest.java new file mode 100644 index 0000000..27736dc --- /dev/null +++ b/gemfire-core/src/test/java/dunit/tests/VMDUnitTest.java @@ -0,0 +1,237 @@ +/* + * 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 dunit.tests; + +import dunit.*; + +import java.io.Serializable; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * This class tests the functionality of the {@link VM} class. + */ +public class VMDUnitTest extends DistributedTestCase { + + private static final boolean BOOLEAN_VALUE = true; + private static final byte BYTE_VALUE = (byte) 40; + private static final long LONG_VALUE = 42L; + private static final String STRING_VALUE = "BLAH BLAH BLAH"; + + public VMDUnitTest(String name) { + super(name); + } + + //////// Test Methods + + public void notestInvokeNonExistentMethod() { + Host host = Host.getHost(0); + VM vm = host.getVM(0); + try { + vm.invoke(VMDUnitTest.class, "nonExistentMethod"); + fail("Should have thrown an RMIException"); + + } catch (RMIException ex) { + String s = "Excepted a NoSuchMethodException, got a " + + ex.getCause();; + assertTrue(s, ex.getCause() instanceof NoSuchMethodException); + } + } + + /** + * Accessed via reflection. DO NOT REMOVE + * @return + */ + protected static byte remoteByteMethod() { + return BYTE_VALUE; + } + + public void notestInvokeStaticBoolean() { + Host host = Host.getHost(0); + VM vm = host.getVM(0); + assertEquals(BOOLEAN_VALUE, + vm.invokeBoolean(VMDUnitTest.class, "remoteBooleanMethod")); + } + + /** + * Accessed via reflection. DO NOT REMOVE + * @return + */ + protected static boolean remoteBooleanMethod() { + return BOOLEAN_VALUE; + } + + public void notestInvokeStaticBooleanNotBoolean() { + Host host = Host.getHost(0); + VM vm = host.getVM(0); + try { + vm.invokeBoolean(VMDUnitTest.class, "remoteByteMethod"); + fail("Should have thrown an IllegalArgumentException"); + + } catch (IllegalArgumentException ex) { + + } + } + + public void notestInvokeStaticLong() { + Host host = Host.getHost(0); + VM vm = host.getVM(0); + assertEquals(LONG_VALUE, + vm.invokeLong(VMDUnitTest.class, "remoteLongMethod")); + } + + /** + * Accessed via reflection. DO NOT REMOVE + * @return + */ + protected static long remoteLongMethod() { + return LONG_VALUE; + } + + public void notestInvokeStaticLongNotLong() { + Host host = Host.getHost(0); + VM vm = host.getVM(0); + try { + vm.invokeLong(VMDUnitTest.class, "remoteByteMethod"); + fail("Should have thrown an IllegalArgumentException"); + + } catch (IllegalArgumentException ex) { + + } + } + + protected static class ClassWithLong implements Serializable { + public long getLong() { + return LONG_VALUE; + } + } + + protected static class ClassWithByte implements Serializable { + public byte getByte() { + return BYTE_VALUE; + } + } + + public void notestInvokeInstanceLong() { + Host host = Host.getHost(0); + VM vm = host.getVM(0); + assertEquals(LONG_VALUE, + vm.invokeLong(new ClassWithLong(), "getLong")); + } + + public void notestInvokeInstanceLongNotLong() { + Host host = Host.getHost(0); + VM vm = host.getVM(0); + try { + vm.invokeLong(new ClassWithByte(), "getByte"); + fail("Should have thrown an IllegalArgumentException"); + + } catch (IllegalArgumentException ex) { + + } + } + + protected static class InvokeRunnable + implements Serializable, Runnable { + + public void run() { + throw new BasicDUnitTest.BasicTestException(); + } + } + + protected static class ClassWithString implements Serializable { + public String getString() { + return STRING_VALUE; + } + } + + public void notestInvokeInstance() { + Host host = Host.getHost(0); + VM vm = host.getVM(0); + assertEquals(STRING_VALUE, + vm.invoke(new ClassWithString(), "getString")); + } + + public void notestInvokeRunnable() { + Host host = Host.getHost(0); + VM vm = host.getVM(0); + try { + vm.invoke(new InvokeRunnable()); + fail("Should have thrown a BasicTestException"); + + } catch (RMIException ex) { + assertTrue(ex.getCause() instanceof BasicDUnitTest.BasicTestException); + } + } + + private static final AtomicInteger COUNTER = new AtomicInteger(); + public static Integer getAndIncStaticCount() { + return new Integer(COUNTER.getAndIncrement()); + } + public static Integer incrementStaticCount(Integer inc) { + return new Integer(COUNTER.addAndGet(inc.intValue())); + } + public static void incStaticCount() { + COUNTER.incrementAndGet(); + } + public static class VMTestObject implements Serializable { + private static final long serialVersionUID = 1L; + private final AtomicInteger val; + public VMTestObject(int init) { + this.val = new AtomicInteger(init); + } + public Integer get() { + return new Integer(this.val.get()); + } + public Integer incrementAndGet() { + return new Integer(this.val.incrementAndGet()); + } + public void set(Integer newVal) { + this.val.set(newVal.intValue()); + } + } + public void testReturnValue() throws Exception { + final Host host = Host.getHost(0); + final VM vm = host.getVM(0); + // Assert class static invocation works + AsyncInvocation a1 = vm.invokeAsync(getClass(), "getAndIncStaticCount"); + a1.join(); + assertEquals(new Integer(0), a1.getReturnValue()); + // Assert class static invocation with args works + a1 = vm.invokeAsync(getClass(), "incrementStaticCount", new Object[] {new Integer(2)}); + a1.join(); + assertEquals(new Integer(3), a1.getReturnValue()); + // Assert that previous values are not returned when invoking method w/ no return val + a1 = vm.invokeAsync(getClass(), "incStaticCount"); + a1.join(); + assertNull(a1.getReturnValue()); + // Assert that previous null returns are over-written + a1 = vm.invokeAsync(getClass(), "getAndIncStaticCount"); + a1.join(); + assertEquals(new Integer(4), a1.getReturnValue()); + + // Assert object method invocation works with zero arg method + final VMTestObject o = new VMTestObject(0); + a1 = vm.invokeAsync(o, "incrementAndGet", new Object[] {}); + a1.join(); + assertEquals(new Integer(1), a1.getReturnValue()); + // Assert object method invocation works with no return + a1 = vm.invokeAsync(o, "set", new Object[] {new Integer(3)}); + a1.join(); + assertNull(a1.getReturnValue()); + } +}