Apache JMeter自带了许多的采样器供我们使用,而且能够满足大部分的测试需求。但是在实际使用过程中,难免需要针对项目自身的特点和需求对Apache JMeter进行扩展。虽然直接继承AbstractJavaSamplerClient即可编写Java采样器,但是其相对应的GUI界面不是很友好,或者我们想编写一个类似HTTP Request那样的sampler,该如何做呢?比如我们需要编写一个TLS的采样器,该采样器允许用户在发送TLS请求的时候制定TLS的版本,以及客户端证书等信息。请参考如下代码及注释:
package kg.apc.jmeter.samplers;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.net.Socket;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.jmeter.samplers.AbstractSampler;
import org.apache.jmeter.samplers.Entry;
import org.apache.jmeter.samplers.Interruptible;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
// FIXME: actually keep-alive does not work!
/**
*
* @author undera
*/
public class TLSRawSampler extends AbstractSampler implements Serializable, Cloneable, Interruptible{
private static final Logger log = LoggingManager.getLoggerForClass();
//following static final String are property keys in JMeter
private static final String HOST_NAME = "TLS_hostName";
private static final String PORT = "TLS_port";
private static final String TLS_VERSON = "TLS_tlsversion";
private static final String CIPHER_LIST = "TLS_cipherlist";
private static final String DATA = "TLS_data";
private static final String CLIENT_CERT = "TLS_client_cert";
private static final String CLIENT_CERT_PASSWORD = "TLS_client_cert_password";
public TLSRawSampler() {
}
/**
* Process sample here
*/
@Override
public SampleResult sample(Entry entry) {
SampleResult sr = new SampleResult();
sr.sampleStart();
sr.setSuccessful(true);
sr.setSampleLabel(getName());
sr.setResponseCode("200");
//do the sample here
try{
Socket socket = getTLSSocket();
socket.getOutputStream().write(getData().getBytes());
StringBuilder headerSB = new StringBuilder();
StringBuilder contentSB = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = null;
boolean header = true;
while((line = reader.readLine()) != null){
if(line.length() == 0){
header = false;
continue;
}
if(header){
headerSB.append(line);
headerSB.append("\n");
}
else{
contentSB.append(line);
contentSB.append("\n");
}
}
sr.setResponseHeaders(headerSB.toString());
sr.setResponseData(contentSB.toString(), "");
socket.close();
}catch(Exception e){
sr.setSuccessful(false);
sr.setResponseCode("500");
sr.setResponseMessage(e.getMessage());
}
sr.sampleEnd();
return sr;
}
@Override
public boolean interrupt() {
// TODO Auto-generated method stub
return false;
}
//following get and set methods are used for get and set properties in JMeter
public String getHostName(){
return getPropertyAsString(TLSRawSampler.HOST_NAME);
}
public void setHostName(String hostName){
setProperty(TLSRawSampler.HOST_NAME, hostName);
}
public String getPort(){
return getPropertyAsString(TLSRawSampler.PORT);
}
public void setPort(String port){
setProperty(TLSRawSampler.PORT, port);
}
public String getTLSVersion(){
return getPropertyAsString(TLSRawSampler.TLS_VERSON);
}
public void setTLSVersion(String version){
setProperty(TLSRawSampler.TLS_VERSON, version);
}
public String getClientCert(){
return getPropertyAsString(TLSRawSampler.CLIENT_CERT);
}
public void setClientCert(String clientCert){
setProperty(TLSRawSampler.CLIENT_CERT, clientCert);
}
public String getCipherList(){
return getPropertyAsString(TLSRawSampler.CIPHER_LIST);
}
public void setCipherList(String list){
setProperty(TLSRawSampler.CIPHER_LIST, list);
}
public String getData(){
return getPropertyAsString(TLSRawSampler.DATA);
}
public void setData(String data){
setProperty(TLSRawSampler.DATA, data);
}
public String getClientCertPassword(){
return getPropertyAsString(TLSRawSampler.CLIENT_CERT_PASSWORD);
}
public void setClientCertPassword(String password){
setProperty(TLSRawSampler.CLIENT_CERT_PASSWORD, password);
}
private Socket getTLSSocket() throws Exception{
TrustManager[] allTrusted = {new X509TrustManager(){
@Override
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
// TODO Auto-generated method stub
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
// TODO Auto-generated method stub
}
@Override
public X509Certificate[] getAcceptedIssuers() {
// TODO Auto-generated method stub
return null;
}
}};
SSLContext ctx = SSLContext.getInstance(getTLSVersion(), "SunJSSE");//use 1.2
//get client cert
String clientCert = getClientCert();
if(clientCert != null && clientCert.length() > 0){
String clientCertPassword = getClientCertPassword();
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
KeyStore keyStore = KeyStore.getInstance("PKCS12");
InputStream keyInput = new FileInputStream(clientCert);
keyStore.load(keyInput, clientCertPassword.toCharArray());
keyInput.close();
keyManagerFactory.init(keyStore, clientCertPassword.toCharArray());
ctx.init(keyManagerFactory.getKeyManagers(), allTrusted, null);
}
else{
ctx.init(null, allTrusted, null);
}
SSLParameters parameters = ctx.getDefaultSSLParameters();
String cipherList = getCipherList();
if(cipherList != null && cipherList.length() > 0){
parameters.setCipherSuites(cipherList.trim().split(","));
}
for(String cipher : parameters.getCipherSuites()){
log.info(cipher);
}
SSLSocket socket = (SSLSocket)ctx.getSocketFactory().createSocket(getHostName(), Integer.valueOf(getPort()));
socket.setTcpNoDelay(true);
socket.setSSLParameters(parameters);
return socket;
}
}
转载于:https://blog.51cto.com/coderlouis/1629635