先看个典型的grinder脚本
from net.grinder.script.Grinder import grinder
from net.grinder.script import Test
from net.grinder.plugin.http import HTTPRequest
test1 = Test(1, "Request resource")
request1 = test1.wrap(HTTPRequest())
from net.grinder.script import Test
from net.grinder.plugin.http import HTTPRequest
test1 = Test(1, "Request resource")
request1 = test1.wrap(HTTPRequest())
class TestRunner:
def __call__(self):
result = request1.GET("http://www.google.com.hk)
def __call__(self):
result = request1.GET("http://www.google.com.hk)
脚本解析的入口:Test 类。
1. 解析脚本:test1 = Test(1, "Request resource")
// number=1,description="Request resource"
public class Test extends AbstractTestSemantics implements Serializable{
public Test( int number, String description) {
m_number = number;
m_description = description;
//Test类在初始化的时候,向registeredTest注册该测试对象Test
m_registeredTest = Grinder.grinder .getTestRegistry().register(this);
}
class TestRegistryImplementation
public RegisteredTest register(Test test) {
//先判断instrumenter是否为空
if ( m_instrumenter == null) {
throw new AssertionError("Instrumenter not set");
}
// 创建测试业务实现对象, TestData可以包装关联被测目标对象 /方法,同时实现计时功能
final TestData newTestData;
//同步信息,从testMap中查询是否存在这个test,如果存在就直接返回。保证test在testMap中的唯一性。
synchronized ( this) {
final TestData existing = m_testMap .get(test);
if (existing != null) {
return existing;
}
//如果不存在,new 一个TestData对象。
newTestData = new TestData(m_threadContextLocator ,
m_statisticsSetFactory,
m_testStatisticsHelper,
m_timeAuthority,
m_instrumenter,
test);
// 把test和newTestData放入testMap 中进行管理。
m_testMap.put(test, newTestData);
m_testStatisticsMap.put(test, newTestData.getTestStatistics());
if (m_newTests == null) {
m_newTests = new ArrayList<Test>();
}
// To avoid many minor console updates we store a collection of
// the new tests which is periodically read and sent to the
// console by the scheduled reporter task.
//Collection<Test> 中新增这个test
m_newTests.add(test);
}
return newTestData;
}
2. 解析脚本:request1 = test1.wrap(HTTPRequest())
//Test类的wrap方法,传入参数 Object对象"HTTPRequest()",返回registerTest的创建proxy方法。
public final Object wrap(Object target) throws NotWrappableTypeException {
return m_registeredTest.createProxy(target);
}
TestData类,TestData实现了RegisteredTest和recorder类。
//传入object对象,实现创建proxy。
public Object createProxy(Object o)
throws NotWrappableTypeException {
//传入 test,testData,object,返回instrumenter的创建instrumentedProxy方法。
return m_instrumenter .createInstrumentedProxy(getTest(), this, o);
}
class TraditionalJythonInstrumenter
//传入test,recoder,因为TestData类实现recoder类,所以这里传入testData。
public Object createInstrumentedProxy(Test test,
Recorder recorder,
Object o)
throws NotWrappableTypeException {
// 返回instrumentObject。
return instrumentObject(test, new PyDispatcher(recorder), o);
}
// instrumentObject 是个pyobject对象了。
private PyObject instrumentObject(Test test,
PyDispatcher pyDispatcher,
Object o)
throws NotWrappableTypeException {
//对Object o 进行判定。如果是python对象。。。。
if (o instanceof PyObject) {
// Jython object.
if (o instanceof PyInstance) {
final PyInstance pyInstance = (PyInstance)o;
final PyClass pyClass =
m_versionAdapter .getClassForInstance(pyInstance);
return new InstrumentedPyInstance(
test, pyClass, pyInstance, pyDispatcher);
}
else if (o instanceof PyFunction) {
return new InstrumentedPyJavaInstanceForPyFunctions(
test, (PyFunction)o, pyDispatcher);
}
else if (o instanceof PyMethod) {
return new InstrumentedPyJavaInstanceForPyMethods(
test, (PyMethod)o, pyDispatcher);
}
else if (o instanceof PyReflectedFunction) {
return new InstrumentedPyReflectedFunction(
test, (PyReflectedFunction)o, pyDispatcher);
}
else {
// Fail, rather than guess a generic approach.
throw new NotWrappableTypeException( "Unknown PyObject: " +
o.getClass());
}
}
else if (o instanceof PyProxy) {
// Jython object that extends a Java class.
final PyInstance pyInstance = ((PyProxy)o)._getPyInstance();
final PyClass pyClass =
m_versionAdapter.getClassForInstance(pyInstance);
return new InstrumentedPyInstance(
test, pyClass, pyInstance, pyDispatcher);
}
//如果O是java class<?>,实现这段逻辑。
else if (o instanceof Class<?>) {
return new InstrumentedPyJavaClass(test, (Class<?>)o, pyDispatcher);
}
else if (o != null) {
// Java object.
// NB Jython uses Java types for some primitives and strings.
if (!o.getClass().isArray() &&
!(o instanceof Number) &&
!(o instanceof String)) {
//如果是java 对象,返回InstrumentedPyJavaInstanceForJavaInstances
return new InstrumentedPyJavaInstanceForJavaInstances(
test, o, pyDispatcher);
}
}
return null;
}
class InstrumentedPyJavaInstanceForJavaInstances
//脚本: request.GET("http://www.google.com.hk/")
public PyObject invoke( final String name, final PyObject arg1) {
//调用
return getInstrumentationHelper().dispatch(
new PyDispatcher.Callable() {
public PyObject call() {
//invoke后,脚本变成request(GET,"http://www.google.com.hk/")
//name=GET,arg1="http://www.google.com.hk/"
return InstrumentedPyJavaInstanceForJavaInstances.super.invoke(
name, arg1);
//
}
}
);
}
//class InstrumentationHelper
//invoke后的PyDispatcher.Callable() ,传入getInstrumentationHelper().dispatch
public PyObject dispatch(PyDispatcher.Callable callable) {
return m_dispatcher.dispatch(callable);
}
return m_dispatcher.dispatch(callable);
}
class PyDispatcher
public PyObject dispatch(Callable callable) {
try {
//开始计时,这里涉及到grinder的数据统计。另外分析。
try {
//开始计时,这里涉及到grinder的数据统计。另外分析。
//计时最小单位是一个request。
m_recorder.start();
boolean success = false;
try {
final PyObject result = callable.call();
success = true;
return result;
}
finally {
m_recorder.start();
boolean success = false;
try {
final PyObject result = callable.call();
success = true;
return result;
}
finally {
//计时结束。
m_recorder.end(success);
}
}
m_recorder.end(success);
}
}