又一次对Jmeter TCP Sampler实现的小改动

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 经历对“动态报文长度”处理后,又一次对JMeter的TCP Sampler作了一次小改

背景介绍

最近遇到国密改造的性能测试项目,有点小趣:

  1. 服务处理逻辑

服务器收到报文,调用动态库,根据报文中多个字段,动态计算出一个值,再与报文某个字段进行对比校验,若校验通过则认为报文合法,不通过则拒绝服务。我们把对比字段称为校验字段,多个字段称为计算字段

  1. 思路历程

首先,考虑在测试的接口不多,为减少测试的复杂性,想到对报文中的字段进行固化,从而达到校验字段不变的目的。

带着想法找到开发人员看看报文的计算字段有哪些,是否有字段影响测试的准确性。

果不其然,这是不行的。每类报文的“计算字段”有可能不同,且同类报文中,字段A或字段B的固化变导致数据库的热点问题。开发人员建议传入整个报文到加密库,线上也是如此。

考虑到开发意见,决定JMeter发送报文前调用加密库对报文进行更新。

  1. 细项考量

与开发约定,开发提供一个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" "$@"

最后的唠叨

  1. 上述更改,可成功的实现我们的目的,即JMeter调用加密库更新字段。
  2. 这样的更改不算难,甚至很简单,作性能测试,无论是压测工具,还是辅助测试的代码,这是达到测试目的的过程而已。
  3. 上述的过程,我们大约需要了解下述几点:

    • 基础的java知识点。
    • 对JMeter的TCP Sampler源码有所了解。
    • 对JMeter的启动引导有所了解。
    • 和开发的沟通协调。
目录
相关文章
|
JavaScript Java Shell
JMeter Sampler之BeanShellSampler的使用
JMeter Sampler之BeanShellSampler的使用
124 0
EMQ
|
消息中间件 自然语言处理 Java
JMeter 扩展插件实现对自定义协议的支持
本文作为JMeter拓展开发的第四期内容,将以扩展一个简单的Apache Kafaka Producer Sampler为例,介绍如何使用JMeter扩展插件实现更完善的新协议插件。
EMQ
279 0
JMeter 扩展插件实现对自定义协议的支持
EMQ
|
Java 测试技术 Linux
JMeter 扩展开发:BeanShell 数据模拟实现及性能探讨
本文是开源测试工具JMeter扩展性开发教程第三期,讲解如何采用JMeter内置功能BeanShell实现动态生成测试数据,并探讨其与Java扩展JMeter的实现方式对比。
EMQ
212 0
JMeter 扩展开发:BeanShell 数据模拟实现及性能探讨
EMQ
|
网络协议 Java 数据库连接
JMeter 扩展开发:自定义 Java Sampler
本文是开源测试工具JMeter扩展性开发教程第二期,主要讲解JMeter如何实现对新协议的支持。以MQTT协议中的连接为例,介绍使用JMeter Java Sampler进行扩展开发的具体步骤。
EMQ
357 0
JMeter 扩展开发:自定义 Java Sampler
|
数据可视化 Java 测试技术
Jmeter快速实现接口测试
Jmeter快速实现接口测试
229 0
|
监控 Java 测试技术
基于Jmeter的性能压测平台实现
很早就想要一套属于自己的性能压测平台,原因是使用了阿里云的性能测试PTS,就挺羡慕能有一个这样的性能测试平台,但毕竟人家的东西我们高攀不起(要钱的),而且阿里云的性能测试平台是不支持多种协议的(比如我有一个项目要用websocket测试,结果人家就支持http压测)。
4495 0
jmeter参数化随机取值实现
jmeter能用来做参数化的组件有几个,但是都没有随机取值的功能,遇到随机取值的需求怎么办呢? 突发奇想,可以用函数__CSVRead()来实现: __CSVRead() CSV file to get values from | *alias:表示要读取的文件路径 CSV文件列号| next| *alias:表示当前变量读取第几列数据,注意第一列是0; 由此可见我们只需将参数化数据在csv中横向排列,然后用随机函数__Random()指定文件序列号即可。
2187 0