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 27d790e8f1..668236515a 100644 --- a/node/src/main/kotlin/net/corda/node/shell/InteractiveShell.kt +++ b/node/src/main/kotlin/net/corda/node/shell/InteractiveShell.kt @@ -29,6 +29,7 @@ import net.corda.node.services.messaging.CURRENT_RPC_CONTEXT import net.corda.node.services.messaging.RpcContext import net.corda.node.services.statemachine.FlowStateMachineImpl import net.corda.node.utilities.ANSIProgressRenderer +import net.corda.node.utilities.CordaPersistence import net.corda.nodeapi.ArtemisMessagingComponent import net.corda.nodeapi.User import org.crsh.command.InvocationContext @@ -77,6 +78,8 @@ import kotlin.concurrent.thread object InteractiveShell { private val log = loggerFor() private lateinit var node: StartedNode + @VisibleForTesting + internal lateinit var database: CordaPersistence /** * Starts an interactive shell connected to the local terminal. This shell gives administrator access to the node @@ -84,6 +87,7 @@ object InteractiveShell { */ fun startShell(dir: Path, runLocalShell: Boolean, runSSHServer: Boolean, node: StartedNode) { this.node = node + this.database = node.database var runSSH = runSSHServer val config = Properties() @@ -287,8 +291,10 @@ object InteractiveShell { try { // Attempt construction with the given arguments. - paramNamesFromConstructor = parser.paramNamesFromConstructor(ctor) - val args = parser.parseArguments(clazz.name, paramNamesFromConstructor.zip(ctor.parameterTypes), inputData) + val args = database.transaction { + paramNamesFromConstructor = parser.paramNamesFromConstructor(ctor) + parser.parseArguments(clazz.name, paramNamesFromConstructor!!.zip(ctor.parameterTypes), inputData) + } if (args.size != ctor.parameterTypes.size) { errors.add("${getPrototype()}: Wrong number of arguments (${args.size} provided, ${ctor.parameterTypes.size} needed)") continue @@ -358,7 +364,7 @@ object InteractiveShell { var result: Any? = null try { InputStreamSerializer.invokeContext = context - val call = parser.parse(context.attributes["ops"] as CordaRPCOps, cmd) + val call = database.transaction { parser.parse(context.attributes["ops"] as CordaRPCOps, cmd) } result = call.call() if (result != null && result !is kotlin.Unit && result !is Void) { result = printAndFollowRPCResponse(result, out) diff --git a/node/src/test/kotlin/net/corda/node/InteractiveShellTest.kt b/node/src/test/kotlin/net/corda/node/InteractiveShellTest.kt index a0c425540d..d13fda0a4c 100644 --- a/node/src/test/kotlin/net/corda/node/InteractiveShellTest.kt +++ b/node/src/test/kotlin/net/corda/node/InteractiveShellTest.kt @@ -7,20 +7,33 @@ import net.corda.core.contracts.Amount import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowLogic import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate import net.corda.core.internal.FlowStateMachine import net.corda.core.utilities.ProgressTracker -import net.corda.core.utilities.UntrustworthyData import net.corda.node.services.identity.InMemoryIdentityService import net.corda.node.shell.InteractiveShell +import net.corda.node.utilities.configureDatabase import net.corda.testing.DEV_TRUST_ROOT import net.corda.testing.MEGA_CORP import net.corda.testing.MEGA_CORP_IDENTITY +import net.corda.testing.node.MockServices +import net.corda.testing.node.MockServices.Companion.makeTestIdentityService +import org.junit.After +import org.junit.Before import org.junit.Test import java.util.* import kotlin.test.assertEquals class InteractiveShellTest { + @Before + fun setup() { + InteractiveShell.database = configureDatabase(MockServices.makeTestDataSourceProperties(), MockServices.makeTestDatabaseProperties(), createIdentityService = ::makeTestIdentityService) + } + + @After + fun shutdown() { + InteractiveShell.database.close() + } + @Suppress("UNUSED") class FlowA(val a: String) : FlowLogic() { constructor(b: Int) : this(b.toString())