diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/dsl/TestDSL.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/dsl/TestDSL.kt index c98a026365..77a243c8dc 100644 --- a/testing/test-utils/src/main/kotlin/net/corda/testing/dsl/TestDSL.kt +++ b/testing/test-utils/src/main/kotlin/net/corda/testing/dsl/TestDSL.kt @@ -155,6 +155,10 @@ data class TestTransactionDSLInterpreter private constructor( attachment((services.cordappProvider as MockCordappProvider).addMockCordapp(contractClassName, services.attachments as MockAttachmentStorage, attachmentId, signers)) } + override fun _attachment(contractClassName: ContractClassName, attachmentId: AttachmentId, signers: List, jarManifestAttributes: Map){ + attachment((services.cordappProvider as MockCordappProvider).addMockCordapp(contractClassName, services.attachments as MockAttachmentStorage, attachmentId, signers, jarManifestAttributes)) + } + } data class TestLedgerDSLInterpreter private constructor( diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/dsl/TransactionDSLInterpreter.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/dsl/TransactionDSLInterpreter.kt index e47a8037e5..e7ccdafb86 100644 --- a/testing/test-utils/src/main/kotlin/net/corda/testing/dsl/TransactionDSLInterpreter.kt +++ b/testing/test-utils/src/main/kotlin/net/corda/testing/dsl/TransactionDSLInterpreter.kt @@ -97,6 +97,15 @@ interface TransactionDSLInterpreter : Verifies, OutputStateLookup { * @param attachmentId The attachment */ fun _attachment(contractClassName: ContractClassName, attachmentId: AttachmentId, signers: List) + + /** + * Attaches an attachment containing the named contract to the transaction. + * @param contractClassName The contract class to attach. + * @param attachmentId The attachment. + * @param signers The signers. + * @param jarManifestAttributes The JAR manifest file attributes. + */ + fun _attachment(contractClassName: ContractClassName, attachmentId: AttachmentId, signers: List, jarManifestAttributes: Map) } /** @@ -203,7 +212,7 @@ class TransactionDSL(interpreter: T, private */ fun attachment(contractClassName: ContractClassName) = _attachment(contractClassName) - fun attachment(contractClassName: ContractClassName, attachmentId: AttachmentId, signers: List) = _attachment(contractClassName, attachmentId, signers) + fun attachment(contractClassName: ContractClassName, attachmentId: AttachmentId, signers: List, jarManifestAttributes: Map = emptyMap()) = _attachment(contractClassName, attachmentId, signers, jarManifestAttributes) fun attachment(contractClassName: ContractClassName, attachmentId: AttachmentId) = _attachment(contractClassName, attachmentId, emptyList()) fun attachments(vararg contractClassNames: ContractClassName) = contractClassNames.forEach { attachment(it) } diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/internal/InternalTestUtils.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/internal/InternalTestUtils.kt index 52ba72d528..a66e956bf8 100644 --- a/testing/test-utils/src/main/kotlin/net/corda/testing/internal/InternalTestUtils.kt +++ b/testing/test-utils/src/main/kotlin/net/corda/testing/internal/InternalTestUtils.kt @@ -13,6 +13,7 @@ import net.corda.core.internal.NamedCacheFactory import net.corda.core.node.NodeInfo import net.corda.core.transactions.WireTransaction import net.corda.core.utilities.loggerFor +import net.corda.node.internal.cordapp.set import net.corda.node.internal.createCordaPersistence import net.corda.node.internal.security.RPCSecurityManagerImpl import net.corda.node.internal.startHikariPool @@ -41,6 +42,7 @@ import java.util.* import java.util.jar.JarOutputStream import java.util.zip.ZipEntry import javax.security.auth.x500.X500Principal +import java.util.jar.Manifest @Suppress("unused") inline fun T.kryoSpecific(reason: String, function: () -> Unit) = if (!AMQP_ENABLED) { @@ -181,9 +183,11 @@ fun configureDatabase(hikariProperties: Properties, /** * Convenience method for creating a fake attachment containing a file with some content. */ -fun fakeAttachment(filePath: String, content: String): ByteArray { +fun fakeAttachment(filePath: String, content: String, manifestAttributes: Map = emptyMap()): ByteArray { val bs = ByteArrayOutputStream() - JarOutputStream(bs).use { js -> + val manifest = Manifest() + manifestAttributes.forEach{ manifest[it.key] = it.value} //adding manually instead of putAll, as it requires typed keys, not strings + JarOutputStream(bs, manifest).use { js -> js.putNextEntry(ZipEntry(filePath)) js.writer().apply { append(content); flush() } js.closeEntry() diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/internal/MockCordappProvider.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/internal/MockCordappProvider.kt index 877a53f934..63af2c3106 100644 --- a/testing/test-utils/src/main/kotlin/net/corda/testing/internal/MockCordappProvider.kt +++ b/testing/test-utils/src/main/kotlin/net/corda/testing/internal/MockCordappProvider.kt @@ -12,7 +12,7 @@ import net.corda.node.internal.cordapp.CordappProviderImpl import net.corda.testing.services.MockAttachmentStorage import java.nio.file.Paths import java.security.PublicKey -import java.util.* +import java.util.jar.Attributes class MockCordappProvider( cordappLoader: CordappLoader, @@ -22,7 +22,7 @@ class MockCordappProvider( private val cordappRegistry = mutableListOf>() - fun addMockCordapp(contractClassName: ContractClassName, attachments: MockAttachmentStorage, contractHash: AttachmentId? = null, signers: List = emptyList()): AttachmentId { + fun addMockCordapp(contractClassName: ContractClassName, attachments: MockAttachmentStorage, contractHash: AttachmentId? = null, signers: List = emptyList(), jarManifestAttributes: Map = emptyMap()): AttachmentId { val cordapp = CordappImpl( contractClassNames = listOf(contractClassName), initiatedFlows = emptyList(), @@ -37,8 +37,10 @@ class MockCordappProvider( info = CordappImpl.Info.UNKNOWN, allFlows = emptyList(), jarHash = SecureHash.allOnesHash) + val jarManifestAttributesWithObligatoryElement = jarManifestAttributes.toMutableMap() + jarManifestAttributesWithObligatoryElement.putIfAbsent(Attributes.Name.MANIFEST_VERSION.toString(), "1.0") if (cordappRegistry.none { it.first.contractClassNames.contains(contractClassName) && it.second == contractHash }) { - cordappRegistry.add(Pair(cordapp, findOrImportAttachment(listOf(contractClassName), fakeAttachmentCached(contractClassName), attachments, contractHash, signers))) + cordappRegistry.add(Pair(cordapp, findOrImportAttachment(listOf(contractClassName), fakeAttachmentCached(contractClassName, jarManifestAttributesWithObligatoryElement), attachments, contractHash, signers))) } return cordappRegistry.findLast { contractClassName in it.first.contractClassNames }?.second!! } @@ -58,7 +60,7 @@ class MockCordappProvider( } private val attachmentsCache = mutableMapOf() - private fun fakeAttachmentCached(contractClass: String): ByteArray = attachmentsCache.computeIfAbsent(contractClass) { - fakeAttachment(contractClass, contractClass) + private fun fakeAttachmentCached(contractClass: String, manifestAttributes: Map = emptyMap()): ByteArray = attachmentsCache.computeIfAbsent(contractClass + manifestAttributes.toSortedMap()) { + fakeAttachment(contractClass, contractClass, manifestAttributes) } }