2018-10-29 17:19:37 +08:00
|
|
|
/*
|
2021-01-08 17:55:38 +01:00
|
|
|
* Copyright (C) 2009-2021 Lightbend Inc. <https://www.lightbend.com>
|
2013-01-30 18:10:45 +01:00
|
|
|
*/
|
2018-03-13 23:45:55 +09:00
|
|
|
|
2013-01-30 18:10:45 +01:00
|
|
|
package akka.io
|
|
|
|
|
|
2020-04-27 20:32:18 +08:00
|
|
|
import java.net.DatagramSocket
|
2013-06-14 14:45:43 +02:00
|
|
|
import java.net.InetSocketAddress
|
2017-02-17 16:41:25 +01:00
|
|
|
|
2013-01-30 18:10:45 +01:00
|
|
|
import akka.actor.ActorRef
|
2013-09-08 09:29:45 -05:00
|
|
|
import akka.io.Inet._
|
2020-04-27 20:32:18 +08:00
|
|
|
import akka.io.Udp._
|
|
|
|
|
import akka.testkit.{ AkkaSpec, ImplicitSender, TestProbe }
|
2018-11-22 16:18:10 +01:00
|
|
|
import akka.testkit.SocketUtil.temporaryServerAddresses
|
2020-04-27 20:32:18 +08:00
|
|
|
import akka.util.ByteString
|
2013-01-30 18:10:45 +01:00
|
|
|
|
2013-05-29 16:13:10 +02:00
|
|
|
class UdpIntegrationSpec extends AkkaSpec("""
|
|
|
|
|
akka.loglevel = INFO
|
2017-02-17 16:41:25 +01:00
|
|
|
# tests expect to be able to mutate messages
|
2019-09-26 22:51:12 +02:00
|
|
|
""") with ImplicitSender {
|
2013-01-30 18:10:45 +01:00
|
|
|
|
2017-05-08 11:08:28 +02:00
|
|
|
def bindUdp(handler: ActorRef): InetSocketAddress = {
|
|
|
|
|
val commander = TestProbe()
|
|
|
|
|
commander.send(IO(Udp), Bind(handler, new InetSocketAddress("127.0.0.1", 0)))
|
|
|
|
|
commander.expectMsgType[Bound].localAddress
|
|
|
|
|
}
|
2013-02-22 14:14:13 +01:00
|
|
|
|
|
|
|
|
def bindUdp(address: InetSocketAddress, handler: ActorRef): ActorRef = {
|
2013-01-30 18:10:45 +01:00
|
|
|
val commander = TestProbe()
|
2013-03-25 10:02:50 +01:00
|
|
|
commander.send(IO(Udp), Bind(handler, address))
|
2013-04-13 20:53:52 +02:00
|
|
|
commander.expectMsg(Bound(address))
|
2014-01-16 15:16:35 +01:00
|
|
|
commander.sender()
|
2013-01-30 18:10:45 +01:00
|
|
|
}
|
|
|
|
|
|
2017-02-11 21:20:41 +03:00
|
|
|
def createSimpleSender(): ActorRef = {
|
2013-01-30 18:10:45 +01:00
|
|
|
val commander = TestProbe()
|
2013-03-25 10:02:50 +01:00
|
|
|
commander.send(IO(Udp), SimpleSender)
|
2013-05-26 18:29:23 +02:00
|
|
|
commander.expectMsg(SimpleSenderReady)
|
2014-01-16 15:16:35 +01:00
|
|
|
commander.sender()
|
2013-01-30 18:10:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"The UDP Fire-and-Forget implementation" must {
|
|
|
|
|
|
|
|
|
|
"be able to send without binding" in {
|
2017-05-08 11:08:28 +02:00
|
|
|
val serverAddress = bindUdp(testActor)
|
2013-01-30 18:10:45 +01:00
|
|
|
val data = ByteString("To infinity and beyond!")
|
2017-02-11 21:20:41 +03:00
|
|
|
val simpleSender = createSimpleSender()
|
2013-01-30 18:10:45 +01:00
|
|
|
simpleSender ! Send(data, serverAddress)
|
|
|
|
|
|
2015-01-16 11:09:59 +01:00
|
|
|
expectMsgType[Received].data should ===(data)
|
2013-01-30 18:10:45 +01:00
|
|
|
}
|
|
|
|
|
|
2017-02-11 21:20:41 +03:00
|
|
|
"be able to deliver subsequent messages after address resolution failure" in {
|
|
|
|
|
val unresolvableServerAddress = new InetSocketAddress("some-unresolvable-host", 10000)
|
|
|
|
|
val cmd = Send(ByteString("Can't be delivered"), unresolvableServerAddress)
|
|
|
|
|
val simpleSender = createSimpleSender()
|
|
|
|
|
simpleSender ! cmd
|
|
|
|
|
expectMsgType[CommandFailed].cmd should ===(cmd)
|
|
|
|
|
|
2017-05-08 11:08:28 +02:00
|
|
|
val serverAddress = bindUdp(testActor)
|
2017-02-11 21:20:41 +03:00
|
|
|
val data = ByteString("To infinity and beyond!")
|
|
|
|
|
simpleSender ! Send(data, serverAddress)
|
|
|
|
|
expectMsgType[Received].data should ===(data)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"be able to send several packet back and forth with binding" in {
|
2017-05-08 11:08:28 +02:00
|
|
|
val Seq(serverAddress, clientAddress) = temporaryServerAddresses(2, udp = true)
|
2013-02-22 14:14:13 +01:00
|
|
|
val server = bindUdp(serverAddress, testActor)
|
|
|
|
|
val client = bindUdp(clientAddress, testActor)
|
2013-01-30 18:10:45 +01:00
|
|
|
val data = ByteString("Fly little packet!")
|
|
|
|
|
|
2013-02-27 09:20:00 +01:00
|
|
|
def checkSendingToClient(): Unit = {
|
|
|
|
|
server ! Send(data, clientAddress)
|
|
|
|
|
expectMsgPF() {
|
2019-02-09 15:25:39 +01:00
|
|
|
case Received(d, a) =>
|
2015-01-16 11:09:59 +01:00
|
|
|
d should ===(data)
|
|
|
|
|
a should ===(serverAddress)
|
2013-02-27 09:20:00 +01:00
|
|
|
}
|
2013-01-30 18:10:45 +01:00
|
|
|
}
|
2013-02-27 09:20:00 +01:00
|
|
|
def checkSendingToServer(): Unit = {
|
|
|
|
|
client ! Send(data, serverAddress)
|
|
|
|
|
expectMsgPF() {
|
2019-02-09 15:25:39 +01:00
|
|
|
case Received(d, a) =>
|
2015-01-16 11:09:59 +01:00
|
|
|
d should ===(data)
|
|
|
|
|
a should ===(clientAddress)
|
2013-02-27 09:20:00 +01:00
|
|
|
}
|
2013-02-07 17:54:42 +01:00
|
|
|
}
|
2013-01-30 18:10:45 +01:00
|
|
|
|
2019-02-09 15:25:39 +01:00
|
|
|
(0 until 20).foreach(_ => checkSendingToServer())
|
|
|
|
|
(0 until 20).foreach(_ => checkSendingToClient())
|
|
|
|
|
(0 until 20).foreach { i =>
|
2013-02-27 09:20:00 +01:00
|
|
|
if (i % 2 == 0) checkSendingToServer()
|
|
|
|
|
else checkSendingToClient()
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-09-08 09:29:45 -05:00
|
|
|
|
|
|
|
|
"call SocketOption.beforeBind method before bind." in {
|
|
|
|
|
val commander = TestProbe()
|
|
|
|
|
val assertOption = AssertBeforeBind()
|
2017-05-08 11:08:28 +02:00
|
|
|
commander.send(IO(Udp), Bind(testActor, new InetSocketAddress("127.0.0.1", 0), options = List(assertOption)))
|
|
|
|
|
commander.expectMsgType[Bound]
|
2013-09-08 09:29:45 -05:00
|
|
|
assert(assertOption.beforeCalled === 1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"call SocketOption.afterConnect method after binding." in {
|
|
|
|
|
val commander = TestProbe()
|
2015-04-30 09:23:18 +02:00
|
|
|
val assertOption = AssertAfterChannelBind()
|
2017-05-08 11:08:28 +02:00
|
|
|
commander.send(IO(Udp), Bind(testActor, new InetSocketAddress("127.0.0.1", 0), options = List(assertOption)))
|
|
|
|
|
commander.expectMsgType[Bound]
|
2013-09-08 09:29:45 -05:00
|
|
|
assert(assertOption.afterCalled === 1)
|
|
|
|
|
}
|
2014-08-19 14:02:23 +03:00
|
|
|
|
|
|
|
|
"call DatagramChannelCreator.create method when opening channel" in {
|
|
|
|
|
val commander = TestProbe()
|
|
|
|
|
val assertOption = AssertOpenDatagramChannel()
|
2017-05-08 11:08:28 +02:00
|
|
|
commander.send(IO(Udp), Bind(testActor, new InetSocketAddress("127.0.0.1", 0), options = List(assertOption)))
|
|
|
|
|
commander.expectMsgType[Bound]
|
2014-08-19 14:02:23 +03:00
|
|
|
assert(assertOption.openCalled === 1)
|
|
|
|
|
}
|
2013-09-08 09:29:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private case class AssertBeforeBind() extends SocketOption {
|
2017-02-17 16:41:25 +01:00
|
|
|
@volatile
|
2013-09-08 09:29:45 -05:00
|
|
|
var beforeCalled = 0
|
|
|
|
|
|
2015-04-30 09:23:18 +02:00
|
|
|
override def beforeDatagramBind(ds: DatagramSocket): Unit = {
|
|
|
|
|
assert(!ds.isBound)
|
2013-09-08 09:29:45 -05:00
|
|
|
beforeCalled += 1
|
2013-01-30 18:10:45 +01:00
|
|
|
}
|
2013-09-08 09:29:45 -05:00
|
|
|
}
|
|
|
|
|
|
2015-04-30 09:23:18 +02:00
|
|
|
private case class AssertAfterChannelBind() extends SocketOptionV2 {
|
2017-02-17 16:41:25 +01:00
|
|
|
@volatile
|
2013-09-08 09:29:45 -05:00
|
|
|
var afterCalled = 0
|
2013-01-30 18:10:45 +01:00
|
|
|
|
2015-04-30 09:23:18 +02:00
|
|
|
override def afterBind(s: DatagramSocket) = {
|
|
|
|
|
assert(s.isBound)
|
2013-09-08 09:29:45 -05:00
|
|
|
afterCalled += 1
|
|
|
|
|
}
|
2013-01-30 18:10:45 +01:00
|
|
|
}
|
2014-08-19 14:02:23 +03:00
|
|
|
|
|
|
|
|
private case class AssertOpenDatagramChannel() extends DatagramChannelCreator {
|
2017-02-17 16:41:25 +01:00
|
|
|
@volatile
|
2014-08-19 14:02:23 +03:00
|
|
|
var openCalled = 0
|
|
|
|
|
|
|
|
|
|
override def create() = {
|
|
|
|
|
openCalled += 1
|
|
|
|
|
super.create()
|
|
|
|
|
}
|
|
|
|
|
}
|