mirror of
https://github.com/corda/corda.git
synced 2024-12-24 07:06:44 +00:00
Improved unit tests.
Cleaned up project structure a bit.
This commit is contained in:
parent
3675675277
commit
527b0f4817
2
.gitignore
vendored
2
.gitignore
vendored
@ -13,7 +13,7 @@ tags
|
||||
.gradle
|
||||
/build/
|
||||
/contracts/build
|
||||
/standalone.test/build
|
||||
/contracts/isolated/build
|
||||
/core/build
|
||||
/docs/build/doctrees
|
||||
|
||||
|
@ -41,6 +41,9 @@ repositories {
|
||||
|
||||
configurations {
|
||||
quasar
|
||||
|
||||
// we don't want isolated.jar in classPath, since we want to test jar being dynamically loaded as an attachment
|
||||
runtime.exclude module: 'isolated'
|
||||
}
|
||||
|
||||
// To find potential version conflicts, run "gradle htmlDependencyReport" and then look in
|
||||
@ -48,6 +51,7 @@ configurations {
|
||||
|
||||
dependencies {
|
||||
compile project(':contracts')
|
||||
testCompile project(':contracts:isolated')
|
||||
|
||||
compile "com.google.code.findbugs:jsr305:3.0.1"
|
||||
compile "org.slf4j:slf4j-jdk14:1.7.13"
|
||||
|
80
contracts/isolated/build.gradle
Normal file
80
contracts/isolated/build.gradle
Normal file
@ -0,0 +1,80 @@
|
||||
import com.google.common.io.ByteStreams
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Paths
|
||||
import java.nio.file.StandardCopyOption
|
||||
import java.nio.file.attribute.FileTime
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipOutputStream
|
||||
import java.util.zip.ZipFile
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath "com.google.guava:guava:19.0"
|
||||
}
|
||||
}
|
||||
|
||||
// Custom Gradle plugin that attempts to make the resulting jar file deterministic.
|
||||
// Ie. same contract definition should result when compiled in same jar file.
|
||||
// This is done by removing date time stamps from the files inside the jar.
|
||||
class CanonicalizerPlugin implements Plugin<Project> {
|
||||
void apply(Project project) {
|
||||
|
||||
project.getTasks().getByName('jar').doLast() {
|
||||
|
||||
def zipPath = (String) project.jar.archivePath
|
||||
def destPath = Files.createTempFile("processzip", null)
|
||||
|
||||
def zeroTime = FileTime.fromMillis(0)
|
||||
|
||||
def input = new ZipFile(zipPath)
|
||||
def entries = input.entries().toList().sort { it.name }
|
||||
|
||||
def output = new ZipOutputStream(new FileOutputStream(destPath.toFile()))
|
||||
output.setMethod(ZipOutputStream.DEFLATED)
|
||||
|
||||
entries.each {
|
||||
def newEntry = new ZipEntry( it.name )
|
||||
|
||||
newEntry.setLastModifiedTime(zeroTime)
|
||||
newEntry.setCreationTime(zeroTime)
|
||||
newEntry.compressedSize = -1
|
||||
newEntry.size = it.size
|
||||
newEntry.crc = it.crc
|
||||
|
||||
output.putNextEntry(newEntry)
|
||||
|
||||
ByteStreams.copy(input.getInputStream(it), output)
|
||||
|
||||
output.closeEntry()
|
||||
}
|
||||
output.close()
|
||||
input.close()
|
||||
|
||||
Files.move(destPath, Paths.get(zipPath), StandardCopyOption.REPLACE_EXISTING)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'kotlin'
|
||||
|
||||
apply plugin: CanonicalizerPlugin
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
maven {
|
||||
url 'http://oss.sonatype.org/content/repositories/snapshots'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':core')
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2015 Distributed Ledger Group LLC. Distributed as Licensed Company IP to DLG Group Members
|
||||
* pursuant to the August 7, 2015 Advisory Services Agreement and subject to the Company IP License terms
|
||||
* set forth therein.
|
||||
*
|
||||
* All other rights reserved.
|
||||
*/
|
||||
|
||||
package contracts.isolated
|
||||
|
||||
import core.Contract
|
||||
import core.ContractState
|
||||
import core.TransactionForVerification
|
||||
import core.crypto.SecureHash
|
||||
|
||||
// The dummy contract doesn't do anything useful. It exists for testing purposes.
|
||||
|
||||
val ANOTHER_DUMMY_PROGRAM_ID = SecureHash.sha256("dummy")
|
||||
|
||||
class AnotherDummyContract : Contract {
|
||||
class State : ContractState {
|
||||
override val programRef: SecureHash = ANOTHER_DUMMY_PROGRAM_ID
|
||||
}
|
||||
|
||||
override fun verify(tx: TransactionForVerification) {
|
||||
// Always accepts.
|
||||
}
|
||||
|
||||
// The "empty contract"
|
||||
override val legalContractReference: SecureHash = SecureHash.sha256("https://anotherdummy.org")
|
||||
}
|
@ -87,7 +87,7 @@ inline fun <reified T : Any> OpaqueBytes.deserialize(kryo: Kryo = THREAD_LOCAL_K
|
||||
// The more specific deserialize version results in the bytes being cached, which is faster.
|
||||
@JvmName("SerializedBytesWireTransaction")
|
||||
fun SerializedBytes<WireTransaction>.deserialize(): WireTransaction = WireTransaction.deserialize(this)
|
||||
inline fun <reified T : Any> SerializedBytes<T>.deserialize(): T = bits.deserialize()
|
||||
inline fun <reified T : Any> SerializedBytes<T>.deserialize(kryo: Kryo = THREAD_LOCAL_KRYO.get(), includeClassName: Boolean = false): T = bits.deserialize(kryo, includeClassName)
|
||||
|
||||
/**
|
||||
* Can be called on any object to convert it to a byte array (wrapped by [SerializedBytes]), regardless of whether
|
||||
|
@ -1,4 +1,5 @@
|
||||
rootProject.name = 'r3prototyping'
|
||||
include 'contracts'
|
||||
include 'contracts:isolated'
|
||||
include 'core'
|
||||
include 'standalone.test'
|
@ -3,19 +3,36 @@ package core.node
|
||||
import core.Contract
|
||||
import core.MockAttachmentStorage
|
||||
import core.crypto.SecureHash
|
||||
import core.serialization.createKryo
|
||||
import core.serialization.deserialize
|
||||
import core.serialization.serialize
|
||||
import org.apache.commons.io.IOUtils
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.FileInputStream
|
||||
import java.net.URL
|
||||
import java.net.URLClassLoader
|
||||
import java.util.jar.JarOutputStream
|
||||
import java.util.zip.ZipEntry
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertNotNull
|
||||
|
||||
class ClassLoaderTests {
|
||||
|
||||
val ISOLATED_CONTRACTS_JAR_PATH = "contracts/isolated/build/libs/isolated.jar"
|
||||
|
||||
@Test
|
||||
fun `dynamically load AnotherDummyContract from isolated contracts jar`() {
|
||||
var child = URLClassLoader(arrayOf(URL("file", "", ISOLATED_CONTRACTS_JAR_PATH)))
|
||||
|
||||
var contractClass = Class.forName("contracts.isolated.AnotherDummyContract", true, child)
|
||||
var contract = contractClass.newInstance() as Contract
|
||||
|
||||
assertEquals(SecureHash.sha256("https://anotherdummy.org"), contract.legalContractReference)
|
||||
}
|
||||
|
||||
fun fakeAttachment(filepath: String, content: String): ByteArray {
|
||||
val bs = ByteArrayOutputStream()
|
||||
val js = JarOutputStream(bs)
|
||||
@ -29,7 +46,7 @@ class ClassLoaderTests {
|
||||
@Test
|
||||
fun `test MockAttachmentStorage open as jar`() {
|
||||
val storage = MockAttachmentStorage()
|
||||
val key = storage.importAttachment( FileInputStream("contracts/build/libs/contracts.jar") )
|
||||
val key = storage.importAttachment( FileInputStream(ISOLATED_CONTRACTS_JAR_PATH) )
|
||||
val attachment = storage.openAttachment(key)!!
|
||||
|
||||
val jar = attachment.openAsJAR()
|
||||
@ -42,7 +59,7 @@ class ClassLoaderTests {
|
||||
|
||||
var storage = MockAttachmentStorage()
|
||||
|
||||
var att0 = storage.importAttachment( FileInputStream("contracts/build/libs/contracts.jar") )
|
||||
var att0 = storage.importAttachment( FileInputStream(ISOLATED_CONTRACTS_JAR_PATH) )
|
||||
var att1 = storage.importAttachment( ByteArrayInputStream(fakeAttachment("file.txt", "some data")) )
|
||||
var att2 = storage.importAttachment( ByteArrayInputStream(fakeAttachment("file.txt", "some other data")) )
|
||||
|
||||
@ -58,7 +75,7 @@ class ClassLoaderTests {
|
||||
|
||||
var storage = MockAttachmentStorage()
|
||||
|
||||
var att0 = storage.importAttachment( FileInputStream("contracts/build/libs/contracts.jar") )
|
||||
var att0 = storage.importAttachment( FileInputStream(ISOLATED_CONTRACTS_JAR_PATH) )
|
||||
var att1 = storage.importAttachment( ByteArrayInputStream(fakeAttachment("file1.txt", "some data")) )
|
||||
var att2 = storage.importAttachment( ByteArrayInputStream(fakeAttachment("file2.txt", "some other data")) )
|
||||
|
||||
@ -69,26 +86,91 @@ class ClassLoaderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `loading class Cash`() {
|
||||
fun `loading class AnotherDummyContract`() {
|
||||
var storage = MockAttachmentStorage()
|
||||
|
||||
var att0 = storage.importAttachment( FileInputStream("contracts/build/libs/contracts.jar") )
|
||||
var att0 = storage.importAttachment( FileInputStream(ISOLATED_CONTRACTS_JAR_PATH) )
|
||||
var att1 = storage.importAttachment( ByteArrayInputStream(fakeAttachment("file1.txt", "some data")) )
|
||||
var att2 = storage.importAttachment( ByteArrayInputStream(fakeAttachment("file2.txt", "some other data")) )
|
||||
|
||||
ClassLoader.create( arrayOf( att0, att1, att2 ).map { storage.openAttachment(it)!! } ).use {
|
||||
|
||||
var contractClass = Class.forName("contracts.Cash", true, it)
|
||||
var contractClass = Class.forName("contracts.isolated.AnotherDummyContract", true, it)
|
||||
var contract = contractClass.newInstance() as Contract
|
||||
|
||||
assertEquals(SecureHash.sha256("https://www.big-book-of-banking-law.gov/cash-claims.html"), contract.legalContractReference)
|
||||
assertEquals(SecureHash.sha256("https://anotherdummy.org"), contract.legalContractReference)
|
||||
}
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
fun `testing Kryo with ClassLoader`() {
|
||||
assert(false) // todo
|
||||
fun `verify that contract AnotherDummyContract is not in classPath`() {
|
||||
assertFailsWith(ClassNotFoundException::class) {
|
||||
var contractClass = Class.forName("contracts.isolated.AnotherDummyContract")
|
||||
contractClass.newInstance() as Contract
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `verify that contract DummyContract is in classPath`() {
|
||||
var contractClass = Class.forName("contracts.DummyContract")
|
||||
var contract = contractClass.newInstance() as Contract
|
||||
|
||||
assertNotNull(contract)
|
||||
}
|
||||
|
||||
fun createContract2Cash() : Contract {
|
||||
var child = URLClassLoader(arrayOf(URL("file", "", ISOLATED_CONTRACTS_JAR_PATH)))
|
||||
|
||||
var contractClass = Class.forName("contracts.isolated.AnotherDummyContract", true, child)
|
||||
var contract = contractClass.newInstance() as Contract
|
||||
return contract
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `testing Kryo with ClassLoader (with top level class name)`() {
|
||||
val contract = createContract2Cash()
|
||||
|
||||
val bytes = contract.serialize(includeClassName = true)
|
||||
|
||||
var storage = MockAttachmentStorage()
|
||||
|
||||
var att0 = storage.importAttachment( FileInputStream(ISOLATED_CONTRACTS_JAR_PATH) )
|
||||
var att1 = storage.importAttachment( ByteArrayInputStream(fakeAttachment("file1.txt", "some data")) )
|
||||
var att2 = storage.importAttachment( ByteArrayInputStream(fakeAttachment("file2.txt", "some other data")) )
|
||||
|
||||
val clsLoader = ClassLoader.create( arrayOf( att0, att1, att2 ).map { storage.openAttachment(it)!! } )
|
||||
|
||||
val kryo = createKryo()
|
||||
kryo.classLoader = clsLoader
|
||||
|
||||
val state2 = bytes.deserialize(kryo, true)
|
||||
|
||||
assertNotNull(state2)
|
||||
}
|
||||
|
||||
// top level wrapper
|
||||
class Data( val contract: Contract )
|
||||
|
||||
@Test
|
||||
fun `testing Kryo with ClassLoader (without top level class name)`() {
|
||||
val data = Data( createContract2Cash() )
|
||||
|
||||
val bytes = data.serialize()
|
||||
|
||||
var storage = MockAttachmentStorage()
|
||||
|
||||
var att0 = storage.importAttachment( FileInputStream(ISOLATED_CONTRACTS_JAR_PATH) )
|
||||
var att1 = storage.importAttachment( ByteArrayInputStream(fakeAttachment("file1.txt", "some data")) )
|
||||
var att2 = storage.importAttachment( ByteArrayInputStream(fakeAttachment("file2.txt", "some other data")) )
|
||||
|
||||
val clsLoader = ClassLoader.create( arrayOf( att0, att1, att2 ).map { storage.openAttachment(it)!! } )
|
||||
|
||||
val kryo = createKryo()
|
||||
kryo.classLoader = clsLoader
|
||||
|
||||
val state2 = bytes.deserialize(kryo)
|
||||
|
||||
assertNotNull(state2)
|
||||
}
|
||||
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath "com.google.guava:guava:19.0"
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'kotlin'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven {
|
||||
url 'http://oss.sonatype.org/content/repositories/snapshots'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testCompile 'junit:junit:4.12'
|
||||
|
||||
compile project(':core')
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
import core.Contract
|
||||
import core.crypto.SecureHash
|
||||
import org.junit.Test
|
||||
import java.net.URL
|
||||
import java.net.URLClassLoader
|
||||
import java.util.jar.JarInputStream
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class LoaderTests {
|
||||
|
||||
@Test
|
||||
fun `dynamically load Cash class from contracts jar`() {
|
||||
var child = URLClassLoader(arrayOf(URL("file", "", "../contracts/build/libs/contracts.jar")))
|
||||
|
||||
var contractClass = Class.forName("contracts.Cash", true, child)
|
||||
var contract = contractClass.newInstance() as Contract
|
||||
|
||||
assertEquals(SecureHash.sha256("https://www.big-book-of-banking-law.gov/cash-claims.html"), contract.legalContractReference)
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user