Merge commit 'ad23bb875482b7b8e17c64fb37342d0d6a5ce94d' into feature/test-merge-szymon

# Conflicts:
#	node/src/integration-test/kotlin/net/corda/node/services/BFTNotaryServiceTests.kt
This commit is contained in:
szymonsztuka 2018-01-02 11:54:29 +00:00
commit f701bc1b9a
3 changed files with 203 additions and 16 deletions

View File

@ -12,7 +12,6 @@ import java.util.*
* Defines a simple domain specific language for the specification of financial contracts. Currently covers: * Defines a simple domain specific language for the specification of financial contracts. Currently covers:
* *
* - Some utilities for working with commands. * - Some utilities for working with commands.
* - An Amount type that represents a positive quantity of a specific token.
* - A simple language extension for specifying requirements in English, along with logic to enforce them. * - A simple language extension for specifying requirements in English, along with logic to enforce them.
*/ */
@ -30,37 +29,44 @@ inline fun <R> requireThat(body: Requirements.() -> R) = Requirements.body()
//// Authenticated commands /////////////////////////////////////////////////////////////////////////////////////////// //// Authenticated commands ///////////////////////////////////////////////////////////////////////////////////////////
// TODO: Provide a version of select that interops with Java
/** Filters the command list by type, party and public key all at once. */ /** Filters the command list by type, party and public key all at once. */
inline fun <reified T : CommandData> Collection<CommandWithParties<CommandData>>.select(signer: PublicKey? = null, inline fun <reified T : CommandData> Collection<CommandWithParties<CommandData>>.select(signer: PublicKey? = null,
party: AbstractParty? = null) = party: AbstractParty? = null) =
filter { it.value is T }. select(T::class.java, signer, party)
/** Filters the command list by type, party and public key all at once. */
fun <C : CommandData> Collection<CommandWithParties<CommandData>>.select(klass: Class<C>,
signer: PublicKey? = null,
party: AbstractParty? = null) =
mapNotNull { if (klass.isInstance(it.value)) uncheckedCast<CommandWithParties<CommandData>, CommandWithParties<C>>(it) else null }.
filter { if (signer == null) true else signer in it.signers }. filter { if (signer == null) true else signer in it.signers }.
filter { if (party == null) true else party in it.signingParties }. filter { if (party == null) true else party in it.signingParties }.
map { CommandWithParties(it.signers, it.signingParties, it.value as T) } map { CommandWithParties(it.signers, it.signingParties, it.value) }
// TODO: Provide a version of select that interops with Java
/** Filters the command list by type, parties and public keys all at once. */ /** Filters the command list by type, parties and public keys all at once. */
inline fun <reified T : CommandData> Collection<CommandWithParties<CommandData>>.select(signers: Collection<PublicKey>?, inline fun <reified T : CommandData> Collection<CommandWithParties<CommandData>>.select(signers: Collection<PublicKey>?,
parties: Collection<Party>?) = parties: Collection<Party>?) =
filter { it.value is T }. select(T::class.java, signers, parties)
/** Filters the command list by type, parties and public keys all at once. */
fun <C : CommandData> Collection<CommandWithParties<CommandData>>.select(klass: Class<C>,
signers: Collection<PublicKey>?,
parties: Collection<Party>?) =
mapNotNull { if (klass.isInstance(it.value)) uncheckedCast<CommandWithParties<CommandData>, CommandWithParties<C>>(it) else null }.
filter { if (signers == null) true else it.signers.containsAll(signers) }. filter { if (signers == null) true else it.signers.containsAll(signers) }.
filter { if (parties == null) true else it.signingParties.containsAll(parties) }. filter { if (parties == null) true else it.signingParties.containsAll(parties) }.
map { CommandWithParties(it.signers, it.signingParties, it.value as T) } map { CommandWithParties(it.signers, it.signingParties, it.value) }
/** Ensures that a transaction has only one command that is of the given type, otherwise throws an exception. */ /** Ensures that a transaction has only one command that is of the given type, otherwise throws an exception. */
inline fun <reified T : CommandData> Collection<CommandWithParties<CommandData>>.requireSingleCommand() = try { inline fun <reified T : CommandData> Collection<CommandWithParties<CommandData>>.requireSingleCommand() = requireSingleCommand(T::class.java)
select<T>().single()
/** Ensures that a transaction has only one command that is of the given type, otherwise throws an exception. */
fun <C : CommandData> Collection<CommandWithParties<CommandData>>.requireSingleCommand(klass: Class<C>) = try {
select(klass).single()
} catch (e: NoSuchElementException) { } catch (e: NoSuchElementException) {
throw IllegalStateException("Required ${T::class.qualifiedName} command") // Better error message. throw IllegalStateException("Required ${klass.kotlin.qualifiedName} command") // Better error message.
} }
/** Ensures that a transaction has only one command that is of the given type, otherwise throws an exception. */
fun <C : CommandData> Collection<CommandWithParties<CommandData>>.requireSingleCommand(klass: Class<C>) =
mapNotNull { if (klass.isInstance(it.value)) uncheckedCast<CommandWithParties<CommandData>, CommandWithParties<C>>(it) else null }.single()
/** /**
* Simple functionality for verifying a move command. Verifies that each input has a signature from its owning key. * Simple functionality for verifying a move command. Verifies that each input has a signature from its owning key.
* *

View File

@ -0,0 +1,179 @@
package net.corda.core.contracts
import net.corda.core.identity.AbstractParty
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.testing.TestIdentity
import org.assertj.core.api.Assertions
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import java.security.PublicKey
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
class ContractsDSLTests {
class UnwantedCommand : CommandData
interface TestCommands : CommandData {
class CommandOne : TypeOnlyCommandData(), TestCommands
class CommandTwo : TypeOnlyCommandData(), TestCommands
}
private companion object {
val megaCorp = TestIdentity(CordaX500Name("MegaCorp", "London", "GB"))
val miniCorp = TestIdentity(CordaX500Name("MiniCorp", "London", "GB"))
val validCommandOne = CommandWithParties(listOf(megaCorp.publicKey, miniCorp.publicKey), listOf(megaCorp.party, miniCorp.party), TestCommands.CommandOne())
val validCommandTwo = CommandWithParties(listOf(megaCorp.publicKey), listOf(megaCorp.party), TestCommands.CommandTwo())
val invalidCommand = CommandWithParties(emptyList(), emptyList(), UnwantedCommand())
}
@RunWith(Parameterized::class)
class RequireSingleCommandTests(private val testFunction: (Collection<CommandWithParties<CommandData>>) -> CommandWithParties<CommandData>, description: String) {
companion object {
@JvmStatic
@Parameterized.Parameters(name = "{1}")
fun data(): Collection<Array<Any>> = listOf(
arrayOf<Any>({ commands: Collection<CommandWithParties<CommandData>> -> commands.requireSingleCommand<TestCommands>() }, "Inline version"),
arrayOf<Any>({ commands: Collection<CommandWithParties<CommandData>> -> commands.requireSingleCommand(TestCommands::class.java) }, "Interop version")
)
}
@Test
fun `check function returns one value`() {
val commands = listOf(validCommandOne, invalidCommand)
val returnedCommand = testFunction(commands)
assertEquals(returnedCommand, validCommandOne, "they should be the same")
}
@Test(expected = IllegalArgumentException::class)
fun `check error is thrown if more than one valid command`() {
val commands = listOf(validCommandOne, validCommandTwo)
testFunction(commands)
}
@Test
fun `check error is thrown when command is of wrong type`() {
val commands = listOf(invalidCommand)
Assertions.assertThatThrownBy { testFunction(commands) }
.isInstanceOf(IllegalStateException::class.java)
.hasMessage("Required net.corda.core.contracts.ContractsDSLTests.TestCommands command")
}
}
@RunWith(Parameterized::class)
class SelectWithSingleInputsTests(private val testFunction: (Collection<CommandWithParties<CommandData>>, PublicKey?, AbstractParty?) -> Iterable<CommandWithParties<CommandData>>, description: String) {
companion object {
@JvmStatic
@Parameterized.Parameters(name = "{1}")
fun data(): Collection<Array<Any>> = listOf(
arrayOf<Any>({ commands: Collection<CommandWithParties<CommandData>>, signer: PublicKey?, party: AbstractParty? -> commands.select<TestCommands>(signer, party) }, "Inline version"),
arrayOf<Any>({ commands: Collection<CommandWithParties<CommandData>>, signer: PublicKey?, party: AbstractParty? -> commands.select(TestCommands::class.java, signer, party) }, "Interop version")
)
}
@Test
fun `check that function returns all values`() {
val commands = listOf(validCommandOne, validCommandTwo)
testFunction(commands, null, null)
assertEquals(2, commands.size)
assertTrue(commands.contains(validCommandOne))
assertTrue(commands.contains(validCommandTwo))
}
@Test
fun `check that function does not return invalid command types`() {
val commands = listOf(validCommandOne, invalidCommand)
val filteredCommands = testFunction(commands, null, null).toList()
assertEquals(1, filteredCommands.size)
assertTrue(filteredCommands.contains(validCommandOne))
assertFalse(filteredCommands.contains(invalidCommand))
}
@Test
fun `check that function returns commands from valid signers`() {
val commands = listOf(validCommandOne, validCommandTwo)
val filteredCommands = testFunction(commands, miniCorp.publicKey, null).toList()
assertEquals(1, filteredCommands.size)
assertTrue(filteredCommands.contains(validCommandOne))
assertFalse(filteredCommands.contains(validCommandTwo))
}
@Test
fun `check that function returns commands from valid parties`() {
val commands = listOf(validCommandOne, validCommandTwo)
val filteredCommands = testFunction(commands, null, miniCorp.party).toList()
assertEquals(1, filteredCommands.size)
assertTrue(filteredCommands.contains(validCommandOne))
assertFalse(filteredCommands.contains(validCommandTwo))
}
}
@RunWith(Parameterized::class)
class SelectWithMultipleInputsTests(private val testFunction: (Collection<CommandWithParties<CommandData>>, Collection<PublicKey>?, Collection<Party>?) -> Iterable<CommandWithParties<CommandData>>, description: String) {
companion object {
@JvmStatic
@Parameterized.Parameters(name = "{1}")
fun data(): Collection<Array<Any>> = listOf(
arrayOf<Any>({ commands: Collection<CommandWithParties<CommandData>>, signers: Collection<PublicKey>?, party: Collection<Party>? -> commands.select<TestCommands>(signers, party) }, "Inline version"),
arrayOf<Any>({ commands: Collection<CommandWithParties<CommandData>>, signers: Collection<PublicKey>?, party: Collection<Party>? -> commands.select(TestCommands::class.java, signers, party) }, "Interop version")
)
}
@Test
fun `check that function returns all values`() {
val commands = listOf(validCommandOne, validCommandTwo)
testFunction(commands, null, null)
assertEquals(2, commands.size)
assertTrue(commands.contains(validCommandOne))
assertTrue(commands.contains(validCommandTwo))
}
@Test
fun `check that function does not return invalid command types`() {
val commands = listOf(validCommandOne, invalidCommand)
val filteredCommands = testFunction(commands, null, null).toList()
assertEquals(1, filteredCommands.size)
assertTrue(filteredCommands.contains(validCommandOne))
assertFalse(filteredCommands.contains(invalidCommand))
}
@Test
fun `check that function returns commands from valid signers`() {
val commands = listOf(validCommandOne, validCommandTwo)
val filteredCommands = testFunction(commands, listOf(megaCorp.publicKey), null).toList()
assertEquals(2, filteredCommands.size)
assertTrue(filteredCommands.contains(validCommandOne))
assertTrue(filteredCommands.contains(validCommandTwo))
}
@Test
fun `check that function returns commands from all valid signers`() {
val commands = listOf(validCommandOne, validCommandTwo)
val filteredCommands = testFunction(commands, listOf(miniCorp.publicKey, megaCorp.publicKey), null).toList()
assertEquals(1, filteredCommands.size)
assertTrue(filteredCommands.contains(validCommandOne))
assertFalse(filteredCommands.contains(validCommandTwo))
}
@Test
fun `check that function returns commands from valid parties`() {
val commands = listOf(validCommandOne, validCommandTwo)
val filteredCommands = testFunction(commands, null, listOf(megaCorp.party)).toList()
assertEquals(2, filteredCommands.size)
assertTrue(filteredCommands.contains(validCommandOne))
assertTrue(filteredCommands.contains(validCommandTwo))
}
@Test
fun `check that function returns commands from all valid parties`() {
val commands = listOf(validCommandOne, validCommandTwo)
val filteredCommands = testFunction(commands, null, listOf(miniCorp.party, megaCorp.party)).toList()
assertEquals(1, filteredCommands.size)
assertTrue(filteredCommands.contains(validCommandOne))
assertFalse(filteredCommands.contains(validCommandTwo))
}
}
}

View File

@ -50,6 +50,7 @@ class BFTNotaryServiceTests : IntegrationTest() {
val databaseSchemas = IntegrationTestSchemas("node_0", "node_1", "node_2", "node_3", "node_4", "node_5", val databaseSchemas = IntegrationTestSchemas("node_0", "node_1", "node_2", "node_3", "node_4", "node_5",
"node_6", "node_7", "node_8", "node_9") "node_6", "node_7", "node_8", "node_9")
} }
private lateinit var mockNet: MockNetwork private lateinit var mockNet: MockNetwork
private lateinit var notary: Party private lateinit var notary: Party
private lateinit var node: StartedNode<MockNode> private lateinit var node: StartedNode<MockNode>
@ -58,6 +59,7 @@ class BFTNotaryServiceTests : IntegrationTest() {
fun before() { fun before() {
mockNet = MockNetwork(emptyList()) mockNet = MockNetwork(emptyList())
} }
@After @After
fun stopNodes() { fun stopNodes() {
mockNet.stopNodes() mockNet.stopNodes()