Karate Clients - JMS

Java Client (JMS Send and JMS Consume) to interact with JMS queues from karate.

It provides features to send and consume JMS Messages (TextMessage or ObjectMessage) for a Queue:

jms

The Supported JMS Providers are:

POM Configuration

POM Karate Tools

If the project has been generated using the Karate Tools Archetype the pom will already contain the corresponding configuration.
Add the karatetools dependency in the karate pom:
<properties>
  ...
  <!-- Karate Tools -->
  <karatetools.version>X.X.X</karatetools.version>
</properties>

<dependencies>
  ...
  <!-- Karate Tools -->
  <dependency>
    <groupId>dev.inditex.karate</groupId>
    <artifactId>karatetools-starter</artifactId>
    <version>${karatetools.version}</version>
    <scope>test</scope>
  </dependency>
</dependencies>

POM Client Factory

Apache Active MQ POM

karatetools-starter already includes the Active MQ JMS dependencies.

If you need to change the dependency version, you can include it in the pom as follows:
  <properties>
    ...
    <!-- Karate Clients -->
    <!-- Karate Clients - JMS -->
    <!-- Karate Clients - JMS - ActiveMQ -->
    <artemis-jms-client.version>X.X.X</artemis-jms-client.version>
  </properties>

  <dependencies>
    ...
    <!-- Karate Clients - JMS -->
    <!-- Karate Clients - JMS - ActiveMQ -->
    <dependency>
      <groupId>org.apache.activemq</groupId>
      <artifactId>artemis-jms-client</artifactId>
      <version>${artemis-jms-client.version}</version>
    </dependency>
  </dependencies>

POM JMS Object

The JMS Client is cappable of processing JMS TextMessage or ObjectMessage.

In order to process JSM ObjectMessages you might need to add in the pom.xml the dependency to the module with the JMS Object classes.

  • POM Properties

      <properties>
        ...
        <!-- Karate Clients - JMS - JMS Objects -->
        <xxxxxx-jms-module.version>X.X.X</xxxxxx-jms-module.version>
        ...
      </properties>
  • POM Dependencies

      <dependencies>
        ...
        <!-- Karate Clients - JMS - JMS Objects -->
        <dependency>
          <groupId>com.mycompany.api</groupId>
          <artifactId>xxxxxx-jms-module</artifactId>
          <version>${xxxxxx-jms-module.version}</version>
        </dependency>
        ...
      </dependencies>

Client Configuration

Configuration parameters for the JMS Clients. These values can be overwritten by the corresponding system properties. System properties can be injected by CI/CD.

If the project has been generated using the Karate Tools Archetype the archetype would have prompted for the creation of the configuration files.

This client can be configured for multi-environment execution with a config file per environment:

\---src
    \---test
        \---resources
            \---config
                \---jms
                    <provider>-config-local.yml
                    ...
                    <provider>-config-pre.yml

For example:

\---src
    \---test
        \---resources
            \---config
                \---jms
                    activemq-config-local.yml
                    ...
                    activemq-config-pre.yml

JMS Client Configuration Properties - Apache Active MQ

⚙️ jmsFactory - JMS Factory to use: ActiveMQ

⚙️ brokerURL - URL of the Active MQ broker

⚙️ username - User name that application uses to connect to ActiveMQ

⚙️ password - Password that the application uses to connect to ActiveMQ

⚙️ sendTimeout - Timeout in milliseconds for sending messages (default 5000)

Example
# docker-compose environment variables:  <AMQ_USER> <AMQ_PASSWORD>
# docker-compose folder structure:       NA
jmsFactory: ActiveMQ
brokerURL: tcp://localhost:61616
username: karate
password: karate-pwd

Client Features and Usage

Instantiate JMSClient

New instance of the JMSClient providing the configuration as a map loaded from a yaml file.

Java Signature
public JMSClient(final Map<Object, Object> configMap)
Gherkin Usage
# public JMSClient(final Map<Object, Object> configMap)
# Instantiate JMSClient
Given def config = read('classpath:config/jms/jms-config-' + karate.env + '.yml')
Given def JMSClient = Java.type('dev.inditex.karate.jms.JMSClient')
Given def jmsClient = new JMSClient(config)

Check if JMS is available

Checks if the JMS connection can be established

Returns true is connection is available, false otherwise

Java Signature
public Boolean available()
Gherkin Usage
# public Boolean available()
When def available = jmsClient.available()
Then if (!available) karate.fail('JMS Client not available')

Send a message to a queue

Send a message to a queue

For example:

JMS Text Message - JSON
Given def jmsMessageJSON = {'id': '1', 'name': 'karate-01', 'value': 1}
JMS Text Message - Plain Text
Given def jmsMessagePlainText = 'Plain Text Message'
JMS Text Message - XML
Given text jmsMessageXML =
"""
<?xml version="1.0"?>
<karate id="1">
  <name>karate-01</name>
  <value>1</value>
</karate>
"""
In order for an XML to be sent as JMS Text Message you need to use text (with enclosed content """) instead of def (def converts to Map anything that looks like JSON/XML).
JMS Object Message
Given def JMSKarateObject = Java.type('dev.inditex.karate.jms.JMSKarateObject')
Given def jmsMessageObject = new JMSKarateObject("2", "karate-02", 2)
Java Signature
public void send(final String queue, final Object value)
Gherkin Usage - JMS Text Message - JSON
# Define Queue
Given def queue = 'global.core.karate.public.queue'

# public void send(final String queue, final Object value)
# Send Message without properties
Given def jmsMessageJSON = {'id': '1', 'name': 'karate-01', 'value': 1}
When jmsClient.send(queue, jmsMessageJSON)
Gherkin Usage - JMS Text Message - Plain Text
# Define Queue
Given def queue = 'global.core.karate.public.queue'

# public void send(final String queue, final Object value)
# Send Message without properties
Given def jmsMessagePlainText = 'Plain Text Message'
When jmsClient.send(queue, jmsMessagePlainText)
Gherkin Usage - JMS Text Message - XML
# Define Queue
Given def queue = 'global.core.karate.public.queue'

# public void send(final String queue, final Object value)
# Send Message without properties
Given text jmsMessageXML =
"""
<?xml version="1.0"?>
<karate id="1">
  <name>karate-01</name>
  <value>1</value>
</karate>
"""
When jmsClient.send(queue, jmsMessageXML)
Gherkin Usage - JMS Object Message
# Define Queue
Given def queue = 'global.core.karate.public.queue'

# public void send(final String queue, final Object value)
Given def JMSKarateObject = Java.type('dev.inditex.karate.jms.JMSKarateObject')
Given def jmsMessageObject = new JMSKarateObject("2", "karate-02", 2)
When jmsClient.send(queue, jmsMessageObject)

Send a message to a queue with optional properties

Send a message to a queue with defined properties (optional)

For example:

JMS Text Message - JSON
Given def jmsMessageJSON = {'id': '1', 'name': 'karate-01', 'value': 1}
JMS Text Message - Plain Text
Given def jmsMessagePlainText = 'Plain Text Message'
JMS Text Message - XML
Given text jmsMessageXML =
"""
<?xml version="1.0"?>
<karate id="1">
  <name>karate-01</name>
  <value>1</value>
</karate>
"""
In order for an XML to be sent as JMS Text Message you need to use text (with enclosed content """) instead of def (def converts to Map anything that looks like JSON/XML).
JMS Object Message
Given def JMSKarateObject = Java.type('dev.inditex.karate.jms.JMSKarateObject')
Given def jmsMessageObject = new JMSKarateObject("2", "karate-02", 2)
JMS Properties
{ 'PRINT_STATUS': 'PRINTING' }
Java Signature
public void send(final String queue, final Object value, final Map<String, Object> properties)
Gherkin Usage - JMS Text Message - JSON
# Define Queue
Given def queue = 'global.core.karate.public.queue'

# public void send(final String queue, final Object value, final Map<String, Object> properties)
# Send Message with properties
Given def jmsMessageJSON = {'id': '1', 'name': 'karate-01', 'value': 1}
Given def jmsProperties = {'PRINT_STATUS':'PRINTING'}
When jmsClient.send(queue, jmsMessageJSON, jmsProperties)

# Send Message without properties
When jmsClient.send(queue, jmsMessageJSON, null)
Gherkin Usage - JMS Text Message - Plain Text
# Define Queue
Given def queue = 'global.core.karate.public.queue'

# public void send(final String queue, final Object value, final Map<String, Object> properties)
# Send Message with properties
Given def jmsMessagePlainText = 'Plain Text Message'
Given def jmsProperties = {'PRINT_STATUS':'PRINTING'}
When jmsClient.send(queue, jmsMessagePlainText, jmsProperties)

# Send Message without properties
When jmsClient.send(queue, jmsMessagePlainText, null)
Gherkin Usage - JMS Text Message - XML
# Define Queue
Given def queue = 'global.core.karate.public.queue'

# public void send(final String queue, final Object value, final Map<String, Object> properties)
# Send Message with properties
Given text jmsMessageXML =
"""
<?xml version="1.0"?>
<karate id="1">
  <name>karate-01</name>
  <value>1</value>
</karate>
"""
Given def jmsProperties = {'PRINT_STATUS':'PRINTING'}
When jmsClient.send(queue, jmsProperties, null)

# Send Message without properties
When jmsClient.send(queue, jmsMessageXML, null)
Gherkin Usage - JMS Object Message
# Define Queue
Given def queue = 'global.core.karate.public.queue'

# public void send(final String queue, final Object value, final Map<String, Object> properties)
# Send Message with properties
Given def JMSKarateObject = Java.type('dev.inditex.karate.jms.JMSKarateObject')
Given def jmsMessageObject = new JMSKarateObject("2", "karate-02", 2)
Given def jmsProperties = {'PRINT_STATUS':'PRINTING'}
When jmsClient.send(queue, jmsMessageObject, jmsProperties)

# Send Message without properties
When jmsClient.send(queue, jmsMessageObject, null)

Consume Messages from a queue

Receive the next messages in the queue within the default timeout interval (5000ms) or custom timeout interval.

Returns a JSON Array representing the obtained messages, where each row is a map << field name, message value >>

For example:

JSON or Object Messages
[
  { "id": 1, "name": "karate-01", "value": 1 },
  { "id": 2, "name": "karate-02", "value": 2 }
]
Plain Text or XML Messages
[
  { "textMessage": "Plain Text Message" },
  { "textMessage": "<?xml version=\"1.0\"?>\n<karate id=\"1\">\n  <name>karate-01</name>\n  <value>1</value>\n</karate>" }
]
Java Signature
public List<Map<String, Object>> consume(final String queue)
Gherkin Usage - JSON or Object Messages
# Define Queue
Given def queue = 'global.core.karate.public.queue'

# public List<Map<String, Object>> consume(final String queue)
When def messages = jmsClient.consume(queue)
Then karate.log('messages=', messages)
Then assert messages.length == 2
Then def result = karate.sort(messages, x => x.id)
Then match result[0].id == '1'
Then match result[0].name == 'karate-01'
Then match result[0].value == 1
Then match result[1].id == '2'
Then match result[1].name == 'karate-02'
Then match result[1].value == 2
Gherkin Usage - JMS Text Message - Plain Text
# Define Queue
Given def queue = 'global.core.karate.public.queue'

# public List<Map<String, Object>> consume(final String queue)
When def messages = jmsClient.consume(queue)
Then assert messages.length == 1
Then match messages[0].textMessage == jmsMessagePlainText
Gherkin Usage - JMS Text Message - XML
# Define Queue
Given def queue = 'global.core.karate.public.queue'

# public List<Map<String, Object>> consume(final String queue)
When def messages = jmsClient.consume(queue)
Then assert messages.length == 1
Then match messages[0].textMessage == jmsMessageXML

Receive the next messages in the queue with custom timeout interval.

Java Signature
public List<Map<String, Object>> consume(final String queue, final long timeout)
Gherkin Usage
# Define Queue
Given def queue = 'global.core.karate.public.queue'

# public List<Map<String, Object>> consume(final String queue, final long timeout)
When def messages = jmsClient.consume(queue, 10000)
Then assert messages.length == 1
Then match messages[0].textMessage == jmsMessagePlainText