Tutorial: Mocking and simulating JMS IBM® WebSphere MQ

For a basic introduction with examples have a look at Mocking and simulating JMS IBM® WebSphere MQ Tutorial.

IBM MQ JMS tutorial

JMS vs. Native IBM® MQ

Traffic Parrot supports IBM® MQ brokers via JMS and native IBM® MQ APIs. If you are connecting to the IBM® MQ broker via JMS, please use JMS in Traffic Parrot as well and follow the instructions below. If you are using native IBM® MQ APIs (no JMS), please follow the instructions from the native IBM® MQ page.

JMS virtual service architecture

A tester uses a web browser to access the console. The console manages the virtual service. The system under test (application under test) connects directly to the virtual service on different ports.

Here is an example of how that could look like for a scenario where the virtual service is replaying messages to an external queue.

screenshot Virtual service replaying JMS messages to and from a queue

JMS Configuration

Supported JMS brokers
  • ActiveMQ TCP (internal broker or external broker)
  • ActiveMQ AMQP 1.0 (internal broker or external broker)
  • Azure AMQP 1.0 (external broker)
  • RabbitMQ AMQP 0.9.1 (external broker)
  • IBM® WebSphere MQ 7.5+ (external broker)
Define JMS connections

To record from or replay to JMS brokers you will need to tell Traffic Parrot how to connect to them.

Those connections are displayed in the dropdown menus on the record and replay panels, for example: screenshot

The "Internal broker" connection is available in the dropdown by default when you choose to use an internal broker in the Broker panel.

To define a new connection that will be available in the dropdown in the record and replay panels:
  1. Open jms-connections.json file located in the main Traffic Parrot directory, using your favourite text editor
  2. Add the new connections (make sure the connectionId field has a unique value!). An example content of the file, with 6 connections defined (two IBM MQ, one Active MQ TCP, one Azure AMQP 1.0, one RabbitMQ AMQP 0.9.1, one Active MQ AMQP 1.0):
    [
      {
        "connectionId": "1",
        "connectionName": "Test Payments Broker",
        "connectionData": {
          "jmsProvider": "IBM_MQ_7_5",
          "hostname": "mqserver.example.com",
          "port": 1415,
          "queueManager": "PAYMENT.QM",
          "channel": "PAYMENT.SVRCONN",
          "username": "payuser",
          "password": "paypassword222"
        }
      },
      {
        "connectionId": "2",
        "connectionName": "TrafficParrot External Payment Broker",
        "connectionData": {
          "jmsProvider": "IBM_MQ_7_5",
          "hostname": "mqserver.example.com",
          "port": 1414,
          "queueManager": "TRAFFICPARROT.DEV.AWS.QM",
          "channel": "TP.PUBLIC.JUNIT",
          "username": "tpuser",
          "password": "tppass333"
        }
      },
      {
        "connectionId": "3",
        "connectionName": "Test Order System Broker",
        "connectionData": {
          "jmsProvider": "ACTIVE_MQ",
          "hostname": "localhost",
          "port": 61616
        }
      },
      {
        "connectionId": "4",
        "connectionName": "Azure AMQP",
        "connectionData": {
          "jmsProvider": "AZURE_AMQP_1_0",
          "hostname": "namespace.servicebus.windows.net",
          "sharedAccessKeyName": "SendListen",
          "sharedAccessKey": "password"
        }
      },
      {
        "connectionId": "5",
        "connectionName": "Local RabbitMQ",
        "connectionData": {
          "jmsProvider": "RABBIT_MQ_3",
          "hostname": "localhost",
          "username": "guest",
          "password": "guest",
          "port": 5672,
          "amqpCompatibilityMode": true
        }
      },
      {
        "connectionId": "6",
        "connectionName": "Local ActiveMQ AMQP",
        "connectionData": {
          "jmsProvider": "ACTIVE_MQ",
          "hostname": "localhost",
          "port": 61617,
          "protocol": "amqp"
        }
      }
    ]
  3. Save the file
  4. Refresh the page in Traffic Parrot to reload the dropdown list.

In the current Traffic Parrot version you edit JMS connections directly in the jms-connections.json file. In near future you will be able to do it via the Web UI as well.

Change the location of jms-connections.json
If you would like to change the location of the jms-connections.json file, change the value of property
trafficparrot.virtualservice.jmsConnectionsUrl=classpath:jms-connections.json
to for example
trafficparrot.virtualservice.jmsConnectionsUrl=file:/home/john/git/project/trafficparrot-jms-connections.json
This can be useful if you would like to version control it with your application source code.
Required JARs for IBM® MQ

To connect to IBM® MQ you need jar files provided by IBM that will allow Traffic Parrot to establish connections with MQ.

Before you proceed please read these instructions to double check your actions are inline with the supported way to install WebSphere MQ Java jar files.

If you are running IBM® MQ version 8 and 9 you will need:
  • com.ibm.mq.allclient.jar
If you are running IBM® MQ version 7.5.x you will need:
  • com.ibm.mq.headers.jar
  • com.ibm.mq.jar
  • com.ibm.mq.jmqi.jar
  • com.ibm.mqjms.jar
  • dhbcore.jar
  • jms.jar
If you do not have the required JAR files yet, follow these instructions to get a copy:

If you have any issues with obtaining the jar files please contact us.

Copy those files to trafficparrot-x.y.z/lib/external and restart Traffic Parrot.

Recording and replaying JMS

Introduction

As with HTTP recording Traffic Parrot, during recording incoming and outgoing messages are matched up to provide mappings. Then upon playback receipt of a matching incoming message will trigger generation of an outgoing message.

Message matching

Traffic Parrot can form mappings in a number of ways.

  • Time: pair messages in the order they happened in time
  • Correlation ID: pair messages with matching correlation id

The default is to use time based matching. This can be changed in the advanced parameter section of the record page.

Recording and replaying JMS Queues using an internal broker

The method which requires least configuration is to use Traffic Parrot's internal broker. Via this method you can record traffic to and from your application by just modifying the broker URL to which your application connects.

This diagram shows how two production systems connect:

Systems communicating via queues

One system generates messages onto a queue; another system consumes these messages and puts responses onto a second queue, which the first system consumes. If our goal is to test the system-under-test in isolation, we must record these interactions in order to replay them.

Recording JMS Queues using an internal broker

As you can see in the diagram, the recording simply introduces two extra queues, to which the system under test connects, as shown in the diagram below:

Recording queue messages using an internal broker
Steps to perform a queue recording using an internal broker
  1. Define JMS connections that will be used for recording
  2. Start Traffic Parrot
  3. Go to the JMS record page
  4. Select "Internal" in the "Broker" panel
  5. Select "Queue"
  6. Choose the jms connections to brokers, and specify the queue name where messages will be received and responses sent. Follow the diagram Configuring recording queue messages using an internal broker which will guide you how to populate those fields.
  7. Click "Turn on"
  8. Reconfigure System A to connect to the virtual service broker
  9. Execute a test case via System A to allow Traffic Parrot to record requests and responses. They will appear on the Messages and Mappings lists on the web page as shown on Mappings and messages lists during recording image.
  10. Click "Turn off"
Configuring recording queue messages using an internal broker

As the system-under-test generates messages they are listed in the bottom table 'Current recording session'. As the second system generates responses to these messages, they are also listed at the bottom, but in addition mappings are generated in the 'Mappings' table showing incoming and outgoing messages that Traffic Parrot has paired up.

Mappings and messages lists during a recording

Replaying JMS Queue messages using an internal broker

To replay the recorded mappings we will use the internal broker and connect the system under test to it.
Replaying queue messages using an internal broker
Steps to perform a queue replay using an internal broker
  1. Start Traffic Parrot
  2. Go to the JMS replay page
  3. Select "Internal" in the "Broker" panel
  4. Select "Queue"
  5. Choose the jms connections to broker "Internal broker" as shown on the Configuring recording queue messages using an internal broker diagram.
  6. Click "Turn on"
  7. Reconfigure System A to connect to the virtual service broker
  8. Execute a test case via System A to allow Traffic Parrot to consume a request message and send a response message.
  9. Click "Turn off"
Configuring replaying queue messages using an internal broker

Recording and replaying JMS Queues using an external broker

In this scenario we don't want to use Traffic Parrot's internal broker - we want Traffic Parrot to work with an existing external broker. This scenario is useful mainly when you would like to work with brokers that are unsupported internally by Traffic Parrot, for example IBM® MQ.

Recording JMS Queues using an external broker

Instead of pointing the system under test at a different broker, we will create extra queues on our existing broker that will be used by the virtual service. Then we will reconfigure the system-under-test to connect to these queues instead of the original ones. Traffic Parrot will move messages between these queues and the original queues, recording and creating mappings as it does so.

screenshot
Steps to perform a queue recording using an external broker
  1. Add the queues that will be used by the virtual service to the broker. In the example above you would add to the existing broker queues "Virtual Service Request Queue" and "Virtual Service Response Queue" (Note - depending on your broker and it's configuration these queues may be auto-created for you when the software first attempts to connect.)
  2. Define JMS connections that will be used for recording
  3. Start Traffic Parrot
  4. Go to the JMS record page
  5. Select "External" in the "Broker" panel
  6. Select "Queue"
  7. Choose the jms connections to brokers, and specify the queue name where messages will be received and responses sent. Follow the diagram Configuring recording queue messages using an external broker which will guide you how to populate those fields.
  8. Click "Turn on"
  9. Reconfigure System A to connect to the virtual service queues
  10. Execute a test case via System A to allow Traffic Parrot to record requests and responses. They will appear on the Messages and Mappings lists on the web page as shown on Mappings and messages lists during recording image.
  11. Click "Turn off"
screenshot

Replaying JMS Queues using an external broker

To replay the recorded mappings we will need the same virtual service queues in place as shown on the image below.

Replaying queue messages using an external broker
Steps to perform a queue replay using an external broker
  1. Add the queues that will be used by the virtual service to the broker. In the example above you would add to the existing broker queues "Virtual Service Request Queue" and "Virtual Service Response Queue" (Note - depending on your broker and it's configuration these queues may be auto-created for you when the software first attempts to connect.)
  2. Start Traffic Parrot
  3. Go to the JMS replay page
  4. Select "External" in the "Broker" panel
  5. Select "Queue"
  6. Choose the jms connections as shown on the Configuring recording queue messages using an external broker diagram.
  7. Click "Turn on"
  8. Reconfigure System A to connect to the virtual service broker
  9. Execute a test case via System A to allow Traffic Parrot to consume a request message and send a response message.
  10. Click "Turn off"
Configuring replaying queue messages using an external broker

Recording and replaying JMS Topics using an internal broker

You can use Traffic Parrot's internal broker to record and replay topic messages. For the purpose fo the examples below, we will use a configuration where the production systems connect in a way described on the diagram below:

Systems communication with topics

The system-under-test generates messages onto a topic which are received by a number of other systems. One of these systems generates responses onto a different topic (which are received by a number of systems, one of which is the system-under-test).

Recoding JMS topics using an internal broker

We will configure Traffic Parrot to connect to the request and response topics and record the messages appearing on both, generating mappings as it goes, as shown on diagram Recording topics using an internal broker

Recording topics using an internal broker
Steps to perform a topic recording using an internal broker
  1. Define JMS connections that will be used for recording
  2. Start Traffic Parrot
  3. Go to the JMS record page
  4. Select "Internal" in the "Broker" panel
  5. Select "Topic"
  6. Choose the jms connection to the "Internal broker", and specify the topic names where messages will be received and responses sent. Follow the diagram Configuring recording topics using an internal broker which will guide you how to populate those fields.
  7. Click "Turn on"
  8. Reconfigure System A to connect to the virtual service queues
  9. Execute a test case via System A to allow Traffic Parrot to record requests and responses. They will appear on the Messages and Mappings lists on the web page as shown on Mappings and messages lists during topic recording image.
  10. Click "Turn off"
Configuring recording topics using an internal broker

Replaying JMS Topics using an internal broker

When replaying to an internal broker Traffic Parrot will subscribe to the request topic and publish to the response topic as shown in the diagram Replaying topic messages using an internal broker.
Replaying topic messages using an internal broker
Steps to perform a topic replay using an internal broker
  1. Start Traffic Parrot
  2. Go to the JMS replay page
  3. Select "Internal" in the "Broker" panel
  4. Select "Topic"
  5. Choose the jms connection as shown on the Configuring replaying topics messages using an internal broker diagram.
  6. Click "Turn on"
  7. Disconnect System B from the broker so it does not produce response messages to the response topic
  8. Execute a test case via System A to allow Traffic Parrot to consume a request message and send a response message.
  9. Click "Turn off"
Configuring replaying topics messages using an internal broker

Recording and replaying JMS Topics using an external broker

Recording and playback of topics using an external broker is less intrusive than queues or internal broker topics, because Traffic Parrot can subscribe to a topic just like any other application and receive messages, without affecting the delivery of those messages to other applications.

This diagram shows how the production systems connect:

Systems communication with topics

The system-under-test generates messages onto a topic which are received by a number of other systems. One of these systems generates responses onto a different topic (which are received by a number of systems, one of which is the system-under-test).

Recoding JMS topics using an external broker

We will configure Traffic Parrot to connect to the request and response topics and record the messages appearing on both, generating mappings as it goes, as shown on diagram Recording topics using an external broker

Recording topics using an external broker
Steps to perform a topic recording using an external broker
  1. Define JMS connections that will be used for recording
  2. Start Traffic Parrot
  3. Go to the JMS record page
  4. Select "External" in the "Broker" panel
  5. Select "Topic"
  6. Choose the jms connections to brokers, and specify the topic names where messages will be received and responses sent. Follow the diagram Configuring recording topics using an external broker which will guide you how to populate those fields.
  7. Click "Turn on"
  8. Reconfigure System A to connect to the virtual service queues
  9. Execute a test case via System A to allow Traffic Parrot to record requests and responses. They will appear on the Messages and Mappings lists on the web page as shown on Mappings and messages lists during recording image.
  10. Click "Turn off"
Configuring recording topics using an external broker
As the system-under-test generates messages they are listed in the bottom table 'Current recording session'. As the second system generates responses to these messages, they are also listed at the bottom, but in addition mappings are generated in the 'Mappings' table showing incoming and outgoing messages that Traffic Parrot has paired up.
Mappings and messages lists during topic recording

Replaying JMS Topics using an external broker

When replaying to an external broker Traffic Parrot will subscribe to the request topic and publish to the response topic as shown in the diagram Replaying topic messages using an external broker.
Replaying topic messages using an external broker
Steps to perform a topic replay using an external broker
  1. Start Traffic Parrot
  2. Go to the JMS replay page
  3. Select "External" in the "Broker" panel
  4. Select "Topic"
  5. Choose the jms connection as shown on the Configuring replaying topics messages using an external broker diagram.
  6. Click "Turn on"
  7. Disconnect System B from the broker so it does not produce response messages to the response topic
  8. Execute a test case via System A to allow Traffic Parrot to consume a request message and send a response message.
  9. Click "Turn off"
Configuring replaying topics messages using an external broker

Edit JMS mappings

Introduction

On the following JMS pages, the edit button will allow you to edit an existing mapping:
  • Add/Edit
  • Record
  • Replay
Traffic Parrot supports the following JMS message types:
  • javax.jms.TextMessage
  • javax.jms.BytesMessage (any bytes message, with special support for java.io.Serializable objects)

Response delay

Traffic Parrot supports postponing the delivery of a JMS message. This can be useful to better simulate a more realistic scenario where the responding system does not send a response message immediately after receiving the request message.

Use the Edit JMS delay screenshot field on the edit mapping panel to specify the delay in milliseconds.

Supported brokers

Priority

The request priority can be set in order to set up a preference order for matching mappings.

The highest priority value is 1. If two or more mappings both match a request, the mapping with the higher priority will be used to provide the response. The default priority is 5.

This can be useful, if you want a "catch-all" mapping that returns a general response for most requests and specific mappings on top that return more specific responses.

Text messages

Traffic Parrot is able to record and replay a javax.jms.TextMessage which could contain text in a variety of formats e.g. JSON, XML or plain text.

Edit JMS text mapping screenshot
Supported features
  • Edit the response body
  • Use parts of the request body in the response body by extracting from the request
  • Use helpers in the response body
  • Programmatically transform the response using JMS response transformers
  • Match requests using the request body matchers (e.g. JsonPath, contains, regexp)
  • Use priority to set up a preference order for matching mappings

Bytes messages

Traffic Parrot is able to record and replay a javax.jms.BytesMessage that could contain bytes in any format.

Edit JMS bytes mapping screenshot
Supported features
  • Edit Base64 representation of the response body
  • Edit Base64 representation of the request body to match
  • Match requests using byte equality only
  • Use priority to set up a preference order for matching mappings

Printable character messages

If the bytes of a javax.jms.BytesMessage are found to contain at least 95% printable characters (e.g. letters, digits, special characters), it will be displayed in plain text in the user interface.

This is configurable using the trafficparrot.mostly.printable.characters.threshold=0.95 property.

Non printable bytes will typically be displayed by the browser as a small box, as you can see in the screenshot below.

Edit JMS printable characters mapping screenshot
Supported features
  • Edit plain text representation of the response body
  • Edit plain text representation of the request body to match
  • Use parts of the request body in the response body by extracting from the request
  • Use helpers in the response body
  • Match requests using any of the request body matchers (e.g. contains, regexp)
  • Use priority to set up a preference order for matching mappings

Java object messages

If the bytes of a javax.jms.BytesMessage are found to contain a single java.io.Serializable object that Traffic Parrot is able to deserialize, it will be displayed as a JSON object in the user interface.

The request and response body can be edited as if they were a JSON body. You are free to change the JSON as you wish, so long as the edits are compatible with the underlying Java class that the JSON represents.

Edit JMS object mapping screenshot
Supported features
  • Edit objects without requiring additional JAR files or agents
  • Edit response object values
  • Edit response object structure (e.g. delete fields, add items to list, add nested fields)
  • Use helpers in the response body
  • Use parts of the request object in the response object by extracting with JsonPath
  • Match request objects using the request body matchers (e.g. JsonPath, contains, regexp) on the JSON representation of the object
  • Use priority to set up a preference order for matching mappings
Dynamic object serialization

By default, Traffic Parrot will use dynamic object serialization to support objects of any class that it is able to understand, including objects that are not on the classpath.

Unlike other tools, we do not require additional JAR files or agents to be installed in order to record, edit and replay object messages.

Standard object serialization

To improve compatibility (and support special handling during the serialization), you can choose to use standard Java object serialization by adding your classes to the Traffic Parrot classpath.

See the notes for developers for instructions on how to do this.

Notes for testers

If you are having trouble with this functionality, please ask the developers on your team to review the notes for developers below.

Please contact us if you require any additional help for your particular configuration.

Notes for developers

In order to deserialize a serialized Java object using standard Java object serialization, the Java class of that object and the classes of all of its fields must be on the Traffic Parrot classpath. Copy the JAR files containing those classes to trafficparrot-x.y.z/lib/external and restart Traffic Parrot.

In order to represent the object as JSON and allow editing, the class must have a public zero argument constructor.

Please contact us if you require any additional help for your particular configuration.

JMS mapping JSON

JMS mapping configuration is stored in the jms-mappings directory as text files in JSON format. You may directly edit these files on the filesystem and store them in a VCS such as Git or SVN.

Some JMS mapping features are not currently supported in the UI and can only be edited directly in the mapping JSON:
  • declareArguments (used e.g. for RabbitMQ queue declaration arguments)
  • skipDeclare (used e.g. to skip RabbitMQ queue declaration and assume a queue already exists)
Example JMS mapping JSON:
{
  "mappingId" : "1bf95fd0-5647-4db0-bae6-729a8b29fd1f",
  "request" : {
    "destination" : {
      "name" : "request-queue",
      "type" : "QUEUE",
      "declareArguments" : {
        "x-queue-mode" : "lazy",
        "x-dead-letter-exchange" : "dead-letter-exchange",
        "x-dead-letter-routing-key" : "dead-letter-routing-key",
        "x-max-length" : 100,
        "x-message-ttl" : 60000
      },
      "skipDeclare" : false
    },
    "bodyMatcher" : {
      "equalTo" : "any"
    },
    "bodyType" : "TEXT",
    "jmsMessageType" : "javax.jms.TextMessage"
  },
  "response" : {
    "destination" : {
      "name" : "response-queue",
      "type" : "QUEUE",
      "declareArguments" : {
        "x-dead-letter-exchange" : "dead-letter-exchange",
        "x-dead-letter-routing-key" : "dead-letter-routing-key",
        "x-max-length" : 100,
        "x-message-ttl" : 60000
      },
      "skipDeclare" : false
    },
    "jmsResponseTransformerClassName" : "NO_TRANSFORMER",
    "text" : "anything",
    "bodyType" : "TEXT",
    "jmsMessageType" : "javax.jms.TextMessage",
    "properties" : [ ],
    "fixedDelayMilliseconds" : 0
  },
  "mappingName" : "saved-mapping-1bf95fd0-5647-4db0-bae6-729a8b29fd1f.json"
}

JMS request message matchers

When Traffic Parrot receives a request message, it will try to simulate the system it is replacing by sending back a response message on the response queue or topic. To decide which response message to send, it will go through all the request to response mappings it has available to find the response to be sent. For more details how request matching works, see Request matching.

There are several matchers available to match JMS request messages, depending on the attribute.

Request type matcher
  • javax.jms.TextMessage - matches only text messages
  • javax.jms.BytesMessage - matches only bytes messages
Request body matchers
Matcher name Matcher Id Description
any any Any request body will match.
equal to equalTo Check that the received request message body is equal to the request body specified in the mapping
contains contains Check that the received request message body contains the sequence of characters specified in the mapping
matches regex matches Check that the received request message body matches the regexp specified in the mapping
does not match regexp doesNotMatch Check that the received request message body does not match the regexp specified in the mapping
equal to JSON equalToJson Check that the received request message body is JSON and that it is equal to the request body JSON specified in the mapping
matches JSON matchesJson

Check that the received request message body matches (allowing for special wildcard tokens) JSON specified in the mapping.

Tokens allowed:
  • {{ anyValue }} - matches any value
  • {{ anyNumber }} - matches any whole or decimal number
  • {{ anyElements }} - matches any number of sub-elements (child-nodes)
For example a "matches JSON" request body matcher:
{
  "name": "{{ anyValue }}",
  "lastName": "{{ anyValue }}",
  "age": "{{ anyNumber }}",
  "children": "{{ anyElements }}"
}
will match a request body:
{
  "name": "Bob",
  "lastName": "Smith",
  "age": 37,
  "children": [{"name": "sam"}, {"name": "mary"}]
}
matches JSONPath matchesJsonPath Check that the received request message body is JSON and that it matches JSONPath specified in the mapping. For example, if we use the following expression as the request body matcher
$[?(@.xyz.size() == 2)]
it will match this request body:
{"xyz":[{"a":true}, {"b":false}]}
but will NOT match this one:
{"xyz":["a":true, "b":false, "c":true]}
equal to XML equalToXml Check that the received request message body is XML and that it is equal to the request body XML specified in the mapping
matches XML matchesXml

Check that the received request message body matches (allowing for special wildcard tokens) XML specified in the mapping.

Tokens allowed:
  • {{ anyValue }} - matches any value
  • {{ anyNumber }} - matches any whole or decimal number
  • <tp:AnyElements/> - matches any number of sub-elements (child-nodes)
For example a matches XML request body matcher:
<example>
  <name>{{ anyValue }}</name>
  <age>{{ anyNumber }}</age>
  <children><tp:AnyElements/></children>
</example>
will match a request body:
<example>
  <name>Sam</name>
  <age>29</age>
  <children><child name="bob"/></children>
</example>
matches XPath matchesXPath Check that the received request message body is XML and that it matches XPath specified in the mapping. For example, if we use the following expression as the request body matcher
/xyz[count(abc) = 2]
it will match this request body:
<xyz><abc/><abc/></xyz>
but will NOT match this one:
<xyz><abc/></xyz>

Configuration

See configuration in the user guide.

Typical environments

See typical environments in the user guide.

Proof of concept with on-premises installation at a large enterprise

See proof of concept in the user guide.

Dynamic responses and custom extensions

Old version warning!

This documentation is for an old version of Traffic Parrot. There is a more recent Traffic Parrot version available for download at trafficparrot.com

Browse documentation for recent version