Run function/behaviour after all behaviours ended in Pony

72 Views Asked by At

I have a simple Publish-Subscriber that I want to write tests for. The methods called here are all behaviours, except get_number_consumed_messages that would be a function.

class iso _SinglePubSub is UnitTest
    fun name(): String => "single publish/consume"

    fun apply(h: TestHelper) =>
        let p = Publisher("publisher message", h.env.out)
        let queue = Queue(1, h.env.out)
        let c = Consumer(h.env.out)

        p.publish_message(queue)
        p.publish_message(queue)
        c.consume_message(queue)
        c.consume_message(queue)

        //Run after all behaviours are done
        let n = c.get_number_consumed_messages()
        h.assert_eq[USize](2, n)

How would someone implement the get_number_consumed_messages function/behaviour or how would you have to modify the test function?

1

There are 1 best solutions below

0
Epic Eric On

First of all, c.get_number_consumed_messages() must be a behaviour as well. It is the only way to let one actor communicate with another. This has the added benefit of behaviours being run in the same order as they are called, which means c.get_number_consumed_messages() would run after both calls to c.consume_message(queue).

Given that, since Consumer is also an actor, calling it with behaviours -- and not methods -- means that we cannot return data from it directly. To actually receive data from another actor, you should use the Promise pattern, for example:

use "promises"

actor Consumer
  var message_count: USize = 0

  be consume_message(queue: OutStream) =>
    ... // Do some things
    message_count = message_count + 1
    ... // Do other things

  be get_number_consumed_messages(p: Promise[USize]) =>
    p(message_count)

To actually test it, you would need to follow an adapted version of the Testing Notifier Interactions pattern for long tests, for example:

use "ponytest"
use "promises"

class iso _SinglePubSub is UnitTest
  fun apply(h: TestHelper) =>
    h.long_test(2_000_000_000)

    ... // Produce and consume messages

    let p = Promise[USize]
    p.next[None]({(n: USize): None =>
      h.assert_eq[USize](2, n)
      h.complete(true) })
    c.get_number_consumed_messages(p)

(Notice the extra calls to h.long_test and h.complete, as well as the promise wrapping a lambda with the end of our test.)

For more information on these concepts, I would recommend familiarizing yourself with the stdlib documentation on Promises and the "Long tests" section of Ponytest.