CORDA-654: Handle non-standard file systems in NodeInfoWatcher (#1818)

Handle non-standard file systems such as JimFs, in NodeInfoWatcher. Instead of using `toFile()` to convert a Path to a File, open the Path for writing to directly.
This commit is contained in:
Ross Nicoll 2017-10-09 16:15:27 +01:00 committed by GitHub
parent 0d15e70d51
commit 7340a2e32f
2 changed files with 42 additions and 31 deletions

View File

@ -1,16 +1,16 @@
package net.corda.node.services.network
import com.google.common.jimfs.Configuration
import com.google.common.jimfs.Jimfs
import net.corda.cordform.CordformNode
import net.corda.core.internal.createDirectories
import net.corda.core.internal.div
import net.corda.core.node.NodeInfo
import net.corda.core.node.services.KeyManagementService
import net.corda.core.utilities.seconds
import net.corda.node.services.identity.InMemoryIdentityService
import net.corda.testing.ALICE
import net.corda.testing.ALICE_KEY
import net.corda.testing.DEV_TRUST_ROOT
import net.corda.testing.eventually
import net.corda.testing.getTestPartyAndCertificate
import net.corda.testing.node.MockKeyManagementService
import net.corda.testing.node.NodeBasedTest
@ -56,6 +56,7 @@ class NodeInfoWatcherTest : NodeBasedTest() {
@Test
fun `save a NodeInfo`() {
assertEquals(0, folder.root.list().size)
NodeInfoWatcher.saveToFile(folder.root.toPath(), nodeInfo, keyManagementService)
assertEquals(1, folder.root.list().size)
@ -66,30 +67,45 @@ class NodeInfoWatcherTest : NodeBasedTest() {
assertThat(contentOf(file)).isNotEmpty()
}
@Test
fun `save a NodeInfo to JimFs`() {
val jimFs = Jimfs.newFileSystem(Configuration.unix())
val jimFolder = jimFs.getPath("/nodeInfo")
NodeInfoWatcher.saveToFile(jimFolder, nodeInfo, keyManagementService)
}
@Test
fun `load an empty Directory`() {
nodeInfoPath.createDirectories()
nodeInfoWatcher.nodeInfoUpdates()
val subscription = nodeInfoWatcher.nodeInfoUpdates()
.subscribe(testSubscriber)
advanceTime()
try {
advanceTime()
val readNodes = testSubscriber.onNextEvents.distinct()
assertEquals(0, readNodes.size)
val readNodes = testSubscriber.onNextEvents.distinct()
assertEquals(0, readNodes.size)
} finally {
subscription.unsubscribe()
}
}
@Test
fun `load a non empty Directory`() {
createNodeInfoFileInPath(nodeInfo)
nodeInfoWatcher.nodeInfoUpdates()
val subscription = nodeInfoWatcher.nodeInfoUpdates()
.subscribe(testSubscriber)
advanceTime()
val readNodes = testSubscriber.onNextEvents.distinct()
try {
val readNodes = testSubscriber.onNextEvents.distinct()
assertEquals(1, readNodes.size)
assertEquals(nodeInfo, readNodes.first())
assertEquals(1, readNodes.size)
assertEquals(nodeInfo, readNodes.first())
} finally {
subscription.unsubscribe()
}
}
@Test
@ -97,22 +113,24 @@ class NodeInfoWatcherTest : NodeBasedTest() {
nodeInfoPath.createDirectories()
// Start polling with an empty folder.
nodeInfoWatcher.nodeInfoUpdates()
val subscription = nodeInfoWatcher.nodeInfoUpdates()
.subscribe(testSubscriber)
// Ensure the watch service is started.
advanceTime()
// Check no nodeInfos are read.
assertEquals(0, testSubscriber.valueCount)
createNodeInfoFileInPath(nodeInfo)
try {
// Ensure the watch service is started.
advanceTime()
// Check no nodeInfos are read.
assertEquals(0, testSubscriber.valueCount)
createNodeInfoFileInPath(nodeInfo)
advanceTime()
advanceTime()
// We need the WatchService to report a change and that might not happen immediately.
eventually<AssertionError, Unit>(5.seconds) {
// We need the WatchService to report a change and that might not happen immediately.
testSubscriber.awaitValueCount(1, 5, TimeUnit.SECONDS)
// The same folder can be reported more than once, so take unique values.
val readNodes = testSubscriber.onNextEvents.distinct()
assertEquals(1, readNodes.size)
assertEquals(nodeInfo, readNodes.first())
} finally {
subscription.unsubscribe()
}
}

View File

@ -1,14 +1,8 @@
package net.corda.node.services.network
import net.corda.cordform.CordformNode
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.SignedData
import net.corda.core.internal.createDirectories
import net.corda.core.internal.div
import net.corda.core.internal.isDirectory
import net.corda.core.internal.isRegularFile
import net.corda.core.internal.list
import net.corda.core.internal.readAll
import net.corda.core.internal.*
import net.corda.core.node.NodeInfo
import net.corda.core.node.services.KeyManagementService
import net.corda.core.serialization.deserialize
@ -17,6 +11,7 @@ import net.corda.core.utilities.loggerFor
import rx.Observable
import rx.Scheduler
import rx.schedulers.Schedulers
import java.nio.file.Files
import java.nio.file.Path
import java.util.concurrent.TimeUnit
import kotlin.streams.toList
@ -52,11 +47,9 @@ class NodeInfoWatcher(private val nodePath: Path,
try {
path.createDirectories()
val serializedBytes = nodeInfo.serialize()
val regSig = keyManager.sign(serializedBytes.bytes,
nodeInfo.legalIdentities.first().owningKey)
val regSig = keyManager.sign(serializedBytes.bytes, nodeInfo.legalIdentities.first().owningKey)
val signedData = SignedData(serializedBytes, regSig)
val file = (path / ("nodeInfo-" + SecureHash.sha256(serializedBytes.bytes).toString())).toFile()
file.writeBytes(signedData.serialize().bytes)
signedData.serialize().open().copyTo(path / "nodeInfo-${serializedBytes.hash}")
} catch (e: Exception) {
logger.warn("Couldn't write node info to file", e)
}