ENT-1382 JMeter changes to allow easy HTML report generation (#382)

* Fixes to allow the HTML reports to be run on JMeter CSV output files, with custom label.  Also adjust each test plan and examples to include the label.

(cherry picked from commit 35fd309)

* Added some documentation to the README.
This commit is contained in:
Rick Parker 2018-01-23 14:00:36 +00:00 committed by GitHub
parent 789ce5d44a
commit f628f30098
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 226 additions and 13 deletions

View File

@ -85,4 +85,12 @@ The interesting bit here are the `jmeterArgs`:
- `-t <filename>` loads the testplan to run
- `-l <filename>` specifies the output to write to (if it exists, it will be appended)
- `-R <hostname:port>` specifies the host to run against - note this is localhost in this case as we are using ssh
tunnels to reach the test nodes.
tunnels to reach the test nodes.
### Generating an HTML report from a recorded CSV file
It's possible to generate a simple but effective HTML report for a JMeter test run that already produced a CSV file.
```./gradlew tools:jmeter:run -PjmeterArgs="['-g', '<input-file>.csv', '-o', '<path-of-report-dir>', '-Jjmeter.reportgenerator.report_title=<report title>']"```
The report output directory must be empty or not exist (in which case JMeter attempts to create it).

View File

@ -16,17 +16,19 @@ import org.apache.jmeter.samplers.SampleResult
*/
abstract class BaseFlowSampler() : AbstractJavaSamplerClient() {
companion object {
val label = Argument("label", "\${__samplerName}", "<meta>", "The value in the label column in the resulting CSV file to dissambiguate this test run from others.")
val host = Argument("host", "localhost", "<meta>", "The remote network address (hostname or IP address) to connect to for RPC.")
val port = Argument("port", "10000", "<meta>", "The remote port to connect to for RPC.")
val username = Argument("username", "corda", "<meta>", "The RPC user to connect to connect as.")
val password = Argument("password", "corda_is_awesome", "<meta>", "The password for the RPC user.")
val allArgs = setOf(host, port, username, password)
val allArgs = setOf(label, host, port, username, password)
}
var rpcClient: CordaRPCClient? = null
var rpcConnection: CordaRPCConnection? = null
var rpcProxy: CordaRPCOps? = null
var labelValue: String? = null
override fun getDefaultParameters(): Arguments {
// Add copies of all args, since they seem to be mutable.
@ -45,6 +47,10 @@ abstract class BaseFlowSampler() : AbstractJavaSamplerClient() {
rpcClient = CordaRPCClient(NetworkHostAndPort(context.getParameter(host.name), context.getIntParameter(port.name)))
rpcConnection = rpcClient!!.start(context.getParameter(username.name), context.getParameter(password.name))
rpcProxy = rpcConnection!!.proxy
labelValue = context.getParameter(label.name)
if (labelValue.isNullOrBlank()) {
labelValue = null
}
setupTest(rpcProxy!!, context)
}
@ -57,7 +63,7 @@ abstract class BaseFlowSampler() : AbstractJavaSamplerClient() {
val result = SampleResult()
result.sampleStart()
val handle = rpcProxy!!.startFlowDynamic(flowInvoke.flowLogicClass, *(flowInvoke.args))
result.sampleLabel = handle.id.toString()
result.sampleLabel = labelValue ?: flowInvoke.flowLogicClass.simpleName
result.latencyEnd()
try {
val flowResult = handle.returnValue.get()
@ -82,6 +88,7 @@ abstract class BaseFlowSampler() : AbstractJavaSamplerClient() {
rpcConnection!!.close()
rpcConnection = null
rpcClient = null
labelValue = null
super.teardownTest(context)
}

View File

@ -29,6 +29,11 @@
<JavaSampler guiclass="JavaTestSamplerGui" testclass="JavaSampler" testname="Cash Issue Request" enabled="true">
<elementProp name="arguments" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" enabled="true">
<collectionProp name="Arguments.arguments">
<elementProp name="label" elementType="Argument">
<stringProp name="Argument.name">label</stringProp>
<stringProp name="Argument.value">${___samplerName}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="host" elementType="Argument">
<stringProp name="Argument.name">host</stringProp>
<stringProp name="Argument.value">localhost</stringProp>

View File

@ -29,6 +29,11 @@
<JavaSampler guiclass="JavaTestSamplerGui" testclass="JavaSampler" testname="Cash Issue Request" enabled="true">
<elementProp name="arguments" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" enabled="true">
<collectionProp name="Arguments.arguments">
<elementProp name="label" elementType="Argument">
<stringProp name="Argument.name">label</stringProp>
<stringProp name="Argument.value">${___samplerName}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="host" elementType="Argument">
<stringProp name="Argument.name">host</stringProp>
<stringProp name="Argument.value">localhost</stringProp>
@ -59,6 +64,11 @@
<stringProp name="Argument.value">O=Perf-10.155.0.7, OU=Corda, L=London, C=GB</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="useCoinSelection" elementType="Argument">
<stringProp name="Argument.name">useCoinSelection</stringProp>
<stringProp name="Argument.value">true</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
</collectionProp>
</elementProp>
<stringProp name="classname">com.r3.corda.jmeter.CashIssueAndPaySampler</stringProp>

View File

@ -63,9 +63,14 @@
<stringProp name="ThreadGroup.delay"></stringProp>
</ThreadGroup>
<hashTree>
<JavaSampler guiclass="JavaTestSamplerGui" testclass="JavaSampler" testname="Linear State Batch Notarise Request" enabled="true">
<JavaSampler guiclass="JavaTestSamplerGui" testclass="JavaSampler" testname="Linear State Batch Notarise Request (Node 1)" enabled="true">
<elementProp name="arguments" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" enabled="true">
<collectionProp name="Arguments.arguments">
<elementProp name="label" elementType="Argument">
<stringProp name="Argument.name">label</stringProp>
<stringProp name="Argument.value">${___samplerName}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="host" elementType="Argument">
<stringProp name="Argument.name">host</stringProp>
<stringProp name="Argument.value">localhost</stringProp>
@ -106,9 +111,9 @@
<stringProp name="Argument.value">true</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="transactionsPerMinute" elementType="Argument">
<stringProp name="Argument.name">transactionsPerMinute</stringProp>
<stringProp name="Argument.value">10</stringProp>
<elementProp name="transactionsPerSecond" elementType="Argument">
<stringProp name="Argument.name">transactionsPerSecond</stringProp>
<stringProp name="Argument.value">1.0</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="repeatInvoke" elementType="Argument">
@ -124,6 +129,11 @@
<JavaSampler guiclass="JavaTestSamplerGui" testclass="JavaSampler" testname="Cash Issue Request" enabled="false">
<elementProp name="arguments" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" enabled="true">
<collectionProp name="Arguments.arguments">
<elementProp name="label" elementType="Argument">
<stringProp name="Argument.name">label</stringProp>
<stringProp name="Argument.value"></stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="host" elementType="Argument">
<stringProp name="Argument.name">host</stringProp>
<stringProp name="Argument.value">localhost</stringProp>
@ -180,9 +190,14 @@
<stringProp name="ThreadGroup.delay"></stringProp>
</ThreadGroup>
<hashTree>
<JavaSampler guiclass="JavaTestSamplerGui" testclass="JavaSampler" testname="Linear State Batch Notarise Request" enabled="true">
<JavaSampler guiclass="JavaTestSamplerGui" testclass="JavaSampler" testname="Linear State Batch Notarise Request (Node 2)" enabled="true">
<elementProp name="arguments" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" enabled="true">
<collectionProp name="Arguments.arguments">
<elementProp name="label" elementType="Argument">
<stringProp name="Argument.name">label</stringProp>
<stringProp name="Argument.value">${___samplerName}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="host" elementType="Argument">
<stringProp name="Argument.name">host</stringProp>
<stringProp name="Argument.value">localhost</stringProp>
@ -223,9 +238,9 @@
<stringProp name="Argument.value">true</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="transactionsPerMinute" elementType="Argument">
<stringProp name="Argument.name">transactionsPerMinute</stringProp>
<stringProp name="Argument.value">10</stringProp>
<elementProp name="transactionsPerSecond" elementType="Argument">
<stringProp name="Argument.name">transactionsPerSecond</stringProp>
<stringProp name="Argument.value">1.0</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="repeatInvoke" elementType="Argument">
@ -241,6 +256,11 @@
<JavaSampler guiclass="JavaTestSamplerGui" testclass="JavaSampler" testname="Cash Issue Request" enabled="false">
<elementProp name="arguments" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" enabled="true">
<collectionProp name="Arguments.arguments">
<elementProp name="label" elementType="Argument">
<stringProp name="Argument.name">label</stringProp>
<stringProp name="Argument.value"></stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="host" elementType="Argument">
<stringProp name="Argument.name">host</stringProp>
<stringProp name="Argument.value">localhost</stringProp>

View File

@ -26,9 +26,14 @@
<stringProp name="ThreadGroup.delay"></stringProp>
</ThreadGroup>
<hashTree>
<JavaSampler guiclass="JavaTestSamplerGui" testclass="JavaSampler" testname="Cash Issue Request" enabled="true">
<JavaSampler guiclass="JavaTestSamplerGui" testclass="JavaSampler" testname="Cash Issue And Pay Request" enabled="true">
<elementProp name="arguments" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" enabled="true">
<collectionProp name="Arguments.arguments">
<elementProp name="label" elementType="Argument">
<stringProp name="Argument.name">label</stringProp>
<stringProp name="Argument.value">${___samplerName}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="host" elementType="Argument">
<stringProp name="Argument.name">host</stringProp>
<stringProp name="Argument.value">localhost</stringProp>
@ -61,7 +66,7 @@
</elementProp>
<elementProp name="useCoinSelection" elementType="Argument">
<stringProp name="Argument.name">useCoinSelection</stringProp>
<stringProp name="Argument.value">true</stringProp>
<stringProp name="Argument.value">false</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
</collectionProp>

View File

@ -29,6 +29,11 @@
<JavaSampler guiclass="JavaTestSamplerGui" testclass="JavaSampler" testname="Cash Issue Request" enabled="true">
<elementProp name="arguments" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" enabled="true">
<collectionProp name="Arguments.arguments">
<elementProp name="label" elementType="Argument">
<stringProp name="Argument.name">label</stringProp>
<stringProp name="Argument.value">${___samplerName}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="host" elementType="Argument">
<stringProp name="Argument.name">host</stringProp>
<stringProp name="Argument.value">localhost</stringProp>

View File

@ -0,0 +1,153 @@
################################################################################
# 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
# 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
# This property is used by menu item "Export transactions for report"
# It is used to select which transactions by default will be exported
#jmeter.reportgenerator.exported_transactions_pattern=[a-zA-Z0-9_\\-{}\\$\\.]*[-_][0-9]*
# 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 = 20000
# Configure this property to change the report title
#jmeter.reportgenerator.report_title=Apache JMeter Dashboard
# Default format
#jmeter.reportgenerator.date_format=yyyyMMddHHmmss
# Used to generate a report based on a date range
# If jmeter.save.saveservice.timestamp_format does not contain year
# then use 1970 as year
# Date range start date as per format declared in jmeter.reportgenerator.date_format
#jmeter.reportgenerator.start_date=
# Date range end date as per format declared in jmeter.reportgenerator.date_format
#jmeter.reportgenerator.end_date=
# Defines the overall granularity for over time graphs
# Granularity must be higher than 1000 (1second) otherwise Throughput graphs will be incorrect
# see Bug 60149
jmeter.reportgenerator.overall_granularity=60000
# Exclude transaction controller from analysis
# true by default
jmeter.reportgenerator.exclude_tc_from_top5_errors_by_sampler=true
# 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.exclude_controllers=true
#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}
# Percentiles Response Times over time
jmeter.reportgenerator.graph.responseTimePercentilesOverTime.classname=org.apache.jmeter.report.processor.graph.impl.ResponseTimePercentilesOverTimeGraphConsumer
jmeter.reportgenerator.graph.responseTimePercentilesOverTime.title Response Time Percentiles Over Time (successful requests only)
jmeter.reportgenerator.graph.responseTimePercentilesOverTime.property.set_granularity=${jmeter.reportgenerator.overall_granularity}
# Synthetic Response Time Distribution
jmeter.reportgenerator.graph.syntheticResponseTimeDistribution.classname=org.apache.jmeter.report.processor.graph.impl.SyntheticResponseTimeDistributionGraphConsumer
jmeter.reportgenerator.graph.syntheticResponseTimeDistribution.title=Synthetic Response Times Distribution
jmeter.reportgenerator.graph.syntheticResponseTimeDistribution.exclude_controllers=true
jmeter.reportgenerator.graph.syntheticResponseTimeDistribution.property.set_satisfied_threshold=${jmeter.reportgenerator.apdex_satisfied_threshold}
jmeter.reportgenerator.graph.syntheticResponseTimeDistribution.property.set_tolerated_threshold=${jmeter.reportgenerator.apdex_tolerated_threshold}
# 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}
# Connect Time Over Time graph definition
#jmeter.reportgenerator.graph.connectTimeOverTime.classname=org.apache.jmeter.report.processor.graph.impl.ConnectTimeOverTimeGraphConsumer
#jmeter.reportgenerator.graph.connectTimeOverTime.title=Connect Time Over Time
#jmeter.reportgenerator.graph.connectTimeOverTime.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
# 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