JMeter WebSockets发布/订阅 - 脚本异步响应

时间:2017-02-23 12:29:01

标签: websocket jmeter stomp

我们已经通过WebSockets在我们的应用程序中构建了一个发布/订阅模型,因此用户可以接收"动态更新"当数据发生变化时我现在正在寻求使用JMeter加载测试。

有没有办法配置JMeter测试以响应收到的WebSocket"已发布"消息,然后运行进一步的采样器,即进一步的Web请求?

我查看了插件示例,但它们似乎专注于请求/回复模型(例如https://bitbucket.org/pjtr/jmeter-websocket-samplers)而不是发布/订阅。

修改

我已经使用WebSocketSampler为此找到了一个解决方案 - 可以找到一个示例JMX文件on BitBucket,该文件在WebSockets上使用STOMP,包括Connect,Subscribe,Handle Publish Message和Initiate JMeter Samplers。

2 个答案:

答案 0 :(得分:1)

误会是https://bitbucket.org/pjtr/jmeter-websocket-samplers/overview插件仅支持请求 - 响应模型对话。

从0.7版开始,该插件提供了#34;单读"和#34;单写"采样。当然,这取决于你的确切协议,但想法是你可以使用"单一写" sampler发送一个模拟创建订阅的WebSocket消息,然后将(标准JMeter)While循环与"单个读取"采样器,用于读取正在发布的任意数量的消息。

如果这不能满足您的需求,请告诉我,我会看到我能为您做些什么(我是这个插件的作者)。

答案 1 :(得分:0)

我的系统是STOMP。因此客户端执行了HTTP消息,并通过异步WebSockets使用此订阅模型获得了实际状态。为了模仿这种行为,我编写了一个类,它通过JMeterContext变量可以与Jmeter线程交换数据(导入部分你可以自己找到导入org.springframework。*):

public class StompWebSocketLoadTestClient {

public static JMeterContext ctx;
public static StompSession session;

public static void start(JMeterContext ctx, String wsURL, String SESSION) throws InterruptedException {
    WebSocketClient transport = new StandardWebSocketClient();

    WebSocketStompClient stompClient = new WebSocketStompClient(transport);
    ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
    threadPoolTaskScheduler.initialize();
    stompClient.setTaskScheduler(threadPoolTaskScheduler);
    stompClient.setDefaultHeartbeat(new long[]{10000, 10000});
    stompClient.setMessageConverter(new ByteArrayMessageConverter());
    StompSessionHandler handler = new MySessionHandler(ctx);
    WebSocketHttpHeaders handshakeHeaders = new WebSocketHttpHeaders();
    handshakeHeaders.add("Cookie", "SESSION=" + SESSION);
    stompClient.connect(wsURL, handshakeHeaders, handler);
    sleep(1000);
}

消息是在这个类中处理的:

private static class MySessionHandler extends StompSessionHandlerAdapter implements TestStateListener {

    private String Login = "";
    private final JMeterContext ctx_;

    private MySessionHandler(JMeterContext ctx) {
        this.ctx_ = ctx;
    }

    @Override
    public void afterConnected(StompSession session, StompHeaders connectedHeaders) {
        session.setAutoReceipt(true);
        this.Login = ctx_.getVariables().get("LOGIN");
        //System.out.println("CONNECTED:" + connectedHeaders.getSession() + ":" + session.getSessionId() + ":" + Login);
        //System.out.println(session.isConnected());
        **//HERE SUBSCRIBTION:**
        session.subscribe("/user/notification", new StompFrameHandler() {

            @Override
            public Type getPayloadType(StompHeaders headers) {
                //System.out.println("getPayloadType:");
                Iterator it = headers.keySet().iterator();
                while (it.hasNext()) {
                    String header = it.next().toString();

                    //System.out.println(header + ":" + headers.get(header));
                }
                //System.out.println("=================");
                return byte[].class;
            }

            @Override
            public void handleFrame(StompHeaders headers, Object payload) {
                //System.out.println("recievedMessage");
                NotificationList nlist = null;
                try {
                    nlist = NotificationList.parseFrom((byte[]) payload);

                    JMeterVariables vars = ctx_.getVariables();
                    Iterator it = nlist.getNotificationList().iterator();
                    while (it.hasNext()) {
                        Notification n = (Notification) it.next();
                        String className = n.getType();
                        //System.out.println("CLASS NAME:" + className);

                        if (className.contains("response.Resource")) {
                            ///After getting some message you can work with jmeter variables:
                            vars.putObject("var1", var1);
                            vars.put("var2",String.valueOf(var2));
                        }
                        //Here is "sending" variables back to Jmeter thread context so you can use the data during the test 
                        ctx_.setVariables(vars);
                        n = null;

                    }
                } catch (InvalidProtocolBufferException ex) {
                    Logger.getLogger(StompWebSocketLoadTestClient.class.getName()).log(Level.SEVERE, null, ex);
                } 
            }

        });
    }

在Jmeter测试计划中,在登录阶段之后我刚刚添加了一个Beanshell采样器,其中包含登录名/密码和会话字符串以及 Jmeter线程上下文

import jmeterstopm.StompWebSocketLoadTestClient;
StompWebSocketLoadTestClient ssltc = new StompWebSocketLoadTestClient();
String SERVER_NAME = vars.get("SERVER_NAME");
String SESSION = vars.get("SESSION");
String ws_pref = vars.get("ws_pref");
ssltc.start(ctx,ws_pref+"://"+SERVER_NAME+"/endpoint/notification-    ws/websocket",SESSION);

还可以通过简单的 vars 变量使用所有传入的Websockets数据:

Object var1= (Object) vars.getObject("var1");