org.jboss.byteman.contrib.dtest.InstrumentedClass Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of byteman-dtest Show documentation
Show all versions of byteman-dtest Show documentation
The Byteman dtest jar supports instrumentation of test code executed on remote server hosts
and validation of assertions describing the expected operation of the instrumented methods.
/*
* JBoss, Home of Professional Open Source
* Copyright 2010, Red Hat, Inc. and/or its affiliates,
* and individual contributors as indicated by the @author tags.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
* (C) 2010,
* @author JBoss, by Red Hat.
*/
package org.jboss.byteman.contrib.dtest;
import java.rmi.RemoteException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import static org.junit.Assert.assertEquals;
/**
* InstrumentedClass instances serve two purposes:
*
* Internally to the framework they provide a communication endpoint for
* receiving information from the remote, Byteman instrumented code execution.
*
* To the framework user, they provide utility methods for verifying expectations relating
* to that remote execution e.g. the number of method calls made.
*
* @author Jonathan Halliday ([email protected]) 2010-05
*/
public class InstrumentedClass implements RemoteInterface
{
private static final Integer STATIC_INSTANCE_ID = new Integer(-1);
private final String className;
private final Map instrumentedInstances = new ConcurrentHashMap();
InstrumentedClass(String className)
{
this.className = className;
}
/**
* Receiving side of the remote communication between the test code and the BytemanTestHelper.
*
* @param methodName the method name that was traced.
* @param args the arguments to the method invocation, in String form.
* @throws RemoteException in case of communication failure.
* @see BytemanTestHelper#remoteTrace(String, String, Object[])
*/
@Override
public void trace(String methodName, Object[] args) throws RemoteException
{
Integer objectId = (Integer) args[0];
if(objectId == null)
{
objectId = STATIC_INSTANCE_ID;
}
InstrumentedInstance createdInstrumentedInstance = new InstrumentedInstance(className, objectId);
InstrumentedInstance instrumentedInstance = instrumentedInstances.putIfAbsent(objectId, createdInstrumentedInstance);
if(instrumentedInstance == null) {
instrumentedInstance = createdInstrumentedInstance;
}
Object[] innerArgs = new Object[args.length-1];
System.arraycopy(args, 1, innerArgs, 0, innerArgs.length);
instrumentedInstance.addMethodTrace(methodName, innerArgs);
}
/**
* Returns the set of known instances of the class.
*
* @return a Set of Objects representing instances of the class.
*/
public Set getInstances()
{
return new HashSet(instrumentedInstances.values());
}
/**
* Returns number of method calls for the class.
* Sum number of method calls on all instrumented instances
* belonging to this instrumented class.
* It's sum of all method calls for all known instrumented instances.
*
* @param methodName name of method which we are interested in how many times was called
* @return number of method calls on the class (sum of method calls of all instances)
*/
public int getInvocationCount(String methodName)
{
int invocationCount = 0;
for(InstrumentedInstance instance: getInstances()) {
invocationCount += instance.getInvocationCount(methodName);
}
return invocationCount;
}
/**
* Checks that the number of known, distinct object instances of this class is as stated.
*
* @param count the expected number of instances of the class.
*/
public void assertKnownInstances(int count)
{
assertEquals("Number of known instances of " + className + " does not match",
count, instrumentedInstances.size());
}
/**
* Checks that the number of known invocations of the given method falls within the specified
* range for each known instances of the class.
*
* @param message the message to print in case of assertion failure.
* @param methodName the method name to look for.
* @param callCount the expected range for the invocation count.
*/
public void assertMethodCallCount(String message, String methodName, CallCount callCount)
{
for(InstrumentedInstance instance : getInstances())
{
instance.assertMethodCallCount(message, methodName, callCount);
}
}
/**
* Checks that the number of known invocations of the given method is specified count.
*
* @param message the message to print in case of assertion failure.
* @param methodName the method name to look for.
* @param callCount the expected number of the invocation count.
*/
public void assertMethodCallCount(String message, String methodName, int callCount)
{
assertMethodCallCount(message, methodName, new CallCount(callCount, callCount));
}
/**
* Checks that the number of known invocations of the given method is specified count.
*
* @param methodName the method name to look for.
* @param callCount the expected number of the invocation count.
*/
public void assertMethodCallCount(String methodName, int callCount)
{
assertMethodCallCount(null, methodName, new CallCount(callCount, callCount));
}
/**
* Check that number of known invocations of the given method of all known instances
* is specified count.
* Difference against {@link #assertMethodCallCount(String, int)} is that here we query
* against all know instances. The other method query each instance to be called
* by the specific number times.
*
* @param method the method name to look for
* @param callCount the expected number of the invocation count summed on all instances
*/
public void assertSumMethodCallCount(String method, int callCount)
{
assertEquals("Method " + className + "#" + method + " was not called " + callCount + " times",
callCount, getInvocationCount(method));
}
/**
* Checks that the given method has been called at least once on each known instance of the class.
* Uses junit internally, hence expect the normal exception throwing in case of failure.
*
* @param methodName the method name to look for.
*/
public void assertMethodCalled(String methodName)
{
assertMethodCallCount(null, methodName, new CallCount(1, Integer.MAX_VALUE));
}
/**
* Checks that the given method has not been seen to be called on any known instance of the class.
* Uses junit internally, hence expect the normal exception throwing in case of failure.
*
* @param methodName the method name to look for.
*/
public void assertMethodNotCalled(String methodName)
{
assertMethodCallCount(null, methodName, new CallCount(0, 0));
}
}