jsonapache-kafkagroovysoapuiready-api

How to check if a message with a certain 'key' arrives exactly once while simulating a consumer for Kafka (JSON via AVRO) in ReadyAPI


I need to subscirbe to a topic in Kafka and check, that a specific message, with specific 'key' arives exactly once to the topic.

A JSONPath Match Assertion with JSONPath expression $['key'] and with appropiate Expected Result 'myKeyValue' ist true for the expected message and false for the other messages.

However, I don't see any possibility to count how often a message with $['key'] equals 'myKeyValue' arives and more over, to check, that this happens exactly once.

May be this is possible using script assertion only. However, I do not see how. If you have an script assertion example for counting arrived messages with $['key'] value equals 'myKeyValue' this would be great.

Any suggestions?

What is the final aimt?

I run end 2 end tests from TestComplete. At some step, the actions on the client must trigger a Kafka message. Via TestComplete ReadyAPI_step, I want to check, that the expected message is send, and this one is send only once. That's the aim.

What I did so far - Part I - no code:

I am using an AND-group of JSONPath Match assertions inside an OR-group.

One JSONPath Match Assertion in the AND-group 'selects' the message of interest by checking the value of $['key'] element of the JSON message.

The other JSONPath Match assertions in the AND-group checks the other members of the JSON Message for correctness.

In the OR-group is at the same level of the AND-group a sigle Smart Assertion.

The Smart Assertion is true for all messages but the one I am looking for. (I.e.: $['key'] is not 'myKeyValue')

This seems to be close to what we need. However:

I have the problem, that all of this is also true if the one message we are looking for does not arrives and even if no message arrives at all.

What I did so far - Part II - trying to code:

I try to write a Script assertion to count how often we get the expected Message.

One problem here: The code runs each time a message arrives.

To solve this, the counter should be saved in a text file in the file system.

The file contains one line; the line contains one single integer; the line is overwritten (i++) each time the assertion runs.

The idea should work.

Now, the shamefull points and questions about this. - The code does not work as expected:

  1. No file is created
  2. I am not able to write code that prints some simple info message to ReadyAPI log, either to the ReadyAPI GUI, nor to one of the famous logfiles present in %userprofile%.soapui or %userprofile%.readyapi\logs
  3. How can I access to ReadyAPI project properties in the groovy script? I need this, for example, to set the file name from TestComplete as ReadyAPI project variable. Hint: this is NOT the answer: com.eviware.soapui.model.testsuite.TestRunContext.hasProperty("myProjectPropertyName")
  4. How can I access to the Kafka message contents, in particular the value of $['key']?

About Question 4: The ReadyAPI documentation for script assertion refers to messageExchange interface. However, I have the feeling, that this class is suited for XML content only instead of JSON. Using messageExanche.getRawRequestData() may be an alternative. However - general speaking: It is not clear, which classes are available in ReadyAPI scripting assertion at all or which classes are available to convert a JSON string to an object or to parse the JSON directly. (Package jackson, for example, is not available, no matter import jackson.*).

An example for solving questions 1 to 4 or some of them would be great!

Thank you very much for your precious time!


Solution

  • With the valuable help of the SmartBear support team, I can write a Script Assertion (belonging to the subscriber step) to count messages that are received as subscriber and meet a certain criteria. Here is the example:

    def messages = context.getCurrentStep().data
    //
    // Sample messages subscriber receive:
    // {    "favorite_city" : "Berlin", "favorite_number" : 2, "favorite_color" : "white" }
    // {    "favorite_city" : "Hamburg", "favorite_number" : 8, "favorite_color" : "purple" }
    // {    "favorite_city" : "Cologne", "favorite_number" : 2, "favorite_color" : "black" }
    //
    // We are looking for messages containing favorite_number == 8, the 'valid' messages. 
    def validMessage = "\"favorite_number\" : 8"; 
    //
    def validCounter = 0; // for counting valid messages.
    //
    // The project variable named global.numberof.expectedmessages contains the number of valid messages we expect.
    // Of course, you may write here the number of valid messages you expect directly.
    // However, this give you an answer for question 3 in the original post: access to project variables, which is the natural way to access them in ReadyAPI.
    def globalNrOfExpectedMsgs = Integer.valueOf (context.expand( '${#Project#global.numberof.expectedmessages}' ) );
    //
    log.info "Validate count for following message:" + validMessage;
    log.info "Expected Number of valid messages: " + globalNrOfExpectedMsgs;
    //
    // Check the messages 
    for(message in messages){
        // variable message is the message data itself as string. 
        // This is the answer to question 4 in original post
        if (message.replace("\\n","").replace("\\","").contains(validMessage)){
            // A valid message found! Count it!
            validCounter++;
        }
    }
    //
    log.info "Number of received valid messages: " +  validCounter
    //
    assert (validCounter == globalNrOfExpectedMsgs);
    

    To check further attributes in the received messages, the script assertion can certainly be extended.

    Because I would like to avoid coding for this, the final solution in our case will be a combination of the assertion contained here to ensure that the expected message arrives as often as expected and my first attempt called ā€œno codeā€, as explained in the original post.

    By the way: This post does not contain answers to questions 1 and 2 of the original posting. We can live without them for the moment.

    I hope this helps you any way.