January 9, 2019

How to Load Test SSE Services with JMeter

Open Source Automation
Performance Testing

Nearly everyone who browses the Internet nowadays has come across notifications that appear on their desktop browsers, desktop applications or mobile devices. New updates from favorite websites, chat messages, messages and social networks events, as well as stock exchange data, prices and many more can be delivered to you with push notifications. The basis for these push notifications is the SSE (Server-Sent Events) technology. In this blog post we will learn to run an Apache JMeter™ load test for SSE.

Keep reading to learn two ways to load test SSE with JMeter: by using Groovy or a Java Sampler.

 

Back to top

What is SSE in Testing?

 

SSE is the technology for transferring data from a server to clients. Clients can be desktops or mobile devices with running applications and services, or web applications open in clients browsers. When a client subscribes for a stream from the server, she/he will receive a notification when an event occurs. After the subscription, a one-way connection is opened between the server and the client and the server sends data to the application when it is required (push notifications).

 

SSE is handled directly on the client side, with the client listening to the channel. However, the connection also consumes server resources. As a result, a number of clients  subscribed to a stream create a considerable load to the service, especially when notifications are massively sent. This is why it’s necessary to load test these types of services.

 

Back to top

Load Testing SSE with JMeter

 

As server-sent events are transmitted over HTTP, there’s no need to implement a specific protocol or service for load testing. In addition, SSE supports reconnection, event IDs and arbitrary events. There is a w3c specification dedicated to the EventSource interface of SSE, over which notifications are sent from a server to a client. The specification can be found here. Both reconnection time and event id can be used to imitate clients behavior in the JMeter script.

 

Back to top

Creating Your JMeter Script

 

JMeter is the best choice among load generator tools for performance testing such services, as the client behavior can be easily imitated by JMeter script. Although JMeter doesn’t have out of the box SSE components or plugins, the script can be implemented in two different ways: with the application of a JSR223 sampler and Groovy code, or with the application of a JAVA sampler.

 

To simulate a server sending notifications, there are many open source libraries, written in different languages, you can choose from. For the implementation of the JMeter script for this article, we have selected the OKHTTP event source library. Just download corresponding jar files and drop them to the /lib/ext directory of the JMeter.

 

Our JMeter script will provide regular performance metrics that are always collected in performance testing and a few metrics specific for the SSE services. These metrics are: the number of reconnections and retrying reconnections for the same event.

 

Back to top

Load Testing SSE with JSR223 sampler and Groovy

 

1. Add a Thread Group.

 

2. Define the variables that you want to parameterize in your script. This can be done either in the variable section of the test plan or in the user variable component, which in this case has to be added to the script.

 

In the example for this article, the defined variables are serverURL, reconnectionTime, lengthOfWork.

Defined variables in load testing SSE with JMeter

 

3. Add a JSR223 Sampler

 

For the demonstration of the work of JMeter script in this blog post, wikimedia.org server is used, which sends push notifications in the JSON format. The serverURL variable contains the URL of this server.

 

The JSR223 sampler will receive all the notifications from the server. Lest the script runs infinitely, the lengthOfWork variable is used to regulate script running time. If the time of work monitored in the JSR223 script is reached or exceeds the lengthOfWork value, the JMeter script finishes.

 

The serverURL, reconnectionTime and lengthOfWork variables are defined in the user variables section of the Test plan and are passed in the parameters field of the JSR223 sampler to the Groovy script.

 

4. The Groovy code of the JSR223 sampler is shown below.

 

importcom.launchdarkly.eventsource.EventSource;importcom.launchdarkly.eventsource.EventHandler;importcom.launchdarkly.eventsource.MessageEvent;importjava.net.URI;importjava.io.StringReader;importjava.util.concurrent.TimeUnit;importjava.util.ArrayList;importjavax.json.Json;importjavax.json.JsonObject;importjavax.json.JsonReader;importjavax.json.JsonValue;publicclassSimpleEventHandlerimplements EventHandler {public List<String> respList =new ArrayList<String>();publicvoidonOpen()throws Exception{
		log.info("The connection has been opened");}publicvoidonClosed()throws Exception{
		log.info("The connection has been closed");}publicvoidonMessage(String Event, MessageEvent messageEvent)throws Exception{
		respList.add(messageEvent.getData());}publicvoidonComment(String comment)throws Exception{
		log.info(comment);}publicvoidonError(Throwable t){
		log.info("Error "+t);}}

	EventHandler eH =new SimpleEventHandler();

	String responseList="";
	
	EventSource.Builder builder =new EventSource.Builder(eH, URI.create(args[0]));

	EventSource eventSource = builder.build();
	eventSource.setReconnectionTimeMs(Integer.parseInt(args[1]));
	eventSource.start();
	TimeUnit.SECONDS.sleep(Integer.parseInt(args[2]));
	eventSource.close();for(String respRecord:eH.respList){
		JsonReader jsonReader = Json.createReader(new StringReader(respRecord));
		JsonObject jsonObject = jsonReader.readObject();
		JsonValue title = jsonObject.getValue(args[3]);
		JsonValue changeType = jsonObject.getValue(args[4]);
		responseList = responseList + changeType.toString()+" : "+title.toString()+"\n";}

	SampleResult.setResponseData(responseList,"866");

 

The code logic includes:

  • the establishment of the connection to the server, which generates notifications;
  • receiving notifications;
  • parsing received notifications;
  • filtering specific ones and outputting them to the result data section of the JSR223 sampler, so that filtered notifications can be viewed in the View Results Tree listener.

 

JMeter receives all the notifications from the server, which are saved in the array list. Notifications from the server ‘wikimedia.org’ are represented in JSON format. The Groovy code in the JSR223 Sampler filters the data by extracting only the notifications that are passed under certain keys of the JSON structure. The names of the keys are set in the variables section in the option1 and option2 variables and are passed as parameters to the Groovy script.

 

5. Add a View Results Tree Listener and run your script.

Add a View Results Tree Listener

 

The script can be downloaded from here together with the OKHTTP and JSON libraries.

 

Load Testing SSE with the Java Sampler

 

Another version of this script can be created with the JAVA request sampler. The logic of establishing a connection to the service and receiving notifications from the server takes place in the JAVA request.

 

To do this, first we need to implement the the Java class for the Java Request Sampler. To implement a Java class for the Java request sampler to receive notifications, follow the steps below:

  1. In any IDE tool (Idea Eclipse) create a project and implement an application that receives notifications from a server. For our example, use the code shown below. Debug and compile the code.
  2. Place the jar file with the compiled code to the /lib/ext folder of the JMeter installation directory.
  3. Restart JMeter, add a Thread group and add a Java request sampler under the thread group.
  4. In the pull down list ‘classname’ of the Java request sampler select the name of the main class of the java project you compiled in step 1. It should appear in the pull down list. The list of parameters, you determined in the getDefaultParameters method will be displayed in the ‘Send parameters with request table’ of the Java request sample.
  5. Define the parameters and add a View Results Tree listener for demonstration purposes.
  6. Launch the script. If the server URL is the same, as it is in the first script example (where we used the JSR223 Sampler), the Java sampler data in the View Results Tree listener will be displayed in the same format as it is in the first implementation.

 

Here is the java code to process the Java Request Sampler. Add it to the IDE in three separate files, compile it, and then put in JMeter’s  /lib/ext folder (steps 1-2). You can create your own code.

 

SSEJavaSampler is the implementation of the JavaSamplerClient interface. This class should appear in the pull down list ‘Classname’ of the Java request sampler. The java code of this class is shown below.

 

importorg.apache.jmeter.config.Arguments;importorg.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;importorg.apache.jmeter.protocol.java.sampler.JavaSamplerContext;importorg.apache.jmeter.samplers.SampleResult;publicclassSSEJavaSamplerextends AbstractJavaSamplerClient {@OverridepublicvoidsetupTest(JavaSamplerContext context){super.setupTest(context);}@Overridepublic Arguments getDefaultParameters(){
       Arguments args =new Arguments();
       args.addArgument("serverURL","${serverURL}");
       args.addArgument("reconnectionTime","${reconnectionTime}");
       args.addArgument("sleepTime","${sleepTime}");
       args.addArgument("option1","${option1}");
       args.addArgument("option2","${option2}");return args;}@Overridepublic SampleResult runTest(JavaSamplerContext jSC){

       SampleResult result =new SampleResult();boolean success =true;
       String[] sseParameters =new String[5];
       sseParameters[0]= jSC.getParameter("serverURL");
       sseParameters[1]= jSC.getParameter("reconnectionTime");
       sseParameters[2]= jSC.getParameter("sleepTime");
       sseParameters[3]= jSC.getParameter("option1");
       sseParameters[4]= jSC.getParameter("option2");

       SSERequest sseRequest =new SSERequest(sseParameters);

       result.sampleStart();
       result.sampleEnd();try{
           sseRequest.makeRequest(sseParameters);
           result.setSuccessful(success);
           result.setSamplerData(sseParameters[3]+":"+sseParameters[4]);
           result.setResponseData(sseRequest.respList,"866");}catch(InterruptedException iE){
           System.out.println("Interrupted exception "+iE);}return result;}@OverridepublicvoidteardownTest(JavaSamplerContext context){super.teardownTest(context);}}

 

The SSERequest java class creates an instance of SimpleEventHandler class and configures a connection to the server, which sends notifications, starts and stops receiving notifications and processes them. The code of this class is shown below.

 

importcom.launchdarkly.eventsource.EventSource;importcom.launchdarkly.eventsource.EventHandler;importjavax.json.Json;importjavax.json.JsonObject;importjavax.json.JsonReader;importjavax.json.JsonValue;importjava.io.StringReader;importjava.net.URI;importjava.util.concurrent.TimeUnit;publicclassSSERequest{private String sURL ="";private Integer rTime =new Integer(0);private Integer sTime =new Integer(0);private String opt1 ="";private String opt2 ="";public String respList ="";

   SSERequest(String[] sseParameters){
       sURL = sseParameters[0];
       rTime = Integer.parseInt(sseParameters[1]);
       sTime = Integer.parseInt(sseParameters[2]);
       opt1 = sseParameters[3];
       opt2 = sseParameters[4];}publicvoidmakeRequest(String[] args)throws InterruptedException{
       EventHandler eventHandler =new SimpleEventHandler();
       String url = sURL;
       EventSource.Builder builder =new EventSource.Builder(eventHandler, URI.create(url));

       EventSource eventSource = builder.build();
       eventSource.setReconnectionTimeMs(rTime);
       eventSource.start();
       TimeUnit.SECONDS.sleep(sTime);
       eventSource.close();
       System.out.println("Filtered output: \n");for(String respRecord:((SimpleEventHandler) eventHandler).respList){
           JsonReader jsonReader = Json.createReader(new StringReader(respRecord));
           JsonObject jsonObject = jsonReader.readObject();
           JsonValue title = jsonObject.getValue(opt1);
           JsonValue chType = jsonObject.getValue(opt2);
           respList = respList +chType.toString()+" : "+ title.toString()+"\n";}}}

 

The SimplerEventHandler class implements EventHandler interface, which is responsible for establishing the connection to the server and receiving notifications. The code of SimpleEventHandler class is shown below:

 

importcom.launchdarkly.eventsource.MessageEvent;importcom.launchdarkly.eventsource.EventHandler;importjava.util.ArrayList;publicclassSimpleEventHandlerimplements EventHandler{public ArrayList<String> respList =new ArrayList<String>();@OverridepublicvoidonOpen()throws Exception{
       System.out.println("The connection has been opened");}@OverridepublicvoidonClosed()throws Exception{
       System.out.println("The connection has been closed");}@OverridepublicvoidonMessage(String Event, MessageEvent messageEvent)throws Exception{
       respList.add(messageEvent.getData());
       System.out.println(messageEvent.getData());}@OverridepublicvoidonComment(String comment)throws Exception{
       System.out.println(comment);}@OverridepublicvoidonError(Throwable t ){
       System.out.println("Error "+t);}}

 

The jar file itself and the java source code are located together with this version of the JMeter script and can be downloaded from here. The JMeter script and Java request samplers are shown in the screenshot below. You can now run your test.

JMeter script and Java request samplers

 

That’s it! You are now ready to run your own load test for SSE services with JMeter.

START TESTING NOW

 

Related Resources

Back to top