123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- ---
- title: Load Testing With Gatling
- order: 51
- layout: page
- ---
-
- [[loading-testing-with-gatling]]
- Load testing with Gatling
- -------------------------
-
- http://gatling.io[Gatling] is a powerful tool for load testing. Compared
- to WebDriver/Selenium/TestBench, it doesn't render the actual content,
- but just simulates messages clients send to the server. The server
- doesn't know if the test tool actually does something with the
- responses, so it gives you perfectly valid numbers for your applications
- performance - on the server side. It scales very well, so you don' t
- need huge army of nodes to bombard your application under test. It can
- be used with Vaadin as such, but with these tips you hopefully get
- started easier.
-
- [[vaadin-tips-to-make-tests-more-stable-and-easier-to-create]]
- Vaadin tips to make tests more stable and easier to create
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- Gatling works with Vaadin "out of the box", but there are some obstacles
- you might face if you don't understand a bit how Vaadin communication
- works. E.g. plain recordings from standard Vaadin apps will not work
- properly.
-
- The communication that Vaadin's "thin client" in browser does with the
- server side has couple of checks that it does to improve robustness and
- security. One can simulate these with Gatling as well, by e.g.
- https://github.com/mstahv/v-quiz/blob/master/src/test/scala/loadtest/WebSocketVaadinSimulation.scala#L84[reading the XSRF prevention key into a variable] and passing the value
- https://github.com/mstahv/v-quiz/blob/master/src/test/scala/loadtest/WebSocketVaadinSimulation.scala#L95[in
- each response]. However, these setting can be disabled during load
- testing to make it easier to write and maintain your application. The
- effect for the scalability, when disabling or configuring these, should
- be negligible. Feel free to do these, but also remember to remove these
- "hacks" when building your production war file. Consider e.g. using
- separate maven profile and inject different parameters with it.
-
- [[disabling-xsrf-presentation-key]]
- Disabling XSRF presentation key
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
- The XSRF prevention can be disabled with following servlet parameter
- (or similar servlet 3 style parameter). NOTE, do not leave this for
- public apps in production.
-
- [source,xml]
- ....
- <context-param>
- <param-name>disable-xsrf-protection</param-name>
- <param-value>true</param-value>
- </context-param>
- ....
-
- [[disabling-syncid-happens-with-similar-parameter]]
- Disabling syncId happens with similar parameter
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
- [source,xml]
- ....
- <context-param>
- <param-name>syncIdCheck</param-name>
- <param-value>false</param-value>
- </context-param>
- ....
-
- If you want to do the above with Java Servlet 3.0 annotations, use the
- following:
-
- [source,java]
- ....
- initParams = {
- @WebInitParam(name = "disable-xsrf-protection", value = "true"),
- @WebInitParam(name = "syncIdCheck", value = "false")}
- ....
-
- [[using-debug-ids-in-communication]]
- Using debug ids in communication
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
- If you want to minimize the effort needed for maintaining your
- scalability tests, you probably want to do a small hack to the Vaadin
- communication mechanism. Normally Vaadin uses a incrementing session
- wide identifier to connect components to their "client side
- counterparts". Thus, if you add a one single component to your login
- screen, the whole load test simulation might be broken.
-
- You can set "id" for each component, but in recent Vaadin versions this
- id is no more used in the communication, but only assigned to
- client dom. This can still be enforced with a specially crafted
- extension to VaadinServlet. An implementation for the "competing tool" JMeter can be
- found at <<jmeter-vaadin-servlet-extension>>. This implementation works for Gatling users
- as well. Note that, it is suggested to do this only for load testing, and NOT
- for the production.
-
- [[ignoring-obsolete-static-file-requests]]
- Ignoring "obsolete" static file requests
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
- One of the most simplest and cheapest method to improve your apps
- scalability is to serve static files form a separate server or from a
- CDN provider. Thus it might make sense to leave loading those files away
- from your test script. If you do the script manually, just don't add
- requests for static files (js/css/images/...). If you recorded you test
- case, just remove these form the script. Check out the example project
- that only uses the required files.
-
- [[testing-with-websockets]]
- Testing with WebSockets
- ~~~~~~~~~~~~~~~~~~~~~~~
-
- If your want to load test your application with the most advanced
- communication channel, WebSockets, you can do that with Gatling as well.
- Using the recorder in this case doesn't work, but handcrafting the test
- case isn't that hard once you get started. The example app has a branch
- with WebSocket test case. With WebSocket communication it might also be
- handy to disable xsrf prevention and the so called "syncid".
-
- First two request are just normal http requests. The first gets the
- "host page" and also the initial state request is done with normal XHR.
- The difference to normal Vaadin communication is that it is to be sent
- to "/PUSH" address.
-
- After the initial state request you start to use the special WebSocket
- API in Gatling. There are lot of things to keep in mind with this
- fundamentally totally different kind of communication mechanism. Check
- out Gatling's generic websocket help for basic info.
-
- When you start handcrafting the WebSocket simulation, the easiest tool
- is probably Chrome's dev tools. With that you can open normal browser
- session and "sniff" the traffic that is sent to the server and also the
- messages that are received. An easy option is just to copy paste the
- payloads and possibly add some verification to ensure proper answers are
- received. The websocket example is built with special variable to work
- without disabling xsrf verification.
-
- If you are using random input in your load tests, something that is
- highly suggested for realistic numbers, you might end up in small
- problems. The message format, by Atmosphere, has a weird number and "|"
- in front of each message. That number tells the message length and it
- must really match the real message length. Create a simple helper
- function to calculate that if your input data length varies.
-
- [source,javascript]
- ....
- import io.gatling.core.session._
- import io.gatling.core.session.el._
-
- def atmoMessage(message: Expression[String]) = message.map(m => m.length + '|' + m)
-
- .sendText(atmoMessage("SomeMessage"))
- ....
-
- If (and when) you probably want to close the websocket connection
- cleanly, you need to notify the server with an extra xhr with a
- identifier given by the atmosphere framework. The key is the first
- message that the server sends when you connect to it.
-
- Check out this script for
- https://github.com/mstahv/v-quiz/blob/master/src/test/scala/loadtest/WebSocketVaadinSimulation.scala[an
- example using WebSocket] communication. It also saves XSRF prevention
- key to variable, so it don't need it to be disabled from the server.
-
- [[configuring-gatling-to-the-web-app-build]]
- Configuring Gatling to the Web app build
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- It is a good habit to keep your tests in the same projects as your
- actual application. Then you can easily verify your application still
- scales, after you have for example written a cryptic SQL query.
-
- Even better if you can make a Gatling script to be executed during
- builds to make. Gatling has http://gatling.io/docs/current/extensions/maven_plugin/[a
- maven plugin] that can do exactly this thing.
- https://github.com/mstahv/gatling-vaadin-example[The example project
- setup] executes a test during basic "mvn install". With similar setup in
- a real project, your CI server most likely saves results stored under
- target directory. This way it is easy to check it out afterwards how the
- performance of your application has evolved during its development.
-
- [[jmeter-vaadin-servlet-extension]]
- JMeter Vaadin Servlet extension
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- The implementation referred to in <<using-debug-ids-in-communication>>
-
- [source,java]
- ....
- package com.example.vaadin7jmeterservlet;
-
- import com.vaadin.server.ClientConnector;
- import com.vaadin.server.DeploymentConfiguration;
- import com.vaadin.server.ServiceException;
- import com.vaadin.server.VaadinRequest;
- import com.vaadin.server.VaadinService;
- import com.vaadin.server.VaadinServlet;
- import com.vaadin.server.VaadinServletService;
- import com.vaadin.server.VaadinSession;
- import com.vaadin.ui.Component;
-
- /**
- * @author Marcus Hellberg (marcus@vaadin.com)
- * Further modified by Johannes Tuikkala (johannes@vaadin.com)
- */
- public class JMeterServlet extends VaadinServlet {
- private static final long serialVersionUID = 898354532369443197L;
-
- public JMeterServlet() {
- System.setProperty(getPackageName() + "." + "disable-xsrf-protection",
- "true");
- }
-
- @Override
- protected VaadinServletService createServletService(
- DeploymentConfiguration deploymentConfiguration)
- throws ServiceException {
- JMeterService service = new JMeterService(this, deploymentConfiguration);
- service.init();
-
- return service;
- }
-
- private String getPackageName() {
- String pkgName;
- final Package pkg = this.getClass().getPackage();
- if (pkg != null) {
- pkgName = pkg.getName();
- } else {
- final String className = this.getClass().getName();
- pkgName = new String(className.toCharArray(), 0,
- className.lastIndexOf('.'));
- }
- return pkgName;
- }
-
- public static class JMeterService extends VaadinServletService {
- private static final long serialVersionUID = -5874716650679865909L;
-
- public JMeterService(VaadinServlet servlet,
- DeploymentConfiguration deploymentConfiguration)
- throws ServiceException {
- super(servlet, deploymentConfiguration);
- }
-
- @Override
- protected VaadinSession createVaadinSession(VaadinRequest request)
- throws ServiceException {
- return new JMeterSession(this);
- }
- }
-
- public static class JMeterSession extends VaadinSession {
- private static final long serialVersionUID = 4596901275146146127L;
-
- public JMeterSession(VaadinService service) {
- super(service);
- }
-
- @Override
- public String createConnectorId(ClientConnector connector) {
- if (connector instanceof Component) {
- Component component = (Component) connector;
- return component.getId() == null ? super
- .createConnectorId(connector) : component.getId();
- }
- return super.createConnectorId(connector);
- }
- }
- }
- ....
|