Simplify CashTests and add some comments/convenience APIs to MockServices (#2241)

This commit is contained in:
Mike Hearn
2018-01-25 16:29:26 +01:00
committed by GitHub
parent 242d9cf7ad
commit 17a6f61eba
5 changed files with 291 additions and 298 deletions

View File

@ -46,9 +46,15 @@ import java.time.Clock
import java.util.*
fun makeTestIdentityService(vararg identities: PartyAndCertificate) = InMemoryIdentityService(identities, DEV_ROOT_CA.certificate)
/**
* A singleton utility that only provides a mock identity, key and storage service. However, this is sufficient for
* building chains of transactions and verifying them. It isn't sufficient for testing flows however.
* An implementation of [ServiceHub] that is designed for in-memory unit tests of contract validation logic. It has
* enough functionality to do tests of code that queries the vault, inserts to the vault, and constructs/checks
* transactions. However it isn't enough to test flows and other aspects of an app that require a network. For that
* you should investigate [MockNetwork].
*
* There are a variety of constructors that can be used to supply enough data to simulate a node. Each mock service hub
* must have at least an identity of its own. The other components have defaults that work in most situations.
*/
open class MockServices private constructor(
cordappLoader: CordappLoader,
@ -80,6 +86,7 @@ open class MockServices private constructor(
/**
* Makes database and mock services appropriate for unit tests.
*
* @param moreKeys a list of additional [KeyPair] instances to be used by [MockServices].
* @param identityService an instance of [IdentityServiceInternal], see [makeTestIdentityService].
* @param initialIdentity the first (typically sole) identity the services will represent.
@ -109,20 +116,68 @@ open class MockServices private constructor(
}
return Pair(database, mockService)
}
@JvmStatic
private fun getCallerPackage(): String {
// TODO: In Java 9 there's a new stack walker API that is better than this.
// The magic number '3' here is to chop off this method, an invisible bridge method generated by the
// compiler and then the c'tor itself.
return Throwable().stackTrace[3].className.split('.').dropLast(1).joinToString(".")
}
}
private constructor(cordappLoader: CordappLoader, identityService: IdentityServiceInternal, initialIdentity: TestIdentity, moreKeys: Array<out KeyPair>) : this(cordappLoader, MockTransactionStorage(), identityService, initialIdentity, moreKeys)
private constructor(cordappLoader: CordappLoader, identityService: IdentityServiceInternal,
initialIdentity: TestIdentity, moreKeys: Array<out KeyPair>)
: this(cordappLoader, MockTransactionStorage(), identityService, initialIdentity, moreKeys)
/**
* Create a mock [ServiceHub] that looks for app code in the given package names, uses the provided identity service
* (you can get one from [makeTestIdentityService]) and represents the given identity.
*/
@JvmOverloads
constructor(cordappPackages: List<String>, identityService: IdentityServiceInternal = makeTestIdentityService(), initialIdentity: TestIdentity, vararg moreKeys: KeyPair) : this(CordappLoader.createWithTestPackages(cordappPackages), identityService, initialIdentity, moreKeys)
/**
* Create a mock [ServiceHub] that looks for app code in the given package names, uses the provided identity service
* (you can get one from [makeTestIdentityService]) and represents the given identity.
*/
@JvmOverloads
constructor(cordappPackages: List<String>, identityService: IdentityServiceInternal = makeTestIdentityService(), initialIdentityName: CordaX500Name, key: KeyPair, vararg moreKeys: KeyPair) : this(cordappPackages, identityService, TestIdentity(initialIdentityName, key), *moreKeys)
/**
* Create a mock [ServiceHub] that can't load CorDapp code, which uses the provided identity service
* (you can get one from [makeTestIdentityService]) and which represents the given identity.
*/
@JvmOverloads
constructor(cordappPackages: List<String>, identityService: IdentityServiceInternal = makeTestIdentityService(), initialIdentityName: CordaX500Name) : this(cordappPackages, identityService, TestIdentity(initialIdentityName))
/**
* Create a mock [ServiceHub] which uses the package of the caller to find CorDapp code. It uses the provided identity service
* (you can get one from [makeTestIdentityService]) and which represents the given identity.
*/
@JvmOverloads
constructor(cordappPackages: List<String>, identityService: IdentityServiceInternal = makeTestIdentityService(), vararg moreKeys: KeyPair) : this(cordappPackages, identityService, TestIdentity.fresh("MockServices"), *moreKeys)
constructor(identityService: IdentityServiceInternal = makeTestIdentityService(), initialIdentityName: CordaX500Name, key: KeyPair, vararg moreKeys: KeyPair)
: this(listOf(getCallerPackage()), identityService, TestIdentity(initialIdentityName, key), *moreKeys)
/**
* Create a mock [ServiceHub] which uses the package of the caller to find CorDapp code. It uses the provided identity service
* (you can get one from [makeTestIdentityService]) and which represents the given identity. It has no keys.
*/
@JvmOverloads
constructor(identityService: IdentityServiceInternal = makeTestIdentityService(), initialIdentityName: CordaX500Name)
: this(listOf(getCallerPackage()), identityService, TestIdentity(initialIdentityName))
/**
* A helper constructor that requires at least one test identity to be registered, and which takes the package of
* the caller as the package in which to find app code. This is the most convenient constructor and the one that
* is normally worth using. The first identity is the identity of this service hub, the rest are identities that
* it is aware of.
*/
constructor(firstIdentity: TestIdentity, vararg moreIdentities: TestIdentity) : this(
listOf(getCallerPackage()),
makeTestIdentityService(*listOf(firstIdentity, *moreIdentities).map { it.identity }.toTypedArray()),
firstIdentity, firstIdentity.keyPair
)
override fun recordTransactions(statesToRecord: StatesToRecord, txs: Iterable<SignedTransaction>) {
txs.forEach {
@ -185,7 +240,7 @@ class MockKeyManagementService(val identityService: IdentityServiceInternal,
private fun getSigner(publicKey: PublicKey): ContentSigner = getSigner(getSigningKeyPair(publicKey))
private fun getSigningKeyPair(publicKey: PublicKey): KeyPair {
val pk = publicKey.keys.first { keyStore.containsKey(it) }
val pk = publicKey.keys.firstOrNull { keyStore.containsKey(it) } ?: throw IllegalArgumentException("Public key not found: ${publicKey.toStringShort()}")
return KeyPair(pk, keyStore[pk]!!)
}