Harden NettyTransportSpec (#25500)

* Harden NettyTransportSpec

Keep the temporary port open while the ActorSystem is created so it
can't select the same port to bind on.

Fixes #25479
This commit is contained in:
Christopher Batey 2018-12-04 15:59:54 +00:00 committed by GitHub
parent b38b407c73
commit af38a1eefd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 39 additions and 15 deletions

View file

@ -5,6 +5,7 @@
package akka.remote.transport.netty
import java.net.{ InetAddress, InetSocketAddress }
import java.nio.channels.ServerSocketChannel
import akka.testkit.SocketUtil
import akka.actor.{ ActorSystem, Address, ExtendedActorSystem }
@ -16,7 +17,8 @@ import scala.concurrent.Await
import scala.concurrent.duration.Duration
object NettyTransportSpec {
val commonConfig = ConfigFactory.parseString("""
val commonConfig = ConfigFactory.parseString(
"""
akka.actor.provider = remote
""")
@ -38,6 +40,7 @@ object NettyTransportSpec {
}
class NettyTransportSpec extends WordSpec with Matchers with BindBehavior {
import akka.remote.transport.netty.NettyTransportSpec._
"NettyTransport" should {
@ -45,7 +48,8 @@ class NettyTransportSpec extends WordSpec with Matchers with BindBehavior {
behave like theOneWhoKnowsTheDifferenceBetweenBoundAndRemotingAddress("udp")
"bind to a random port" in {
val bindConfig = ConfigFactory.parseString(s"""
val bindConfig = ConfigFactory.parseString(
s"""
akka.remote.netty.tcp {
port = 0
}
@ -58,26 +62,40 @@ class NettyTransportSpec extends WordSpec with Matchers with BindBehavior {
}
"bind to a random port but remoting accepts from a specified port" in {
val address = SocketUtil.temporaryServerAddress(InetAddress.getLocalHost.getHostAddress, udp = false)
//keep open to ensure it isn't used for the bind-port
val (openSS, address) = randomOpenServerSocket()
val bindConfig = ConfigFactory.parseString(s"""
try {
val bindConfig = ConfigFactory.parseString(
s"""
akka.remote.netty.tcp {
port = ${address.getPort}
bind-port = 0
}
""")
implicit val sys = ActorSystem("sys", bindConfig.withFallback(commonConfig))
implicit val sys = ActorSystem("sys", bindConfig.withFallback(commonConfig))
getExternal should ===(address.toAkkaAddress("akka.tcp"))
getInternal should not contain (address.toAkkaAddress("tcp"))
getExternal should ===(address.toAkkaAddress("akka.tcp"))
getInternal should not contain address.toAkkaAddress("tcp")
Await.result(sys.terminate(), Duration.Inf)
Await.result(sys.terminate(), Duration.Inf)
} finally {
openSS.close()
}
}
def randomOpenServerSocket(address: String = InetAddress.getLocalHost.getHostAddress) = {
val ss = ServerSocketChannel.open().socket()
ss.bind(new InetSocketAddress(address, 0))
(ss, new InetSocketAddress(address, ss.getLocalPort))
}
"bind to a specified port and remoting accepts from a bound port" in {
val address = SocketUtil.temporaryServerAddress(InetAddress.getLocalHost.getHostAddress, udp = false)
val bindConfig = ConfigFactory.parseString(s"""
val bindConfig = ConfigFactory.parseString(
s"""
akka.remote.netty.tcp {
port = 0
bind-port = ${address.getPort}
@ -92,7 +110,8 @@ class NettyTransportSpec extends WordSpec with Matchers with BindBehavior {
}
"bind to multiple transports" in {
val bindConfig = ConfigFactory.parseString(s"""
val bindConfig = ConfigFactory.parseString(
s"""
akka.remote {
netty.tcp.port = 0
netty.udp.port = 0
@ -108,7 +127,8 @@ class NettyTransportSpec extends WordSpec with Matchers with BindBehavior {
}
"bind to all interfaces" in {
val bindConfig = ConfigFactory.parseString(s"""
val bindConfig = ConfigFactory.parseString(
s"""
akka.remote {
netty.tcp.bind-hostname = "0.0.0.0"
}
@ -123,14 +143,17 @@ class NettyTransportSpec extends WordSpec with Matchers with BindBehavior {
}
}
trait BindBehavior { this: WordSpec with Matchers
trait BindBehavior {
this: WordSpec with Matchers
import akka.remote.transport.netty.NettyTransportSpec._
def theOneWhoKnowsTheDifferenceBetweenBoundAndRemotingAddress(proto: String) = {
s"bind to default $proto address" in {
val address = SocketUtil.temporaryServerAddress(udp = proto == "udp")
val bindConfig = ConfigFactory.parseString(s"""
val bindConfig = ConfigFactory.parseString(
s"""
akka.remote {
netty.$proto {
hostname = ${address.getAddress.getHostAddress}
@ -158,7 +181,8 @@ trait BindBehavior { this: WordSpec with Matchers ⇒
null
}
val bindConfig = ConfigFactory.parseString(s"""
val bindConfig = ConfigFactory.parseString(
s"""
akka.remote {
netty.$proto {
hostname = ${address.getAddress.getHostAddress}

View file

@ -24,7 +24,7 @@ object SocketUtil {
SocketUtil.temporaryServerAddress(address = "127.20.0.0")
true
} catch {
case e: java.net.BindException
case _: java.net.BindException
false
}
}