diff --git a/tools/jmeter/src/main/kotlin/net/corda/jmeter/CordaRPCSampler.kt b/tools/jmeter/src/main/kotlin/com/r3/corda/jmeter/FlowSampler.kt
similarity index 71%
rename from tools/jmeter/src/main/kotlin/net/corda/jmeter/CordaRPCSampler.kt
rename to tools/jmeter/src/main/kotlin/com/r3/corda/jmeter/FlowSampler.kt
index b6d385fec1..206937da97 100644
--- a/tools/jmeter/src/main/kotlin/net/corda/jmeter/CordaRPCSampler.kt
+++ b/tools/jmeter/src/main/kotlin/com/r3/corda/jmeter/FlowSampler.kt
@@ -1,4 +1,4 @@
-package net.corda.jmeter
+package com.r3.corda.jmeter
import net.corda.client.rpc.CordaRPCClient
import net.corda.client.rpc.CordaRPCConnection
@@ -12,25 +12,30 @@ import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext
import org.apache.jmeter.samplers.SampleResult
-class CordaRPCSampler() : AbstractJavaSamplerClient() {
+abstract class FlowSampler() : AbstractJavaSamplerClient() {
companion object {
val host = Argument("host", "localhost", "", "The remote network address (hostname or IP address) to connect to for RPC.")
val port = Argument("port", "10000", "", "The remote port to connect to for RPC.")
val username = Argument("username", "corda", "", "The RPC user to connect to connect as.")
val password = Argument("password", "corda_is_awesome", "", "The password for the RPC user.")
- val className = Argument("pluginClassName", "", "", "The class name of the implementation of ${CordaRPCSampler.Plugin::class.java}.")
- val allArgs = setOf(host, port, username, password, className)
+ val allArgs = setOf(host, port, username, password)
}
var rpcClient: CordaRPCClient? = null
var rpcConnection: CordaRPCConnection? = null
var rpcProxy: CordaRPCOps? = null
- var plugin: Plugin? = null
override fun getDefaultParameters(): Arguments {
// Add copies of all args, since they seem to be mutable.
- return Arguments().apply { for(arg in allArgs) { addArgument(arg.clone() as Argument) } }
+ return Arguments().apply {
+ for (arg in allArgs) {
+ addArgument(arg.clone() as Argument)
+ }
+ for (arg in additionalArgs) {
+ addArgument(arg.clone() as Argument)
+ }
+ }
}
override fun setupTest(context: JavaSamplerContext) {
@@ -38,12 +43,11 @@ class CordaRPCSampler() : 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
- plugin = Class.forName(context.getParameter(className.name)).newInstance() as Plugin
- plugin!!.setupTest(rpcProxy!!, context)
+ setupTest(rpcProxy!!, context)
}
override fun runTest(context: JavaSamplerContext): SampleResult {
- val flowInvoke = plugin!!.createFlowInvoke(rpcProxy!!, context)
+ val flowInvoke = createFlowInvoke(rpcProxy!!, context)
val result = SampleResult()
result.sampleStart()
val handle = rpcProxy!!.startFlowDynamic(flowInvoke!!.flowLogicClass, *(flowInvoke!!.args))
@@ -55,7 +59,7 @@ class CordaRPCSampler() : AbstractJavaSamplerClient() {
return result.apply {
isSuccessful = true
}
- } catch(e: Exception) {
+ } catch (e: Exception) {
result.sampleEnd()
return result.apply {
isSuccessful = false
@@ -64,8 +68,7 @@ class CordaRPCSampler() : AbstractJavaSamplerClient() {
}
override fun teardownTest(context: JavaSamplerContext) {
- plugin!!.teardownTest(rpcProxy!!, context)
- plugin = null
+ teardownTest(rpcProxy!!, context)
rpcProxy = null
rpcConnection!!.close()
rpcConnection = null
@@ -73,11 +76,10 @@ class CordaRPCSampler() : AbstractJavaSamplerClient() {
super.teardownTest(context)
}
- interface Plugin {
- fun setupTest(rpcProxy: CordaRPCOps, testContext: JavaSamplerContext)
- fun createFlowInvoke(rpcProxy: CordaRPCOps, testContext: JavaSamplerContext): FlowInvoke<*>
- fun teardownTest(rpcProxy: CordaRPCOps, testContext: JavaSamplerContext)
- }
+ abstract val additionalArgs: Set
+ abstract fun setupTest(rpcProxy: CordaRPCOps, testContext: JavaSamplerContext)
+ abstract fun createFlowInvoke(rpcProxy: CordaRPCOps, testContext: JavaSamplerContext): FlowInvoke<*>
+ abstract fun teardownTest(rpcProxy: CordaRPCOps, testContext: JavaSamplerContext)
class FlowInvoke>(val flowLogicClass: Class, val args: Array)
}
\ No newline at end of file
diff --git a/tools/jmeter/src/main/kotlin/com/r3/corda/jmeter/Launcher.kt b/tools/jmeter/src/main/kotlin/com/r3/corda/jmeter/Launcher.kt
index f4695cebfa..b45302471f 100644
--- a/tools/jmeter/src/main/kotlin/com/r3/corda/jmeter/Launcher.kt
+++ b/tools/jmeter/src/main/kotlin/com/r3/corda/jmeter/Launcher.kt
@@ -8,11 +8,6 @@ import java.nio.file.Files
import java.nio.file.Paths
import kotlin.streams.asSequence
-/**
- * A wrapper around JMeter to make it run without having a JMeter download installed locally. One mode is used for
- * running on a remote cluster using an all-in-one bundle JAR using Capsule. The other is just used to run based on current
- * classpath, but with optional SSH tunnelling logic automatically invoked.
- */
class Launcher {
companion object {
@JvmStatic
@@ -50,16 +45,11 @@ class Launcher {
}
jmeter.start(arrayOf("-s", "-p", (capsuleDirPath / "jmeter.properties").toString()) + extraArgs + args)
} else {
- val searchPath = Files.readAllLines(Paths.get(System.getProperty("search_paths_file"))).first()
- logger.info("search_paths = $searchPath")
- System.setProperty("search_paths", searchPath)
jmeter.start(maybeOpenSshTunnels(args))
}
}
private fun maybeOpenSshTunnels(args: Array): Array {
- // We trim the args at the point "-Xssh" appears in the array of args. Anything after that is a host to
- // SSH tunnel to.
var index = 0
for (arg in args) {
if (arg == "-Xssh") {
diff --git a/tools/jmeter/src/main/kotlin/com/r3/corda/jmeter/Ssh.kt b/tools/jmeter/src/main/kotlin/com/r3/corda/jmeter/Ssh.kt
index 93cc88cd7c..3c4a38391a 100644
--- a/tools/jmeter/src/main/kotlin/com/r3/corda/jmeter/Ssh.kt
+++ b/tools/jmeter/src/main/kotlin/com/r3/corda/jmeter/Ssh.kt
@@ -10,9 +10,7 @@ import java.io.BufferedReader
import java.io.InputStreamReader
import java.util.*
-/**
- * Creates SSH tunnels for remote controlling SSH servers/agents from the local host (via UI or headless).
- */
+
class Ssh {
companion object {
val log = LoggerFactory.getLogger(this::class.java)
@@ -30,7 +28,7 @@ class Ssh {
val jmeterProps = loadProps("/jmeter.properties")
// The port the JMeter remote agents call back to on this client host.
val clientRmiLocalPort = jmeterProps.getProperty("client.rmi.localport").toInt()
- // Remote RMI registry port.
+ // TODO: Where is this value used? Just on the remote agent to set up the RMI registry?
val serverRmiPort = jmeterProps.getProperty("server.rmi.port", "1099").toInt()
// Where JMeter driver will try to connect for remote agents (should all be localhost so can ssh tunnel).
@@ -49,6 +47,7 @@ class Ssh {
val session = connectToHost(jsch, remoteHost, userName)
sessions += session
+ // TODO: maybe check the local host is actually "localhost"?
// For tunnelling the RMI registry on the remote agent
// ssh ${remoteHostAndPort.host} -L 0.0.0.0:${localHostAndPort.port}:localhost:$serverRmiPort -N
createOutboundTunnel(session, NetworkHostAndPort("0.0.0.0", localHostAndPort.port), NetworkHostAndPort("localhost", serverRmiPort))
diff --git a/tools/jmeter/src/main/kotlin/net/corda/jmeter/Launcher.kt b/tools/jmeter/src/main/kotlin/net/corda/jmeter/Launcher.kt
deleted file mode 100644
index 827e76cef4..0000000000
--- a/tools/jmeter/src/main/kotlin/net/corda/jmeter/Launcher.kt
+++ /dev/null
@@ -1,65 +0,0 @@
-package net.corda.jmeter
-
-import net.corda.core.internal.div
-import org.apache.jmeter.JMeter
-import org.slf4j.LoggerFactory
-import java.net.InetAddress
-import java.nio.file.Files
-import java.nio.file.Paths
-import kotlin.streams.asSequence
-
-class Launcher {
- companion object {
- @JvmStatic
- fun main(args: Array) {
- val logger = LoggerFactory.getLogger(this::class.java)
- logger.info("Launcher called with ${args.toList()}")
- val jmeter = JMeter()
- val capsuleDir = System.getProperty("capsule.dir")
- if (capsuleDir != null) {
- // We are running under Capsule, so assume we want a JMeter slave server to be controlled from
- // elsewhere.
- logger.info("Starting JMeter in server mode from $capsuleDir")
- val capsuleDirPath = Paths.get(capsuleDir)
- // Add all JMeter and Corda jars onto the JMeter search_paths
- val searchPath = Files.list(capsuleDirPath).asSequence().filter {
- val filename = it.fileName.toString()
- filename.endsWith(".jar") && (filename.contains("corda") || filename.contains("jmeter", true))
- }.joinToString(";")
- logger.info("search_paths = $searchPath")
- System.setProperty("search_paths", searchPath)
- // Set the JMeter home as a property rather than command line arg, due to inconsistent code in JMeter.
- System.setProperty("jmeter.home", capsuleDir)
- // Create two dirs that JMeter expects, if they don't already exist.
- Files.createDirectories(capsuleDirPath / "lib" / "ext")
- Files.createDirectories(capsuleDirPath / "lib" / "junit")
- // Now see if we have a hostname specific property file, and if so, add it.
- val hostName = InetAddress.getLocalHost().hostName
- val hostSpecificConfigFile = capsuleDirPath / "$hostName.properties"
- logger.info("Attempting to use host-specific properties file $hostSpecificConfigFile")
- val extraArgs = if (Files.exists(hostSpecificConfigFile)) {
- logger.info("Found host-specific properties file")
- arrayOf("-q", hostSpecificConfigFile.toString())
- } else {
- emptyArray()
- }
- jmeter.start(arrayOf("-s", "-p", (capsuleDirPath / "jmeter.properties").toString()) + extraArgs + args)
- } else {
- jmeter.start(maybeOpenSshTunnels(args))
- }
- }
-
- private fun maybeOpenSshTunnels(args: Array): Array {
- var index = 0
- for (arg in args) {
- if (arg == "-Xssh") {
- // start ssh
- Ssh.main(args.copyOfRange(index + 1, args.size), false)
- return if (index == 0) emptyArray() else args.copyOfRange(0, index)
- }
- index++
- }
- return args
- }
- }
-}
\ No newline at end of file
diff --git a/tools/jmeter/src/main/kotlin/net/corda/jmeter/Ssh.kt b/tools/jmeter/src/main/kotlin/net/corda/jmeter/Ssh.kt
deleted file mode 100644
index 47060966ca..0000000000
--- a/tools/jmeter/src/main/kotlin/net/corda/jmeter/Ssh.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-package net.corda.jmeter
-
-import com.jcraft.jsch.JSch
-import com.jcraft.jsch.Session
-import net.corda.core.utilities.NetworkHostAndPort
-import net.corda.loadtest.setupJSchWithSshAgent
-import net.corda.nodeapi.internal.addShutdownHook
-import org.slf4j.LoggerFactory
-import java.io.BufferedReader
-import java.io.InputStreamReader
-import java.util.*
-
-
-class Ssh {
- companion object {
- val log = LoggerFactory.getLogger(this::class.java)
-
- @JvmStatic
- @JvmOverloads
- fun main(args: Array, wait: Boolean = true) {
- val userName = System.getProperty("user.name")
- val jsch = setupJSchWithSshAgent()
- val sessions = mutableListOf()
-
- // Read jmeter.properties
- // For each host:port combo, map them to hosts from command line
-
- val jmeterProps = loadProps("/jmeter.properties")
- // The port the JMeter remote agents call back to on this client host.
- val clientRmiLocalPort = jmeterProps.getProperty("client.rmi.localport").toInt()
- // TODO: Where is this value used? Just on the remote agent to set up the RMI registry?
- val serverRmiPort = jmeterProps.getProperty("server.rmi.port", "1099").toInt()
-
- // Where JMeter driver will try to connect for remote agents (should all be localhost so can ssh tunnel).
- val localHostsAndPorts = jmeterProps.getProperty("remote_hosts", "").split(',').map { it.trim() }
- args.zip(localHostsAndPorts) { remoteHost, localHostAndPortString ->
- // Actual remote host and port we will tunnel to.
- log.info("Creating tunnels for $remoteHost")
- val localHostAndPort = NetworkHostAndPort.parse(localHostAndPortString)
-
- // For the remote host, load their specific property file, since it specifies remote RMI server port
- val unqualifiedHostName = remoteHost.substringBefore('.')
- val hostProps = loadProps("/$unqualifiedHostName.properties")
-
- val serverRmiLocalPort = hostProps.getProperty("server.rmi.localport", jmeterProps.getProperty("server.rmi.localport")).toInt()
-
- val session = connectToHost(jsch, remoteHost, userName)
- sessions += session
-
- // TODO: maybe check the local host is actually "localhost"?
- // For tunnelling the RMI registry on the remote agent
- // ssh ${remoteHostAndPort.host} -L 0.0.0.0:${localHostAndPort.port}:localhost:$serverRmiPort -N
- createOutboundTunnel(session, NetworkHostAndPort("0.0.0.0", localHostAndPort.port), NetworkHostAndPort("localhost", serverRmiPort))
-
- // For tunnelling the actual connection to the remote agent
- // ssh ${remoteHostAndPort.host} -L 0.0.0.0:$serverRmiLocalPort:localhost:$serverRmiLocalPort -N
- createOutboundTunnel(session, NetworkHostAndPort("0.0.0.0", serverRmiLocalPort), NetworkHostAndPort("localhost", serverRmiLocalPort))
-
- // For returning results to the client
- // ssh ${remoteHostAndPort.host} -R 0.0.0.0:clientRmiLocalPort:localhost:clientRmiLocalPort -N
- createInboundTunnel(session, NetworkHostAndPort("0.0.0.0", clientRmiLocalPort), NetworkHostAndPort("localhost", clientRmiLocalPort))
- }
-
- if (wait) {
- val input = BufferedReader(InputStreamReader(System.`in`))
- do {
- log.info("Type 'quit' to exit cleanly.")
- } while (input.readLine() != "quit")
- sessions.forEach {
- log.info("Closing tunnels for ${it.host}")
- it.disconnect()
- }
- } else {
- addShutdownHook {
- sessions.forEach {
- log.info("Closing tunnels for ${it.host}")
- it.disconnect()
- }
- }
- }
- }
-
- private fun loadProps(filename: String): Properties {
- val props = Properties()
- this::class.java.getResourceAsStream(filename).use {
- props.load(it)
- }
- return props
- }
-
- fun connectToHost(jSch: JSch, remoteHost: String, remoteUserName: String): Session {
- val session = jSch.getSession(remoteUserName, remoteHost, 22)
- // We don't check the host fingerprints because they may change often
- session.setConfig("StrictHostKeyChecking", "no")
- log.info("Connecting to $remoteHost...")
- session.connect()
- log.info("Connected to $remoteHost!")
- return session
- }
-
- fun createOutboundTunnel(session: Session, local: NetworkHostAndPort, remote: NetworkHostAndPort) {
- log.info("Creating outbound tunnel from $local to $remote with ${session.host}...")
- session.setPortForwardingL(local.host, local.port, remote.host, remote.port)
- log.info("Tunnel created!")
- }
-
- fun createInboundTunnel(session: Session, local: NetworkHostAndPort, remote: NetworkHostAndPort) {
- log.info("Creating inbound tunnel from $remote to $local on ${session.host}...")
- session.setPortForwardingR(remote.host, remote.port, local.host, local.port)
- log.info("Tunnel created!")
- }
- }
-}
\ No newline at end of file
diff --git a/tools/jmeter/src/main/kotlin/net/corda/jmeter/TraderDemoPlugins.kt b/tools/jmeter/src/main/kotlin/net/corda/jmeter/TraderDemoPlugins.kt
deleted file mode 100644
index 357a1067f0..0000000000
--- a/tools/jmeter/src/main/kotlin/net/corda/jmeter/TraderDemoPlugins.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-package net.corda.jmeter
-
-import net.corda.core.identity.CordaX500Name
-import net.corda.core.identity.Party
-import net.corda.core.messaging.CordaRPCOps
-import net.corda.core.utilities.OpaqueBytes
-import net.corda.finance.DOLLARS
-import net.corda.finance.flows.CashIssueFlow
-import net.corda.jmeter.CordaRPCSampler.FlowInvoke
-import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext
-
-
-abstract class AsbtractTraderDemoPlugin : CordaRPCSampler.Plugin {
-
- //lateinit var buyer: Party
- //lateinit var seller: Party
- lateinit var notary: Party
-
- //val bankA = CordaX500Name(organisation = "Bank A", locality = "London", country = "GB")
- //val bankB = CordaX500Name(organisation = "Bank B", locality = "New York", country = "US")
- val node1 = CordaX500Name(commonName = null, state = null, organisation = "Perf-10.155.0.4", organisationUnit = "Corda", locality = "London", country = "GB")
-
- protected fun getIdentities(rpc: CordaRPCOps) {
- //buyer = rpc.wellKnownPartyFromX500Name(bankA) ?: throw IllegalStateException("Don't know $bankA")
- //seller = rpc.wellKnownPartyFromX500Name(bankB) ?: throw IllegalStateException("Don't know $bankB")
- //notary = rpc.notaryIdentities().first()
- notary = rpc.wellKnownPartyFromX500Name(node1) ?: throw IllegalStateException("Don't know $node1")
- }
-}
-
-class CashIssuerPlugin : AsbtractTraderDemoPlugin() {
- override fun setupTest(rpcProxy: CordaRPCOps, testContext: JavaSamplerContext) {
- getIdentities(rpcProxy)
- }
-
- override fun teardownTest(rpcProxy: CordaRPCOps, testContext: JavaSamplerContext) {
- }
-
- override fun createFlowInvoke(rpcProxy: CordaRPCOps, testContext: JavaSamplerContext): FlowInvoke {
- val amount = 1_100_000_000_000.DOLLARS
- //val amounts = calculateRandomlySizedAmounts(amount, 3, 10, Random())
- //rpc.startFlow(net.corda.finance.flows::CashIssueFlow, amount, OpaqueBytes.of(1), notary).returnValue.getOrThrow()
- return FlowInvoke(CashIssueFlow::class.java, arrayOf(amount, OpaqueBytes.of(1), notary))
- }
-
-}
\ No newline at end of file
diff --git a/tools/jmeter/src/main/resources/Example Flow Request.jmx b/tools/jmeter/src/main/resources/Example Flow Request.jmx
index 6a2d25cfcf..257573d05e 100644
--- a/tools/jmeter/src/main/resources/Example Flow Request.jmx
+++ b/tools/jmeter/src/main/resources/Example Flow Request.jmx
@@ -46,7 +46,7 @@
password
- Password Here
+ corda_is_awesome
=
diff --git a/tools/jmeter/src/main/resources/Java Request.jmx b/tools/jmeter/src/main/resources/Java Request.jmx
deleted file mode 100644
index e0718d0211..0000000000
--- a/tools/jmeter/src/main/resources/Java Request.jmx
+++ /dev/null
@@ -1,177 +0,0 @@
-
-
-
-
-
- false
- false
-
-
-
-
-
-
-
- continue
-
- false
- 10
-
- 3
-
- 1509455820000
- 1509455820000
- false
-
-
-
-
-
-
-
-
- host
- localhost
- =
-
-
- port
- 10012
- =
-
-
- username
- demo
- =
-
-
- password
- demo
- =
-
-
- pluginClassName
- net.corda.jmeter.CashIssuerPlugin
- =
-
-
-
- net.corda.jmeter.CordaRPCSampler
-
-
-
-
- false
-
- saveConfig
-
-
- true
- true
- true
-
- true
- true
- true
- true
- false
- true
- true
- false
- false
- false
- true
- false
- false
- false
- true
- 0
- true
- true
- true
- true
- true
-
-
-
-
-
-
- false
-
- saveConfig
-
-
- true
- true
- true
-
- true
- true
- true
- true
- false
- true
- true
- false
- false
- false
- true
- false
- false
- false
- true
- 0
- true
- true
- true
- true
- true
-
-
-
-
-
-
- false
-
- saveConfig
-
-
- true
- true
- true
-
- true
- true
- true
- true
- false
- true
- true
- false
- false
- false
- true
- false
- false
- false
- true
- 0
- true
- true
- true
- true
- true
-
-
-
-
-
-
-
- true
-
-
-
-