You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jmeter.apache.org by pm...@apache.org on 2019/10/03 18:52:25 UTC

[jmeter] branch master updated: Added simple tests InfluxdbBackendListenerClientSpec (#509)

This is an automated email from the ASF dual-hosted git repository.

pmouawad pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jmeter.git


The following commit(s) were added to refs/heads/master by this push:
     new 9143129  Added simple tests InfluxdbBackendListenerClientSpec (#509)
9143129 is described below

commit 91431299da490891a338f4f40326c8645f570c39
Author: Graham Russell <gr...@ham1.co.uk>
AuthorDate: Thu Oct 3 19:52:21 2019 +0100

    Added simple tests InfluxdbBackendListenerClientSpec (#509)
    
    * Added simple tests InfluxdbBackendListenerClientSpec
    
    * Formatting/whitespace/JavaDoc,simplified code, reduced visibility,
    extracted methods and added guard clauses
---
 .../visualizers/backend/BackendListener.java       |  73 ++---
 .../backend/BackendListenerContext.java            | 120 +++-----
 .../influxdb/InfluxdbBackendListenerClient.java    | 336 +++++++++++----------
 .../InfluxdbBackendListenerClientSpec.groovy       |  50 +++
 4 files changed, 297 insertions(+), 282 deletions(-)

diff --git a/src/components/src/main/java/org/apache/jmeter/visualizers/backend/BackendListener.java b/src/components/src/main/java/org/apache/jmeter/visualizers/backend/BackendListener.java
index ab703d3..1b4c29f 100644
--- a/src/components/src/main/java/org/apache/jmeter/visualizers/backend/BackendListener.java
+++ b/src/components/src/main/java/org/apache/jmeter/visualizers/backend/BackendListener.java
@@ -45,11 +45,12 @@ import org.slf4j.LoggerFactory;
 
 /**
  * Async Listener that delegates SampleResult handling to implementations of {@link BackendListenerClient}
+ *
  * @since 2.13
  */
-public class BackendListener extends AbstractTestElement
-    implements Backend, Serializable, SampleListener,
-        TestStateListener, NoThreadClone, Remoteable {
+public class BackendListener
+        extends AbstractTestElement
+        implements Backend, Serializable, SampleListener, TestStateListener, NoThreadClone, Remoteable {
 
     private static final class ListenerClientData {
         private BackendListenerClient client;
@@ -70,9 +71,7 @@ public class BackendListener extends AbstractTestElement
      */
     public static final String CLASSNAME = "classname";
 
-    /**
-     * Queue size
-     */
+    /** Queue size */
     public static final String QUEUE_SIZE = "QUEUE_SIZE";
 
     /**
@@ -106,12 +105,9 @@ public class BackendListener extends AbstractTestElement
     // Name of the test element. Set up by testStarted().
     private transient String myName;
 
-    // Holds listenerClientData for this test element
     private transient ListenerClientData listenerClientData;
 
-    /**
-     * Create a BackendListener.
-     */
+    /** Create a BackendListener. */
     public BackendListener() {
         setArguments(new Arguments());
     }
@@ -146,10 +142,6 @@ public class BackendListener extends AbstractTestElement
         return Thread.currentThread().getName() + "@" + Integer.toHexString(hashCode()) + "-" + getName();
     }
 
-
-    /* (non-Javadoc)
-     * @see org.apache.jmeter.samplers.SampleListener#sampleOccurred(org.apache.jmeter.samplers.SampleEvent)
-     */
     @Override
     public void sampleOccurred(SampleEvent event) {
         Arguments args = getArguments();
@@ -163,12 +155,12 @@ public class BackendListener extends AbstractTestElement
             return;
         }
         try {
-            if (!listenerClientData.queue.offer(sr)){ // we failed to add the element first time
+            if (!listenerClientData.queue.offer(sr)) { // we failed to add the element first time
                 listenerClientData.queueWaits.add(1L);
                 long t1 = System.nanoTime();
                 listenerClientData.queue.put(sr);
                 long t2 = System.nanoTime();
-                listenerClientData.queueWaitTime.add(t2-t1);
+                listenerClientData.queueWaitTime.add(t2 - t1);
             }
         } catch (Exception err) {
             log.error("sampleOccurred, failed to queue the sample", err);
@@ -183,7 +175,8 @@ public class BackendListener extends AbstractTestElement
         private final ListenerClientData listenerClientData;
         private final BackendListenerContext context;
         private final BackendListenerClient backendListenerClient;
-        private Worker(BackendListenerClient backendListenerClient, Arguments arguments, ListenerClientData listenerClientData){
+
+        private Worker(BackendListenerClient backendListenerClient, Arguments arguments, ListenerClientData listenerClientData) {
             this.listenerClientData = listenerClientData;
             // Allow BackendListenerClient implementations to get access to test element name
             arguments.addArgument(TestElement.NAME, getName());
@@ -213,7 +206,7 @@ public class BackendListener extends AbstractTestElement
                         }
                         // try to process as many as possible
                         // The == comparison is not a mistake
-                        while (!(endOfLoop = sampleResult == FINAL_SAMPLE_RESULT) && sampleResult != null ) {
+                        while (!(endOfLoop = sampleResult == FINAL_SAMPLE_RESULT) && sampleResult != null) {
                             sampleResults.add(sampleResult);
                             if (isDebugEnabled) {
                                 log.debug("Thread: {} polling from queue: {}", Thread.currentThread().getName(),
@@ -231,7 +224,7 @@ public class BackendListener extends AbstractTestElement
                                     sampleResult == null);
                         }
                         sendToListener(backendListenerClient, context, sampleResults);
-                        if(!endOfLoop) {
+                        if (!endOfLoop) {
                             LockSupport.parkNanos(100);
                         }
                     }
@@ -249,14 +242,15 @@ public class BackendListener extends AbstractTestElement
 
     /**
      * Send sampleResults to {@link BackendListenerClient}
+     *
      * @param backendListenerClient {@link BackendListenerClient}
-     * @param context {@link BackendListenerContext}
-     * @param sampleResults List of {@link SampleResult}
+     * @param context               {@link BackendListenerContext}
+     * @param sampleResults         List of {@link SampleResult}
      */
-    static void sendToListener(
-            final BackendListenerClient backendListenerClient,
-            final BackendListenerContext context,
-            final List<SampleResult> sampleResults) {
+    private static void sendToListener(
+            BackendListenerClient backendListenerClient,
+            BackendListenerContext context,
+            List<SampleResult> sampleResults) {
         if (!sampleResults.isEmpty()) {
             backendListenerClient.handleSampleResults(sampleResults, context);
             sampleResults.clear();
@@ -265,10 +259,11 @@ public class BackendListener extends AbstractTestElement
 
     /**
      * Returns reference to {@link BackendListener}
+     *
      * @param clientClass {@link BackendListenerClient} client class
      * @return BackendListenerClient reference.
      */
-    static BackendListenerClient createBackendListenerClientImpl(Class<?> clientClass) {
+    private static BackendListenerClient createBackendListenerClientImpl(Class<?> clientClass) {
         if (clientClass == null) { // failed to initialise the class
             return new ErrorBackendListenerClient();
         }
@@ -304,12 +299,12 @@ public class BackendListener extends AbstractTestElement
         synchronized (LOCK) {
             myName = getName();
             listenerClientData = queuesByTestElementName.get(myName);
-            if (listenerClientData == null){
+            if (listenerClientData == null) {
                 // We need to do this to ensure in Distributed testing
                 // that only 1 instance of BackendListenerClient is used
                 clientClass = initClass(); // may be null
                 BackendListenerClient backendListenerClient = createBackendListenerClientImpl(clientClass);
-                BackendListenerContext context = new BackendListenerContext((Arguments)getArguments().clone());
+                BackendListenerContext context = new BackendListenerContext((Arguments) getArguments().clone());
 
                 listenerClientData = new ListenerClientData();
                 listenerClientData.queue = new ArrayBlockingQueue<>(queueSize);
@@ -330,7 +325,7 @@ public class BackendListener extends AbstractTestElement
                 try {
                     backendListenerClient.setupTest(context);
                 } catch (Exception e) {
-                    throw new java.lang.IllegalStateException("Failed calling setupTest", e);
+                    throw new IllegalStateException("Failed calling setupTest", e);
                 }
                 queuesByTestElementName.put(myName, listenerClientData);
             }
@@ -353,9 +348,9 @@ public class BackendListener extends AbstractTestElement
             if (log.isDebugEnabled()) {
                 log.debug("testEnded called on instance {}#{}", myName, listenerClientDataForName.instanceCount);
             }
-            if(listenerClientDataForName != null) {
+            if (listenerClientDataForName != null) {
                 listenerClientDataForName.instanceCount--;
-                if (listenerClientDataForName.instanceCount > 0){
+                if (listenerClientDataForName.instanceCount > 0) {
                     // Not the last instance of myName
                     return;
                 } else {
@@ -368,7 +363,7 @@ public class BackendListener extends AbstractTestElement
         try {
             listenerClientData.queue.put(FINAL_SAMPLE_RESULT);
         } catch (Exception ex) {
-            log.warn("testEnded() with exception: {}", ex, ex);
+            log.warn("testEnded() with exception: {}", ex.getMessage(), ex);
         }
         if (listenerClientData.queueWaits.longValue() > 0) {
             log.warn(
@@ -380,7 +375,7 @@ public class BackendListener extends AbstractTestElement
             BackendListenerContext context = new BackendListenerContext(getArguments());
             listenerClientData.client.teardownTest(context);
         } catch (Exception e) {
-            throw new java.lang.IllegalStateException("Failed calling teardownTest", e);
+            throw new IllegalStateException("Failed calling teardownTest", e);
         }
     }
 
@@ -409,17 +404,11 @@ public class BackendListener extends AbstractTestElement
         }
     }
 
-    /* (non-Javadoc)
-     * @see org.apache.jmeter.samplers.SampleListener#sampleStarted(org.apache.jmeter.samplers.SampleEvent)
-     */
     @Override
     public void sampleStarted(SampleEvent e) {
         // NOOP
     }
 
-    /* (non-Javadoc)
-     * @see org.apache.jmeter.samplers.SampleListener#sampleStopped(org.apache.jmeter.samplers.SampleEvent)
-     */
     @Override
     public void sampleStopped(SampleEvent e) {
         // NOOP
@@ -429,8 +418,7 @@ public class BackendListener extends AbstractTestElement
      * Set the arguments (parameters) for the BackendListenerClient to be executed
      * with.
      *
-     * @param args
-     *            the new arguments. These replace any existing arguments.
+     * @param args the new arguments. These replace any existing arguments.
      */
     public void setArguments(Arguments args) {
         // Bug 59173 - don't save new default argument
@@ -452,8 +440,7 @@ public class BackendListener extends AbstractTestElement
     /**
      * Sets the Classname of the BackendListenerClient object
      *
-     * @param classname
-     *            the new Classname value
+     * @param classname the new Classname value
      */
     public void setClassname(String classname) {
         setProperty(CLASSNAME, classname);
diff --git a/src/components/src/main/java/org/apache/jmeter/visualizers/backend/BackendListenerContext.java b/src/components/src/main/java/org/apache/jmeter/visualizers/backend/BackendListenerContext.java
index aa3803d..ae1438c 100644
--- a/src/components/src/main/java/org/apache/jmeter/visualizers/backend/BackendListenerContext.java
+++ b/src/components/src/main/java/org/apache/jmeter/visualizers/backend/BackendListenerContext.java
@@ -29,41 +29,37 @@ import org.slf4j.LoggerFactory;
  * BackendListenerContext is used to provide context information to a
  * BackendListenerClient implementation. This currently consists of the
  * initialization parameters which were specified in the GUI.
+ * <p>
+ * All of the methods in this class are currently read-only. If update methods
+ * are included in the future, they should be defined so that a single instance
+ * of {@link BackendListenerContext} can be associated with each thread.
+ * Therefore, no synchronization should be needed. The same instance should
+ * be used for all calls to setupTest, runTest, and teardownTest.
+ *
  * @since 2.13
  */
 public class BackendListenerContext {
-    /*
-     * Implementation notes:
-     *
-     * All of the methods in this class are currently read-only. If update
-     * methods are included in the future, they should be defined so that a
-     * single instance of BackendListenerContext can be associated with each thread.
-     * Therefore, no synchronization should be needed. The same instance should
-     * be used for the call to setupTest, all calls to runTest, and the call to
-     * teardownTest.
-     */
 
     private static final Logger log = LoggerFactory.getLogger(BackendListenerContext.class);
 
-    /**
-     * Map containing the initialization parameters for the BackendListenerClient.
-     */
+    /** The initialization parameters. */
     private final Map<String, String> params;
 
-    /**
-     * @param args
-     *            the initialization parameters.
-     */
+    /** @param args the initialization parameters. */
     public BackendListenerContext(Arguments args) {
         this.params = args.getArgumentsAsMap();
     }
 
+    /** @param params the initialization parameters. */
+    public BackendListenerContext(Map<String, String> params) {
+        this.params = params;
+    }
+
     /**
      * Determine whether or not a value has been specified for the parameter
      * with this name.
      *
-     * @param name
-     *            the name of the parameter to test
+     * @param name the name of the parameter to test
      * @return true if the parameter value has been specified, false otherwise.
      */
     public boolean containsParameter(String name) {
@@ -71,11 +67,10 @@ public class BackendListenerContext {
     }
 
     /**
-     * Get an iterator of the parameter names. Each entry in the Iterator is a
-     * String.
+     * Get an iterator of the parameter names.
      *
-     * @return an Iterator of Strings listing the names of the parameters which
-     *         have been specified for this test.
+     * @return an Iterator of Strings of the names of the parameters which
+     * have been specified for this test.
      */
     public Iterator<String> getParameterNamesIterator() {
         return params.keySet().iterator();
@@ -85,10 +80,8 @@ public class BackendListenerContext {
      * Get the value of a specific parameter as a String, or null if the value
      * was not specified.
      *
-     * @param name
-     *            the name of the parameter whose value should be retrieved
-     * @return the value of the parameter, or null if the value was not
-     *         specified
+     * @param name the name of the parameter whose value should be retrieved
+     * @return the value of the parameter, or null if the value was not specified
      */
     public String getParameter(String name) {
         return getParameter(name, null);
@@ -98,13 +91,11 @@ public class BackendListenerContext {
      * Get the value of a specified parameter as a String, or return the
      * specified default value if the value was not specified.
      *
-     * @param name
-     *            the name of the parameter whose value should be retrieved
-     * @param defaultValue
-     *            the default value to return if the value of this parameter was
-     *            not specified
+     * @param name         the name of the parameter whose value should be retrieved
+     * @param defaultValue the default value to return if the value of this parameter was
+     *                     not specified
      * @return the value of the parameter, or the default value if the parameter
-     *         was not specified
+     * was not specified
      */
     public String getParameter(String name, String defaultValue) {
         if (params == null || !params.containsKey(name)) {
@@ -116,21 +107,14 @@ public class BackendListenerContext {
     /**
      * Get the value of a specified parameter as an integer. An exception will
      * be thrown if the parameter is not specified or if it is not an integer.
-     * The value may be specified in decimal, hexadecimal, or octal, as defined
-     * by Integer.decode().
      *
-     * @param name
-     *            the name of the parameter whose value should be retrieved
+     * @param name the name of the parameter whose value should be retrieved
      * @return the value of the parameter
-     *
-     * @throws IllegalArgumentException
-     *             if no value defined
-     * @throws NumberFormatException
-     *             if the parameter is not specified or is not an integer
-     *
-     * @see java.lang.Integer#decode(java.lang.String)
+     * @throws IllegalArgumentException if no value defined
+     * @throws NumberFormatException    if the parameter is not specified or is not an integer
+     * @see Integer#parseInt(String)
      */
-    public int getIntParameter(String name)  {
+    public int getIntParameter(String name) {
         if (params == null || !params.containsKey(name)) {
             throw new IllegalArgumentException("No value for parameter named '" + name + "'.");
         }
@@ -141,19 +125,14 @@ public class BackendListenerContext {
     /**
      * Get the value of a specified parameter as an integer, or return the
      * specified default value if the value was not specified or is not an
-     * integer. A warning will be logged if the value is not an integer. The
-     * value may be specified in decimal, hexadecimal, or octal, as defined by
-     * Integer.decode().
+     * integer. A warning will be logged if the value is not an integer.
      *
-     * @param name
-     *            the name of the parameter whose value should be retrieved
-     * @param defaultValue
-     *            the default value to return if the value of this parameter was
-     *            not specified
+     * @param name         the name of the parameter whose value should be retrieved
+     * @param defaultValue the default value to return if the value of this parameter was
+     *                     not specified
      * @return the value of the parameter, or the default value if the parameter
-     *         was not specified
-     *
-     * @see java.lang.Integer#decode(java.lang.String)
+     * was not specified
+     * @see Integer#parseInt(String)
      */
     public int getIntParameter(String name, int defaultValue) {
         if (params == null || !params.containsKey(name)) {
@@ -172,18 +151,12 @@ public class BackendListenerContext {
 
     /**
      * Get the value of a specified parameter as a long. An exception will be
-     * thrown if the parameter is not specified or if it is not a long. The
-     * value may be specified in decimal, hexadecimal, or octal, as defined by
-     * Long.decode().
+     * thrown if the parameter is not specified or if it is not a long.
      *
-     * @param name
-     *            the name of the parameter whose value should be retrieved
+     * @param name the name of the parameter whose value should be retrieved
      * @return the value of the parameter
-     *
-     * @throws NumberFormatException
-     *             if the parameter is not specified or is not a long
-     *
-     * @see Long#decode(String)
+     * @throws NumberFormatException if the parameter is not specified or is not a long
+     * @see Long#parseLong(String)
      */
     public long getLongParameter(String name) {
         if (params == null || !params.containsKey(name)) {
@@ -199,14 +172,11 @@ public class BackendListenerContext {
      * will be logged if the value is not a long. The value may be specified in
      * decimal, hexadecimal, or octal, as defined by Long.decode().
      *
-     * @param name
-     *            the name of the parameter whose value should be retrieved
-     * @param defaultValue
-     *            the default value to return if the value of this parameter was
-     *            not specified
+     * @param name         the name of the parameter whose value should be retrieved
+     * @param defaultValue the default value to return if the value of this parameter was
+     *                     not specified
      * @return the value of the parameter, or the default value if the parameter
-     *         was not specified
-     *
+     * was not specified
      * @see Long#decode(String)
      */
     public long getLongParameter(String name, long defaultValue) {
@@ -224,9 +194,9 @@ public class BackendListenerContext {
     }
 
     /**
-     * @param name Parameter name
+     * @param name         Parameter name
      * @param defaultValue Default value used if name is not in params
-     * @return boolean
+     * @return boolean the value of the parameter in the map, or the default value
      */
     public boolean getBooleanParameter(String name, boolean defaultValue) {
         if (params == null || !params.containsKey(name)) {
diff --git a/src/components/src/main/java/org/apache/jmeter/visualizers/backend/influxdb/InfluxdbBackendListenerClient.java b/src/components/src/main/java/org/apache/jmeter/visualizers/backend/influxdb/InfluxdbBackendListenerClient.java
index 212fe1b..ace1a22 100644
--- a/src/components/src/main/java/org/apache/jmeter/visualizers/backend/influxdb/InfluxdbBackendListenerClient.java
+++ b/src/components/src/main/java/org/apache/jmeter/visualizers/backend/influxdb/InfluxdbBackendListenerClient.java
@@ -38,6 +38,7 @@ import org.apache.jmeter.samplers.SampleResult;
 import org.apache.jmeter.util.JMeterUtils;
 import org.apache.jmeter.visualizers.backend.AbstractBackendListenerClient;
 import org.apache.jmeter.visualizers.backend.BackendListenerContext;
+import org.apache.jmeter.visualizers.backend.ErrorMetric;
 import org.apache.jmeter.visualizers.backend.SamplerMetric;
 import org.apache.jmeter.visualizers.backend.UserMetric;
 import org.slf4j.Logger;
@@ -46,6 +47,7 @@ import org.slf4j.LoggerFactory;
 /**
  * Implementation of {@link AbstractBackendListenerClient} to write in an InfluxDB using
  * custom schema
+ *
  * @since 3.2
  */
 public class InfluxdbBackendListenerClient extends AbstractBackendListenerClient implements Runnable {
@@ -96,6 +98,7 @@ public class InfluxdbBackendListenerClient extends AbstractBackendListenerClient
     private static final String SEPARATOR = ";"; //$NON-NLS-1$
     private static final Object LOCK = new Object();
     private static final Map<String, String> DEFAULT_ARGS = new LinkedHashMap<>();
+
     static {
         DEFAULT_ARGS.put("influxdbMetricsSender", HttpMetricsSender.class.getName());
         DEFAULT_ARGS.put("influxdbUrl", "http://host_to_change:8086/write?db=jmeter");
@@ -117,8 +120,7 @@ public class InfluxdbBackendListenerClient extends AbstractBackendListenerClient
     private Map<String, Float> allPercentiles;
     private String testTitle;
     private String testTags;
-    // Name of the application tested
-    private String application = "";
+    private String applicationName = "";
     private String userTag = "";
     private InfluxdbMetricsSender influxdbMetricsManager;
 
@@ -134,13 +136,10 @@ public class InfluxdbBackendListenerClient extends AbstractBackendListenerClient
         sendMetrics();
     }
 
-    /**
-     * Send metrics
-     */
-    protected void sendMetrics() {
+    private void sendMetrics() {
 
         synchronized (LOCK) {
-            for (Map.Entry<String, SamplerMetric> entry : getMetricsInfluxdbPerSampler().entrySet()) {
+            for (Map.Entry<String, SamplerMetric> entry : metricsPerSampler.entrySet()) {
                 SamplerMetric metric = entry.getValue();
                 if (entry.getKey().equals(CUMULATED_METRICS)) {
                     addCumulatedMetrics(metric);
@@ -155,7 +154,7 @@ public class InfluxdbBackendListenerClient extends AbstractBackendListenerClient
         UserMetric userMetrics = getUserMetrics();
         // For JMETER context
         StringBuilder tag = new StringBuilder(80);
-        tag.append(TAG_APPLICATION).append(application);
+        tag.append(TAG_APPLICATION).append(applicationName);
         tag.append(TAG_TRANSACTION).append("internal");
         tag.append(userTag);
         StringBuilder field = new StringBuilder(80);
@@ -172,124 +171,120 @@ public class InfluxdbBackendListenerClient extends AbstractBackendListenerClient
 
     @FunctionalInterface
     private interface PercentileProvider {
-        public double getPercentileValue(double percentile);
+        double getPercentileValue(double percentile);
     }
-    /**
-     * Add request metrics to metrics manager.
-     *
-     * @param metric
-     *            {@link SamplerMetric}
-     */
+
     private void addMetrics(String transaction, SamplerMetric metric) {
-        // FOR ALL STATUS
-        addMetric(transaction, metric.getTotal(), metric.getSentBytes(), metric.getReceivedBytes(), TAG_ALL, metric.getAllMean(), metric.getAllMinTime(),
+        // ALL
+        addMetric(transaction, metric.getTotal(), metric.getSentBytes(), metric.getReceivedBytes(),
+                TAG_ALL, metric.getAllMean(), metric.getAllMinTime(),
                 metric.getAllMaxTime(), allPercentiles.values(), metric::getAllPercentile);
-        // FOR OK STATUS
-        addMetric(transaction, metric.getSuccesses(), null, null, TAG_OK, metric.getOkMean(), metric.getOkMinTime(),
+        // OK
+        addMetric(transaction, metric.getSuccesses(), null, null,
+                TAG_OK, metric.getOkMean(), metric.getOkMinTime(),
                 metric.getOkMaxTime(), okPercentiles.values(), metric::getOkPercentile);
-        // FOR KO STATUS
-        addMetric(transaction, metric.getFailures(), null, null, TAG_KO, metric.getKoMean(), metric.getKoMinTime(),
+        // KO
+        addMetric(transaction, metric.getFailures(), null, null,
+                TAG_KO, metric.getKoMean(), metric.getKoMinTime(),
                 metric.getKoMaxTime(), koPercentiles.values(), metric::getKoPercentile);
 
-        metric.getErrors().forEach((error, count) -> addErrorMetric(transaction, error.getResponseCode(),
-                    error.getResponseMessage(), count));
+        metric.getErrors().forEach((err, count) -> addErrorMetric(transaction, err, count));
     }
 
-    private void addErrorMetric(String transaction, String responseCode, String responseMessage, long count) {
-        if (count > 0) {
-            StringBuilder tag = new StringBuilder(70);
-            tag.append(TAG_APPLICATION).append(application);
-            tag.append(TAG_TRANSACTION).append(transaction);
-            tag.append(TAG_RESPONSE_CODE).append(AbstractInfluxdbMetricsSender.tagToStringValue(responseCode));
-            tag.append(TAG_RESPONSE_MESSAGE).append(AbstractInfluxdbMetricsSender.tagToStringValue(responseMessage));
-            tag.append(userTag);
-
-            StringBuilder field = new StringBuilder(30);
-            field.append(METRIC_COUNT).append(count);
-            influxdbMetricsManager.addMetric(measurement, tag.toString(), field.toString());
+    private void addErrorMetric(String transaction, ErrorMetric err, long count) {
+        if (count <= 0) {
+            return;
         }
+        StringBuilder tag = new StringBuilder(70);
+        tag.append(TAG_APPLICATION).append(applicationName);
+        tag.append(TAG_TRANSACTION).append(transaction);
+        tag.append(TAG_RESPONSE_CODE).append(AbstractInfluxdbMetricsSender.tagToStringValue(err.getResponseCode()));
+        tag.append(TAG_RESPONSE_MESSAGE).append(AbstractInfluxdbMetricsSender.tagToStringValue(err.getResponseMessage()));
+        tag.append(userTag);
+
+        StringBuilder field = new StringBuilder(30);
+        field.append(METRIC_COUNT).append(count);
+        influxdbMetricsManager.addMetric(measurement, tag.toString(), field.toString());
     }
 
     private void addMetric(String transaction, int count,
-            Long sentBytes, Long receivedBytes,
-            String statut, double mean, double minTime, double maxTime,
-            Collection<Float> pcts, PercentileProvider percentileProvider) {
-        if (count > 0) {
-            StringBuilder tag = new StringBuilder(95);
-            tag.append(TAG_APPLICATION).append(application);
-            tag.append(TAG_STATUS).append(statut);
-            tag.append(TAG_TRANSACTION).append(transaction);
-            tag.append(userTag);
-
-            StringBuilder field = new StringBuilder(80);
-            field.append(METRIC_COUNT).append(count);
-            if (!Double.isNaN(mean)) {
-                field.append(',').append(METRIC_AVG).append(mean);
-            }
-            if (!Double.isNaN(minTime)) {
-                field.append(',').append(METRIC_MIN).append(minTime);
-            }
-            if (!Double.isNaN(maxTime)) {
-                field.append(',').append(METRIC_MAX).append(maxTime);
-            }
-            if(sentBytes != null) {
-                field.append(',').append(METRIC_SENT_BYTES).append(sentBytes);
-            }
-            if(receivedBytes != null) {
-                field.append(',').append(METRIC_RECEIVED_BYTES).append(receivedBytes);
-            }
-            for (Float pct : pcts) {
-                field.append(',').append(METRIC_PCT_PREFIX).append(pct).append('=').append(
-                        percentileProvider.getPercentileValue(pct));
-            }
-            influxdbMetricsManager.addMetric(measurement, tag.toString(), field.toString());
+                           Long sentBytes, Long receivedBytes,
+                           String statut, double mean, double minTime, double maxTime,
+                           Collection<Float> pcts, PercentileProvider percentileProvider) {
+        if (count <= 0) {
+            return;
+        }
+        StringBuilder tag = new StringBuilder(95);
+        tag.append(TAG_APPLICATION).append(applicationName);
+        tag.append(TAG_STATUS).append(statut);
+        tag.append(TAG_TRANSACTION).append(transaction);
+        tag.append(userTag);
+
+        StringBuilder field = new StringBuilder(80);
+        field.append(METRIC_COUNT).append(count);
+        if (!Double.isNaN(mean)) {
+            field.append(',').append(METRIC_AVG).append(mean);
+        }
+        if (!Double.isNaN(minTime)) {
+            field.append(',').append(METRIC_MIN).append(minTime);
+        }
+        if (!Double.isNaN(maxTime)) {
+            field.append(',').append(METRIC_MAX).append(maxTime);
         }
+        if (sentBytes != null) {
+            field.append(',').append(METRIC_SENT_BYTES).append(sentBytes);
+        }
+        if (receivedBytes != null) {
+            field.append(',').append(METRIC_RECEIVED_BYTES).append(receivedBytes);
+        }
+        for (Float pct : pcts) {
+            field.append(',').append(METRIC_PCT_PREFIX).append(pct).append('=').append(
+                    percentileProvider.getPercentileValue(pct));
+        }
+        influxdbMetricsManager.addMetric(measurement, tag.toString(), field.toString());
     }
 
     private void addCumulatedMetrics(SamplerMetric metric) {
         int total = metric.getTotal();
-        if (total > 0) {
-            StringBuilder tag = new StringBuilder(70);
-            StringBuilder field = new StringBuilder(100);
-            Collection<Float> pcts = allPercentiles.values();
-            tag.append(TAG_APPLICATION).append(application);
-            tag.append(TAG_TRANSACTION).append(CUMULATED_METRICS);
-            tag.append(TAG_STATUS).append(CUMULATED_METRICS);
-            tag.append(userTag);
-
-            field.append(METRIC_COUNT).append(total);
-            field.append(',').append(METRIC_COUNT_ERROR).append(metric.getFailures());
-
-            if (!Double.isNaN(metric.getOkMean())) {
-                field.append(',').append(METRIC_AVG).append(Double.toString(metric.getOkMean()));
-            }
-            if (!Double.isNaN(metric.getOkMinTime())) {
-                field.append(',').append(METRIC_MIN).append(Double.toString(metric.getOkMinTime()));
-            }
-            if (!Double.isNaN(metric.getOkMaxTime())) {
-                field.append(',').append(METRIC_MAX).append(Double.toString(metric.getOkMaxTime()));
-            }
+        if (total <= 0) {
+            return;
+        }
+        StringBuilder tag = new StringBuilder(70);
+        StringBuilder field = new StringBuilder(100);
+        Collection<Float> pcts = allPercentiles.values();
+        tag.append(TAG_APPLICATION).append(applicationName);
+        tag.append(TAG_TRANSACTION).append(CUMULATED_METRICS);
+        tag.append(TAG_STATUS).append(CUMULATED_METRICS);
+        tag.append(userTag);
 
-            field.append(',').append(METRIC_HIT).append(metric.getHits());
-            field.append(',').append(METRIC_SENT_BYTES).append(metric.getSentBytes());
-            field.append(',').append(METRIC_RECEIVED_BYTES).append(metric.getReceivedBytes());
-            for (Float pct : pcts) {
-                field.append(',').append(METRIC_PCT_PREFIX).append(pct).append('=').append(Double.toString(metric.getAllPercentile(pct)));
-            }
-            influxdbMetricsManager.addMetric(measurement, tag.toString(), field.toString());
+        field.append(METRIC_COUNT).append(total);
+        field.append(',').append(METRIC_COUNT_ERROR).append(metric.getFailures());
+
+        if (!Double.isNaN(metric.getOkMean())) {
+            field.append(',').append(METRIC_AVG).append(Double.toString(metric.getOkMean()));
         }
+        if (!Double.isNaN(metric.getOkMinTime())) {
+            field.append(',').append(METRIC_MIN).append(Double.toString(metric.getOkMinTime()));
+        }
+        if (!Double.isNaN(metric.getOkMaxTime())) {
+            field.append(',').append(METRIC_MAX).append(Double.toString(metric.getOkMaxTime()));
+        }
+
+        field.append(',').append(METRIC_HIT).append(metric.getHits());
+        field.append(',').append(METRIC_SENT_BYTES).append(metric.getSentBytes());
+        field.append(',').append(METRIC_RECEIVED_BYTES).append(metric.getReceivedBytes());
+        for (Float pct : pcts) {
+            field.append(',').append(METRIC_PCT_PREFIX).append(pct).append('=').append(Double.toString(metric.getAllPercentile(pct)));
+        }
+        influxdbMetricsManager.addMetric(measurement, tag.toString(), field.toString());
     }
 
-    /**
-     * @return the samplersList
-     */
     public String getSamplersRegex() {
         return samplersRegex;
     }
 
     /**
-     * @param samplersList
-     *            the samplersList to set
+     * @param samplersList the samplersList to set
      */
     public void setSamplersList(String samplersList) {
         this.samplersRegex = samplersList;
@@ -314,83 +309,93 @@ public class InfluxdbBackendListenerClient extends AbstractBackendListenerClient
 
     @Override
     public void setupTest(BackendListenerContext context) throws Exception {
-        String influxdbMetricsSender = context.getParameter("influxdbMetricsSender");
-        String influxdbUrl = context.getParameter("influxdbUrl");
-        String influxdbToken = context.getParameter("influxdbToken");
         summaryOnly = context.getBooleanParameter("summaryOnly", false);
         samplersRegex = context.getParameter("samplersRegex", "");
-        application = AbstractInfluxdbMetricsSender.tagToStringValue(context.getParameter("application", ""));
-        measurement = AbstractInfluxdbMetricsSender
-                .tagToStringValue(context.getParameter("measurement", DEFAULT_MEASUREMENT));
+        applicationName = AbstractInfluxdbMetricsSender.tagToStringValue(
+                context.getParameter("application", ""));
+        measurement = AbstractInfluxdbMetricsSender.tagToStringValue(
+                context.getParameter("measurement", DEFAULT_MEASUREMENT));
         testTitle = context.getParameter("testTitle", "Test");
-        testTags = AbstractInfluxdbMetricsSender.tagToStringValue(context.getParameter("eventTags", ""));
-        String percentilesAsString = context.getParameter("percentiles", "");
-        String[] percentilesStringArray = percentilesAsString.split(SEPARATOR);
-        okPercentiles = new HashMap<>(percentilesStringArray.length);
-        koPercentiles = new HashMap<>(percentilesStringArray.length);
-        allPercentiles = new HashMap<>(percentilesStringArray.length);
-        DecimalFormat format = new DecimalFormat("0.##");
-        for (int i = 0; i < percentilesStringArray.length; i++) {
-            if (!StringUtils.isEmpty(percentilesStringArray[i].trim())) {
-                try {
-                    Float percentileValue = Float.valueOf(percentilesStringArray[i].trim());
-                    okPercentiles.put(AbstractInfluxdbMetricsSender.tagToStringValue(format.format(percentileValue)),
-                            percentileValue);
-                    koPercentiles.put(AbstractInfluxdbMetricsSender.tagToStringValue(format.format(percentileValue)),
-                            percentileValue);
-                    allPercentiles.put(AbstractInfluxdbMetricsSender.tagToStringValue(format.format(percentileValue)),
-                            percentileValue);
-
-                } catch (Exception e) {
-                    log.error("Error parsing percentile: '{}'", percentilesStringArray[i], e);
-                }
-            }
-        }
-        // Check if more row which started with 'TAG_' are filled ( corresponding to user tag )
+        testTags = AbstractInfluxdbMetricsSender.tagToStringValue(
+                context.getParameter("eventTags", ""));
+
+        initPercentiles(context);
+        initUserTags(context);
+        initInfluxdbMetricsManager(context);
+
+        samplersToFilter = Pattern.compile(samplersRegex);
+        addAnnotation(true);
+
+        scheduler = Executors.newScheduledThreadPool(MAX_POOL_SIZE);
+        // Start immediately the scheduler and put the pooling ( 5 seconds by default )
+        this.timerHandle = scheduler.scheduleAtFixedRate(this, 0, SEND_INTERVAL, TimeUnit.SECONDS);
+    }
+
+    private void initInfluxdbMetricsManager(BackendListenerContext context) throws Exception {
+        Class<?> clazz = Class.forName(context.getParameter("influxdbMetricsSender"));
+        influxdbMetricsManager = (InfluxdbMetricsSender) clazz.getDeclaredConstructor().newInstance();
+
+        String influxdbUrl = context.getParameter("influxdbUrl");
+        String influxdbToken = context.getParameter("influxdbToken");
+        influxdbMetricsManager.setup(influxdbUrl, influxdbToken);
+    }
+
+    private void initUserTags(BackendListenerContext context) {
+        // Check if more rows which started with 'TAG_' are filled ( corresponding to user tag )
         StringBuilder userTagBuilder = new StringBuilder();
         context.getParameterNamesIterator().forEachRemaining(name -> {
-            if (StringUtils.isNotBlank(name) && !DEFAULT_ARGS.containsKey(name.trim())
+            if (StringUtils.isNotBlank(name)
+                    && !DEFAULT_ARGS.containsKey(name.trim())
                     && name.startsWith("TAG_")
                     && StringUtils.isNotBlank(context.getParameter(name))) {
                 final String tagName = name.trim().substring(4);
                 final String tagValue = context.getParameter(name).trim();
                 userTagBuilder.append(',')
-                        .append(AbstractInfluxdbMetricsSender
-                                .tagToStringValue(tagName))
+                        .append(AbstractInfluxdbMetricsSender.tagToStringValue(tagName))
                         .append('=')
-                        .append(AbstractInfluxdbMetricsSender.tagToStringValue(
-                                tagValue));
+                        .append(AbstractInfluxdbMetricsSender.tagToStringValue(tagValue));
                 log.debug("Adding '{}' tag with '{}' value ", tagName, tagValue);
             }
         });
         userTag = userTagBuilder.toString();
-
-        Class<?> clazz = Class.forName(influxdbMetricsSender);
-        this.influxdbMetricsManager = (InfluxdbMetricsSender) clazz.getDeclaredConstructor().newInstance();
-        influxdbMetricsManager.setup(influxdbUrl, influxdbToken);
-        samplersToFilter = Pattern.compile(samplersRegex);
-        addAnnotation(true);
-
-        scheduler = Executors.newScheduledThreadPool(MAX_POOL_SIZE);
-        // Start immediately the scheduler and put the pooling ( 5 seconds by default )
-        this.timerHandle = scheduler.scheduleAtFixedRate(this, 0, SEND_INTERVAL, TimeUnit.SECONDS);
-
     }
 
-    protected SamplerMetric getSamplerMetricInfluxdb(String sampleLabel) {
-        SamplerMetric samplerMetric = metricsPerSampler.get(sampleLabel);
-        if (samplerMetric == null) {
-            samplerMetric = new SamplerMetric();
-            SamplerMetric oldValue = metricsPerSampler.putIfAbsent(sampleLabel, samplerMetric);
-            if (oldValue != null) {
-                samplerMetric = oldValue;
+    private void initPercentiles(BackendListenerContext context) {
+        String percentilesAsString = context.getParameter("percentiles", "");
+        String[] percentilesStringArray = percentilesAsString.split(SEPARATOR);
+        okPercentiles = new HashMap<>(percentilesStringArray.length);
+        koPercentiles = new HashMap<>(percentilesStringArray.length);
+        allPercentiles = new HashMap<>(percentilesStringArray.length);
+        DecimalFormat format = new DecimalFormat("0.##");
+        for (String percentile : percentilesStringArray) {
+            String trimmedPercentile = percentile.trim();
+            if (StringUtils.isEmpty(trimmedPercentile)) {
+                continue;
+            }
+            try {
+                Float percentileValue = Float.valueOf(trimmedPercentile);
+                String key = AbstractInfluxdbMetricsSender.tagToStringValue(format.format(percentileValue));
+                okPercentiles.put(key, percentileValue);
+                koPercentiles.put(key, percentileValue);
+                allPercentiles.put(key, percentileValue);
+            } catch (Exception e) {
+                log.error("Error parsing percentile: '{}'", percentile, e);
             }
         }
-        return samplerMetric;
     }
 
-    private Map<String, SamplerMetric> getMetricsInfluxdbPerSampler() {
-        return metricsPerSampler;
+    private SamplerMetric getSamplerMetricInfluxdb(String sampleLabel) {
+        SamplerMetric samplerMetric = metricsPerSampler.get(sampleLabel);
+        if (samplerMetric != null) {
+            return samplerMetric;
+        }
+
+        SamplerMetric newSamplerMetric = new SamplerMetric();
+        SamplerMetric oldValue = metricsPerSampler.putIfAbsent(sampleLabel, newSamplerMetric);
+        if (oldValue != null) {
+            newSamplerMetric = oldValue;
+        }
+        return newSamplerMetric;
     }
 
     @Override
@@ -422,15 +427,18 @@ public class InfluxdbBackendListenerClient extends AbstractBackendListenerClient
      * Tags is put as InfluxdbTag for better query performance on it
      * Never double or single quotes in influxdb except for string field
      * see : https://docs.influxdata.com/influxdb/v1.1/write_protocols/line_protocol_reference/#quoting-special-characters-and-additional-naming-guidelines
-     * * @param startOrEnd boolean true for start, false for end
+     *
+     * @param isStartOfTest boolean true for start, false for end
      */
-    private void addAnnotation(boolean startOrEnd) {
-        influxdbMetricsManager.addMetric(EVENTS_FOR_ANNOTATION,
-                TAG_APPLICATION + application + ",title=ApacheJMeter"+ userTag +
-                (StringUtils.isNotEmpty(testTags) ? TAGS+ testTags : ""),
-                TEXT +
-                        AbstractInfluxdbMetricsSender.fieldToStringValue(testTitle +
-                                (startOrEnd ? " started" : " ended")) + "\"" );
+    private void addAnnotation(boolean isStartOfTest) {
+        String tags = TAG_APPLICATION + applicationName +
+                ",title=ApacheJMeter" + userTag +
+                (StringUtils.isNotEmpty(testTags) ? TAGS + testTags : "");
+        String field = TEXT +
+                AbstractInfluxdbMetricsSender.fieldToStringValue(
+                        testTitle + (isStartOfTest ? " started" : " ended")) + "\"";
+
+        influxdbMetricsManager.addMetric(EVENTS_FOR_ANNOTATION, tags, field);
     }
 
     @Override
diff --git a/src/components/src/test/groovy/org/apache/jmeter/visualizers/backend/influxdb/InfluxdbBackendListenerClientSpec.groovy b/src/components/src/test/groovy/org/apache/jmeter/visualizers/backend/influxdb/InfluxdbBackendListenerClientSpec.groovy
new file mode 100644
index 0000000..f303d57
--- /dev/null
+++ b/src/components/src/test/groovy/org/apache/jmeter/visualizers/backend/influxdb/InfluxdbBackendListenerClientSpec.groovy
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.jmeter.visualizers.backend.influxdb
+
+import org.apache.jmeter.visualizers.backend.BackendListenerContext
+
+import spock.lang.Specification
+
+class InfluxdbBackendListenerClientSpec extends Specification {
+
+    def sut = new InfluxdbBackendListenerClient()
+    def defaultContext = new BackendListenerContext(InfluxdbBackendListenerClient.DEFAULT_ARGS)
+
+    def "setupTest with default config does not raise an exception"() {
+        when:
+            sut.setupTest(defaultContext)
+        then:
+            noExceptionThrown()
+    }
+
+    def "Sending metrics when empty does not raise an exception"() {
+        given:
+            sut.setupTest(defaultContext)
+        when:
+            sut.run()
+        then:
+            noExceptionThrown()
+    }
+
+    def "Default parameters are equal to default args"() {
+        expect:
+            sut.getDefaultParameters().getArgumentsAsMap() == InfluxdbBackendListenerClient.DEFAULT_ARGS
+    }
+}