mirror of
https://github.com/corda/corda.git
synced 2025-06-13 04:38:19 +00:00
Fixing flow snapshot feature (#1685)
This commit is contained in:
@ -2,23 +2,25 @@ package net.corda.testing
|
|||||||
|
|
||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import net.corda.client.jackson.JacksonSupport
|
import net.corda.client.jackson.JacksonSupport
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.*
|
||||||
import net.corda.core.flows.FlowStackSnapshot
|
|
||||||
import net.corda.core.flows.StartableByRPC
|
|
||||||
import net.corda.core.flows.StateMachineRunId
|
|
||||||
import net.corda.core.internal.div
|
import net.corda.core.internal.div
|
||||||
import net.corda.core.internal.list
|
import net.corda.core.internal.list
|
||||||
import net.corda.core.internal.read
|
import net.corda.core.internal.read
|
||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
import net.corda.node.services.FlowPermissions.Companion.startFlowPermission
|
import net.corda.node.services.FlowPermissions.Companion.startFlowPermission
|
||||||
|
import net.corda.node.services.network.NetworkMapService
|
||||||
|
import net.corda.node.services.transactions.ValidatingNotaryService
|
||||||
import net.corda.nodeapi.User
|
import net.corda.nodeapi.User
|
||||||
|
import net.corda.nodeapi.internal.ServiceInfo
|
||||||
import net.corda.testing.driver.driver
|
import net.corda.testing.driver.driver
|
||||||
|
import net.corda.testing.node.MockNetwork
|
||||||
import org.junit.Ignore
|
import org.junit.Ignore
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertNull
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
@CordaSerializable
|
@CordaSerializable
|
||||||
@ -178,6 +180,31 @@ class MultiplePersistingSideEffectFlow(val persistCallCount: Int) : FlowLogic<St
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flow that tests whether the serialization works correctly.
|
||||||
|
*/
|
||||||
|
@StartableByRPC
|
||||||
|
@InitiatingFlow
|
||||||
|
class FlowStackSnapshotSerializationTestingFlow : FlowLogic<Unit>() {
|
||||||
|
|
||||||
|
@Suspendable
|
||||||
|
override fun call() {
|
||||||
|
val flowStackSnapshot = flowStackSnapshot()
|
||||||
|
val mySession = initiateFlow(ourIdentity)
|
||||||
|
mySession.sendAndReceive<String>("Ping")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@InitiatedBy(FlowStackSnapshotSerializationTestingFlow::class)
|
||||||
|
class DummyFlow(private val otherSideSession: FlowSession) : FlowLogic<Unit>() {
|
||||||
|
|
||||||
|
@Suspendable
|
||||||
|
override fun call() {
|
||||||
|
val message = otherSideSession.receive<String>()
|
||||||
|
otherSideSession.send("$message Pong")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun readFlowStackSnapshotFromDir(baseDir: Path, flowId: StateMachineRunId): FlowStackSnapshot {
|
fun readFlowStackSnapshotFromDir(baseDir: Path, flowId: StateMachineRunId): FlowStackSnapshot {
|
||||||
val snapshotFile = flowSnapshotDir(baseDir, flowId) / "flowStackSnapshot.json"
|
val snapshotFile = flowSnapshotDir(baseDir, flowId) / "flowStackSnapshot.json"
|
||||||
return snapshotFile.read {
|
return snapshotFile.read {
|
||||||
@ -263,6 +290,26 @@ class FlowStackSnapshotTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `flowStackSnapshot object is serializable`() {
|
||||||
|
val mockNet = MockNetwork(threadPerNode = true)
|
||||||
|
val notaryService = ServiceInfo(ValidatingNotaryService.type)
|
||||||
|
val notaryNode = mockNet.createNode(
|
||||||
|
legalName = DUMMY_NOTARY.name,
|
||||||
|
overrideServices = mapOf(notaryService to DUMMY_NOTARY_KEY),
|
||||||
|
advertisedServices = *arrayOf(ServiceInfo(NetworkMapService.type), notaryService))
|
||||||
|
val node = mockNet.createPartyNode(notaryNode.network.myAddress)
|
||||||
|
node.internals.registerInitiatedFlow(DummyFlow::class.java)
|
||||||
|
node.services.startFlow(FlowStackSnapshotSerializationTestingFlow()).resultFuture.get()
|
||||||
|
val thrown = try {
|
||||||
|
mockNet.stopNodes()
|
||||||
|
null
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
exception
|
||||||
|
}
|
||||||
|
assertNull(thrown)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `persistFlowStackSnapshot stack traces are aligned with stack objects`() {
|
fun `persistFlowStackSnapshot stack traces are aligned with stack objects`() {
|
||||||
driver(startNodesInProcess = true) {
|
driver(startNodesInProcess = true) {
|
||||||
|
@ -54,7 +54,8 @@ class FlowStackSnapshotFactoryImpl : FlowStackSnapshotFactory {
|
|||||||
val objectStack = getObjectStack(stack).toList()
|
val objectStack = getObjectStack(stack).toList()
|
||||||
val frameOffsets = getFrameOffsets(stack)
|
val frameOffsets = getFrameOffsets(stack)
|
||||||
val frameObjects = frameOffsets.map { (frameOffset, frameSize) ->
|
val frameObjects = frameOffsets.map { (frameOffset, frameSize) ->
|
||||||
objectStack.subList(frameOffset + 1, frameOffset + frameSize + 1)
|
// We need to convert the sublist to a list due to the Kryo lack of support when serializing
|
||||||
|
objectStack.subList(frameOffset + 1, frameOffset + frameSize + 1).toList()
|
||||||
}
|
}
|
||||||
// We drop the first element as it is corda internal call irrelevant from the perspective of a CordApp developer
|
// We drop the first element as it is corda internal call irrelevant from the perspective of a CordApp developer
|
||||||
val relevantStackTrace = removeConstructorStackTraceElements(stackTrace).drop(1)
|
val relevantStackTrace = removeConstructorStackTraceElements(stackTrace).drop(1)
|
||||||
|
Reference in New Issue
Block a user