Chris Stewart
Chris Stewart

Reputation: 1689

Testing akka tells without using Thread.sleep

i'm trying to develop a simple unit test to bind a port on my machine, test that the port is bound, then release the port and test that it is release. Currently I'm using this naive approach

class ServerTest extends FlatSpec with MustMatchers {
  "Server" must "bind a tcp server to an address on our machine" in {
    //if this fails this means that the port is in use before our test case is run
    val port = 18333
    isBound(port) must be (false)
    val actor = Server()
    actor ! Tcp.Bind(actor, new InetSocketAddress(port))
    Thread.sleep(1000)
    isBound(port) must be (true)
    Thread.sleep(1000)
    actor ! Tcp.Unbind
    Thread.sleep(1000)
    isBound(port) must be (false)
  }


  /**
    * Tests if a specific port number is bound on our machine
    * @param port
    * @return
    */
  def isBound(port : Int) : Boolean = {
    val tryBinding : Try[Unit] = Try {
      val socket = new java.net.Socket()
      socket.connect(new java.net.InetSocketAddress(port),1000)
      socket.close()
    }

    tryBinding.isSuccess
  }
}

I would like to test this without using the calls to Thread.sleep since this is a blocking call. Can anyone provide me with a more idiomatic solution?

Upvotes: 1

Views: 408

Answers (2)

mattinbits
mattinbits

Reputation: 10428

When sending TCP.Bind , you should expect a reply stating either success or failure: http://doc.akka.io/japi/akka/2.3.2/akka/io/Tcp.Bind.html

The Bind message is send to the TCP manager actor, which is obtained via TcpExt.manager() in order to bind to a listening socket. The manager replies either with a Tcp.CommandFailed or the actor handling the listen socket replies with a Tcp.Bound message. If the local port is set to 0 in the Bind message, then the Tcp.Bound message should be inspected to find the actual port which was bound to.

You should use AkkaTestKit (http://doc.akka.io/docs/akka/snapshot/scala/testing.html) and use either ImplicitSender or a TestProbe to send the TCP.Bind, and then wait for the answer.

For example:

val probe = TestProbe()
probe.send(actor, Tcp.Bind(actor, new InetSocketAddress(port)))
probe.expectMsg(Tcp.Bound)

Your test code will either continue when the reply is received, or fail if not received within the timeout (which is configurable in the expectMsg call).

Upvotes: 2

Max Markov
Max Markov

Reputation: 936

You can use

within (1000 millisends) {
...
}

see https://github.com/RayRoestenburg/AkkaExamples/blob/master/src/test/scala/unit/akka/TestKitUsageSpec.scala for more examples

Upvotes: 1

Related Questions