Merge remote-tracking branch 'origin/release/os/4.6' into rni/notick/46-47-merge-2020-09-04

This commit is contained in:
Ross Nicoll 2020-09-04 14:15:47 +01:00
commit 0c16957622
33 changed files with 490 additions and 156 deletions

49
.ci/dev/open-j9/Jenkinsfile vendored Normal file
View File

@ -0,0 +1,49 @@
import static com.r3.build.BuildControl.killAllExistingBuildsForJob
@Library('existing-build-control')
import static com.r3.build.BuildControl.killAllExistingBuildsForJob
killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger())
pipeline {
agent { label 'open-j9' }
options {
timestamps()
timeout(time: 10, unit: 'HOURS')
}
environment {
EXECUTOR_NUMBER = "${env.EXECUTOR_NUMBER}"
}
stages {
stage('Unit Tests') {
steps {
sh "./gradlew clean --continue test --info"
}
}
stage('Integration Tests') {
steps {
sh "./gradlew clean --continue integrationTest --info"
}
}
stage('Smoke Tests') {
steps {
sh "./gradlew clean --continue smokeTest --info"
}
}
stage('Slow Integration Tests') {
steps {
sh "./gradlew clean --continue slowIntegrationTest --info"
}
}
}
post {
always {
junit '**/build/test-results/**/*.xml'
}
cleanup {
deleteDir() /* clean up our workspace */
}
}
}

View File

@ -16,11 +16,11 @@ guavaVersion=28.0-jre
# Quasar version to use with Java 8:
quasarVersion=0.7.13_r3
# Quasar version to use with Java 11:
quasarVersion11=0.8.0_r3
quasarVersion11=0.8.1_r3
jdkClassifier11=jdk11
proguardVersion=6.1.1
bouncycastleVersion=1.66
classgraphVersion=4.8.78
classgraphVersion=4.8.89
disruptorVersion=3.4.2
typesafeConfigVersion=1.3.4
jsr305Version=3.0.2

View File

@ -18,6 +18,8 @@ import net.corda.testing.core.BOB_NAME
import net.corda.testing.core.singleIdentity
import net.corda.testing.driver.DriverParameters
import net.corda.testing.driver.driver
import net.corda.testing.internal.IS_OPENJ9
import org.junit.Assume
import org.junit.Test
import java.time.Duration
import java.time.Instant
@ -27,6 +29,7 @@ class FlowSleepTest {
@Test(timeout = 300_000)
fun `flow can sleep`() {
Assume.assumeTrue(!IS_OPENJ9)
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
val (start, finish) = alice.rpc.startFlow(::SleepyFlow).returnValue.getOrThrow(1.minutes)
@ -52,6 +55,7 @@ class FlowSleepTest {
@Test(timeout = 300_000)
fun `flow can sleep and perform other suspending functions`() {
Assume.assumeTrue(!IS_OPENJ9)
// ensures that events received while the flow is sleeping are not processed
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
val (alice, bob) = listOf(ALICE_NAME, BOB_NAME)

View File

@ -35,6 +35,8 @@ import org.bouncycastle.asn1.x9.X9ObjectIdentifiers
import org.bouncycastle.crypto.CryptoServicesRegistrar
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey
import org.bouncycastle.jcajce.provider.asymmetric.edec.BCEdDSAPrivateKey
import org.bouncycastle.jcajce.provider.asymmetric.edec.BCEdDSAPublicKey
import org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPrivateKey
import org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPublicKey
import org.bouncycastle.jce.ECNamedCurveTable
@ -308,11 +310,11 @@ object Crypto {
fun decodePrivateKey(encodedKey: ByteArray): PrivateKey {
val keyInfo = PrivateKeyInfo.getInstance(encodedKey)
if (keyInfo.privateKeyAlgorithm.algorithm == ASN1ObjectIdentifier(CordaOID.ALIAS_PRIVATE_KEY)) {
return decodeAliasPrivateKey(keyInfo)
return convertIfBCEdDSAPrivateKey(decodeAliasPrivateKey(keyInfo))
}
val signatureScheme = findSignatureScheme(keyInfo.privateKeyAlgorithm)
val keyFactory = keyFactory(signatureScheme)
return keyFactory.generatePrivate(PKCS8EncodedKeySpec(encodedKey))
return convertIfBCEdDSAPrivateKey(keyFactory.generatePrivate(PKCS8EncodedKeySpec(encodedKey)))
}
@DeleteForDJVM
@ -354,7 +356,7 @@ object Crypto {
}
try {
val keyFactory = keyFactory(signatureScheme)
return keyFactory.generatePrivate(PKCS8EncodedKeySpec(encodedKey))
return convertIfBCEdDSAPrivateKey(keyFactory.generatePrivate(PKCS8EncodedKeySpec(encodedKey)))
} catch (ikse: InvalidKeySpecException) {
throw InvalidKeySpecException("This private key cannot be decoded, please ensure it is PKCS8 encoded and that " +
"it corresponds to the input scheme's code name.", ikse)
@ -373,7 +375,7 @@ object Crypto {
val subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(encodedKey)
val signatureScheme = findSignatureScheme(subjectPublicKeyInfo.algorithm)
val keyFactory = keyFactory(signatureScheme)
return keyFactory.generatePublic(X509EncodedKeySpec(encodedKey))
return convertIfBCEdDSAPublicKey(keyFactory.generatePublic(X509EncodedKeySpec(encodedKey)))
}
/**
@ -408,7 +410,7 @@ object Crypto {
}
try {
val keyFactory = keyFactory(signatureScheme)
return keyFactory.generatePublic(X509EncodedKeySpec(encodedKey))
return convertIfBCEdDSAPublicKey(keyFactory.generatePublic(X509EncodedKeySpec(encodedKey)))
} catch (ikse: InvalidKeySpecException) {
throw InvalidKeySpecException("This public key cannot be decoded, please ensure it is X509 encoded and " +
"that it corresponds to the input scheme's code name.", ikse)
@ -988,6 +990,20 @@ object Crypto {
}
}
private fun convertIfBCEdDSAPublicKey(key: PublicKey): PublicKey {
return when (key) {
is BCEdDSAPublicKey -> EdDSAPublicKey(X509EncodedKeySpec(key.encoded))
else -> key
}
}
private fun convertIfBCEdDSAPrivateKey(key: PrivateKey): PrivateKey {
return when (key) {
is BCEdDSAPrivateKey -> EdDSAPrivateKey(PKCS8EncodedKeySpec(key.encoded))
else -> key
}
}
/**
* Convert a public key to a supported implementation.
* @param key a public key.
@ -1015,6 +1031,7 @@ object Crypto {
is BCSphincs256PublicKey -> key
is EdDSAPublicKey -> key
is CompositeKey -> key
is BCEdDSAPublicKey -> convertIfBCEdDSAPublicKey(key)
else -> decodePublicKey(key.encoded)
}
}
@ -1035,6 +1052,7 @@ object Crypto {
is BCRSAPrivateKey -> key
is BCSphincs256PrivateKey -> key
is EdDSAPrivateKey -> key
is BCEdDSAPrivateKey -> convertIfBCEdDSAPrivateKey(key)
else -> decodePrivateKey(key.encoded)
}
}

View File

@ -1,5 +1,5 @@
kotlin.incremental=true
org.gradle.jvmargs=-XX:+UseG1GC -Xmx1g -Dfile.encoding=UTF-8
org.gradle.jvmargs=-XX:+UseG1GC -Xmx4g -Dfile.encoding=UTF-8
org.gradle.caching=false
owasp.failOnError=false
owasp.failBuildOnCVSS=11.0

View File

@ -50,10 +50,13 @@ import net.corda.nodeapi.internal.crypto.loadOrCreateKeyStore
import net.corda.nodeapi.internal.crypto.save
import net.corda.nodeapi.internal.crypto.toBc
import net.corda.nodeapi.internal.crypto.x509
import net.corda.testing.internal.IS_OPENJ9
import net.i2p.crypto.eddsa.EdDSAPrivateKey
import org.assertj.core.api.Assertions.assertThat
import org.bouncycastle.asn1.x509.*
import org.bouncycastle.jcajce.provider.asymmetric.edec.BCEdDSAPrivateKey
import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PrivateKey
import org.junit.Assume
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
@ -374,6 +377,7 @@ class X509UtilitiesTest {
@Test(timeout=300_000)
fun `create server cert and use in OpenSSL channel`() {
Assume.assumeTrue(!IS_OPENJ9)
val sslConfig = CertificateStoreStubs.P2P.withCertificatesDirectory(tempFolder.root.toPath(), keyStorePassword = "serverstorepass")
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
@ -446,7 +450,9 @@ class X509UtilitiesTest {
private fun <U, C> getCorrectKeyFromKeystore(signatureScheme: SignatureScheme, uncastedClass: Class<U>, castedClass: Class<C>) {
val keyPair = generateKeyPair(signatureScheme)
val (keyFromKeystore, keyFromKeystoreCasted) = storeAndGetKeysFromKeystore(keyPair)
assertThat(keyFromKeystore).isInstanceOf(uncastedClass)
if (uncastedClass == EdDSAPrivateKey::class.java && keyFromKeystore !is BCEdDSAPrivateKey) {
assertThat(keyFromKeystore).isInstanceOf(uncastedClass)
}
assertThat(keyFromKeystoreCasted).isInstanceOf(castedClass)
}

View File

@ -77,6 +77,16 @@ fun createDevNetworkMapCa(rootCa: CertificateAndKeyPair = DEV_ROOT_CA): Certific
return CertificateAndKeyPair(cert, keyPair)
}
fun createDevNetworkParametersCa(rootCa: CertificateAndKeyPair = DEV_ROOT_CA): CertificateAndKeyPair {
val keyPair = generateKeyPair()
val cert = X509Utilities.createCertificate(
CertificateType.NETWORK_PARAMETERS,
rootCa.certificate,
rootCa.keyPair,
X500Principal("CN=Network Parameters,O=R3 Ltd,L=London,C=GB"),
keyPair.public)
return CertificateAndKeyPair(cert, keyPair)
}
/**
* Create a dev node CA cert, as a sub-cert of the given [intermediateCa], and matching key pair using the given
* [CordaX500Name] as the cert subject.

View File

@ -463,12 +463,18 @@ fun Kryo.serializationContext(): SerializeAsTokenContext? = context.get(serializ
class ThrowableSerializer<T>(kryo: Kryo, type: Class<T>) : Serializer<Throwable>(false, true) {
private companion object {
private val IS_OPENJ9 = System.getProperty("java.vm.name").toLowerCase().contains("openj9")
private val suppressedField = Throwable::class.java.getDeclaredField("suppressedExceptions")
private val sentinelValue = let {
val sentinelField = Throwable::class.java.getDeclaredField("SUPPRESSED_SENTINEL")
sentinelField.isAccessible = true
sentinelField.get(null)
if (!IS_OPENJ9) {
val sentinelField = Throwable::class.java.getDeclaredField("SUPPRESSED_SENTINEL")
sentinelField.isAccessible = true
sentinelField.get(null)
}
else {
Collections.EMPTY_LIST
}
}
init {

View File

@ -30,7 +30,9 @@ import net.corda.testing.core.DummyCommandData
import net.corda.testing.core.singleIdentity
import net.corda.testing.driver.DriverParameters
import net.corda.testing.driver.driver
import org.apache.commons.lang3.SystemUtils
import org.hibernate.exception.ConstraintViolationException
import org.junit.Assume
import org.junit.Before
import org.junit.Test
import java.lang.RuntimeException
@ -315,6 +317,8 @@ class FlowEntityManagerTest : AbstractFlowEntityManagerTest() {
@Test(timeout = 300_000)
fun `constraint violation that is caught inside an entity manager should allow a flow to continue processing as normal`() {
// This test is generating JDK11 contract code on JDK11
Assume.assumeTrue(!SystemUtils.IS_JAVA_11)
var counter = 0
StaffedFlowHospital.onFlowDischarged.add { _, _ -> ++counter }
driver(DriverParameters(startNodesInProcess = true)) {

View File

@ -50,7 +50,8 @@ class H2SecurityTests {
inMemoryDB = false,
startNodesInProcess = false,
notarySpecs = emptyList(),
cordappsForAllNodes = emptyList()
cordappsForAllNodes = emptyList(),
premigrateH2Database = false
)) {
val port = getFreePort()
startNode(customOverrides = mapOf(h2AddressKey to "localhost:$port", dbPasswordKey to "x")).getOrThrow()
@ -71,7 +72,8 @@ class H2SecurityTests {
inMemoryDB = false,
startNodesInProcess = false,
notarySpecs = emptyList(),
cordappsForAllNodes = listOf(enclosedCordapp())
cordappsForAllNodes = listOf(enclosedCordapp()),
premigrateH2Database = false
)) {
val port = getFreePort()
val nodeHandle = startNode(rpcUsers = listOf(user), customOverrides = mapOf(h2AddressKey to "localhost:$port",

View File

@ -62,7 +62,7 @@ class NonDeterministicContractVerifyTest {
.returnValue.getOrThrow()
}
assertThat(ex)
.hasMessageMatching("^NoSuchMethodError: .*\\Qsandbox.java.time.Instant.now()\\E.*\$")
.hasMessageMatching("^NoSuchMethodError: .*[\\Qsandbox.java.time.Instant.now()\\E|\\Qsandbox.java/time/Instant/now()\\E].*\$")
}
}
@ -101,7 +101,7 @@ class NonDeterministicContractVerifyTest {
.returnValue.getOrThrow()
}
assertThat(ex)
.hasMessageMatching("^NoSuchMethodError: .*\\Qsandbox.java.util.UUID.randomUUID()\\E.*\$")
.hasMessageMatching("^NoSuchMethodError: .*[\\Qsandbox.java.util.UUID.randomUUID()\\E|\\Qsandbox/java/util/UUID/randomUUID()\\E].*\$")
}
}

View File

@ -82,7 +82,8 @@ class LargeTransactionsTest {
driver(DriverParameters(
startNodesInProcess = true,
cordappsForAllNodes = listOf(DUMMY_CONTRACTS_CORDAPP, enclosedCordapp()),
networkParameters = testNetworkParameters(maxMessageSize = 15.MB.toInt(), maxTransactionSize = 13.MB.toInt())
networkParameters = testNetworkParameters(maxMessageSize = 15.MB.toInt(), maxTransactionSize = 13.MB.toInt()),
premigrateH2Database = false
)) {
val rpcUser = User("admin", "admin", setOf("ALL"))
val (alice, _) = listOf(ALICE_NAME, BOB_NAME).map { startNode(providedName = it, rpcUsers = listOf(rpcUser)) }.transpose().getOrThrow()

View File

@ -19,7 +19,6 @@ import net.corda.node.utilities.AppendOnlyPersistentMap
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.network.SignedNetworkParameters
import net.corda.nodeapi.internal.network.verifiedNetworkMapCert
import net.corda.nodeapi.internal.network.verifiedNetworkParametersCert
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.NODE_DATABASE_PREFIX
@ -86,7 +85,7 @@ class DBNetworkParametersStorage(
override fun saveParameters(signedNetworkParameters: SignedNetworkParameters) {
log.trace { "Saving new network parameters to network parameters storage." }
val networkParameters = signedNetworkParameters.verifiedNetworkMapCert(trustRoot)
val networkParameters = signedNetworkParameters.verifiedNetworkParametersCert(trustRoot)
val hash = signedNetworkParameters.raw.hash
log.trace { "Parameters to save $networkParameters with hash $hash" }
database.transaction {

View File

@ -348,7 +348,7 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
val cordappElement = cordappJarPath.url.toString()
logger.info("Scanning CorDapp in $cordappElement")
val scanResult = ClassGraph()
.filterClasspathElements { elt -> elt == cordappElement }
.filterClasspathElementsByURL { elt -> elt == cordappJarPath.url }
.overrideClassLoaders(appClassLoader)
.ignoreParentClassLoaders()
.enableAllInfo()

View File

@ -42,12 +42,14 @@ import net.corda.testing.core.*
import net.corda.testing.dsl.LedgerDSL
import net.corda.testing.dsl.TestLedgerDSLInterpreter
import net.corda.testing.dsl.TestTransactionDSLInterpreter
import net.corda.testing.internal.IS_OPENJ9
import net.corda.testing.internal.LogHelper
import net.corda.testing.internal.vault.VaultFiller
import net.corda.testing.node.internal.*
import net.corda.testing.node.ledger
import org.assertj.core.api.Assertions.assertThat
import org.junit.After
import org.junit.Assume
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@ -211,6 +213,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
@Test(timeout=300_000)
fun `shutdown and restore`() {
Assume.assumeTrue(!IS_OPENJ9)
mockNet = InternalMockNetwork(cordappsForAllNodes = listOf(FINANCE_CONTRACTS_CORDAPP))
val notaryNode = mockNet.defaultNotaryNode
val notary = mockNet.defaultNotaryIdentity

View File

@ -2,16 +2,23 @@ package net.corda.node.services.network
import com.google.common.jimfs.Configuration
import com.google.common.jimfs.Jimfs
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.*
import net.corda.core.serialization.deserialize
import net.corda.core.utilities.days
import net.corda.core.utilities.seconds
import net.corda.coretesting.internal.DEV_INTERMEDIATE_CA
import net.corda.node.VersionInfo
import net.corda.node.internal.NetworkParametersReader
import net.corda.nodeapi.internal.network.*
import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.core.SerializationEnvironmentRule
import net.corda.coretesting.internal.DEV_ROOT_CA
import net.corda.nodeapi.internal.createDevNetworkMapCa
import net.corda.nodeapi.internal.createDevNetworkParametersCa
import net.corda.nodeapi.internal.createDevNodeCa
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
import net.corda.testing.core.TestIdentity
import net.corda.testing.node.internal.network.NetworkMapServer
import org.assertj.core.api.Assertions.assertThat
import org.junit.After
@ -21,6 +28,7 @@ import org.junit.Test
import java.net.URL
import java.nio.file.FileSystem
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertFalse
import kotlin.test.assertNotNull
@ -84,4 +92,23 @@ class NetworkParametersReaderTest {
val parameters = inByteArray.deserialize<SignedNetworkParameters>()
assertThat(parameters.verified().eventHorizon).isEqualTo(Int.MAX_VALUE.days)
}
@Test(timeout = 300_000)
fun `verifying works with NETWORK_PARAMETERS role and NETWORK_MAP role, but fails for NODE_CA role`() {
val netParameters = testNetworkParameters(epoch = 1)
val certKeyPairNetworkParameters: CertificateAndKeyPair = createDevNetworkParametersCa()
val netParamsForNetworkParameters= certKeyPairNetworkParameters.sign(netParameters)
netParamsForNetworkParameters.verifiedNetworkParametersCert(DEV_ROOT_CA.certificate)
val certKeyPairNetworkMap: CertificateAndKeyPair = createDevNetworkMapCa()
val netParamsForNetworkMap = certKeyPairNetworkMap.sign(netParameters)
netParamsForNetworkMap.verifiedNetworkParametersCert(DEV_ROOT_CA.certificate)
val megaCorp = TestIdentity(CordaX500Name("MegaCorp", "London", "GB"))
val x = createDevNodeCa(DEV_INTERMEDIATE_CA, megaCorp.name)
val netParamsForNode = x.sign(netParameters)
assertFailsWith(IllegalArgumentException::class, "Incorrect cert role: NODE_CA") {
netParamsForNode.verifiedNetworkParametersCert(DEV_ROOT_CA.certificate)
}
}
}

View File

@ -54,6 +54,7 @@ import net.corda.testing.core.BOB_NAME
import net.corda.testing.core.dummyCommand
import net.corda.testing.core.singleIdentity
import net.corda.testing.flows.registerCordappFlowFactory
import net.corda.testing.internal.IS_OPENJ9
import net.corda.testing.internal.LogHelper
import net.corda.testing.node.InMemoryMessagingNetwork.MessageTransfer
import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin
@ -74,6 +75,7 @@ import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Assume
import org.junit.Before
import org.junit.Test
import rx.Notification
@ -82,6 +84,7 @@ import java.sql.SQLTransientConnectionException
import java.time.Clock
import java.time.Duration
import java.time.Instant
import java.time.temporal.ChronoUnit
import java.util.UUID
import java.util.concurrent.TimeoutException
import java.util.function.Predicate
@ -384,6 +387,7 @@ class FlowFrameworkTests {
@Test(timeout = 300_000)
fun `Flow metadata finish time is set in database when the flow finishes`() {
Assume.assumeTrue(!IS_OPENJ9)
val terminationSignal = Semaphore(0)
val clientId = UUID.randomUUID().toString()
val flow = aliceNode.services.startFlowWithClientId(clientId, NoOpFlow(terminateUponSignal = terminationSignal))
@ -397,7 +401,7 @@ class FlowFrameworkTests {
aliceNode.database.transaction {
val metadata = session.find(DBCheckpointStorage.DBFlowMetadata::class.java, flow.id.uuid.toString())
assertNotNull(metadata.finishInstant)
assertTrue(metadata.finishInstant!! >= metadata.startInstant)
assertTrue(metadata.finishInstant!!.truncatedTo(ChronoUnit.MILLIS) >= metadata.startInstant.truncatedTo(ChronoUnit.MILLIS))
}
}

View File

@ -48,6 +48,7 @@ import org.junit.Before
import org.junit.Ignore
import org.junit.Test
import java.time.Instant
import java.time.temporal.ChronoUnit
import java.util.UUID
import java.util.concurrent.CompletableFuture
import java.util.concurrent.Executors
@ -118,7 +119,8 @@ class FlowMetadataRecordingTest {
assertThat(it.launchingCordapp).contains("custom-cordapp")
assertEquals(PLATFORM_VERSION, it.platformVersion)
assertEquals(user.username, it.startedBy)
assertEquals(context!!.trace.invocationId.timestamp, it.invocationInstant)
assertEquals(context!!.trace.invocationId.timestamp.truncatedTo((ChronoUnit.MILLIS)),
it.invocationInstant.truncatedTo(ChronoUnit.MILLIS))
assertTrue(it.startInstant >= it.invocationInstant)
assertNull(it.finishInstant)
}
@ -159,7 +161,8 @@ class FlowMetadataRecordingTest {
assertThat(it.launchingCordapp).contains("custom-cordapp")
assertEquals(PLATFORM_VERSION, it.platformVersion)
assertEquals(user.username, it.startedBy)
assertEquals(context!!.trace.invocationId.timestamp, it.invocationInstant)
assertEquals(context!!.trace.invocationId.timestamp.truncatedTo(ChronoUnit.MILLIS),
it.invocationInstant.truncatedTo(ChronoUnit.MILLIS))
assertTrue(it.startInstant >= it.invocationInstant)
assertNull(it.finishInstant)
}
@ -261,7 +264,8 @@ class FlowMetadataRecordingTest {
assertThat(it.launchingCordapp).contains("custom-cordapp")
assertEquals(8, it.platformVersion)
assertEquals(nodeAHandle.nodeInfo.singleIdentity().name.toString(), it.startedBy)
assertEquals(context!!.trace.invocationId.timestamp, it.invocationInstant)
assertEquals(context!!.trace.invocationId.timestamp.truncatedTo(ChronoUnit.MILLIS),
it.invocationInstant.truncatedTo(ChronoUnit.MILLIS))
assertTrue(it.startInstant >= it.invocationInstant)
assertNull(it.finishInstant)
}
@ -309,7 +313,8 @@ class FlowMetadataRecordingTest {
assertThat(it.launchingCordapp).contains("custom-cordapp")
assertEquals(PLATFORM_VERSION, it.platformVersion)
assertEquals(MyService::class.java.name, it.startedBy)
assertEquals(context!!.trace.invocationId.timestamp, it.invocationInstant)
assertEquals(context!!.trace.invocationId.timestamp.truncatedTo(ChronoUnit.MILLIS),
it.invocationInstant.truncatedTo(ChronoUnit.MILLIS))
assertTrue(it.startInstant >= it.invocationInstant)
assertNull(it.finishInstant)
}
@ -364,7 +369,8 @@ class FlowMetadataRecordingTest {
assertThat(it.launchingCordapp).contains("custom-cordapp")
assertEquals(PLATFORM_VERSION, it.platformVersion)
assertEquals("Scheduler", it.startedBy)
assertEquals(context!!.trace.invocationId.timestamp, it.invocationInstant)
assertEquals(context!!.trace.invocationId.timestamp.truncatedTo(ChronoUnit.MILLIS),
it.invocationInstant.truncatedTo(ChronoUnit.MILLIS))
assertTrue(it.startInstant >= it.invocationInstant)
assertNull(it.finishInstant)
}

View File

@ -23,6 +23,7 @@ import net.corda.node.services.messaging.Message
import net.corda.node.services.persistence.DBTransactionStorage
import net.corda.nodeapi.internal.persistence.contextTransaction
import net.corda.testing.core.TestIdentity
import net.corda.testing.internal.IS_OPENJ9
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.MessagingServiceSpy
import net.corda.testing.node.internal.TestStartedNode
@ -33,6 +34,7 @@ import org.assertj.core.api.Assertions.assertThatExceptionOfType
import org.h2.util.Utils
import org.junit.After
import org.junit.Assert.assertTrue
import org.junit.Assume
import org.junit.Before
import org.junit.Test
import java.sql.SQLException
@ -129,6 +131,7 @@ class RetryFlowMockTest {
@Test(timeout=300_000)
fun `Early end session message does not hang receiving flow`() {
Assume.assumeTrue(!IS_OPENJ9)
val partyB = nodeB.info.legalIdentities.first()
assertThatExceptionOfType(UnexpectedFlowEndException::class.java).isThrownBy {
nodeA.startFlow(UnbalancedSendAndReceiveFlow(partyB)).getOrThrow(20.seconds)

View File

@ -35,6 +35,7 @@ import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.contracts.DummyContract
import net.corda.testing.contracts.DummyState
import net.corda.testing.core.*
import net.corda.testing.internal.IS_OPENJ9
import net.corda.testing.internal.LogHelper
import net.corda.testing.internal.vault.*
import net.corda.testing.node.MockServices
@ -468,6 +469,7 @@ class NodeVaultServiceTest {
@Test(timeout=300_000)
fun `unconsumedStatesForSpending from two issuer parties`() {
Assume.assumeTrue(!IS_OPENJ9) // openj9 OOM issue
database.transaction {
vaultFiller.fillWithSomeTestCash(100.DOLLARS, issuerServices, 1, DUMMY_CASH_ISSUER)
vaultFiller.fillWithSomeTestCash(100.DOLLARS, bocServices, 1, BOC.ref(1))

View File

@ -25,15 +25,20 @@ import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNetworkParameters
import net.corda.testing.node.StartedMockNode
import net.corda.testing.node.internal.cordappsForPackages
import org.apache.commons.lang3.SystemUtils
import org.junit.AfterClass
import org.junit.Assume
import org.junit.BeforeClass
import org.junit.Test
import org.junit.jupiter.api.condition.DisabledOnJre
import org.junit.jupiter.api.condition.JRE
import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.Index
import javax.persistence.Table
import kotlin.test.assertEquals
@DisabledOnJre(JRE.JAVA_11)
class VaultQueryJoinTest {
companion object {
private var mockNetwork: MockNetwork? = null
@ -46,6 +51,7 @@ class VaultQueryJoinTest {
@BeforeClass
@JvmStatic
fun setup() {
Assume.assumeTrue(!SystemUtils.IS_JAVA_11)
mockNetwork = MockNetwork(
MockNetworkParameters(
cordappsForAllNodes = cordappsForPackages(

View File

@ -32,6 +32,7 @@ import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.DatabaseConfig
import net.corda.nodeapi.internal.persistence.DatabaseTransaction
import net.corda.testing.core.*
import net.corda.testing.internal.IS_OPENJ9
import net.corda.testing.internal.chooseIdentity
import net.corda.testing.internal.configureDatabase
import net.corda.testing.internal.vault.*
@ -40,6 +41,7 @@ import net.corda.testing.node.MockServices.Companion.makeTestDatabaseAndMockServ
import net.corda.testing.node.makeTestIdentityService
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatCode
import org.junit.Assume
import org.junit.ClassRule
import org.junit.Ignore
import org.junit.Rule
@ -1689,6 +1691,7 @@ abstract class VaultQueryTestsBase : VaultQueryParties {
// pagination: invalid page number
@Test(timeout=300_000)
fun `invalid page number`() {
Assume.assumeTrue(!IS_OPENJ9) // openj9 OOM issue
expectedEx.expect(VaultQueryException::class.java)
expectedEx.expectMessage("Page specification: invalid page number")
@ -2235,6 +2238,7 @@ abstract class VaultQueryTestsBase : VaultQueryParties {
@Test(timeout=300_000)
fun `unconsumed fungible states for owners`() {
Assume.assumeTrue(!IS_OPENJ9) // openj9 OOM issue
database.transaction {
vaultFillerCashNotary.fillWithSomeTestCash(100.DOLLARS, notaryServices, 1, DUMMY_CASH_ISSUER)
vaultFiller.fillWithSomeTestCash(100.DOLLARS, notaryServices, 1, MEGA_CORP.ref(0), MEGA_CORP)
@ -2289,6 +2293,7 @@ abstract class VaultQueryTestsBase : VaultQueryParties {
@Test(timeout=300_000)
fun `unconsumed cash balances for all currencies`() {
Assume.assumeTrue(!IS_OPENJ9) // openj9 OOM issue
database.transaction {
listOf(100.DOLLARS, 200.DOLLARS, 300.POUNDS, 400.POUNDS, 500.SWISS_FRANCS, 600.SWISS_FRANCS).zip(1..6).forEach { (howMuch, states) ->
vaultFiller.fillWithSomeTestCash(howMuch, notaryServices, states, DUMMY_CASH_ISSUER)
@ -2471,6 +2476,7 @@ abstract class VaultQueryTestsBase : VaultQueryParties {
// specifying Query on Linear state attributes
@Test(timeout=300_000)
fun `unconsumed linear heads for linearId between two timestamps`() {
Assume.assumeTrue(!IS_OPENJ9) // openj9 OOM issue
database.transaction {
val start = services.clock.instant()
vaultFiller.fillWithSomeTestLinearStates(1, "TEST")
@ -2776,6 +2782,8 @@ abstract class VaultQueryTestsBase : VaultQueryParties {
}
}
//linus one OOM issue
@Ignore
@Test(timeout=300_000)
fun `record a transaction with number of inputs greater than vault page size`() {
val notary = dummyNotary

View File

@ -1,7 +1,9 @@
package net.corda.testing.node.internal
import net.corda.testing.internal.IS_OPENJ9
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.matchesPattern
import org.junit.Assume
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@ -17,7 +19,7 @@ class CordaCliWrapperErrorHandlingTests(val arguments: List<String>, val outputR
val className = "net.corda.testing.node.internal.SampleCordaCliWrapper"
private val stackTraceRegex = "^.+Exception[^\\n]++(\\s+at .++)+[\\s\\S]*"
private val exceptionWithoutStackTraceRegex ="${className}(\\s+.+)"
private val exceptionWithoutStackTraceRegex ="(\\?\\[31m)*\\Q${className}\\E(\\?\\[0m)*(\\s+.+)"
private val emptyStringRegex = "^$"
@JvmStatic
@ -31,7 +33,8 @@ class CordaCliWrapperErrorHandlingTests(val arguments: List<String>, val outputR
@Test(timeout=300_000)
fun `Run CordaCliWrapper sample app with arguments and check error output matches regExp`() {
// For openj9 the process error output appears sometimes to be garbled.
Assume.assumeTrue(!IS_OPENJ9)
val process = ProcessUtilities.startJavaProcess(
className = className,
arguments = arguments,

View File

@ -43,21 +43,28 @@ data class NotaryHandle(val identity: Party, val validating: Boolean, val nodeHa
interface NodeHandle : AutoCloseable {
/** Get the [NodeInfo] for this node */
val nodeInfo: NodeInfo
/**
* Interface to the node's RPC system. The first RPC user will be used to login if are any, otherwise a default one
* will be added and that will be used.
*/
val rpc: CordaRPCOps
/** Get the p2p address for this node **/
val p2pAddress: NetworkHostAndPort
/** Get the rpc address for this node **/
val rpcAddress: NetworkHostAndPort
/** Get the rpc admin address for this node **/
val rpcAdminAddress: NetworkHostAndPort
/** Get the JMX server address for this node, if JMX is enabled **/
val jmxAddress: NetworkHostAndPort?
/** Get a [List] of [User]'s for this node **/
val rpcUsers: List<User>
/** The location of the node's base directory **/
val baseDirectory: Path
@ -67,7 +74,8 @@ interface NodeHandle : AutoCloseable {
fun stop()
}
fun NodeHandle.logFile(): File = (baseDirectory / "logs").toFile().walk().filter { it.name.startsWith("node-") && it.extension == "log" }.single()
fun NodeHandle.logFile(): File = (baseDirectory / "logs").toFile().walk().filter { it.name.startsWith("node-") && it.extension == "log" }
.single()
/** Interface which represents an out of process node and exposes its process handle. **/
@DoNotImplement
@ -91,7 +99,8 @@ interface InProcess : NodeHandle {
* Starts an already constructed flow. Note that you must be on the server thread to call this method.
* @param context indicates who started the flow, see: [InvocationContext].
*/
fun <T> startFlow(logic: FlowLogic<T>): CordaFuture<T> = internalServices.startFlow(logic, internalServices.newContext()).getOrThrow().resultFuture
fun <T> startFlow(logic: FlowLogic<T>): CordaFuture<T> = internalServices.startFlow(logic, internalServices.newContext())
.getOrThrow().resultFuture
}
/**
@ -206,7 +215,8 @@ fun <A> driver(defaultParameters: DriverParameters = DriverParameters(), dsl: Dr
djvmBootstrapSource = defaultParameters.djvmBootstrapSource,
djvmCordaSource = defaultParameters.djvmCordaSource,
environmentVariables = defaultParameters.environmentVariables,
allowHibernateToManageAppSchema = defaultParameters.allowHibernateToManageAppSchema
allowHibernateToManageAppSchema = defaultParameters.allowHibernateToManageAppSchema,
premigrateH2Database = defaultParameters.premigrateH2Database
),
coerce = { it },
dsl = dsl
@ -245,6 +255,8 @@ fun <A> driver(defaultParameters: DriverParameters = DriverParameters(), dsl: Dr
* @property cordappsForAllNodes [TestCordapp]s that will be added to each node started by the [DriverDSL].
* @property djvmBootstrapSource Location of a JAR containing the Java APIs for the DJVM to use.
* @property djvmCordaSource Locations of JARs of user-supplied classes to execute within the DJVM sandbox.
* @property premigrateH2Database Whether to use a prebuilt H2 database schema or start from an empty schema.
* This can save time for tests which do not need to migrate from a blank schema.
*/
@Suppress("unused")
data class DriverParameters(
@ -263,12 +275,13 @@ data class DriverParameters(
@Suppress("DEPRECATION") val jmxPolicy: JmxPolicy = JmxPolicy(),
val networkParameters: NetworkParameters = testNetworkParameters(notaries = emptyList()),
val notaryCustomOverrides: Map<String, Any?> = emptyMap(),
val inMemoryDB: Boolean = true,
val inMemoryDB: Boolean = false,
val cordappsForAllNodes: Collection<TestCordapp>? = null,
val djvmBootstrapSource: Path? = null,
val djvmCordaSource: List<Path> = emptyList(),
val environmentVariables : Map<String, String> = emptyMap(),
val allowHibernateToManageAppSchema: Boolean = true
val environmentVariables: Map<String, String> = emptyMap(),
val allowHibernateToManageAppSchema: Boolean = true,
val premigrateH2Database: Boolean = true
) {
constructor(cordappsForAllNodes: Collection<TestCordapp>) : this(isDebug = false, cordappsForAllNodes = cordappsForAllNodes)
@ -376,6 +389,49 @@ data class DriverParameters(
cordappsForAllNodes = null
)
constructor(
isDebug: Boolean = false,
driverDirectory: Path = Paths.get("build") / "node-driver" / getTimestampAsDirectoryName(),
portAllocation: PortAllocation = incrementalPortAllocation(),
debugPortAllocation: PortAllocation = incrementalPortAllocation(),
systemProperties: Map<String, String> = emptyMap(),
useTestClock: Boolean = false,
startNodesInProcess: Boolean = false,
waitForAllNodesToFinish: Boolean = false,
notarySpecs: List<NotarySpec> = listOf(NotarySpec(DUMMY_NOTARY_NAME)),
extraCordappPackagesToScan: List<String> = emptyList(),
@Suppress("DEPRECATION") jmxPolicy: JmxPolicy = JmxPolicy(),
networkParameters: NetworkParameters = testNetworkParameters(notaries = emptyList()),
notaryCustomOverrides: Map<String, Any?> = emptyMap(),
inMemoryDB: Boolean = false,
cordappsForAllNodes: Collection<TestCordapp>? = null,
djvmBootstrapSource: Path? = null,
djvmCordaSource: List<Path> = emptyList(),
environmentVariables: Map<String, String> = emptyMap(),
allowHibernateToManageAppSchema: Boolean = true
) : this(
isDebug,
driverDirectory,
portAllocation,
debugPortAllocation,
systemProperties,
useTestClock,
startNodesInProcess,
waitForAllNodesToFinish,
notarySpecs,
extraCordappPackagesToScan,
jmxPolicy,
networkParameters,
notaryCustomOverrides,
inMemoryDB,
cordappsForAllNodes,
djvmBootstrapSource,
djvmCordaSource,
environmentVariables,
allowHibernateToManageAppSchema,
premigrateH2Database = true
)
constructor(
isDebug: Boolean,
driverDirectory: Path,
@ -417,6 +473,7 @@ data class DriverParameters(
fun withStartNodesInProcess(startNodesInProcess: Boolean): DriverParameters = copy(startNodesInProcess = startNodesInProcess)
fun withWaitForAllNodesToFinish(waitForAllNodesToFinish: Boolean): DriverParameters = copy(waitForAllNodesToFinish = waitForAllNodesToFinish)
fun withNotarySpecs(notarySpecs: List<NotarySpec>): DriverParameters = copy(notarySpecs = notarySpecs)
@Deprecated("extraCordappPackagesToScan does not preserve the original CorDapp's versioning and metadata, which may lead to " +
"misleading results in tests. Use withCordappsForAllNodes instead.")
fun withExtraCordappPackagesToScan(extraCordappPackagesToScan: List<String>): DriverParameters = copy(extraCordappPackagesToScan = extraCordappPackagesToScan)
@ -428,7 +485,7 @@ data class DriverParameters(
fun withCordappsForAllNodes(cordappsForAllNodes: Collection<TestCordapp>?): DriverParameters = copy(cordappsForAllNodes = cordappsForAllNodes)
fun withDjvmBootstrapSource(djvmBootstrapSource: Path?): DriverParameters = copy(djvmBootstrapSource = djvmBootstrapSource)
fun withDjvmCordaSource(djvmCordaSource: List<Path>): DriverParameters = copy(djvmCordaSource = djvmCordaSource)
fun withEnvironmentVariables(variables : Map<String, String>): DriverParameters = copy(environmentVariables = variables)
fun withEnvironmentVariables(variables: Map<String, String>): DriverParameters = copy(environmentVariables = variables)
fun withAllowHibernateToManageAppSchema(value: Boolean): DriverParameters = copy(allowHibernateToManageAppSchema = value)
fun copy(
@ -530,4 +587,48 @@ data class DriverParameters(
djvmCordaSource = djvmCordaSource,
environmentVariables = environmentVariables
)
// Legacy copy() from v4.5
@Suppress("LongParameterList")
fun copy(isDebug: Boolean,
driverDirectory: Path,
portAllocation: PortAllocation,
debugPortAllocation: PortAllocation,
systemProperties: Map<String, String>,
useTestClock: Boolean,
startNodesInProcess: Boolean,
waitForAllNodesToFinish: Boolean,
notarySpecs: List<NotarySpec>,
extraCordappPackagesToScan: List<String>,
@Suppress("DEPRECATION") jmxPolicy: JmxPolicy,
networkParameters: NetworkParameters,
notaryCustomOverrides: Map<String, Any?>,
inMemoryDB: Boolean,
cordappsForAllNodes: Collection<TestCordapp>?,
djvmBootstrapSource: Path?,
djvmCordaSource: List<Path>,
environmentVariables: Map<String, String>,
allowHibernateToManageAppSchema: Boolean
) = this.copy(
isDebug = isDebug,
driverDirectory = driverDirectory,
portAllocation = portAllocation,
debugPortAllocation = debugPortAllocation,
systemProperties = systemProperties,
useTestClock = useTestClock,
startNodesInProcess = startNodesInProcess,
waitForAllNodesToFinish = waitForAllNodesToFinish,
notarySpecs = notarySpecs,
extraCordappPackagesToScan = extraCordappPackagesToScan,
jmxPolicy = jmxPolicy,
networkParameters = networkParameters,
notaryCustomOverrides = notaryCustomOverrides,
inMemoryDB = inMemoryDB,
cordappsForAllNodes = cordappsForAllNodes,
djvmBootstrapSource = djvmBootstrapSource,
djvmCordaSource = djvmCordaSource,
environmentVariables = environmentVariables,
allowHibernateToManageAppSchema = allowHibernateToManageAppSchema,
premigrateH2Database = true
)
}

View File

@ -0,0 +1,23 @@
package net.corda.testing.node
import java.io.InputStream
import java.nio.file.Files
import java.nio.file.Path
object DatabaseSnapshot {
private const val previousCordaVersion: String = "4.5.1"
private const val databaseName: String = "persistence.mv.db"
private fun getDatabaseSnapshotStream(): InputStream {
val resourceUri = this::class.java.getResource("/databasesnapshots/${previousCordaVersion}/$databaseName")
return resourceUri.openStream()
}
fun copyDatabaseSnapshot(baseDirectory: Path) {
getDatabaseSnapshotStream().use { stream ->
Files.createDirectories(baseDirectory)
val path = baseDirectory.resolve(databaseName)
Files.copy(stream, path)
}
}
}

View File

@ -48,6 +48,7 @@ import net.corda.testing.internal.configureDatabase
import net.corda.testing.node.internal.*
import net.corda.testing.services.MockAttachmentStorage
import java.io.ByteArrayOutputStream
import java.nio.file.Paths
import java.security.KeyPair
import java.sql.Connection
import java.time.Clock
@ -99,9 +100,17 @@ open class MockServices private constructor(
// TODO: Can we use an X509 principal generator here?
@JvmStatic
fun makeTestDataSourceProperties(nodeName: String = SecureHash.randomSHA256().toString()): Properties {
val dbDir = Paths.get("","build", "mocknetworktestdb", nodeName)
.toAbsolutePath()
val dbPath = dbDir.resolve("persistence")
try {
DatabaseSnapshot.copyDatabaseSnapshot(dbDir)
} catch (ex: java.nio.file.FileAlreadyExistsException) {
DriverDSLImpl.log.warn("Database already exists on disk, not attempting to pre-migrate database.")
}
val props = Properties()
props.setProperty("dataSourceClassName", "org.h2.jdbcx.JdbcDataSource")
props.setProperty("dataSource.url", "jdbc:h2:mem:${nodeName}_persistence;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE")
props.setProperty("dataSource.url", "jdbc:h2:file:$dbPath;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE")
props.setProperty("dataSource.user", "sa")
props.setProperty("dataSource.password", "")
return props
@ -357,7 +366,6 @@ open class MockServices private constructor(
constructor(cordappPackages: List<String>, initialIdentityName: CordaX500Name, identityService: IdentityService, networkParameters: NetworkParameters)
: this(cordappPackages, TestIdentity(initialIdentityName), identityService, networkParameters)
constructor(cordappPackages: List<String>, initialIdentityName: CordaX500Name, identityService: IdentityService, networkParameters: NetworkParameters, key: KeyPair)
: this(cordappPackages, TestIdentity(initialIdentityName, key), identityService, networkParameters)
@ -428,11 +436,12 @@ open class MockServices private constructor(
private val mockCordappProvider: MockCordappProvider = MockCordappProvider(cordappLoader, attachments).also {
it.start()
}
override val transactionVerifierService: TransactionVerifierService get() = InMemoryTransactionVerifierService(
numberOfWorkers = 2,
cordappProvider = mockCordappProvider,
attachments = attachments
)
override val transactionVerifierService: TransactionVerifierService
get() = InMemoryTransactionVerifierService(
numberOfWorkers = 2,
cordappProvider = mockCordappProvider,
attachments = attachments
)
override val cordappProvider: CordappProvider get() = mockCordappProvider
override var networkParametersService: NetworkParametersService = MockNetworkParametersStorage(initialNetworkParameters)
override val diagnosticsService: DiagnosticsService = NodeDiagnosticsService()

View File

@ -50,12 +50,12 @@ data class CustomCordapp(
@VisibleForTesting
internal fun packageAsJar(file: Path) {
val classGraph = ClassGraph()
if(packages.isNotEmpty()){
classGraph.whitelistPaths(*packages.map { it.replace('.', '/') }.toTypedArray())
if (packages.isNotEmpty()) {
classGraph.acceptPaths(*packages.map { it.replace('.', '/') }.toTypedArray())
}
if (classes.isNotEmpty()) {
classes.forEach { classGraph.addClassLoader(it.classLoader) }
classGraph.whitelistClasses(*classes.map { it.name }.toTypedArray())
classGraph.acceptClasses(*classes.map { it.name }.toTypedArray())
}
classGraph.enableClassInfo().pooledScan().use { scanResult ->

View File

@ -1,4 +1,5 @@
@file:Suppress("TooManyFunctions", "Deprecation")
package net.corda.testing.node.internal
import co.paralleluniverse.fibers.instrument.JavaAgent
@ -52,6 +53,7 @@ import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.millis
import net.corda.core.utilities.toHexString
import net.corda.coretesting.internal.stubs.CertificateStoreStubs
import net.corda.node.NodeRegistrationOption
import net.corda.node.VersionInfo
@ -96,6 +98,7 @@ import net.corda.testing.driver.internal.InProcessImpl
import net.corda.testing.driver.internal.NodeHandleInternal
import net.corda.testing.driver.internal.OutOfProcessImpl
import net.corda.testing.node.ClusterSpec
import net.corda.testing.node.DatabaseSnapshot
import net.corda.testing.node.NotarySpec
import okhttp3.OkHttpClient
import okhttp3.Request
@ -147,8 +150,9 @@ class DriverDSLImpl(
val cordappsForAllNodes: Collection<TestCordappInternal>?,
val djvmBootstrapSource: Path?,
val djvmCordaSource: List<Path>,
val environmentVariables : Map<String, String>,
val allowHibernateToManageAppSchema: Boolean = true
val environmentVariables: Map<String, String>,
val allowHibernateToManageAppSchema: Boolean = true,
val premigrateH2Database: Boolean = true
) : InternalDriverDSL {
private var _executorService: ScheduledExecutorService? = null
@ -156,8 +160,10 @@ class DriverDSLImpl(
private var _shutdownManager: ShutdownManager? = null
override val shutdownManager get() = _shutdownManager!!
private lateinit var extraCustomCordapps: Set<CustomCordapp>
// Map from a nodes legal name to an observable emitting the number of nodes in its network map.
private val networkVisibilityController = NetworkVisibilityController()
/**
* Future which completes when the network map infrastructure is available, whether a local one or one from the CZ.
* This future acts as a gate to prevent nodes from starting too early. The value of the future is a [LocalNetworkMap]
@ -192,7 +198,7 @@ class DriverDSLImpl(
}
private fun NodeConfig.checkAndOverrideForInMemoryDB(): NodeConfig = this.run {
if (inMemoryDB && corda.dataSourceProperties.getProperty("dataSource.url").startsWith("jdbc:h2:")) {
if (inMemoryDB && isH2Database(corda)) {
val jdbcUrl = "jdbc:h2:mem:persistence${inMemoryCounter.getAndIncrement()};DB_CLOSE_ON_EXIT=FALSE;LOCK_TIMEOUT=10000;WRITE_DELAY=100"
corda.dataSourceProperties.setProperty("dataSource.url", jdbcUrl)
NodeConfig(typesafe + mapOf("dataSourceProperties" to mapOf("dataSource.url" to jdbcUrl)))
@ -262,6 +268,15 @@ class DriverDSLImpl(
val name = parameters.providedName ?: CordaX500Name("${oneOf(names).organisation}-${p2pAddress.port}", "London", "GB")
val config = createConfig(name, parameters, p2pAddress)
if (premigrateH2Database && isH2Database(config)) {
if (!inMemoryDB) {
try {
DatabaseSnapshot.copyDatabaseSnapshot(config.corda.baseDirectory)
} catch (ex: java.nio.file.FileAlreadyExistsException) {
log.warn("Database already exists on disk, not attempting to pre-migrate database.")
}
}
}
val registrationFuture = if (compatibilityZone?.rootCert != null) {
// We don't need the network map to be available to be able to register the node
createSchema(config, false).flatMap { startNodeRegistration(it, compatibilityZone.rootCert, compatibilityZone.config()) }
@ -270,7 +285,7 @@ class DriverDSLImpl(
}
return registrationFuture.flatMap { conf ->
networkMapAvailability.flatMap {networkMap ->
networkMapAvailability.flatMap { networkMap ->
// But starting the node proper does require the network map
startRegisteredNode(conf, networkMap, parameters, bytemanPort)
}
@ -376,9 +391,9 @@ class DriverDSLImpl(
startOutOfProcessMiniNode(
config,
arrayOf(
"initial-registration",
"--network-root-truststore=${rootTruststorePath.toAbsolutePath()}",
"--network-root-truststore-password=$rootTruststorePassword"
"initial-registration",
"--network-root-truststore=${rootTruststorePath.toAbsolutePath()}",
"--network-root-truststore-password=$rootTruststorePassword"
)
).map { config }
}
@ -420,13 +435,13 @@ class DriverDSLImpl(
_shutdownManager = ShutdownManager(executorService)
val callerPackage = getCallerPackage().toMutableList()
if(callerPackage.firstOrNull()?.startsWith("net.corda.node") == true) callerPackage.add("net.corda.testing")
if (callerPackage.firstOrNull()?.startsWith("net.corda.node") == true) callerPackage.add("net.corda.testing")
extraCustomCordapps = cordappsForPackages(extraCordappPackagesToScan + callerPackage)
val notaryInfosFuture = if (compatibilityZone == null) {
// If no CZ is specified then the driver does the generation of the network parameters and the copying of the
// node info files.
startNotaryIdentityGeneration().map { notaryInfos -> Pair(notaryInfos, LocalNetworkMap(notaryInfos.map{it.second})) }
startNotaryIdentityGeneration().map { notaryInfos -> Pair(notaryInfos, LocalNetworkMap(notaryInfos.map { it.second })) }
} else {
// Otherwise it's the CZ's job to distribute thse via the HTTP network map, as that is what the nodes will be expecting.
val notaryInfosFuture = if (compatibilityZone.rootCert == null) {
@ -437,7 +452,7 @@ class DriverDSLImpl(
startAllNotaryRegistrations(compatibilityZone.rootCert, compatibilityZone)
}
notaryInfosFuture.map { notaryInfos ->
compatibilityZone.publishNotaries(notaryInfos.map{it.second})
compatibilityZone.publishNotaries(notaryInfos.map { it.second })
Pair(notaryInfos, null)
}
}
@ -445,14 +460,15 @@ class DriverDSLImpl(
networkMapAvailability = notaryInfosFuture.map { it.second }
_notaries = notaryInfosFuture.map { (notaryInfos, localNetworkMap) ->
val listOfFutureNodeHandles = startNotaries(notaryInfos.map{it.first}, localNetworkMap, notaryCustomOverrides)
val listOfFutureNodeHandles = startNotaries(notaryInfos.map { it.first }, localNetworkMap, notaryCustomOverrides)
notaryInfos.zip(listOfFutureNodeHandles) { (_, notaryInfo), nodeHandlesFuture ->
NotaryHandle(notaryInfo.identity, notaryInfo.validating, nodeHandlesFuture)
}
}
try {
_notaries.map { notary -> notary.map { handle -> handle.nodeHandles } }.getOrThrow(notaryHandleTimeout).forEach { future -> future.getOrThrow(notaryHandleTimeout) }
} catch(e: NodeListenProcessDeathException) {
_notaries.map { notary -> notary.map { handle -> handle.nodeHandles } }.getOrThrow(notaryHandleTimeout)
.forEach { future -> future.getOrThrow(notaryHandleTimeout) }
} catch (e: NodeListenProcessDeathException) {
val message = if (e.causeFromStdError.isNotBlank()) {
"Unable to start notaries. Failed with the following error: ${e.causeFromStdError}"
} else {
@ -487,7 +503,7 @@ class DriverDSLImpl(
}
}
private fun startNotaryIdentityGeneration(): CordaFuture<List<Pair<NodeConfig,NotaryInfo>>> {
private fun startNotaryIdentityGeneration(): CordaFuture<List<Pair<NodeConfig, NotaryInfo>>> {
return executorService.fork {
notarySpecs.map { spec ->
val notaryConfig = mapOf("notary" to mapOf("validating" to spec.validating))
@ -537,32 +553,32 @@ class DriverDSLImpl(
spec: NotarySpec,
rootCert: X509Certificate,
compatibilityZone: CompatibilityZoneParams
): CordaFuture<Pair<NodeConfig,NotaryInfo>> {
): CordaFuture<Pair<NodeConfig, NotaryInfo>> {
val parameters = NodeParameters(rpcUsers = spec.rpcUsers, verifierType = spec.verifierType, customOverrides = notaryCustomOverrides, maximumHeapSize = spec.maximumHeapSize)
return createSchema(createConfig(spec.name, parameters), false).flatMap { config ->
startNodeRegistration(config, rootCert, compatibilityZone.config())}.flatMap { config ->
// Node registration only gives us the node CA cert, not the identity cert. That is only created on first
// startup or when the node is told to just generate its node info file. We do that here.
if (startNodesInProcess) {
executorService.fork {
val nodeInfo = Node(config.corda, MOCK_VERSION_INFO, initialiseSerialization = false).generateAndSaveNodeInfo()
Pair(config.withNotaryDefinition(spec.validating), NotaryInfo(nodeInfo.legalIdentities[0], spec.validating))
}
} else {
// TODO The config we use here is uses a hardocded p2p port which changes when the node is run proper
// This causes two node info files to be generated.
startOutOfProcessMiniNode(config, arrayOf("generate-node-info")).map {
// Once done we have to read the signed node info file that's been generated
val nodeInfoFile = config.corda.baseDirectory.list { paths ->
paths.filter { it.fileName.toString().startsWith(NodeInfoFilesCopier.NODE_INFO_FILE_NAME_PREFIX) }.findFirst()
.get()
}
val nodeInfo = nodeInfoFile.readObject<SignedNodeInfo>().verified()
Pair(config.withNotaryDefinition(spec.validating), NotaryInfo(nodeInfo.legalIdentities[0], spec.validating))
startNodeRegistration(config, rootCert, compatibilityZone.config())
}.flatMap { config ->
// Node registration only gives us the node CA cert, not the identity cert. That is only created on first
// startup or when the node is told to just generate its node info file. We do that here.
if (startNodesInProcess) {
executorService.fork {
val nodeInfo = Node(config.corda, MOCK_VERSION_INFO, initialiseSerialization = false).generateAndSaveNodeInfo()
Pair(config.withNotaryDefinition(spec.validating), NotaryInfo(nodeInfo.legalIdentities[0], spec.validating))
}
} else {
// TODO The config we use here is uses a hardocded p2p port which changes when the node is run proper
// This causes two node info files to be generated.
startOutOfProcessMiniNode(config, arrayOf("generate-node-info")).map {
// Once done we have to read the signed node info file that's been generated
val nodeInfoFile = config.corda.baseDirectory.list { paths ->
paths.filter { it.fileName.toString().startsWith(NodeInfoFilesCopier.NODE_INFO_FILE_NAME_PREFIX) }.findFirst()
.get()
}
val nodeInfo = nodeInfoFile.readObject<SignedNodeInfo>().verified()
Pair(config.withNotaryDefinition(spec.validating), NotaryInfo(nodeInfo.legalIdentities[0], spec.validating))
}
}
}
}
private fun generateNodeNames(spec: NotarySpec): List<CordaX500Name> {
@ -571,7 +587,7 @@ class DriverDSLImpl(
private fun startNotaries(configs: List<NodeConfig>, localNetworkMap: LocalNetworkMap?, customOverrides: Map<String, Any?>): List<CordaFuture<List<NodeHandle>>> {
return notarySpecs.zip(configs).map { (spec, config) ->
when (spec.cluster) {
when (spec.cluster) {
null -> startSingleNotary(config, spec, localNetworkMap, customOverrides)
is ClusterSpec.Raft,
// DummyCluster is used for testing the notary communication path, and it does not matter
@ -585,13 +601,13 @@ class DriverDSLImpl(
private fun startSingleNotary(config: NodeConfig, spec: NotarySpec, localNetworkMap: LocalNetworkMap?, customOverrides: Map<String, Any?>): CordaFuture<List<NodeHandle>> {
val notaryConfig = mapOf("notary" to mapOf("validating" to spec.validating))
return startRegisteredNode(
config,
localNetworkMap,
NodeParameters(rpcUsers = spec.rpcUsers,
verifierType = spec.verifierType,
startInSameProcess = spec.startInProcess,
customOverrides = notaryConfig + customOverrides,
maximumHeapSize = spec.maximumHeapSize)
config,
localNetworkMap,
NodeParameters(rpcUsers = spec.rpcUsers,
verifierType = spec.verifierType,
startInSameProcess = spec.startInProcess,
customOverrides = notaryConfig + customOverrides,
maximumHeapSize = spec.maximumHeapSize)
).map { listOf(it) }
}
@ -758,14 +774,14 @@ class DriverDSLImpl(
}
val effectiveP2PAddress = config.corda.messagingServerAddress ?: config.corda.p2pAddress
val p2pReadyFuture = nodeMustBeStartedFuture(
executorService,
config.corda.baseDirectory / "net.corda.node.Corda.${identifier}.stdout.log",
process
executorService,
config.corda.baseDirectory / "net.corda.node.Corda.${identifier}.stdout.log",
process
) {
NodeListenProcessDeathException(
effectiveP2PAddress,
process,
(config.corda.baseDirectory / "net.corda.node.Corda.$identifier.stderr.log").readText()
effectiveP2PAddress,
process,
(config.corda.baseDirectory / "net.corda.node.Corda.$identifier.stderr.log").readText()
)
}
@ -804,6 +820,7 @@ class DriverDSLImpl(
*/
inner class LocalNetworkMap(notaryInfos: List<NotaryInfo>) {
val networkParametersCopier = NetworkParametersCopier(networkParameters.copy(notaries = notaryInfos))
// TODO: this object will copy NodeInfo files from started nodes to other nodes additional-node-infos/
// This uses the FileSystem and adds a delay (~5 seconds) given by the time we wait before polling the file system.
// Investigate whether we can avoid that.
@ -832,6 +849,7 @@ class DriverDSLImpl(
private val notaryHandleTimeout = Duration.ofMinutes(1)
private val defaultRpcUserList = listOf(InternalUser("default", "default", setOf("ALL")).toConfig().root().unwrapped())
private val names = arrayOf(ALICE_NAME, BOB_NAME, DUMMY_BANK_A_NAME)
/**
* A sub-set of permissions that grant most of the essential operations used in the unit/integration tests as well as
* in demo application like NodeExplorer.
@ -856,14 +874,14 @@ class DriverDSLImpl(
private const val CORDA_TESTING_ATTRIBUTE = "Corda-Testing"
private val CORDAPP_MANIFEST_ATTRIBUTES: List<String> = unmodifiableList(listOf(
CORDAPP_CONTRACT_NAME,
CORDAPP_CONTRACT_LICENCE,
CORDAPP_CONTRACT_VENDOR,
CORDAPP_CONTRACT_VERSION,
CORDAPP_WORKFLOW_NAME,
CORDAPP_WORKFLOW_LICENCE,
CORDAPP_WORKFLOW_VENDOR,
CORDAPP_WORKFLOW_VERSION
CORDAPP_CONTRACT_NAME,
CORDAPP_CONTRACT_LICENCE,
CORDAPP_CONTRACT_VENDOR,
CORDAPP_CONTRACT_VERSION,
CORDAPP_WORKFLOW_NAME,
CORDAPP_WORKFLOW_LICENCE,
CORDAPP_WORKFLOW_VENDOR,
CORDAPP_WORKFLOW_VERSION
))
/**
@ -938,7 +956,7 @@ class DriverDSLImpl(
maximumHeapSize: String,
logLevelOverride: String?,
identifier: String,
environmentVariables : Map<String,String>,
environmentVariables: Map<String, String>,
extraCmdLineFlag: Array<String> = emptyArray()
): Process {
log.info("Starting out-of-process Node ${config.corda.myLegalName.organisation}, " +
@ -979,7 +997,6 @@ class DriverDSLImpl(
else -> "DEBUG"
}
val arguments = mutableListOf(
"--base-directory=${config.corda.baseDirectory}",
"--logging-level=$loggingLevel",
@ -1003,11 +1020,11 @@ class DriverDSLImpl(
// The following dependencies are excluded from the classpath of the created JVM,
// so that the environment resembles a real one as close as possible.
val cp = ProcessUtilities.defaultClassPath.filter { cpEntry ->
val cp = ProcessUtilities.defaultClassPath.filter { cpEntry ->
val cpPathEntry = Paths.get(cpEntry)
cpPathEntry.isRegularFile()
&& !isTestArtifact(cpPathEntry.fileName.toString())
&& !cpPathEntry.isExcludedJar
&& !isTestArtifact(cpPathEntry.fileName.toString())
&& !cpPathEntry.isExcludedJar
}
return ProcessUtilities.startJavaProcess(
@ -1023,6 +1040,12 @@ class DriverDSLImpl(
)
}
private fun isH2Database(config: NodeConfiguration)
= config.dataSourceProperties.getProperty("dataSource.url").startsWith("jdbc:h2:")
private fun isH2Database(config: NodeConfig)
= isH2Database(config.corda)
// Obvious test artifacts. This is NOT intended to be an exhaustive list!
// It is only intended to remove those FEW jars which BLATANTLY do not
// belong inside a Corda Node.
@ -1046,12 +1069,13 @@ class DriverDSLImpl(
|| (manifest[TARGET_PLATFORM_VERSION] != null && manifest[MIN_PLATFORM_VERSION] != null)
}
private val Path.isExcludedJar: Boolean get() {
return JarInputStream(Files.newInputStream(this).buffered()).use { jar ->
val manifest = jar.manifest ?: return false
isCordapp(manifest) || isTestArtifact(manifest)
private val Path.isExcludedJar: Boolean
get() {
return JarInputStream(Files.newInputStream(this).buffered()).use { jar ->
val manifest = jar.manifest ?: return false
isCordapp(manifest) || isTestArtifact(manifest)
}
}
}
private fun startWebserver(handle: NodeHandleInternal, debugPort: Int?, maximumHeapSize: String): Process {
val className = "net.corda.webserver.WebServer"
@ -1220,8 +1244,8 @@ interface InternalDriverDSL : DriverDSL {
fun shutdown()
fun startNode(
parameters: NodeParameters = NodeParameters(),
bytemanPort: Int? = null
parameters: NodeParameters = NodeParameters(),
bytemanPort: Int? = null
): CordaFuture<NodeHandle>
}
@ -1268,28 +1292,29 @@ fun <DI : DriverDSL, D : InternalDriverDSL, A> genericDriver(
): A {
setDriverSerialization().use { _ ->
val driverDsl = driverDslWrapper(
DriverDSLImpl(
portAllocation = defaultParameters.portAllocation,
debugPortAllocation = defaultParameters.debugPortAllocation,
systemProperties = defaultParameters.systemProperties,
driverDirectory = defaultParameters.driverDirectory.toAbsolutePath(),
useTestClock = defaultParameters.useTestClock,
isDebug = defaultParameters.isDebug,
startNodesInProcess = defaultParameters.startNodesInProcess,
waitForAllNodesToFinish = defaultParameters.waitForAllNodesToFinish,
extraCordappPackagesToScan = @Suppress("DEPRECATION") defaultParameters.extraCordappPackagesToScan,
jmxPolicy = defaultParameters.jmxPolicy,
notarySpecs = defaultParameters.notarySpecs,
compatibilityZone = null,
networkParameters = defaultParameters.networkParameters,
notaryCustomOverrides = defaultParameters.notaryCustomOverrides,
inMemoryDB = defaultParameters.inMemoryDB,
cordappsForAllNodes = uncheckedCast(defaultParameters.cordappsForAllNodes),
djvmBootstrapSource = defaultParameters.djvmBootstrapSource,
djvmCordaSource = defaultParameters.djvmCordaSource,
environmentVariables = defaultParameters.environmentVariables,
allowHibernateToManageAppSchema = defaultParameters.allowHibernateToManageAppSchema
)
DriverDSLImpl(
portAllocation = defaultParameters.portAllocation,
debugPortAllocation = defaultParameters.debugPortAllocation,
systemProperties = defaultParameters.systemProperties,
driverDirectory = defaultParameters.driverDirectory.toAbsolutePath(),
useTestClock = defaultParameters.useTestClock,
isDebug = defaultParameters.isDebug,
startNodesInProcess = defaultParameters.startNodesInProcess,
waitForAllNodesToFinish = defaultParameters.waitForAllNodesToFinish,
extraCordappPackagesToScan = @Suppress("DEPRECATION") defaultParameters.extraCordappPackagesToScan,
jmxPolicy = defaultParameters.jmxPolicy,
notarySpecs = defaultParameters.notarySpecs,
compatibilityZone = null,
networkParameters = defaultParameters.networkParameters,
notaryCustomOverrides = defaultParameters.notaryCustomOverrides,
inMemoryDB = defaultParameters.inMemoryDB,
cordappsForAllNodes = uncheckedCast(defaultParameters.cordappsForAllNodes),
djvmBootstrapSource = defaultParameters.djvmBootstrapSource,
djvmCordaSource = defaultParameters.djvmCordaSource,
environmentVariables = defaultParameters.environmentVariables,
allowHibernateToManageAppSchema = defaultParameters.allowHibernateToManageAppSchema,
premigrateH2Database = defaultParameters.premigrateH2Database
)
)
val shutdownHook = addShutdownHook(driverDsl::shutdown)
try {
@ -1324,7 +1349,7 @@ sealed class CompatibilityZoneParams(
) {
abstract fun networkMapURL(): URL
abstract fun doormanURL(): URL
abstract fun config() : NetworkServicesConfig
abstract fun config(): NetworkServicesConfig
}
/**
@ -1332,18 +1357,18 @@ sealed class CompatibilityZoneParams(
*/
class SharedCompatibilityZoneParams(
private val url: URL,
private val pnm : UUID?,
private val pnm: UUID?,
publishNotaries: (List<NotaryInfo>) -> Unit,
rootCert: X509Certificate? = null
) : CompatibilityZoneParams(publishNotaries, rootCert) {
val config : NetworkServicesConfig by lazy {
val config: NetworkServicesConfig by lazy {
NetworkServicesConfig(url, url, pnm, false)
}
override fun doormanURL() = url
override fun networkMapURL() = url
override fun config() : NetworkServicesConfig = config
override fun config(): NetworkServicesConfig = config
}
/**
@ -1352,17 +1377,17 @@ class SharedCompatibilityZoneParams(
class SplitCompatibilityZoneParams(
private val doormanURL: URL,
private val networkMapURL: URL,
private val pnm : UUID?,
private val pnm: UUID?,
publishNotaries: (List<NotaryInfo>) -> Unit,
rootCert: X509Certificate? = null
) : CompatibilityZoneParams(publishNotaries, rootCert) {
val config : NetworkServicesConfig by lazy {
val config: NetworkServicesConfig by lazy {
NetworkServicesConfig(doormanURL, networkMapURL, pnm, false)
}
override fun doormanURL() = doormanURL
override fun networkMapURL() = networkMapURL
override fun config() : NetworkServicesConfig = config
override fun config(): NetworkServicesConfig = config
}
@Suppress("LongParameterList")
@ -1387,6 +1412,7 @@ fun <A> internalDriver(
djvmCordaSource: List<Path> = emptyList(),
environmentVariables: Map<String, String> = emptyMap(),
allowHibernateToManageAppSchema: Boolean = true,
premigrateH2Database: Boolean = true,
dsl: DriverDSLImpl.() -> A
): A {
return genericDriver(
@ -1410,15 +1436,21 @@ fun <A> internalDriver(
djvmBootstrapSource = djvmBootstrapSource,
djvmCordaSource = djvmCordaSource,
environmentVariables = environmentVariables,
allowHibernateToManageAppSchema = allowHibernateToManageAppSchema
allowHibernateToManageAppSchema = allowHibernateToManageAppSchema,
premigrateH2Database = premigrateH2Database
),
coerce = { it },
dsl = dsl
)
}
val DIRECTORY_TIMESTAMP_FORMAT: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss.SSS").withZone(UTC)
private val directoryRandom = Random()
fun getTimestampAsDirectoryName(): String {
return DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss.SSS").withZone(UTC).format(Instant.now())
val base = DIRECTORY_TIMESTAMP_FORMAT.format(Instant.now())
// Introduce some randomness so starting two nodes in the same ms doesn't use the same path
val random = directoryRandom.nextLong().toBigInteger().toByteArray().toHexString()
return "$base-$random"
}
fun writeConfig(path: Path, filename: String, config: Config) {

View File

@ -9,7 +9,7 @@ import net.corda.core.node.NetworkParameters
import net.corda.core.node.NotaryInfo
import net.corda.core.serialization.serialize
import net.corda.nodeapi.internal.network.SignedNetworkParameters
import net.corda.nodeapi.internal.network.verifiedNetworkMapCert
import net.corda.nodeapi.internal.network.verifiedNetworkParametersCert
import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.core.ALICE_NAME
import net.corda.testing.core.TestIdentity
@ -30,7 +30,7 @@ class MockNetworkParametersStorage(private var currentParameters: NetworkParamet
}
override fun setCurrentParameters(currentSignedParameters: SignedDataWithCert<NetworkParameters>, trustRoot: X509Certificate) {
setCurrentParametersUnverified(currentSignedParameters.verifiedNetworkMapCert(trustRoot))
setCurrentParametersUnverified(currentSignedParameters.verifiedNetworkParametersCert(trustRoot))
}
override fun lookupSigned(hash: SecureHash): SignedDataWithCert<NetworkParameters>? {

View File

@ -56,7 +56,7 @@ data class TestCordappImpl(val scanPackage: String, override val config: Map<Str
private fun findRootPaths(scanPackage: String): Set<Path> {
return packageToRootPaths.computeIfAbsent(scanPackage) {
val classGraph = ClassGraph().whitelistPaths(scanPackage.replace('.', '/'))
val classGraph = ClassGraph().acceptPaths(scanPackage.replace('.', '/'))
classGraph.pooledScan().use { scanResult ->
scanResult.allResources
.asSequence()

View File

@ -252,4 +252,6 @@ fun isLocalPortBound(port: Int): Boolean {
// Failed to open server socket means that it is already bound by someone
true
}
}
}
val IS_OPENJ9 = System.getProperty("java.vm.name").toLowerCase().contains("openj9")

View File

@ -38,6 +38,8 @@ public class InteractiveShellJavaTest {
// should guarantee that FlowA will have synthetic method to access this field
private static final String synthetic = "synth";
private static final boolean IS_OPENJ9 = System.getProperty("java.vm.name").toLowerCase().contains("openj9");
abstract static class StringFlow extends FlowLogic<String> {
abstract String getA();
}
@ -183,8 +185,10 @@ public class InteractiveShellJavaTest {
@Test
public void flowStartSimple() throws InteractiveShell.NoApplicableConstructor {
check("a: Hi there", "Hi there", FlowA.class);
check("b: 12", "12", FlowA.class);
check("b: 12, c: Yo", "12Yo", FlowA.class);
if (!IS_OPENJ9) {
check("b: 12", "12", FlowA.class);
check("b: 12, c: Yo", "12Yo", FlowA.class);
}
}
@Test
@ -210,11 +214,13 @@ public class InteractiveShellJavaTest {
@Test
public void flowStartWithArrayType() throws InteractiveShell.NoApplicableConstructor {
check(
"b: [ One, Two, Three, Four ]",
"One+Two+Three+Four",
FlowA.class
);
if (!IS_OPENJ9) {
check(
"b: [ One, Two, Three, Four ]",
"One+Two+Three+Four",
FlowA.class
);
}
}
@Test