Tutorial #1 de Gatling: Instalación y Recorder

Dado que tenía que actualizar el post en el antiguo blog de Abstracta, decidí pasarlo para acá. Este es el primer paso del tutorial de Gatling. En este veremos de las primeras cosas a encarar al querer probar Gatling: instalación y recorder.

Realmente creo que Gatling es una muy buena opción para aprender a preparar pruebas de performance, así como también para cuando nos importa mantener nuestro código de pruebas limpio y legible, ya que el lenguaje Scala y el DSL de Gatling brindan ventajas muy claras para que los scripts sean mantenibles. Te dejo aquí una serie de pasos como para que puedas probar la herramienta y sacarte las dudas.

Instalación y ejecución con Gatling

Se baja de aquí, descomprime y se cuenta con dos ejecutables del tipo bat para Windows, y sh para basados en Unix. El directorio de instalación queda con las siguientes carpetas:

  • /results: Contiene los resultados en formato HTML.
  • /bin: Contiene los ejecutables de Gatling.
  • /target: Contiene los archivos de la compilación de los escenarios.
  • /conf: Archivos de configuración. 
  • /user-files: Acá estarán nuestros archivos, los scripts y archivos de datos.
  • /lib: Archivos jar de Gatling.

Recorder de Gatling

Al ejecutar gatling/bin/recorder.bat se abre una ventana como la siguiente, que nos permite configurar las opciones de grabación.

Algo que me resulta curioso es que en el sitio de Gatling ponen como ventaja que el Recorder sirve para varios navegadores, pero en realidad es una aplicación que funciona separada de los navegadores, con lo cual, hace falta configurar el browser para derivar los requests hacia el recorder (sí, igual que con JMeter). O sea, sí es cierto que funciona con cualquier navegador, pero en realidad funciona con cualquier elemento que envíe peticiones HTTP que se le pueda configurar manualmente el proxy.

Aspectos destacables del recorder

  • Podemos grabar con el recorder, funcionando este como un proxy (tal como lo hacen todas las herramientas de grabación de pruebas de performance) y podemos también generar un script a partir de un archivo HAR, lo cual es una sesión grabada con alguna herramienta como Fiddler o CharlesProxy o el propio navegador. Esto se puede seleccionar en el combo marcado en el cuadro rojo número 1. 
  • Al igual que las últimas versiones de JMeter, se puede trabajar con “follow redirect” (recuadro número 3) y “infer html resources” (recuadro número 4) de forma automática. Esto reduce la cantidad de líneas en el script y facilita la mantenibilidad, haciendo la prueba más real y menos costosa. El problema que trae aparejado es que necesita más procesamiento de la máquina generadora de carga, ya que debe realizar mucho más procesamiento. 
  • Se pueden agregar automáticamente verificaciones de las respuestas obtenidas (recuadro número 5). O sea, al momento de la grabación se guardan las respuestas en archivos TXT y en el script se agrega una validación que compara byte a byte la respuesta obtenida de las peticiones correspondientes con las que se obtuvieron en la grabación y se guardaron. Esto no es muy útil para sistemas dinámicos, sí para páginas estáticas, aunque imagino que debe agregar una sobrecarga en las máquinas generadoras de carga. 

Follow redirect: se manejan los mensajes con código de respuesta 3XX automáticamente, tal como lo hace el browser. O sea, si la respuesta es 302 – Moved temporarly, la respuesta tiene un header llamado “location” que indica la URL a donde hay que ir a buscar el recurso solicitado, y si la opción “follow redirect” está habilitada el mismo motor de ejecución de la herramienta hará el pedido correspondiente en forma adecuada. Si esto no está habilitado, entonces sería necesario tener otra invocación en el script, y muchas veces es necesario correlacionar variables en caso que esa URL maneje parámetros.

Infer html resources: también en forma automática, se analiza el HTML de una respuesta, se buscan los recursos embebidos (como ser imágenes, archivos CSS o JavaScript) y se invocan las peticiones correspondientes. Si esto no está habilitado, entonces estos pedidos deberían estar explícitos en el script. Esto lo he visto muy útil por ejemplo si tenemos un test case en el que se compra un producto en un sitio de e-commerce, primero se busca el producto, y en ese script parametrizamos la palabra clave de búsqueda; en este caso el resultado de cada búsqueda traerá una lista de productos diferentes, entonces las imágenes que se soliciten en cada caso serán diferentes (si se busca “macbook” traerá imágenes de computadoras Mac, y si se busca “cellphone” traerá imágenes de distintos celulares). Entonces, el hecho que los recursos embebidos se pidan en forma automática realmente simplifica y mejora la veracidad de la prueba.

Una vez que todo está configurado, se presiona START (en la imagen, recuadro número 6). Esto significa que hay un socket en el puerto 8000 (o el que se configure en el input del recuadro número 2 de la imagen) escuchando para funcionar como proxy. Para poder capturar las peticiones que realiza el browser, es necesario configurar el proxy del browser a localhost en el puerto 8000 (o el puerto que se haya configurado en el Recorder de Gatling).

Yo lo que suelo hacer para facilitar el cambio entre grabar y no grabar, es instalar alguna extensión del browser para manejar las configuraciones de proxy. En el caso de Chrome, que es el navegador que suelo utilizar actualmente, utilizo SwitchySharp. Entonces, configuro una vez sola y luego con un solo clic paso de grabar a conexión sin proxy y viceversa.

TL;DR

Entonces, por lo general lo único que hay que hacer es abrir el Recorder, poner el nombre con el que grabar el script, presionar Start, y configurar el browser para que utilice ese proxy, y ejecutar los pasos del caso de prueba.

Ejemplo de grabación con Gatling

Me definí el siguiente ejemplo para grabar la prueba:

  1. Acceder a opencart.abstracta.us.
  2. Introducir el texto “macbook” en el campo de búsqueda y presionar el botón de búsqueda.
  3. Acceder al primer producto que aparece en la lista para ver sus detalles.

Mientras uno va grabando tiene la posibilidad de ir insertando comentarios. Acá a mí lo que me resulta útil es ir identificando qué paso de mi caso de prueba voy ejecutando, algo descriptivo en lenguaje natural, para que luego sea más fácil identificar lo que hace el script en cada línea. En la siguiente imagen se puede ver un ejemplo grabando sobre un sitio de prueba, se puede ver cómo el Recorder va mostrando todos los requests que va capturando, y un TAG que agregué al que le puse “Paso 2 – realizar búsqueda”.

Al finalizar todos los pasos del script uno presiona el botón “Stop & Save” y se genera el script en la carpeta indicada.

La semana que viene continúo con el tutorial, viendo cómo editar el script guardado, incluso algunas recomendaciones para armar un buen entorno de trabajo.

Otras referencias a Gatling en Español:

One thought on “Tutorial #1 de Gatling: Instalación y Recorder

  1. Osvaldo Zamora says:

    Solicito de su apoyo ya que al ejecutar el grabador de Gatling me envia el siguiente error:

    GATLING_HOME is set to “C:\Gatling\gatling-charts-highcharts-bundle-3.9.3-bundle\gatling-charts-highcharts-bundle-3.9.3”
    JAVA = “C:\Program Files (x86)\Java\jdk1.8.0_202\\bin\java.exe”
    GATLING_HOME is set to C:\Gatling\gatling-charts-highcharts-bundle-3.9.3-bundle\gatling-charts-highcharts-bundle-3.9.3
    java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at io.gatling.plugin.util.ForkMain.runMain(ForkMain.java:67)
    at io.gatling.plugin.util.ForkMain.main(ForkMain.java:35)
    Caused by: java.lang.OutOfMemoryError: unable to create new native thread
    at java.lang.Thread.start0(Native Method)
    at java.lang.Thread.start(Thread.java:717)
    at sun.awt.AWTAutoShutdown.activateBlockerThread(AWTAutoShutdown.java:347)
    at sun.awt.AWTAutoShutdown.setToolkitBusy(AWTAutoShutdown.java:262)
    at sun.awt.AWTAutoShutdown.notifyToolkitThreadBusy(AWTAutoShutdown.java:145)
    at sun.awt.windows.WToolkit.(WToolkit.java:254)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at java.lang.Class.newInstance(Class.java:442)
    at java.awt.Toolkit$2.run(Toolkit.java:873)
    at java.awt.Toolkit$2.run(Toolkit.java:855)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.awt.Toolkit.getDefaultToolkit(Toolkit.java:854)
    at sun.java2d.d3d.D3DGraphicsDevice.(D3DGraphicsDevice.java:65)
    at sun.awt.Win32GraphicsEnvironment.makeScreenDevice(Win32GraphicsEnvironment.java:214)
    at sun.java2d.SunGraphicsEnvironment.getScreenDevices(SunGraphicsEnvironment.java:140)
    at sun.awt.Win32GraphicsEnvironment.getDefaultScreenDevice(Win32GraphicsEnvironment.java:97)
    at java.awt.Window.initGC(Window.java:476)
    at java.awt.Window.init(Window.java:495)
    at java.awt.Window.(Window.java:436)
    at java.awt.Frame.(Frame.java:446)
    at java.awt.Frame.(Frame.java:404)
    at javax.swing.JFrame.(JFrame.java:213)
    at scala.swing.Frame$$anon$1.(RichWindow.scala:82)
    at scala.swing.Frame.peer$lzycompute(RichWindow.scala:82)
    at scala.swing.Frame.peer(RichWindow.scala:82)
    at scala.swing.Frame.peer(RichWindow.scala:81)
    at scala.swing.UIElement$.scala$swing$UIElement$$cache(UIElement.scala:25)
    at scala.swing.UIElement.$init$(UIElement.scala:83)
    at scala.swing.Window.(Window.scala:28)
    at scala.swing.Frame.(RichWindow.scala:81)
    at scala.swing.MainFrame.(MainFrame.scala:19)
    at io.gatling.recorder.ui.swing.frame.ConfigurationFrame.(ConfigurationFrame.scala:48)
    at io.gatling.recorder.ui.swing.SwingFrontEnd.configurationFrame$lzycompute(SwingFrontEnd.scala:33)
    at io.gatling.recorder.ui.swing.SwingFrontEnd.configurationFrame(SwingFrontEnd.scala:33)
    at io.gatling.recorder.ui.swing.SwingFrontEnd.init(SwingFrontEnd.scala:95)
    at io.gatling.recorder.controller.RecorderController.(RecorderController.scala:46)
    at io.gatling.recorder.GatlingRecorder$.initRecorder(GatlingRecorder.scala:39)
    at io.gatling.recorder.GatlingRecorder$.$anonfun$fromArgs$1(GatlingRecorder.scala:31)
    at scala.Option.map(Option.scala:242)
    at io.gatling.recorder.GatlingRecorder$.fromArgs(GatlingRecorder.scala:31)
    at io.gatling.recorder.GatlingRecorder$.main(GatlingRecorder.scala:27)
    at io.gatling.recorder.GatlingRecorder.main(GatlingRecorder.scala)
    … 6 more
    Exception in thread “main” io.gatling.plugin.util.Fork$ForkException
    at io.gatling.plugin.util.Fork.run(Fork.java:213)
    at io.gatling.bundle.commands.RecorderCommand.run(RecorderCommand.scala:44)
    at io.gatling.bundle.RecorderCLI$.main(RecorderCLI.scala:46)
    at io.gatling.bundle.RecorderCLI.main(RecorderCLI.scala)

Leave a Reply

Your email address will not be published. Required fields are marked *