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 2017/03/28 18:59:34 UTC

svn commit: r1789193 - in /jmeter/trunk: bin/ src/core/org/apache/jmeter/report/config/ src/core/org/apache/jmeter/report/dashboard/ test/resources/ test/src/org/apache/jmeter/report/dashboard/ xdocs/ xdocs/usermanual/

Author: pmouawad
Date: Tue Mar 28 18:59:34 2017
New Revision: 1789193

URL: http://svn.apache.org/viewvc?rev=1789193&view=rev
Log:
Bug 60112 - Report / Dashboard : Add ability to customize APDEX thresholds per Transaction name
Contributed by Stephane Leplus
This closes #287
Bugzilla Id: 60112

Added:
    jmeter/trunk/test/resources/reportgenerator_test.properties   (with props)
    jmeter/trunk/test/src/org/apache/jmeter/report/dashboard/
    jmeter/trunk/test/src/org/apache/jmeter/report/dashboard/ApdexPerTransactionTest.java   (with props)
Modified:
    jmeter/trunk/bin/reportgenerator.properties
    jmeter/trunk/src/core/org/apache/jmeter/report/config/ReportGeneratorConfiguration.java
    jmeter/trunk/src/core/org/apache/jmeter/report/dashboard/ReportGenerator.java
    jmeter/trunk/xdocs/changes.xml
    jmeter/trunk/xdocs/usermanual/generating-dashboard.xml

Modified: jmeter/trunk/bin/reportgenerator.properties
URL: http://svn.apache.org/viewvc/jmeter/trunk/bin/reportgenerator.properties?rev=1789193&r1=1789192&r2=1789193&view=diff
==============================================================================
--- jmeter/trunk/bin/reportgenerator.properties (original)
+++ jmeter/trunk/bin/reportgenerator.properties Tue Mar 28 18:59:34 2017
@@ -38,6 +38,16 @@
 # Sets the tolerance threshold for the APDEX calculation (in milliseconds).
 #jmeter.reportgenerator.apdex_tolerated_threshold=1500
 
+# Sets satisfaction and tolerance threshold to specific samples.
+# Use sample names or regular expression. 
+# Format is : sample_name:satisfaction|tolerance[;]
+# Notice the colon between sample name and values, the pipe between thresholds and the 
+# semicolon at the end to separate different samples. Don't forget to escape after
+# semicolon to span multiple lines. Ex : 
+#jmeter.reportgenerator.apdex_per_transaction=sample(\\d+):1000|2000,\
+#                                            samples12:3000|4000;\
+#                                            scenar01-12:5000|6000 
+
 # Regular Expression which Indicates which samples to keep for graphs and statistics generation.
 # Empty value means no filtering
 #jmeter.reportgenerator.sample_filter=

Modified: jmeter/trunk/src/core/org/apache/jmeter/report/config/ReportGeneratorConfiguration.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/report/config/ReportGeneratorConfiguration.java?rev=1789193&r1=1789192&r2=1789193&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/report/config/ReportGeneratorConfiguration.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/report/config/ReportGeneratorConfiguration.java Tue Mar 28 18:59:34 2017
@@ -15,6 +15,7 @@
  * limitations under the License.
  *
  */
+
 package org.apache.jmeter.report.config;
 
 import java.io.File;
@@ -71,6 +72,10 @@ public class ReportGeneratorConfiguratio
     private static final String REPORT_GENERATOR_KEY_APDEX_TOLERATED_THRESHOLD = REPORT_GENERATOR_KEY_PREFIX
             + KEY_DELIMITER + "apdex_tolerated_threshold";
     private static final Long REPORT_GENERATOR_KEY_APDEX_TOLERATED_THRESHOLD_DEFAULT = Long.valueOf(1500L);
+    
+    // Apdex per transaction Thresholds
+    private static final String REPORT_GENERATOR_KEY_APDEX_PER_TRANSACTION = REPORT_GENERATOR_KEY_PREFIX
+            + KEY_DELIMITER + "apdex_per_transaction";
 
     // Exclude Transaction Controller from Top5 Errors by Sampler consumer
     private static final String REPORT_GENERATOR_KEY_EXCLUDE_TC_FROM_TOP5_ERRORS_BY_SAMPLER = REPORT_GENERATOR_KEY_PREFIX
@@ -275,6 +280,7 @@ public class ReportGeneratorConfiguratio
     private File tempDirectory;
     private long apdexSatisfiedThreshold;
     private long apdexToleratedThreshold;
+    private Map<String, Long[]> apdexPerTransaction = new HashMap<>();
     private Pattern filteredSamplesPattern;
     private boolean ignoreTCFromTop5ErrorsBySampler;
     private Map<String, ExporterConfiguration> exportConfigurations = new HashMap<>();
@@ -355,6 +361,25 @@ public class ReportGeneratorConfiguratio
     public final void setApdexToleratedThreshold(long apdexToleratedThreshold) {
         this.apdexToleratedThreshold = apdexToleratedThreshold;
     }
+    
+    /**
+     * Gets the apdex per transaction map
+     *
+     * @return the apdex per transaction map
+     */
+    public Map<String, Long[]> getApdexPerTransaction() {
+        return apdexPerTransaction;
+    }
+
+    /**
+     * Sets the apdex per transaction map.
+     *
+     * @param apdexPerTransaction
+     *            a map containing thresholds for one or more samples
+     */
+    public void setApdexPerTransaction(Map<String, Long[]> apdexPerTransaction) {
+        this.apdexPerTransaction = apdexPerTransaction;
+    }
 
     /**
      * Gets the export configurations.
@@ -612,6 +637,12 @@ public class ReportGeneratorConfiguratio
                 REPORT_GENERATOR_KEY_APDEX_TOLERATED_THRESHOLD_DEFAULT,
                 long.class).longValue();
         configuration.setApdexToleratedThreshold(apdexToleratedThreshold);
+        
+        // Load apdex per transactions, overriden by user
+        final String apdexPerTransaction = getOptionalProperty(props, 
+                REPORT_GENERATOR_KEY_APDEX_PER_TRANSACTION, 
+                String.class);
+        configuration.setApdexPerTransaction(getApdexPerTransactionParts(apdexPerTransaction));
 
         final boolean ignoreTCFromTop5ErrorsBySampler = getRequiredProperty(
                 props, 
@@ -689,6 +720,41 @@ public class ReportGeneratorConfiguratio
 
         return configuration;
     }
+    
+    /**
+     * Parses a string coming from properties to fill a map containing
+     * sample names as keys and an array of 2 longs [satisfied, tolerated] as values.
+     * The sample name can be a regex supplied by the user.
+     * @param apdexPerTransaction, the string coming from properties
+     * @return {@link Map} containing for each sample name or sample name regex an array of Long corresponding to satisfied and tolerated apdex thresholds.
+     */
+    public static Map<String, Long[]> getApdexPerTransactionParts(String apdexPerTransaction) {
+        Map <String, Long[]> specificApdexes = new HashMap<>();
+        if (StringUtils.isEmpty(apdexPerTransaction) || 
+                apdexPerTransaction.trim().length()==0) {
+            log.info(
+                    "apdex_per_transaction : {} is empty, not APDEX per transaction customization");
+        } else {
+            // data looks like : sample(\d+):1000|2000;samples12:3000|4000;scenar01-12:5000|6000
+            String[] parts = apdexPerTransaction.split("[;]");
+            for (String chunk : parts) {
+                int colonSeparator = chunk.lastIndexOf(":");
+                int pipeSeparator = chunk.lastIndexOf("|");
+                if (colonSeparator == -1 || pipeSeparator == -1 ||
+                        pipeSeparator <= colonSeparator) {
+                    log.error(
+                        "error parsing property apdex_per_transaction around chunk {}. "
+                        + "Wrong format, should have been: 'sample:satisfiedMs|toleratedMS', ignoring", chunk);
+                    continue;
+                }
+                String key = chunk.substring(0, colonSeparator).trim();
+                Long satisfied = Long.valueOf(chunk.substring(colonSeparator + 1, pipeSeparator).trim());
+                Long tolerated = Long.valueOf(chunk.substring(pipeSeparator + 1).trim());
+                specificApdexes.put(key, new Long[] {satisfied, tolerated});
+            }
+        }
+        return specificApdexes;
+    }
 
     /**
      * @return the reportTitle

Modified: jmeter/trunk/src/core/org/apache/jmeter/report/dashboard/ReportGenerator.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/report/dashboard/ReportGenerator.java?rev=1789193&r1=1789192&r2=1789193&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/report/dashboard/ReportGenerator.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/report/dashboard/ReportGenerator.java Tue Mar 28 18:59:34 2017
@@ -57,6 +57,7 @@ import org.apache.jmeter.report.processo
 import org.apache.jmeter.reporters.ResultCollector;
 import org.apache.jmeter.samplers.SampleSaveConfiguration;
 import org.apache.jmeter.util.JMeterUtils;
+import org.apache.oro.text.regex.PatternMatcher;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -432,10 +433,29 @@ public class ReportGenerator {
         apdexSummaryConsumer.setHasOverallResult(true);
         apdexSummaryConsumer.setThresholdSelector(sampleName -> {
                 ApdexThresholdsInfo info = new ApdexThresholdsInfo();
+                // set default values anyway for safety
                 info.setSatisfiedThreshold(configuration
                         .getApdexSatisfiedThreshold());
                 info.setToleratedThreshold(configuration
                         .getApdexToleratedThreshold());
+                // see if the sample name is in the special cases targeted
+                // by property jmeter.reportgenerator.apdex_per_transaction
+                // key in entry below can be a hardcoded name or a regex
+                for (Map.Entry<String, Long[]> entry : configuration.getApdexPerTransaction().entrySet()) {
+                    org.apache.oro.text.regex.Pattern regex = JMeterUtils.getPatternCache().getPattern(entry.getKey());
+                    PatternMatcher matcher = JMeterUtils.getMatcher();
+                    if (matcher.matches(sampleName, regex)) {
+                        Long satisfied = entry.getValue()[0];
+                        Long tolerated = entry.getValue()[1];
+                        if(log.isDebugEnabled()) {
+                            log.debug("Found match for sampleName:{}, Regex:{}, satisfied value:{}, tolerated value:{}", 
+                                    entry.getKey(), satisfied, tolerated);
+                        }
+                        info.setSatisfiedThreshold(satisfied);
+                        info.setToleratedThreshold(tolerated);
+                        break;
+                    }
+                }
                 return info;
         });
         return apdexSummaryConsumer;

Added: jmeter/trunk/test/resources/reportgenerator_test.properties
URL: http://svn.apache.org/viewvc/jmeter/trunk/test/resources/reportgenerator_test.properties?rev=1789193&view=auto
==============================================================================
--- jmeter/trunk/test/resources/reportgenerator_test.properties (added)
+++ jmeter/trunk/test/resources/reportgenerator_test.properties Tue Mar 28 18:59:34 2017
@@ -0,0 +1,144 @@
+################################################################################
+# Apache JMeter Property file for Report Generator
+################################################################################
+
+##   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.
+
+################################################################################
+#
+#                      THIS FILE SHOULD NOT BE MODIFIED
+#
+# This avoids having to re-apply the modifications when upgrading JMeter
+# Instead only user.properties should be modified:
+# 1/ copy the property you want to modify to user.properties from here
+# 2/ Change its value there
+#
+################################################################################
+
+#---------------------------------------------------------------------------
+# Reporting configuration
+#---------------------------------------------------------------------------
+
+# Sets the satisfaction threshold for the APDEX calculation (in milliseconds).
+#jmeter.reportgenerator.apdex_satisfied_threshold=500
+
+# Sets the tolerance threshold for the APDEX calculation (in milliseconds).
+#jmeter.reportgenerator.apdex_tolerated_threshold=1500
+
+# Regular Expression which Indicates which samples to keep for graphs and statistics generation.
+# Empty value means no filtering
+#jmeter.reportgenerator.sample_filter=
+
+# Sets the temporary directory used by the generation process if it needs file I/O operations.
+#jmeter.reportgenerator.temp_dir=temp
+
+# Sets the size of the sliding window used by percentile evaluation.
+# Caution : higher value provides a better accuracy but needs more memory.
+#jmeter.reportgenerator.statistic_window = 200000
+
+# Configure this property to change the report title
+#jmeter.reportgenerator.report_title=Apache JMeter Dashboard
+
+# Defines the overall granularity for over time graphs
+jmeter.reportgenerator.overall_granularity=60000
+
+# Response Time Percentiles graph definition
+jmeter.reportgenerator.graph.responseTimePercentiles.classname=org.apache.jmeter.report.processor.graph.impl.ResponseTimePercentilesGraphConsumer
+jmeter.reportgenerator.graph.responseTimePercentiles.title=Response Time Percentiles
+
+# Response Time Distribution graph definition
+jmeter.reportgenerator.graph.responseTimeDistribution.classname=org.apache.jmeter.report.processor.graph.impl.ResponseTimeDistributionGraphConsumer
+jmeter.reportgenerator.graph.responseTimeDistribution.title=Response Time Distribution
+jmeter.reportgenerator.graph.responseTimeDistribution.property.set_granularity=500
+
+# Active Threads Over Time graph definition
+jmeter.reportgenerator.graph.activeThreadsOverTime.classname=org.apache.jmeter.report.processor.graph.impl.ActiveThreadsGraphConsumer
+jmeter.reportgenerator.graph.activeThreadsOverTime.title=Active Threads Over Time
+jmeter.reportgenerator.graph.activeThreadsOverTime.property.set_granularity=${jmeter.reportgenerator.overall_granularity}
+
+# Time VS Threads graph definition
+jmeter.reportgenerator.graph.timeVsThreads.classname=org.apache.jmeter.report.processor.graph.impl.TimeVSThreadGraphConsumer
+jmeter.reportgenerator.graph.timeVsThreads.title=Time VS Threads
+
+# Bytes Throughput Over Time graph definition
+jmeter.reportgenerator.graph.bytesThroughputOverTime.classname=org.apache.jmeter.report.processor.graph.impl.BytesThroughputGraphConsumer
+jmeter.reportgenerator.graph.bytesThroughputOverTime.title=Bytes Throughput Over Time
+jmeter.reportgenerator.graph.bytesThroughputOverTime.property.set_granularity=${jmeter.reportgenerator.overall_granularity}
+
+# Response Time Over Time graph definition
+jmeter.reportgenerator.graph.responseTimesOverTime.classname=org.apache.jmeter.report.processor.graph.impl.ResponseTimeOverTimeGraphConsumer
+jmeter.reportgenerator.graph.responseTimesOverTime.title=Response Time Over Time
+jmeter.reportgenerator.graph.responseTimesOverTime.property.set_granularity=${jmeter.reportgenerator.overall_granularity}
+
+# Latencies Over Time graph definition
+jmeter.reportgenerator.graph.latenciesOverTime.classname=org.apache.jmeter.report.processor.graph.impl.LatencyOverTimeGraphConsumer
+jmeter.reportgenerator.graph.latenciesOverTime.title=Latencies Over Time
+jmeter.reportgenerator.graph.latenciesOverTime.property.set_granularity=${jmeter.reportgenerator.overall_granularity}
+
+# Response Time Vs Request graph definition
+jmeter.reportgenerator.graph.responseTimeVsRequest.classname=org.apache.jmeter.report.processor.graph.impl.ResponseTimeVSRequestGraphConsumer
+jmeter.reportgenerator.graph.responseTimeVsRequest.title=Response Time Vs Request
+jmeter.reportgenerator.graph.responseTimeVsRequest.exclude_controllers=true
+jmeter.reportgenerator.graph.responseTimeVsRequest.property.set_granularity=${jmeter.reportgenerator.overall_granularity}
+
+# Latencies Vs Request graph definition
+jmeter.reportgenerator.graph.latencyVsRequest.classname=org.apache.jmeter.report.processor.graph.impl.LatencyVSRequestGraphConsumer
+jmeter.reportgenerator.graph.latencyVsRequest.title=Latencies Vs Request
+jmeter.reportgenerator.graph.latencyVsRequest.exclude_controllers=true
+jmeter.reportgenerator.graph.latencyVsRequest.property.set_granularity=${jmeter.reportgenerator.overall_granularity}
+
+# Hits Per Second graph definition
+jmeter.reportgenerator.graph.hitsPerSecond.classname=org.apache.jmeter.report.processor.graph.impl.HitsPerSecondGraphConsumer
+jmeter.reportgenerator.graph.hitsPerSecond.title=Hits Per Second
+jmeter.reportgenerator.graph.hitsPerSecond.exclude_controllers=true
+jmeter.reportgenerator.graph.hitsPerSecond.property.set_granularity=${jmeter.reportgenerator.overall_granularity}
+
+# Codes Per Second graph definition
+jmeter.reportgenerator.graph.codesPerSecond.classname=org.apache.jmeter.report.processor.graph.impl.CodesPerSecondGraphConsumer
+jmeter.reportgenerator.graph.codesPerSecond.title=Codes Per Second
+jmeter.reportgenerator.graph.codesPerSecond.exclude_controllers=true
+jmeter.reportgenerator.graph.codesPerSecond.property.set_granularity=${jmeter.reportgenerator.overall_granularity}
+
+# Transactions Per Second graph definition
+jmeter.reportgenerator.graph.transactionsPerSecond.classname=org.apache.jmeter.report.processor.graph.impl.TransactionsPerSecondGraphConsumer
+jmeter.reportgenerator.graph.transactionsPerSecond.title=Transactions Per Second
+jmeter.reportgenerator.graph.transactionsPerSecond.property.set_granularity=${jmeter.reportgenerator.overall_granularity}
+
+# HTML Export
+jmeter.reportgenerator.exporter.html.classname=org.apache.jmeter.report.dashboard.HtmlTemplateExporter
+
+jmeter.reportgenerator.apdex_per_transaction=sample(\\d+):1000|2000;\
+                                            samples12:3000|4000;\
+                                            scenar01-12:5000|6000
+
+# Sets the source directory of templated files from which the html pages are generated.
+#jmeter.reportgenerator.exporter.html.property.template_dir=report-template
+
+# Sets the destination directory for generated html pages.
+# This will be overridden by the command line option -o 
+#jmeter.reportgenerator.exporter.html.property.output_dir=report-output
+
+# Regular Expression which Indicates which graph series are filtered in display
+# Empty value means no filtering
+#jmeter.reportgenerator.exporter.html.series_filter=
+
+# Indicates whether series filter apply only on sample series or to all series
+# setting this to false can lead to empty graphs if series_filter does not
+# contain required series
+#jmeter.reportgenerator.exporter.html.filters_only_sample_series=true
+
+# Indicates whether only controller samples are displayed on graphs that support it.
+#jmeter.reportgenerator.exporter.html.show_controllers_only=false

Propchange: jmeter/trunk/test/resources/reportgenerator_test.properties
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jmeter/trunk/test/resources/reportgenerator_test.properties
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: jmeter/trunk/test/src/org/apache/jmeter/report/dashboard/ApdexPerTransactionTest.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/test/src/org/apache/jmeter/report/dashboard/ApdexPerTransactionTest.java?rev=1789193&view=auto
==============================================================================
--- jmeter/trunk/test/src/org/apache/jmeter/report/dashboard/ApdexPerTransactionTest.java (added)
+++ jmeter/trunk/test/src/org/apache/jmeter/report/dashboard/ApdexPerTransactionTest.java Tue Mar 28 18:59:34 2017
@@ -0,0 +1,144 @@
+/*
+ * 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.report.dashboard;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.jmeter.report.config.ReportGeneratorConfiguration;
+import org.apache.jmeter.util.JMeterUtils;
+import org.apache.oro.text.regex.PatternMatcher;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import jodd.props.Props;
+
+public class ApdexPerTransactionTest {
+	
+	private static final Logger log = LoggerFactory.getLogger(ApdexPerTransactionTest.class);
+	
+	// prop in the file mixes comma, semicolon and spans several lines.
+	// it also includes hardcoded sample names mixed with regexes 
+	private static final String apdexString = "sample(\\d+):1000|2000;samples12:3000|4000;scenar01-12:5000|6000";
+	
+	@Test
+	public void testgetApdexPerTransactionProperty() {
+		final Properties merged = new Properties();
+		final Props props = new Props();
+		final String REPORT_GENERATOR_KEY_PREFIX = "jmeter.reportgenerator";
+		final char KEY_DELIMITER = '.';
+		final String REPORT_GENERATOR_KEY_APDEX_PER_TRANSACTION = REPORT_GENERATOR_KEY_PREFIX
+	            + KEY_DELIMITER + "apdex_per_transaction";
+		
+		File rgp = new File("test/resources/", "reportgenerator_test.properties");
+		merged.putAll(loadProps(rgp));
+		props.load(merged);
+		final String apdexPerTransaction = getOptionalProperty(props, 
+        		REPORT_GENERATOR_KEY_APDEX_PER_TRANSACTION, 
+        		String.class);
+		assertEquals(apdexString, apdexPerTransaction);
+		
+	}
+	
+	@Test
+	public void testGetApdexPerTransactionParts() {
+		Map<String, Long[]> apdex = ReportGeneratorConfiguration.getApdexPerTransactionParts(apdexString);
+		assertNotNull("map should not be null", apdex);
+		assertEquals(3, apdex.size());
+		Set<String> keys = apdex.keySet();
+		assertTrue(keys.contains("samples12"));
+		assertTrue(keys.contains("scenar01-12"));
+		assertTrue(keys.contains("sample(\\d+)"));
+		assertArrayEquals(new Long[] {1000L,  2000L}, apdex.get("sample(\\d+)"));
+	}
+
+   @Test
+    public void testGetApdexPerTransactionPartsOneCustomization() {
+        Map<String, Long[]> apdex = ReportGeneratorConfiguration.getApdexPerTransactionParts("sample(\\d+):1000|2000");
+        assertNotNull("map should not be null", apdex);
+        assertEquals(1, apdex.size());
+        Set<String> keys = apdex.keySet();
+        assertTrue(keys.contains("sample(\\d+)"));
+        assertArrayEquals(new Long[] {1000L,  2000L}, apdex.get("sample(\\d+)"));
+    }
+	
+	@Test
+	public void testSampleNameMatching() {
+		/* matching pairs : 
+		 * sample(\d+) sample2
+		 * sample(\d+) sample12
+		 * scenar01-12 scenar01-12
+		 * samples12 samples12
+		 * */
+		
+		String[] sampleNames = {"sample2","sample12", "scenar01-12", "samples12"};
+		
+		Map<String, Long[]> apdex = ReportGeneratorConfiguration.getApdexPerTransactionParts(apdexString);
+		for (String sampleName : sampleNames) {
+			boolean hasMatched = false;
+			for (Map.Entry<String, Long[]> entry : apdex.entrySet()) {
+				org.apache.oro.text.regex.Pattern regex = JMeterUtils.getPatternCache().getPattern(entry.getKey());
+    			PatternMatcher matcher = JMeterUtils.getMatcher();
+    			if(matcher.matches(sampleName, regex)) {
+    				hasMatched= true;
+    			}
+    		}
+			assertTrue(hasMatched);
+    	}
+		
+	}
+	
+	private static Properties loadProps(File file) {
+        final Properties props = new Properties();
+        try (FileInputStream inStream = new FileInputStream(file)) {
+            props.load(inStream);
+        } catch (IOException e) {
+            log.error("Problem loading properties. " + e); // NOSONAR
+        }
+        return props;
+    }
+	
+	private static String getOptionalProperty(Props props,
+            String key, Class clazz) {
+        String property = getProperty(props, key, null, clazz);
+        if (property != null) {
+        }
+        return property;
+    }
+	
+	private static String getProperty(Props props, String key,
+            String defaultValue, Class clazz)
+             {
+        String value = props.getValue(key);
+        if (value == null) {
+            return defaultValue;
+        }
+        return value;
+    }
+}

Propchange: jmeter/trunk/test/src/org/apache/jmeter/report/dashboard/ApdexPerTransactionTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jmeter/trunk/test/src/org/apache/jmeter/report/dashboard/ApdexPerTransactionTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: jmeter/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/changes.xml?rev=1789193&r1=1789192&r2=1789193&view=diff
==============================================================================
--- jmeter/trunk/xdocs/changes.xml [utf-8] (original)
+++ jmeter/trunk/xdocs/changes.xml [utf-8] Tue Mar 28 18:59:34 2017
@@ -289,6 +289,7 @@ listeners hold and a rework of the way G
 <h3>Report / Dashboard</h3>
 <ul>
     <li><bug>60637</bug>Improve Statistics table design <figure image="dashboard/report_statistics.png" ></figure></li>
+    <li><bug>60112</bug>Report / Dashboard : Add ability to customize APDEX thresholds per Transaction name. Contributed by Stephane Leplus (s.leplus at ubik-ingenierie.com)</li>
 </ul>
 
 <h3>General</h3>
@@ -446,6 +447,7 @@ listeners hold and a rework of the way G
 <li>Bartosz Siewniak (barteksiewniak at gmail.com)</li>
 <li>Kimono (kimono.outfit.am at gmail.com)</li>
 <li>Michael Osipov (michaelo at apache.org)</li>
+<li>Stephane Leplus (s.leplus at ubik-ingenierie.com)</li>
 </ul>
 <p>We also thank bug reporters who helped us improve JMeter. <br/>
 For this release we want to give special thanks to the following reporters for the clear reports and tests made after our fixes:</p>

Modified: jmeter/trunk/xdocs/usermanual/generating-dashboard.xml
URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/usermanual/generating-dashboard.xml?rev=1789193&r1=1789192&r2=1789193&view=diff
==============================================================================
--- jmeter/trunk/xdocs/usermanual/generating-dashboard.xml (original)
+++ jmeter/trunk/xdocs/usermanual/generating-dashboard.xml Tue Mar 28 18:59:34 2017
@@ -163,6 +163,20 @@ jmeter.save.saveservice.timestamp_format
                             (in ms).<br/>
                             Default: <code>1500</code>
                         </property>
+                        <property name="jmeter.reportgenerator.apdex_per_transaction" required="No">
+                             Sets satisfaction and tolerance threshold to specific samples.<br/>
+                             Use sample names or regular expression.<br/> 
+                             Format is <code>sample_name:satisfaction|tolerance[;]</code>(in ms).<br/>
+                             <note>
+                             Notice the colon between sample name and values, the pipe between thresholds and the 
+                             semicolon at the end to separate different samples. Don't forget to escape after
+                             semicolon to span multiple lines.
+                             </note>
+                             Example:
+                             <source>jmeter.reportgenerator.apdex_per_transaction=sample(\\d+):1000|2000,\
+    										samples12:3000|4000;\
+										    scenar01-12:5000|6000</source>
+                        </property>
                         <property name="sample_filter" required="No">
                             Sets the filter of samples to keep for generating
                             graphs and statistics. An empty value deactivates the



Re: svn commit: r1789193 - in /jmeter/trunk: bin/ src/core/org/apache/jmeter/report/config/ src/core/org/apache/jmeter/report/dashboard/ test/resources/ test/src/org/apache/jmeter/report/dashboard/ xdocs/ xdocs/usermanual/

Posted by sebb <se...@gmail.com>.
On 28 March 2017 at 19:59,  <pm...@apache.org> wrote:
> Author: pmouawad
> Date: Tue Mar 28 18:59:34 2017
> New Revision: 1789193
>
> URL: http://svn.apache.org/viewvc?rev=1789193&view=rev
> Log:
> Bug 60112 - Report / Dashboard : Add ability to customize APDEX thresholds per Transaction name
> Contributed by Stephane Leplus
> This closes #287
> Bugzilla Id: 60112
>
==============================================================================
> --- jmeter/trunk/test/src/org/apache/jmeter/report/dashboard/ApdexPerTransactionTest.java (added)
> +++ jmeter/trunk/test/src/org/apache/jmeter/report/dashboard/ApdexPerTransactionTest.java Tue Mar 28 18:59:34 2017
> @@ -0,0 +1,144 @@
> +       private static String getOptionalProperty(Props props,
> +            String key, Class clazz) {
> +        String property = getProperty(props, key, null, clazz);
> +        if (property != null) {
> +        }

What is the point of the previous statement?

> +        return property;
> +    }
> +
> +       private static String getProperty(Props props, String key,
> +            String defaultValue, Class clazz)

The clazz parameter is not used.
Why not?

If the parameter is not needed here, then it's also not needed by the
previous method.

> +             {
> +        String value = props.getValue(key);
> +        if (value == null) {
> +            return defaultValue;
> +        }
> +        return value;
> +    }
> +}
>

Note: this class is the one that fails on Windows.