背景介绍
最近遇到国密改造的性能测试项目,有点小趣:
- 服务处理逻辑
服务器收到报文,调用动态库,根据报文中多个字段,动态计算出一个值,再与报文某个字段进行对比校验,若校验通过则认为报文合法,不通过则拒绝服务。我们把对比字段称为校验字段,多个字段称为计算字段。
- 思路历程
首先,考虑在测试的接口不多,为减少测试的复杂性,想到对报文中的字段进行固化,从而达到校验字段不变的目的。
带着想法找到开发人员看看报文的计算字段有哪些,是否有字段影响测试的准确性。
果不其然,这是不行的。每类报文的“计算字段”有可能不同,且同类报文中,字段A或字段B的固化变导致数据库的热点问题。开发人员建议传入整个报文到加密库,线上也是如此。
考虑到开发意见,决定JMeter发送报文前调用加密库对报文进行更新。
- 细项考量
与开发约定,开发提供一个Jar包(封装加密库的实现细节),且Bytes和String传入参数类型统一约定为String。
根据开发人员提供的对Jar的测试代码,实现对Tcp Sampler的小改。
TCP Sampler的小改
这是开发提供的对Jar包的测试代码:
public class MacTest {
public static void main(String[] args) {
MacGenerator mg = new MacGenerator();
//String secKey = "111111111111111111111111111111111"; //A用
String secKey="22222222222222222222"; //B用
String testStr = "this is a message";
testStr = mg.genMac(testStr, secKey);
System.out.println(testStr);
}
}
很简单的代码,生成一个实例,再调用实例方法,传入“报文”和“KEY"值即可。
上述经在测试环境验证成功后,参考我之前在知乎上写过相于动态报文长度的处理方法。更改TCP Sampler实现如下:
import ...;
public class prelenTCPWithMacUpdateImpl extends TCPClientImpl {
//存在其他私有成员,不重要,为减少文章长度,忽略
//在user.properties里配置KEY值
private final String secKey = JMeterUtils.getPropDefault("tcp.cipher_cn.secKey", "0");
public prelenTCPWithMacUpdateImpl() {
super();
}
@Override
public void write(OutputStream os, String s) throws IOException {
//这是新增代码的开始
MacGenerator mg = new MacGenerator();
String strWithMacVal = mg.genMac(s, this.secKey);
//这里新增代码的结束
//这是”动态报文长度“的小改开始
byte[] sb = strWithMacVal.getBytes(CHARSET);
ByteBuffer bb = ByteBuffer.allocate(sb.length + this.lengthPrefixLen);
String headStr = Integer.toString(sb.length);
int len = headStr.length();
byte[] prefixCharByte = this.prefixChar.getBytes(CHARSET);
if(prefixCharByte.length != 1) {
log.error("prefixCharByte.length not is 1:" + prefixCharByte.length);
return;
}
for(int i=0; i<this.lengthPrefixLen - len; i++) {
bb.put(prefixCharByte);
}
bb.put(headStr.getBytes(CHARSET));
bb.put(sb);
if(log.isDebugEnabled()) {
//不重要,为减少文章长度,忽略
}
//这是”动态报文长度“的小改结束
os.write(bb.array());
os.flush();
}
private String showEOL(final String input) {
//不重要,为减少文章长度,忽略
}
}
更改后,重新编辑打包,和开发提供的Jar包,一起放入$JMETER_HOME/lib/ext目录里,同时在user.properties配置tcp.cipher_cn.secKey和jmeter tcp.handler。
到这里差不多完成了,还差一个,让JMeter的运行环境可以找到我们的加密库,参考开发给的运行代码:
java -Djava.library.path=/dir_path/加密库文件 -cp ./xxxx.jar:./ 开发给的测试代码
因我的JMeter在linux环境下运行,故更改$JMETER_HOME/bin/jmeter文件最后一行,如下:
MAC_OPTS="-Djava.library.path=/dir_path/加密库文件"
"$JAVA_HOME/bin/java" $ARGS $JVM_ARGS $JMETER_OPTS $MAC_OPTS -jar "$PRGDIR/ApacheJMeter.jar" "$@"
最后的唠叨
- 上述更改,可成功的实现我们的目的,即JMeter调用加密库更新字段。
- 这样的更改不算难,甚至很简单,作性能测试,无论是压测工具,还是辅助测试的代码,这是达到测试目的的过程而已。
-
上述的过程,我们大约需要了解下述几点:
- 基础的java知识点。
- 对JMeter的TCP Sampler源码有所了解。
- 对JMeter的启动引导有所了解。
- 和开发的沟通协调。