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

View File

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