Rupert Smith wrote:
I'm particuarly interested in getting some constructive feedback on
this. If you disagree with something, please also suggest an
alternative way of doing it, that you feel will be better, more
reliable, easier to implement, or whatever. Thanks.

I think the approach is great. One thought that occurred is that by offloading more work to the controller/master we minimise the amount of framework code we need to write for each test in each language. The controller would only need to be written in one language.

I like the idea of having a single client executable for each language also, that can run a named test under a particular role. That makes it easy to start up a given number of instances of different client implementations without having to remember too many script options etc. The controller can handle the test to run and the role each client should take on.

I'd suggest we use an unspecified virtual host. Assuming we will be using a dedicated broker instance for the tests we won't need the isolation virtual hosts provide and just using the default make setup easier in my view.

Attached are some notes that offer an alternative system. I find it simpler and yet quite flexible, but as is often the case that might just be because it fits more with my preconceptions. Its not as tightly specified as your document but if you like the direction we can work on the details a bit more. If you don't like the direction I won't be offended, so please feel free to ignore it!



==Actors==

There are two types of actor in the test:

1. controller 

A single controller will operate every test. The controller framework
only needs to be written in one language. The steps a controller
follows for each test are:

    creates and binds an exclusive queue to the nameless exchange with
    key 'control'. consumes from this queue.
        
    sends out a 'invite' for a named test to amq.topic with routing
    key 'control'. any listening clients that are able to be part of
    that test respond with an 'enlist' message.

    checks a queue exists for each enlisted client and binds them to
    one of two new fanout exchanges created for the senders and
    receivers on this test

    sends a 'role-assignment' message to each exchange

    wait for 'ready' messages from all enlisted receivers

    sends a 'start' message to the senders exchange

    waits for 'sent-report's from each sender(*)

    send an 'end-test' to all receivers

    waits for 'received-report's from each receiver(*)

    compares actual and expected reports and prints results

    deletes senders and receivers exchanges

    (*)if not all reports are received in a given time, the controller
    will send an 'end-test' message to all outstanding participants

2. participant

Each client is capable of participating in a set of named tests in a
particular role. Each client has a unique id. The roles are for now
'sender' and 'receiver'.

In general the clients follow the following steps:

    create a queue named after clients id, bind it to amq.topic
    with routing key 'control' and consume from it

    listen for 'invite's to tests they are able to participate in

    when such an 'invite' is received, send an 'enlist' message to the
    control queue

    wait for a 'role assignment' then carry out the relevant role

    when a 'terminate' message is received, shutdown
    
The steps for the different roles are:

    2(a) sender 

    waits for 'start' message

    sends messages to a defined 'route'
    
    sends a 'sent-report' to the master

    2(b) receiver

    prepares to consume messages from a defined 'route'

    sends a 'ready' message to control queue

    records all received messages

    detects completion by receiving an 'end-test' marker

    on completion sends a 'received-report' to the master and carries
    out any cleanup required

==Control Messages==

All control messages have the 'control-type' property set to the name
of the message type. E.g. a sent-report contains 'sent-report' in the
control-type property. Unless otherwise specified all control messages
are empty messages.

A sent-report is:

    A text message with a line for each sent message using the tests
    stringified format.

    It also contains a string header indicating the senders id.

A received-report is:

    A text message with a line for each received message using the
    tests stringified format.

    It also contains a string header indicating the receivers id.
    
A role-assignment message is:

    A text message containing the test name and a string header 'role'
    containing one of the valid roles for the test (i.e. sender or
    receiver to begin with). It may also contain other properties for
    paramterised tests.

An invite is:

    A text message containing the name of the test that the master
    wants to run. The 'control-type' property is set to 'invite'. The
    parameters of the test may also be specified in the invite
    allowing participants that don't support them to opt out.

An enlist message is:

    A text message containing the name of the test.

    It also contains string properties indicating the client identity
    and a description of the client (language, platform or whatever
    seems relevant).

==Tests==

A named test defines:

    The details of the route through which messages will be sent, in
    particular the exchange, routing key and headers to be used by
    senders and the details receivers need to subscribe (e.g. queue to
    consume from, whether to create the queue, whether to bind the
    queue etc).

    The details of the message content and properties that will be
    sent.

    A stringified format for those messages.

    Aspects of a test may be parameterised, details are defined on a
    case-by-case basis. Parameters are sent in the test invite and
    also in the role-assignment. Both tests below take a message-count
    parameter.

===Simple Pub/Sub===

A simple pub-sub test where messages are sent to amq.topic with a
controller specified routing key. Receivers create their own exclusive
queues and bind them to the amq.topic with the supplied topic name,
they consume from them in no_ack mode. On cleanup, receivers delete
their queues.

Messages are text messages containing the string 'Message %d' where %d
is replaced by a monotonically increasing number. They also have a
string property containing the senders id. The format in which they
are reported is a line with the client id followed by a '#' followed
by the message text.

The controller can decide to have a single publisher or multiple
publishers. At the end of the test it checks each sender sent the
correct number of messages and each receiver received the correct
number. It also checks the values of messages sent against those
received by a comparison of the lines in the sent- and received-
reports as well as their relative order.

The topic name is passed as part of the role-assignment to allow tests
operating with different topics e.g. to test wildcard matching or to
ensure two topics are kept distinct. It is passed as a string property
called 'topic-name'.

===Simple P2P===

A simple point-to-point test where messages are sent to the nameless
exchange with a routing key equal to the supplied queue name (passed
in on role-assignment). The controller creates the queue to use and
binds it to this routing key (it is also responsible for deleting it
when the test is over). Receivers create a consumer on that queue. On
completion receivers cancel their consumers.

Messages are sent and reported in the same format as for Simple
Pub/Sub.

The controller can start the senders before or after the receivers. It
can create varying numbers of each role. At the end it ensures that
every message that was sent was received once and checks for relative
ordering. It also checks that no messages remain in the queue. (It
could also report on more statistical checks such as reasonably fair
distribution). 

This test has an ack-frequency parameter, passed as an int property on
the role-assignment. If 0 it implies that no_ack should be used by
receivers. Else it implies that an ack should be sent every x
messages, acking all messages to that point. An ack should be sent on
completion for any outstanding messages.

It also has a txn-frequency parameter, again passed as an int
property. If 0, no transactions are used. If non-zero a transaction
should be used by both senders and receivers and they should commit
after sending/receiving that number of messages. All transactions
should be commited on completion.

===Future work===

Extra tests can be defined that do more complicated things, perhaps
involving different properties, new roles, bi-directional
communication rollback etc etc. The two simple tests above should be
relatively easy to code in each language and should still allow a fair
bit of flexibility in how they are put together. The code for each
scenario only needs to be defined in the controller framework which we
only need to write once in one language.

Reply via email to