diff --git a/node/src/main/kotlin/net/corda/node/services/network/NodeInfoWatcher.kt b/node/src/main/kotlin/net/corda/node/services/network/NodeInfoWatcher.kt index f21546b0bc..f9adde022c 100644 --- a/node/src/main/kotlin/net/corda/node/services/network/NodeInfoWatcher.kt +++ b/node/src/main/kotlin/net/corda/node/services/network/NodeInfoWatcher.kt @@ -41,17 +41,20 @@ class NodeInfoWatcher(private val nodePath: Path, private val logger = contextLogger() // TODO This method doesn't belong in this class - fun saveToFile(path: Path, nodeInfoAndSigned: NodeInfoAndSigned) { + fun saveToFile(path: Path, nodeInfoAndSigned: NodeInfoAndSigned): Path { // By using the hash of the node's first name we ensure: // 1) node info files for the same node map to the same filename and thus avoid having duplicate files for // the same node // 2) avoid having to deal with characters in the X.500 name which are incompatible with the local filesystem val fileNameHash = nodeInfoAndSigned.nodeInfo.legalIdentities[0].name.serialize().hash + val target = path / "${NodeInfoFilesCopier.NODE_INFO_FILE_NAME_PREFIX}$fileNameHash" nodeInfoAndSigned .signed .serialize() .open() - .copyTo(path / "${NodeInfoFilesCopier.NODE_INFO_FILE_NAME_PREFIX}$fileNameHash", REPLACE_EXISTING) + .copyTo(target, REPLACE_EXISTING) + + return target } } @@ -85,7 +88,7 @@ class NodeInfoWatcher(private val nodePath: Path, logger.debug { "Examining $it" } true } - .filter { !it.endsWith(".tmp") } + .filter { !it.toString().endsWith(".tmp") } .filter { it.isRegularFile() } .filter { file -> val lastModifiedTime = file.lastModifiedTime() diff --git a/node/src/test/kotlin/net/corda/node/services/network/NodeInfoWatcherTest.kt b/node/src/test/kotlin/net/corda/node/services/network/NodeInfoWatcherTest.kt index 6ec93664a3..2a9f450cb0 100644 --- a/node/src/test/kotlin/net/corda/node/services/network/NodeInfoWatcherTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/network/NodeInfoWatcherTest.kt @@ -7,11 +7,11 @@ import net.corda.core.internal.createDirectories import net.corda.core.internal.div import net.corda.core.internal.size import net.corda.core.node.services.KeyManagementService +import net.corda.coretesting.internal.createNodeInfoAndSigned import net.corda.nodeapi.internal.NodeInfoAndSigned import net.corda.nodeapi.internal.network.NodeInfoFilesCopier import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.SerializationEnvironmentRule -import net.corda.coretesting.internal.createNodeInfoAndSigned import net.corda.testing.node.internal.MockKeyManagementService import net.corda.testing.node.makeTestIdentityService import org.assertj.core.api.Assertions.assertThat @@ -21,7 +21,9 @@ import org.junit.Test import org.junit.rules.TemporaryFolder import rx.observers.TestSubscriber import rx.schedulers.TestScheduler +import java.nio.file.Files import java.nio.file.Path +import java.nio.file.Paths import java.util.concurrent.TimeUnit import kotlin.test.assertEquals import kotlin.test.assertTrue @@ -132,6 +134,31 @@ class NodeInfoWatcherTest { } } + @Test(timeout=300_000) + fun `ignore tmp files`() { + nodeInfoPath.createDirectories() + + // Start polling with an empty folder. + val subscription = nodeInfoWatcher.nodeInfoUpdates().subscribe(testSubscriber) + try { + // Ensure the watch service is started. + advanceTime() + + + // create file + // boohoo, we shouldn't create real files, instead mock Path + val file = NodeInfoWatcher.saveToFile(nodeInfoPath, nodeInfoAndSigned) + Files.move(file, Paths.get("$file.tmp")) + + advanceTime() + + // Check no nodeInfos are read. + assertEquals(0, testSubscriber.onNextEvents.distinct().flatten().size) + } finally { + subscription.unsubscribe() + } + } + private fun advanceTime() { scheduler.advanceTimeBy(1, TimeUnit.MINUTES) }