From cb4db31b3b5c503b15713dc897cd171e9b7c7cb9 Mon Sep 17 00:00:00 2001 From: josecoll <jose.coll@r3cev.com> Date: Thu, 13 Sep 2018 13:46:39 +0100 Subject: [PATCH] CORDA-1892 - CRaSH shell flow start fix for similar flow names. (#3874) (#3928) * CORDA-1892 CRaSH shell flow start fix for similar flow names. (#3874) * Added fix and associated unit test. * Fixed broken unit test + added another test case + used NoOpFlows + use Mock output object to assert correct result output. * Remove unnecessary additional println. * Minor cleanup in test code. * Relax nameFragment matching to cater for fully qualified and simple Flow classname specifications. * Remove superfluous check. * Minor fix + added additional Unit Test cases to cover all scenarios. * Reverted back to original behaviour + extra check to avoid ambiguity for exact match. * Changes following final PR review comments. * Revert to non visible latch as no associated integration tests defined in this release. --- .../net/corda/node/shell/InteractiveShell.kt | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/node/src/main/kotlin/net/corda/node/shell/InteractiveShell.kt b/node/src/main/kotlin/net/corda/node/shell/InteractiveShell.kt index d13997d2c3..c6f232a453 100644 --- a/node/src/main/kotlin/net/corda/node/shell/InteractiveShell.kt +++ b/node/src/main/kotlin/net/corda/node/shell/InteractiveShell.kt @@ -220,26 +220,32 @@ object InteractiveShell { */ @JvmStatic fun runFlowByNameFragment(nameFragment: String, inputData: String, output: RenderPrintWriter, rpcOps: CordaRPCOps, ansiProgressRenderer: ANSIProgressRenderer) { - val matches = + val matches = try { rpcOps.registeredFlows().filter { nameFragment in it } - + } catch (e: PermissionException) { + output.println(e.message ?: "Access denied", Color.red) + return + } if (matches.isEmpty()) { output.println("No matching flow found, run 'flow list' to see your options.", Color.red) return - } else if (matches.size > 1) { + } else if (matches.size > 1 && matches.find { it.endsWith(nameFragment)} == null) { output.println("Ambiguous name provided, please be more specific. Your options are:") matches.forEachIndexed { i, s -> output.println("${i + 1}. $s", Color.yellow) } return } - val clazz: Class<FlowLogic<*>> = uncheckedCast(Class.forName(matches.single())) + val flowName = matches.find { it.endsWith(nameFragment)} ?: matches.single() + val clazz: Class<FlowLogic<*>> = uncheckedCast(Class.forName(flowName)) try { // Show the progress tracker on the console until the flow completes or is interrupted with a // Ctrl-C keypress. val stateObservable = runFlowFromString({ clazz, args -> rpcOps.startTrackedFlowDynamic(clazz, *args) }, inputData, clazz) val latch = CountDownLatch(1) - ansiProgressRenderer.render(stateObservable, { latch.countDown() }) + ansiProgressRenderer.render(stateObservable, latch::countDown) + // Wait for the flow to end and the progress tracker to notice. By the time the latch is released + // the tracker is done with the screen. while (!Thread.currentThread().isInterrupted) { try { latch.await()