http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/83b89fe4/src/python/qpid-interop-test/amqp_types_test.py
----------------------------------------------------------------------
diff --git a/src/python/qpid-interop-test/amqp_types_test.py 
b/src/python/qpid-interop-test/amqp_types_test.py
new file mode 100755
index 0000000..30d0577
--- /dev/null
+++ b/src/python/qpid-interop-test/amqp_types_test.py
@@ -0,0 +1,435 @@
+#!/usr/bin/env python
+
+"""
+Module to test AMQP primitive types across different APIs
+"""
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import argparse
+import sys
+import unittest
+
+from itertools import product
+from json import dumps
+from os import getenv, path
+from sys import stdout
+from time import mktime, time
+from uuid import UUID, uuid4
+
+import broker_properties
+import shims
+from proton import symbol
+from test_type_map import TestTypeMap
+
+# TODO: propose a sensible default when installation details are worked out
+QPID_INTEROP_TEST_HOME = getenv('QPID_INTEROP_TEST_HOME')
+if QPID_INTEROP_TEST_HOME is None:
+    print 'ERROR: Environment variable QPID_INTEROP_TEST_HOME is not set'
+    sys.exit(1)
+
+
+class AmqpPrimitiveTypes(TestTypeMap):
+    """
+    Class which contains all the described AMQP primitive types and the test 
values to be used in testing.
+    """
+
+    TYPE_MAP = {
+        'null': ['None'],
+        'boolean': ['True',
+                    'False'],
+        'ubyte': ['0x0',
+                  '0x7f',
+                  '0x80',
+                  '0xff'],
+        'ushort': ['0x0',
+                   '0x7fff',
+                   '0x8000',
+                   '0xffff'],
+        'uint': ['0x0',
+                 '0x7fffffff',
+                 '0x80000000',
+                 '0xffffffff'],
+        'ulong': ['0x0',
+                  '0x1',
+                  '0xff',
+                  '0x100',
+                  '0x7fffffffffffffff',
+                  '0x8000000000000000',
+                  '0xffffffffffffffff'],
+        'byte': ['-0x80',
+                 '-0x1',
+                 '0x0',
+                 '0x7f'],
+        'short': ['-0x8000',
+                  '-0x1',
+                  '0x0',
+                  '0x7fff'],
+        'int': ['-0x80000000',
+                '-0x1',
+                '0x0',
+                '0x7fffffff'],
+        'long': ['-0x8000000000000000',
+                 '-0x81',
+                 '-0x80',
+                 '-0x1',
+                 '0x0',
+                 '0x7f',
+                 '0x80',
+                 '0x7fffffffffffffff'],
+        # float and double: Because of difficulty with rounding of floating 
point numbers, we use the binary
+        # representation instead which should be exact when comparing sent and 
received values.
+        'float': ['0x00000000', # 0.0
+                  '0x80000000', # -0.0
+                  '0x40490fdb', # pi (3.14159265359) positive decimal
+                  '0xc02df854', # -e (-2.71828182846) negative decimal
+                  '0x00000001', # Smallest positive denormalized number
+                  '0x80000001', # Smallest negative denormalized number
+                  '0x007fffff', # Largest positive denormalized number
+                  '0x807fffff', # Largest negative denormalized number
+                  '0x00800000', # Smallest positive normalized number
+                  '0x80800000', # Smallest negative normalized number
+                  '0x7f7fffff', # Largest positive normalized number
+                  '0xff7fffff', # Largest negative normalized number
+                  #'0x7f800000', # +Infinity # PROTON-1149 - fails on RHEL7
+                  #'0xff800000', # -Infinity # PROTON-1149 - fails on RHEL7
+                  '0x7fc00000', # +NaN
+                  '0xffc00000'], # -NaN
+        'double': ['0x0000000000000000', # 0.0
+                   '0x8000000000000000', # -0.0
+                   '0x400921fb54442eea', # pi (3.14159265359) positive decimal
+                   '0xc005bf0a8b145fcf', # -e (-2.71828182846) negative decimal
+                   '0x0000000000000001', # Smallest positive denormalized 
number
+                   '0x8000000000000001', # Smallest negative denormalized 
number
+                   '0x000fffffffffffff', # Largest positive denormalized number
+                   '0x800fffffffffffff', # Largest negative denormalized number
+                   '0x0010000000000000', # Smallest positive normalized number
+                   '0x8010000000000000', # Smallest negative normalized number
+                   '0x7fefffffffffffff', # Largest positive normalized number
+                   '0xffefffffffffffff', # Largest negative normalized number
+                   '0x7ff0000000000000', # +Infinity
+                   '0xfff0000000000000', # -Infinity
+                   '0x7ff8000000000000', # +NaN
+                   '0xfff8000000000000'], # -NaN
+        # decimal32, decimal64, decimal128:
+        # Until more formal support for decimal32, decimal64 and decimal128 
are included in Python, we use
+        # a hex format for basic tests, and treat the data as a binary blob.
+        'decimal32': ['0x00000000',
+                      '0x40490fdb',
+                      '0xc02df854',
+                      '0xff7fffff'],
+        'decimal64': ['0x0000000000000000',
+                      '0x400921fb54442eea',
+                      '0xc005bf0a8b145fcf',
+                      '0xffefffffffffffff'],
+        'decimal128': ['0x00000000000000000000000000000000',
+                       '0xff0102030405060708090a0b0c0d0e0f'],
+        'char': [u'a',
+                 u'Z',
+                 u'0x1',
+                 u'0x7f',
+                 u'0x16b5', # Rune 'G'
+                 u'0x10ffff'],
+        # timestamp: Must be in milliseconds since the Unix epoch
+        'timestamp': ['0x0',
+                      '0x%x' % int(mktime((2000, 1, 1, 0, 0, 0, 5, 1, 
0))*1000),
+                      '0x%x' % int(time()*1000)
+                     ],
+        'uuid': [str(UUID(int=0x0)),
+                 str(UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')),
+                 str(uuid4())],
+        'binary': [bytes(),
+                   bytes(12345),
+                   b'Hello, world!',
+                   b'\\x01\\x02\\x03\\x04\\x05abcde\\x80\\x81\\xfe\\xff',
+                   b'The quick brown fox jumped over the lazy dog 0123456789.' 
* 100
+                  ],
+        # strings must be unicode to comply with AMQP spec
+        'string': [u'',
+                   u'Hello, world!',
+                   u'"Hello, world!"',
+                   u"Charlie's peach",
+                   u'The quick brown fox jumped over the lazy dog 0123456789.' 
* 100
+                  ],
+        'symbol': ['',
+                   'myDomain.123',
+                   'domain.0123456789.' * 100],
+        'list': [[],
+                 ['ubyte:1', 'int:-2', 'float:3.14'],
+                 ['string:a', 'string:b', 'string:c'],
+                 ['ulong:12345',
+                  'timestamp:%d' % (time()*1000),
+                  'short:-2500',
+                  'uuid:%s' % uuid4(),
+                  'symbol:a.b.c',
+                  'none:',
+                  'decimal64:0x400921fb54442eea'
+                 ],
+                 [[],
+                  'none',
+                  ['ubyte:1', 'ubyte:2', 'ubyte:3'],
+                  'boolean:True',
+                  'boolean:False',
+                  {'string:hello': 'long:1234', 'string:goodbye': 
'boolean:True'}
+                 ],
+                 [[], [[], [[], [], []], []], []],
+                 ['short:0',
+                  'short:1',
+                  'short:2',
+                  'short:3',
+                  'short:4',
+                  'short:5',
+                  'short:6',
+                  'short:7',
+                  'short:8',
+                  'short:9'] * 10
+                ],
+        'map': [
+            # Enpty map
+            {},
+            # Map with string keys
+            {'string:one': 'ubyte:1',
+             'string:two': 'ushort:2'},
+            # Map with other AMQP simple types as keys
+            {'none:': 'string:None',
+             'string:None': 'none:',
+             'string:One': 'long:-1234567890',
+             'short:2': 'int:2',
+             'boolean:True': 'string:True',
+             'string:False': 'boolean:False',
+             #['string:AAA', 'ushort:5951']: 'string:list value',
+             #{'byte:-55': 'ubyte:200',
+             # 'boolean:True': 'string:Hello, world!'}: 'symbol:map.value',
+             #'string:list': [],
+             'string:map': {'char:A': 'int:1',
+                            'char:B': 'int:2'}},
+            ],
+        # TODO: Support all AMQP types in array (including keys)
+        #'array': [[],
+        #          [1, 2, 3],
+        #          ['Hello', 'world'],
+        #          [[1, 2, 3],
+        #           ['a', 'b', 'c'],
+        #           [2.3, 3.4, 4,5],
+        #           [True, False, True, True]]
+        #          ]
+        }
+
+    # This section contains tests that should be skipped because of know 
issues that would cause the test to fail.
+    # As the issues are resolved, these should be removed.
+    BROKER_SKIP = {'null': {'ActiveMQ': 'Null type not sent in Proton Python 
binding: PROTON-1091',
+                            'qpid-cpp': 'Null type not sent in Proton Python 
binding: PROTON-1091',},
+                   'decimal32': {'ActiveMQ': 'decimal32 and decimal64 are sent 
byte reversed: PROTON-1160',
+                                 'qpid-cpp': 'decimal32 not supported on 
qpid-cpp broker: QPIDIT-5, QPID-6328',
+                                 'apache-activemq-artemis': 'decimal32 and 
decimal64 are sent byte reversed: PROTON-1160',
+                                 'qpid-dispatch-router': 'decimal32 and 
decimal64 are sent byte reversed: PROTON-1160'},
+                   'decimal64': {'ActiveMQ': 'decimal32 and decimal64 are sent 
byte reversed: PROTON-1160',
+                                 'qpid-cpp': 'decimal64 not supported on 
qpid-cpp broker: QPIDIT-6, QPID-6328',
+                                 'apache-activemq-artemis': 'decimal32 and 
decimal64 are sent byte reversed: PROTON-1160',
+                                 'qpid-dispatch-router': 'decimal32 and 
decimal64 are sent byte reversed: PROTON-1160'},
+                   'decimal128': {'qpid-cpp': 'decimal128 not supported on 
qpid-cpp broker: QPIDIT-3, QPID-6328',},
+                   'char': {'qpid-cpp': 'char not supported on qpid-cpp 
broker: QPIDIT-4, QPID-6328',
+                            'apache-activemq-artemis': 'char types > 16 bits 
truncated on Artemis: ENTMQ-1685'},
+                   'float': {'apache-activemq-artemis': '-NaN is stripped of 
its sign: ENTMQ-1686'},
+                   'double': {'apache-activemq-artemis': '-NaN is stripped of 
its sign: ENTMQ-1686'},
+                  }
+
+
+class AmqpTypeTestCase(unittest.TestCase):
+    """
+    Abstract base class for AMQP Type test cases
+    """
+
+    def run_test(self, broker_addr, amqp_type, test_value_list, send_shim, 
receive_shim):
+        """
+        Run this test by invoking the shim send method to send the test 
values, followed by the shim receive method
+        to receive the values. Finally, compare the sent values with the 
received values.
+        """
+        if len(test_value_list) > 0:
+            # TODO: When Artemis can support it (in the next release), revert 
the queue name back to 'qpid-interop...'
+            # Currently, Artemis only supports auto-create queues for JMS, and 
the queue name must be prefixed by
+            # 'jms.queue.'
+            #queue_name = 'qpid-interop.simple_type_tests.%s.%s.%s' % 
(amqp_type, send_shim.NAME, receive_shim.NAME)
+            queue_name = 'jms.queue.qpid-interop.simple_type_tests.%s.%s.%s' % 
\
+                         (amqp_type, send_shim.NAME, receive_shim.NAME)
+
+            # Start the receive shim first (for queueless brokers/dispatch)
+            receiver = receive_shim.create_receiver(broker_addr, queue_name, 
amqp_type,
+                                                    str(len(test_value_list)))
+            receiver.start()
+
+            # Start the send shim
+            sender = send_shim.create_sender(broker_addr, queue_name, 
amqp_type,
+                                             dumps(test_value_list))
+            sender.start()
+
+            # Wait for both shims to finish
+            sender.join_or_kill(shims.THREAD_TIMEOUT)
+            receiver.join_or_kill(shims.THREAD_TIMEOUT)
+
+            # Process return string from sender
+            send_obj = sender.get_return_object()
+            if send_obj is not None:
+                if isinstance(send_obj, str) and len(send_obj) > 0:
+                    self.fail('Send shim \'%s\':\n%s' % (send_shim.NAME, 
send_obj))
+                else:
+                    self.fail('Sender error: %s' % str(send_obj))
+
+            # Process return string from receiver
+            receive_obj = receiver.get_return_object()
+            if isinstance(receive_obj, list):
+                self.assertEqual(receive_obj, test_value_list, msg='\n    
sent:%s\nreceived:%s' % \
+                                 (test_value_list, receive_obj))
+            else:
+                self.fail('Receiver error: %s' % str(receive_obj))
+
+def create_testcase_class(broker_name, types, broker_addr, amqp_type, 
shim_product):
+    """
+    Class factory function which creates new subclasses to AmqpTypeTestCase.
+    """
+
+    def __repr__(self):
+        """Print the class name"""
+        return self.__class__.__name__
+
+    def add_test_method(cls, send_shim, receive_shim):
+        """Function which creates a new test method in class cls"""
+
+        @unittest.skipIf(types.skip_test(amqp_type, broker_name),
+                         types.skip_test_message(amqp_type, broker_name))
+        def inner_test_method(self):
+            self.run_test(self.broker_addr, self.amqp_type, 
self.test_value_list, send_shim, receive_shim)
+
+        inner_test_method.__name__ = 'test_%s_%s->%s' % (amqp_type, 
send_shim.NAME, receive_shim.NAME)
+        setattr(cls, inner_test_method.__name__, inner_test_method)
+
+    class_name = amqp_type.title() + 'TestCase'
+    class_dict = {'__name__': class_name,
+                  '__repr__': __repr__,
+                  '__doc__': 'Test case for AMQP 1.0 simple type \'%s\'' % 
amqp_type,
+                  'amqp_type': amqp_type,
+                  'broker_addr': broker_addr,
+                  'test_value_list': types.get_test_values(amqp_type)}
+    new_class = type(class_name, (AmqpTypeTestCase,), class_dict)
+    for send_shim, receive_shim in shim_product:
+        add_test_method(new_class, send_shim, receive_shim)
+    return new_class
+
+
+# SHIM_MAP contains an instance of each client language shim that is to be 
tested as a part of this test. For
+# every shim in this list, a test is dynamically constructed which tests it 
against itself as well as every
+# other shim in the list.
+#
+# As new shims are added, add them into this map to have them included in the 
test cases.
+PROTON_CPP_RECEIVER_SHIM = path.join(QPID_INTEROP_TEST_HOME, 'shims', 
'qpid-proton-cpp', 'build', 'amqp_types_test',
+                                     'Receiver')
+PROTON_CPP_SENDER_SHIM = path.join(QPID_INTEROP_TEST_HOME, 'shims', 
'qpid-proton-cpp', 'build', 'amqp_types_test',
+                                   'Sender')
+PROTON_PYTHON_RECEIVER_SHIM = path.join(QPID_INTEROP_TEST_HOME, 'shims', 
'qpid-proton-python', 'src', 'amqp_types_test',
+                                        'Receiver.py')
+PROTON_PYTHON_SENDER_SHIM = path.join(QPID_INTEROP_TEST_HOME, 'shims', 
'qpid-proton-python', 'src', 'amqp_types_test',
+                                      'Sender.py')
+
+SHIM_MAP = {shims.ProtonCppShim.NAME: 
shims.ProtonCppShim(PROTON_CPP_SENDER_SHIM, PROTON_CPP_RECEIVER_SHIM),
+            shims.ProtonPythonShim.NAME: 
shims.ProtonPythonShim(PROTON_PYTHON_SENDER_SHIM, PROTON_PYTHON_RECEIVER_SHIM),
+           }
+
+
+class TestOptions(object):
+    """
+    Class controlling command-line arguments used to control the test.
+    """
+    def __init__(self):
+        parser = argparse.ArgumentParser(description='Qpid-interop AMQP client 
interoparability test suite '
+                                         'for AMQP simple types')
+        parser.add_argument('--broker', action='store', 
default='localhost:5672', metavar='BROKER:PORT',
+                            help='Broker against which to run test suite.')
+#        test_group = parser.add_mutually_exclusive_group()
+#        test_group.add_argument('--include-test', action='append', 
metavar='TEST-NAME',
+#                                help='Name of test to include')
+#        test_group.add_argument('--exclude-test', action='append', 
metavar='TEST-NAME',
+#                                help='Name of test to exclude')
+#        type_group = test_group.add_mutually_exclusive_group()
+#        type_group.add_argument('--include-type', action='append', 
metavar='AMQP-TYPE',
+#                                help='Name of AMQP type to include. Supported 
types:\n%s' %
+#                                sorted(AmqpPrimitiveTypes.TYPE_MAP.keys()))
+        parser.add_argument('--exclude-type', action='append', 
metavar='AMQP-TYPE',
+                            help='Name of AMQP type to exclude. Supported 
types:\n%s' %
+                            sorted(AmqpPrimitiveTypes.TYPE_MAP.keys()))
+#        shim_group = test_group.add_mutually_exclusive_group()
+#        shim_group.add_argument('--include-shim', action='append', 
metavar='SHIM-NAME',
+#                                help='Name of shim to include. Supported 
shims:\n%s' % sorted(SHIM_MAP.keys()))
+        parser.add_argument('--exclude-shim', action='append', 
metavar='SHIM-NAME',
+                            help='Name of shim to exclude. Supported 
shims:\n%s' % sorted(SHIM_MAP.keys()))
+        self.args = parser.parse_args()
+
+
+#--- Main program start ---
+
+if __name__ == '__main__':
+
+    ARGS = TestOptions().args
+    #print 'ARGS:', ARGS # debug
+
+    # Connect to broker to find broker type
+    CONNECTION_PROPS = broker_properties.getBrokerProperties(ARGS.broker)
+    if CONNECTION_PROPS is None:
+        print 'WARNING: Unable to get connection properties - unknown broker'
+        BROKER = 'unknown'
+    else:
+        BROKER = CONNECTION_PROPS[symbol(u'product')] if symbol(u'product') in 
CONNECTION_PROPS \
+                 else '<product not found>'
+        BROKER_VERSION = CONNECTION_PROPS[symbol(u'version')] if 
symbol(u'version') in CONNECTION_PROPS \
+                         else '<version not found>'
+        BROKER_PLATFORM = CONNECTION_PROPS[symbol(u'platform')] if 
symbol(u'platform') in CONNECTION_PROPS \
+                          else '<platform not found>'
+        print 'Test Broker: %s v.%s on %s' % (BROKER, BROKER_VERSION, 
BROKER_PLATFORM)
+        print
+        stdout.flush()
+
+    TYPES = AmqpPrimitiveTypes()
+
+    # TEST_CASE_CLASSES is a list that collects all the test classes that are 
constructed. One class is constructed
+    # per AMQP type used as the key in map AmqpPrimitiveTypes.TYPE_MAP.
+    TEST_CASE_CLASSES = []
+
+    # TEST_SUITE is the final suite of tests that will be run and which 
contains all the dynamically created
+    # type classes, each of which contains a test for the combinations of 
client shims
+    TEST_SUITE = unittest.TestSuite()
+
+    # Remove shims excluded from the command-line
+    if ARGS.exclude_shim is not None:
+        for shim in ARGS.exclude_shim:
+            SHIM_MAP.pop(shim)
+    # Create test classes dynamically
+    for at in sorted(TYPES.get_type_list()):
+        if ARGS.exclude_type is None or at not in ARGS.exclude_type:
+            test_case_class = create_testcase_class(BROKER,
+                                                    TYPES,
+                                                    ARGS.broker,
+                                                    at,
+                                                    product(SHIM_MAP.values(), 
repeat=2))
+            TEST_CASE_CLASSES.append(test_case_class)
+            TEST_SUITE.addTest(unittest.makeSuite(test_case_class))
+
+    # Finally, run all the dynamically created tests
+    RES = unittest.TextTestRunner(verbosity=2).run(TEST_SUITE)
+    if not RES.wasSuccessful():
+        sys.exit(1) # Errors or failures present

http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/83b89fe4/src/python/qpid-interop-test/jms/jms_message_tests.py
----------------------------------------------------------------------
diff --git a/src/python/qpid-interop-test/jms/jms_message_tests.py 
b/src/python/qpid-interop-test/jms/jms_message_tests.py
deleted file mode 100755
index bb9fc9b..0000000
--- a/src/python/qpid-interop-test/jms/jms_message_tests.py
+++ /dev/null
@@ -1,511 +0,0 @@
-#!/usr/bin/env python
-
-"""
-Module to test JMS message types across different APIs
-"""
-
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-import argparse
-import sys
-import unittest
-
-from itertools import product
-from json import dumps
-from os import getenv, path
-from sys import stdout
-
-import broker_properties
-import shims
-from proton import symbol
-from test_type_map import TestTypeMap
-
-
-# TODO: propose a sensible default when installation details are worked out
-QPID_INTEROP_TEST_HOME = getenv('QPID_INTEROP_TEST_HOME')
-if QPID_INTEROP_TEST_HOME is None:
-    print 'ERROR: Environment variable QPID_INTEROP_TEST_HOME is not set'
-    sys.exit(1)
-MAVEN_REPO_PATH = getenv('MAVEN_REPO_PATH', path.join(getenv('HOME'), '.m2', 
'repository'))
-
-class JmsMessageTypes(TestTypeMap):
-    """
-    Class which contains all the described JMS message types and the test 
values to be used in testing.
-    """
-
-    COMMON_SUBMAP = {
-        'boolean': ['True',
-                    'False'],
-        'byte': ['-0x80',
-                 '-0x1',
-                 '0x0',
-                 '0x7f'],
-        'double': ['0x0000000000000000', # 0.0
-                   '0x8000000000000000', # -0.0
-                   '0x400921fb54442eea', # pi (3.14159265359) positive decimal
-                   '0xc005bf0a8b145fcf', # -e (-2.71828182846) negative decimal
-                   '0x0000000000000001', # Smallest positive denormalized 
number
-                   '0x8000000000000001', # Smallest negative denormalized 
number
-                   '0x000fffffffffffff', # Largest positive denormalized number
-                   '0x8010000000000000', # Largest negative denormalized number
-                   '0x7fefffffffffffff', # Largest positive normalized number
-                   '0xffefffffffffffff', # Largest negative normalized number
-                   '0x7ff0000000000000', # +Infinity
-                   '0xfff0000000000000', # -Infinity
-                   '0x7ff8000000000000'], # +NaN
-        'float': ['0x00000000', # 0.0
-                  '0x80000000', # -0.0
-                  '0x40490fdb', # pi (3.14159265359) positive decimal
-                  '0xc02df854', # -e (-2.71828182846) negative decimal
-                  '0x00000001', # Smallest positive denormalized number
-                  '0x80000001', # Smallest negative denormalized number
-                  '0x007fffff', # Largest positive denormalized number
-                  '0x807fffff', # Largest negative denormalized number
-                  '0x00800000', # Smallest positive normalized number
-                  '0x80800000', # Smallest negative normalized number
-                  '0x7f7fffff', # Largest positive normalized number
-                  '0xff7fffff', # Largest negative normalized number
-                  #'0x7f800000', # +Infinity  # PROTON-1149 - fails on RHEL7
-                  #'0xff800000', # -Infinity # PROTON-1149 - fails on RHEL7
-                  '0x7fc00000'], # +NaN
-        'int': ['-0x80000000',
-                '-0x81',
-                '-0x80',
-                '-0x1',
-                '0x0',
-                '0x7f',
-                '0x80',
-                '0x7fffffff'],
-        'long': ['-0x8000000000000000',
-                 '-0x81',
-                 '-0x80',
-                 '-0x1',
-                 '0x0',
-                 '0x7f',
-                 '0x80',
-                 '0x7fffffffffffffff'],
-        'short': ['-0x8000',
-                  '-0x1',
-                  '0x0',
-                  '0x7fff'],
-        'string': ['',
-                   'Hello, world',
-                   '"Hello, world"',
-                   "Charlie's \"peach\"",
-                   'Charlie\'s "peach"',
-                   'The quick brown fox jumped over the lazy dog 0123456789.'# 
* 100]
-                  ]
-        }
-
-    TYPE_ADDITIONAL_SUBMAP = {
-        'bytes': [b'',
-                  b'12345',
-                  b'Hello, world',
-                  b'\\x01\\x02\\x03\\x04\\x05abcde\\x80\\x81\\xfe\\xff',
-                  b'The quick brown fox jumped over the lazy dog 0123456789.' 
#* 100],
-                 ],
-        'char': ['a',
-                 'Z',
-                 '\x01',
-                 '\x7f'],
-        }
-
-    # The TYPE_SUBMAP defines test values for JMS message types that allow 
typed message content. Note that the
-    # types defined here are understood to be *Java* types and the stringified 
values are to be interpreted
-    # as the appropriate Java type by the send shim.
-    TYPE_SUBMAP = TestTypeMap.merge_dicts(COMMON_SUBMAP, 
TYPE_ADDITIONAL_SUBMAP)
-
-    # Defines JMS headers that should be set by the send or publish API call 
of the client
-    HEADERS_PUBLISH_LIST = [
-        'JMS_DESTINATION',
-        'JMS_DELIVERY_MODE',
-        'JMS_EXPIRATION',
-        'JMS_PRIORITY',
-        'JMS_MESSAGEID',
-        'JMS_TIMESTAMP',
-        ]
-
-    # Defines JMS headers that are modified by the broker when he message is 
consumed
-    HEADERS_BROKER_LIST = [
-        'JMS_REDELIVERED',
-        ]
-
-    # JMS headers that can be set by the client prior to send / publish, and 
that should be preserved byt he broker
-    HEADERS_MAP = {
-        'JMS_CORRELATIONID_HEADER': {'string': ['Hello, world',
-                                                '"Hello, world"',
-                                                "Charlie's \"peach\"",
-                                                'Charlie\'s "peach"',
-                                                'The quick brown fox jumped 
over the lazy dog 0123456789.' * 10,
-                                                #'', # TODO: Re-enable when 
PROTON-1288 is fixed
-                                               ],
-                                     'bytes': [b'12345\\x006789',
-                                               b'Hello, world',
-                                               b'"Hello, world"',
-                                               
b'\\x01\\x02\\x03\\x04\\x05abcde\\x80\\x81\\xfe\\xff',
-                                               b'The quick brown fox jumped 
over the lazy dog 0123456789.' * 10,
-                                               #b'', # TODO: Re-enable when 
PROTON-1288 is fixed
-                                              ],
-                                    },
-        'JMS_REPLYTO_HEADER': {'queue': ['q_aaa', 'q_bbb'],
-                               'topic': ['t_aaa', 't_bbb'],
-                              },
-        'JMS_TYPE_HEADER': {'string': ['Hello, world',
-                                       '"Hello, world"',
-                                       "Charlie's \"peach\"",
-                                       'Charlie\'s "peach"',
-                                       'The quick brown fox jumped over the 
lazy dog 0123456789.' * 10,
-                                       #'', # TODO: Re-enable when PROTON-1288 
is fixed
-                                      ],
-                           },
-        }
-
-    PROPERTIES_MAP = COMMON_SUBMAP # disabled until PROTON-1284 is fixed
-
-    TYPE_MAP = {
-        'JMS_MESSAGE_TYPE': {'none': [None]},
-        'JMS_BYTESMESSAGE_TYPE': TYPE_SUBMAP,
-        'JMS_MAPMESSAGE_TYPE': TYPE_SUBMAP,
-        'JMS_STREAMMESSAGE_TYPE': TYPE_SUBMAP,
-        'JMS_TEXTMESSAGE_TYPE': {'text': ['',
-                                          'Hello, world',
-                                          '"Hello, world"',
-                                          "Charlie's \"peach\"",
-                                          'Charlie\'s "peach"',
-                                          'The quick brown fox jumped over the 
lazy dog 0123456789.' * 10
-                                         ]
-                                },
-        # TODO: Add Object messages when other (non-JMS clients) can generate 
Java class strings used in this message
-        # type
-        #'JMS_OBJECTMESSAGE_TYPE': {
-        #    'java.lang.Boolean': ['true',
-        #                          'false'],
-        #    'java.lang.Byte': ['-128',
-        #                       '0',
-        #                       '127'],
-        #    'java.lang.Character': [u'a',
-        #                            u'Z'],
-        #    'java.lang.Double': ['0.0',
-        #                         '3.141592654',
-        #                         '-2.71828182846'],
-        #    'java.lang.Float': ['0.0',
-        #                        '3.14159',
-        #                        '-2.71828'],
-        #    'java.lang.Integer': ['-2147483648',
-        #                          '-129',
-        #                          '-128',
-        #                          '-1',
-        #                          '0',
-        #                          '127',
-        #                          '128',
-        #                          '2147483647'],
-        #    'java.lang.Long' : ['-9223372036854775808',
-        #                        '-129',
-        #                        '-128',
-        #                        '-1',
-        #                        '0',
-        #                        '127',
-        #                        '128',
-        #                        '9223372036854775807'],
-        #    'java.lang.Short': ['-32768',
-        #                        '-129',
-        #                        '-128',
-        #                        '-1',
-        #                        '0',
-        #                        '127',
-        #                        '128',
-        #                        '32767'],
-        #    'java.lang.String': [u'',
-        #                         u'Hello, world',
-        #                         u'"Hello, world"',
-        #                         u"Charlie's \"peach\"",
-        #                         u'Charlie\'s "peach"']
-        #    },
-        }
-
-    BROKER_SKIP = {}
-
-
-class JmsMessageTypeTestCase(unittest.TestCase):
-    """
-    Abstract base class for JMS message type test cases
-    """
-
-    def run_test(self, broker_addr, jms_message_type, test_values, msg_hdrs, 
msg_props, send_shim, receive_shim):
-        """
-        Run this test by invoking the shim send method to send the test 
values, followed by the shim receive method
-        to receive the values. Finally, compare the sent values with the 
received values.
-        """
-        queue_name = 'jms.queue.qpid-interop.jms_message_type_tests.%s.%s.%s' 
% (jms_message_type, send_shim.NAME,
-                                                                               
  receive_shim.NAME)
-
-        # First create a map containing the numbers of expected mesasges for 
each JMS message type
-        num_test_values_map = {}
-        if len(test_values) > 0:
-            for index in test_values.keys():
-                num_test_values_map[index] = len(test_values[index])
-        # Create a map of flags which indicate to the receiver the details of 
some of the messages so that it can
-        # be correctly handled (as these require some prior knowledge)
-        flags_map = {}
-        if 'JMS_CORRELATIONID_HEADER' in msg_hdrs and 'bytes' in 
msg_hdrs['JMS_CORRELATIONID_HEADER']:
-            flags_map['JMS_CORRELATIONID_AS_BYTES'] = True
-        if 'JMS_REPLYTO_HEADER' in msg_hdrs and 'topic' in 
msg_hdrs['JMS_REPLYTO_HEADER']:
-            flags_map['JMS_REPLYTO_AS_TOPIC'] = True
-        # Start the receiver shim
-        receiver = receive_shim.create_receiver(broker_addr, queue_name, 
jms_message_type,
-                                                dumps([num_test_values_map, 
flags_map]))
-        receiver.start()
-
-        # Start the send shim
-        sender = send_shim.create_sender(broker_addr, queue_name, 
jms_message_type,
-                                         dumps([test_values, msg_hdrs, 
msg_props]))
-        sender.start()
-
-        # Wait for both shims to finish
-        sender.join_or_kill(shims.THREAD_TIMEOUT)
-        receiver.join_or_kill(shims.THREAD_TIMEOUT)
-
-        # Process return string from sender
-        send_obj = sender.get_return_object()
-        if send_obj is not None:
-            if isinstance(send_obj, str) and len(send_obj) > 0:
-                self.fail('Send shim \'%s\':\n%s' % (send_shim.NAME, send_obj))
-            else:
-                self.fail('Send shim \'%s\':\n%s' % str(send_obj))
-
-        # Process return string from receiver
-        receive_obj = receiver.get_return_object()
-        if receive_obj is None:
-            self.fail('JmsReceiver shim returned None')
-        else:
-            if isinstance(receive_obj, tuple):
-                if len(receive_obj) == 4:
-                    return_jms_message_type, return_test_values, 
return_msg_hdrs, return_msg_props = receive_obj
-                    self.assertEqual(return_jms_message_type, jms_message_type,
-                                     msg='JMS message type error:\n\n    
sent:%s\n\n    received:%s' % \
-                                     (jms_message_type, 
return_jms_message_type))
-                    self.assertEqual(return_test_values, test_values,
-                                     msg='JMS message body error:\n\n    
sent:%s\n\n    received:%s' % \
-                                     (test_values, return_test_values))
-                    self.assertEqual(return_msg_hdrs, msg_hdrs,
-                                     msg='JMS message headers error:\n\n    
sent:%s\n\n    received:%s' % \
-                                     (msg_hdrs, return_msg_hdrs))
-                    self.assertEqual(return_msg_props, msg_props,
-                                     msg='JMS message properties error:\n\n    
sent:%s\n\n    received:%s' % \
-                                     (msg_props, return_msg_props))
-            else:
-                self.fail(str(receive_obj))
-
-
-def create_testcase_class(broker_name, types, broker_addr, jms_message_type, 
shim_product):
-    """
-    Class factory function which creates new subclasses to 
JmsMessageTypeTestCase. Each call creates a single new
-    test case named and based on the parameters supplied to the method
-    """
-
-    def __repr__(self):
-        """Print the class name"""
-        return self.__class__.__name__
-
-    def add_test_method(cls, hdrs, props, send_shim, receive_shim):
-        """Function which creates a new test method in class cls"""
-
-        @unittest.skipIf(types.skip_test(jms_message_type, broker_name),
-                         types.skip_test_message(jms_message_type, 
broker_name))
-        def inner_test_method(self):
-            self.run_test(self.broker_addr,
-                          self.jms_message_type,
-                          self.test_values,
-                          hdrs[1],
-                          props[1],
-                          send_shim,
-                          receive_shim)
-
-        inner_test_method.__name__ = 'test_%s%s%s_%s->%s' % 
(jms_message_type[4:-5], hdrs[0], props[0], send_shim.NAME,
-                                                             receive_shim.NAME)
-        setattr(cls, inner_test_method.__name__, inner_test_method)
-
-    class_name = jms_message_type[4:-5].title() + 'TestCase'
-    class_dict = {'__name__': class_name,
-                  '__repr__': __repr__,
-                  '__doc__': 'Test case for JMS message type \'%s\'' % 
jms_message_type,
-                  'jms_message_type': jms_message_type,
-                  'broker_addr': broker_addr,
-                  'test_values': types.get_test_values(jms_message_type)} # 
tuple (tot_size, {...}
-    new_class = type(class_name, (JmsMessageTypeTestCase,), class_dict)
-    for send_shim, receive_shim in shim_product:
-        # Message without any headers or properties
-        add_test_method(new_class, ('', {}), ('', {}), send_shim, receive_shim)
-
-        # Iterate through message headers, add one test per header value, no 
combinations
-        # Structure: {HEADER_NAME_1; {header_type_1: [val_1_1, val_1_2, 
val_1_3, ...],
-        #                             header_type_2: [val_2_1, val_2_2, 
val_2_3, ...],
-        #                             ...
-        #                            },
-        #             ...
-        #            }
-        for msg_header, header_type_dict in types.HEADERS_MAP.iteritems():
-            for header_type, header_val_list in header_type_dict.iteritems():
-                hdr_val_cnt = 0
-                for header_val in header_val_list:
-                    hdr_val_cnt += 1
-                    test_name = '_hdr.%s.%s.%02d' % (msg_header[4:-7], 
header_type, hdr_val_cnt)
-                    add_test_method(new_class,
-                                    (test_name, {msg_header: {header_type: 
header_val}}),
-                                    ('', {}),
-                                    send_shim,
-                                    receive_shim)
-
-        # One message with all the headers together using type[0] and val[0]
-        all_hdrs = {}
-        for msg_header in types.HEADERS_MAP.iterkeys():
-            header_type_dict = types.HEADERS_MAP[msg_header]
-            header_type, header_val_list = header_type_dict.iteritems().next()
-            header_val = header_val_list[0]
-            all_hdrs[msg_header] = {header_type: header_val}
-        add_test_method(new_class, ('_hdrs', all_hdrs), ('', {}), send_shim, 
receive_shim)
-
-        # Properties tests disabled until PROTON-1284 fixed
-        ## Iterate through properties
-        ## Structure: {prop_type_1: [val_1_1, val_1_2, ...],
-        ##             prop_type_2: [val_2_1, val_2_2, ...],
-        ##             ...
-        ##            }
-        #all_props = {}
-        #for prop_type, prop_val_list in types.PROPERTIES_MAP.iteritems():
-        #    prop_val_cnt = 0
-        #    for prop_val in prop_val_list:
-        #        prop_val_cnt += 1
-        #        all_props['%s_%02d' % (prop_type, prop_val_cnt)] = 
{prop_type: prop_val}
-
-        ## One message with all properties together
-        #add_test_method(new_class, ('', {}), ('_props', all_props), 
send_shim, receive_shim)
-
-        ## One message with all headers and all properties together
-        #add_test_method(new_class, ('_hdrs', all_hdrs), ('_props', 
all_props), send_shim, receive_shim)
-
-    return new_class
-
-
-PROTON_CPP_RECEIVER_SHIM = path.join(QPID_INTEROP_TEST_HOME, 'shims', 
'qpid-proton-cpp', 'build', 'src',
-                                     'JmsReceiver')
-PROTON_CPP_SENDER_SHIM = path.join(QPID_INTEROP_TEST_HOME, 'shims', 
'qpid-proton-cpp', 'build', 'src',
-                                   'JmsSender')
-PROTON_PYTHON_RECEIVER_SHIM = path.join(QPID_INTEROP_TEST_HOME, 'shims', 
'qpid-proton-python', 'src',
-                                        'JmsReceiverShim.py')
-PROTON_PYTHON_SENDER_SHIM = path.join(QPID_INTEROP_TEST_HOME, 'shims', 
'qpid-proton-python', 'src',
-                                      'JmsSenderShim.py')
-QIT_JMS_CLASSPATH_FILE = path.join(QPID_INTEROP_TEST_HOME, 'shims', 
'qpid-jms', 'cp.txt')
-with open(QIT_JMS_CLASSPATH_FILE, 'r') as classpath_file:
-    QIT_JMS_CLASSPATH = classpath_file.read()
-QPID_JMS_RECEIVER_SHIM = 'org.apache.qpid.interop_test.shim.JmsReceiverShim'
-QPID_JMS_SENDER_SHIM = 'org.apache.qpid.interop_test.shim.JmsSenderShim'
-
-# SHIM_MAP contains an instance of each client language shim that is to be 
tested as a part of this test. For
-# every shim in this list, a test is dynamically constructed which tests it 
against itself as well as every
-# other shim in the list.
-#
-# As new shims are added, add them into this map to have them included in the 
test cases.
-SHIM_MAP = {shims.ProtonCppShim.NAME: 
shims.ProtonCppShim(PROTON_CPP_SENDER_SHIM, PROTON_CPP_RECEIVER_SHIM),
-            shims.ProtonPythonShim.NAME: 
shims.ProtonPythonShim(PROTON_PYTHON_SENDER_SHIM, PROTON_PYTHON_RECEIVER_SHIM),
-            shims.QpidJmsShim.NAME: shims.QpidJmsShim(QIT_JMS_CLASSPATH, 
QPID_JMS_SENDER_SHIM, QPID_JMS_RECEIVER_SHIM),
-           }
-
-# TODO: Complete the test options to give fine control over running tests
-class TestOptions(object):
-    """
-    Class controlling command-line arguments used to control the test.
-    """
-    def __init__(self,):
-        parser = argparse.ArgumentParser(description='Qpid-interop AMQP client 
interoparability test suite '
-                                         'for JMS message types')
-        parser.add_argument('--broker', action='store', 
default='localhost:5672', metavar='BROKER:PORT',
-                            help='Broker against which to run test suite.')
-#        test_group = parser.add_mutually_exclusive_group()
-#        test_group.add_argument('--include-test', action='append', 
metavar='TEST-NAME',
-#                                help='Name of test to include')
-#        test_group.add_argument('--exclude-test', action='append', 
metavar='TEST-NAME',
-#                                help='Name of test to exclude')
-#        type_group = test_group.add_mutually_exclusive_group()
-#        type_group.add_argument('--include-type', action='append', 
metavar='AMQP-TYPE',
-#                                help='Name of AMQP type to include. Supported 
types:\n%s' %
-#                                sorted(JmsMessageTypes.TYPE_MAP.keys()))
-        parser.add_argument('--exclude-type', action='append', 
metavar='JMS-MESSAGE-TYPE',
-                            help='Name of JMS message type to exclude. 
Supported types:\n%s' %
-                            sorted(JmsMessageTypes.TYPE_MAP.keys()))
-#        shim_group = test_group.add_mutually_exclusive_group()
-#        shim_group.add_argument('--include-shim', action='append', 
metavar='SHIM-NAME',
-#                                help='Name of shim to include. Supported 
shims:\n%s' % sorted(SHIM_MAP.keys()))
-        parser.add_argument('--exclude-shim', action='append', 
metavar='SHIM-NAME',
-                            help='Name of shim to exclude. Supported 
shims:\n%s' % sorted(SHIM_MAP.keys()))
-        self.args = parser.parse_args()
-
-
-#--- Main program start ---
-
-if __name__ == '__main__':
-    ARGS = TestOptions().args
-    #print 'ARGS:', ARGS # debug
-
-    # Connect to broker to find broker type
-    CONNECTION_PROPS = broker_properties.getBrokerProperties(ARGS.broker)
-    if CONNECTION_PROPS is None:
-        print 'WARNING: Unable to get connection properties - unknown broker'
-        BROKER = 'unknown'
-    else:
-        BROKER = CONNECTION_PROPS[symbol(u'product')] if symbol(u'product') in 
CONNECTION_PROPS \
-                 else '<product not found>'
-        BROKER_VERSION = CONNECTION_PROPS[symbol(u'version')] if 
symbol(u'version') in CONNECTION_PROPS \
-                         else '<version not found>'
-        BROKER_PLATFORM = CONNECTION_PROPS[symbol(u'platform')] if 
symbol(u'platform') in CONNECTION_PROPS \
-                          else '<platform not found>'
-        print 'Test Broker: %s v.%s on %s' % (BROKER, BROKER_VERSION, 
BROKER_PLATFORM)
-        print
-        stdout.flush()
-
-    TYPES = JmsMessageTypes()
-
-    # TEST_CASE_CLASSES is a list that collects all the test classes that are 
constructed. One class is constructed
-    # per AMQP type used as the key in map JmsMessageTypes.TYPE_MAP.
-    TEST_CASE_CLASSES = []
-
-    # TEST_SUITE is the final suite of tests that will be run and which 
contains all the dynamically created
-    # type classes, each of which contains a test for the combinations of 
client shims
-    TEST_SUITE = unittest.TestSuite()
-
-    # Remove shims excluded from the command-line
-    if ARGS.exclude_shim is not None:
-        for shim in ARGS.exclude_shim:
-            SHIM_MAP.pop(shim)
-    # Create test classes dynamically
-    for jmt in sorted(TYPES.get_type_list()):
-        if ARGS.exclude_type is None or jmt not in ARGS.exclude_type:
-            test_case_class = create_testcase_class(BROKER,
-                                                    TYPES,
-                                                    ARGS.broker,
-                                                    jmt,
-                                                    product(SHIM_MAP.values(), 
repeat=2))
-            TEST_CASE_CLASSES.append(test_case_class)
-            TEST_SUITE.addTest(unittest.makeSuite(test_case_class))
-
-    # Finally, run all the dynamically created tests
-    RES = unittest.TextTestRunner(verbosity=2).run(TEST_SUITE)
-    if not RES.wasSuccessful():
-        sys.exit(1)

http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/83b89fe4/src/python/qpid-interop-test/jms_messages_test.py
----------------------------------------------------------------------
diff --git a/src/python/qpid-interop-test/jms_messages_test.py 
b/src/python/qpid-interop-test/jms_messages_test.py
new file mode 100755
index 0000000..56cb203
--- /dev/null
+++ b/src/python/qpid-interop-test/jms_messages_test.py
@@ -0,0 +1,511 @@
+#!/usr/bin/env python
+
+"""
+Module to test JMS message types across different APIs
+"""
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import argparse
+import sys
+import unittest
+
+from itertools import product
+from json import dumps
+from os import getenv, path
+from sys import stdout
+
+import broker_properties
+import shims
+from proton import symbol
+from test_type_map import TestTypeMap
+
+
+# TODO: propose a sensible default when installation details are worked out
+QPID_INTEROP_TEST_HOME = getenv('QPID_INTEROP_TEST_HOME')
+if QPID_INTEROP_TEST_HOME is None:
+    print 'ERROR: Environment variable QPID_INTEROP_TEST_HOME is not set'
+    sys.exit(1)
+MAVEN_REPO_PATH = getenv('MAVEN_REPO_PATH', path.join(getenv('HOME'), '.m2', 
'repository'))
+
+class JmsMessageTypes(TestTypeMap):
+    """
+    Class which contains all the described JMS message types and the test 
values to be used in testing.
+    """
+
+    COMMON_SUBMAP = {
+        'boolean': ['True',
+                    'False'],
+        'byte': ['-0x80',
+                 '-0x1',
+                 '0x0',
+                 '0x7f'],
+        'double': ['0x0000000000000000', # 0.0
+                   '0x8000000000000000', # -0.0
+                   '0x400921fb54442eea', # pi (3.14159265359) positive decimal
+                   '0xc005bf0a8b145fcf', # -e (-2.71828182846) negative decimal
+                   '0x0000000000000001', # Smallest positive denormalized 
number
+                   '0x8000000000000001', # Smallest negative denormalized 
number
+                   '0x000fffffffffffff', # Largest positive denormalized number
+                   '0x8010000000000000', # Largest negative denormalized number
+                   '0x7fefffffffffffff', # Largest positive normalized number
+                   '0xffefffffffffffff', # Largest negative normalized number
+                   '0x7ff0000000000000', # +Infinity
+                   '0xfff0000000000000', # -Infinity
+                   '0x7ff8000000000000'], # +NaN
+        'float': ['0x00000000', # 0.0
+                  '0x80000000', # -0.0
+                  '0x40490fdb', # pi (3.14159265359) positive decimal
+                  '0xc02df854', # -e (-2.71828182846) negative decimal
+                  '0x00000001', # Smallest positive denormalized number
+                  '0x80000001', # Smallest negative denormalized number
+                  '0x007fffff', # Largest positive denormalized number
+                  '0x807fffff', # Largest negative denormalized number
+                  '0x00800000', # Smallest positive normalized number
+                  '0x80800000', # Smallest negative normalized number
+                  '0x7f7fffff', # Largest positive normalized number
+                  '0xff7fffff', # Largest negative normalized number
+                  #'0x7f800000', # +Infinity  # PROTON-1149 - fails on RHEL7
+                  #'0xff800000', # -Infinity # PROTON-1149 - fails on RHEL7
+                  '0x7fc00000'], # +NaN
+        'int': ['-0x80000000',
+                '-0x81',
+                '-0x80',
+                '-0x1',
+                '0x0',
+                '0x7f',
+                '0x80',
+                '0x7fffffff'],
+        'long': ['-0x8000000000000000',
+                 '-0x81',
+                 '-0x80',
+                 '-0x1',
+                 '0x0',
+                 '0x7f',
+                 '0x80',
+                 '0x7fffffffffffffff'],
+        'short': ['-0x8000',
+                  '-0x1',
+                  '0x0',
+                  '0x7fff'],
+        'string': ['',
+                   'Hello, world',
+                   '"Hello, world"',
+                   "Charlie's \"peach\"",
+                   'Charlie\'s "peach"',
+                   'The quick brown fox jumped over the lazy dog 0123456789.'# 
* 100]
+                  ]
+        }
+
+    TYPE_ADDITIONAL_SUBMAP = {
+        'bytes': [b'',
+                  b'12345',
+                  b'Hello, world',
+                  b'\\x01\\x02\\x03\\x04\\x05abcde\\x80\\x81\\xfe\\xff',
+                  b'The quick brown fox jumped over the lazy dog 0123456789.' 
#* 100],
+                 ],
+        'char': ['a',
+                 'Z',
+                 '\x01',
+                 '\x7f'],
+        }
+
+    # The TYPE_SUBMAP defines test values for JMS message types that allow 
typed message content. Note that the
+    # types defined here are understood to be *Java* types and the stringified 
values are to be interpreted
+    # as the appropriate Java type by the send shim.
+    TYPE_SUBMAP = TestTypeMap.merge_dicts(COMMON_SUBMAP, 
TYPE_ADDITIONAL_SUBMAP)
+
+    # Defines JMS headers that should be set by the send or publish API call 
of the client
+    HEADERS_PUBLISH_LIST = [
+        'JMS_DESTINATION',
+        'JMS_DELIVERY_MODE',
+        'JMS_EXPIRATION',
+        'JMS_PRIORITY',
+        'JMS_MESSAGEID',
+        'JMS_TIMESTAMP',
+        ]
+
+    # Defines JMS headers that are modified by the broker when he message is 
consumed
+    HEADERS_BROKER_LIST = [
+        'JMS_REDELIVERED',
+        ]
+
+    # JMS headers that can be set by the client prior to send / publish, and 
that should be preserved byt he broker
+    HEADERS_MAP = {
+        'JMS_CORRELATIONID_HEADER': {'string': ['Hello, world',
+                                                '"Hello, world"',
+                                                "Charlie's \"peach\"",
+                                                'Charlie\'s "peach"',
+                                                'The quick brown fox jumped 
over the lazy dog 0123456789.' * 10,
+                                                #'', # TODO: Re-enable when 
PROTON-1288 is fixed
+                                               ],
+                                     'bytes': [b'12345\\x006789',
+                                               b'Hello, world',
+                                               b'"Hello, world"',
+                                               
b'\\x01\\x02\\x03\\x04\\x05abcde\\x80\\x81\\xfe\\xff',
+                                               b'The quick brown fox jumped 
over the lazy dog 0123456789.' * 10,
+                                               #b'', # TODO: Re-enable when 
PROTON-1288 is fixed
+                                              ],
+                                    },
+        'JMS_REPLYTO_HEADER': {'queue': ['q_aaa', 'q_bbb'],
+                               'topic': ['t_aaa', 't_bbb'],
+                              },
+        'JMS_TYPE_HEADER': {'string': ['Hello, world',
+                                       '"Hello, world"',
+                                       "Charlie's \"peach\"",
+                                       'Charlie\'s "peach"',
+                                       'The quick brown fox jumped over the 
lazy dog 0123456789.' * 10,
+                                       #'', # TODO: Re-enable when PROTON-1288 
is fixed
+                                      ],
+                           },
+        }
+
+    PROPERTIES_MAP = COMMON_SUBMAP # disabled until PROTON-1284 is fixed
+
+    TYPE_MAP = {
+        'JMS_MESSAGE_TYPE': {'none': [None]},
+        'JMS_BYTESMESSAGE_TYPE': TYPE_SUBMAP,
+        'JMS_MAPMESSAGE_TYPE': TYPE_SUBMAP,
+        'JMS_STREAMMESSAGE_TYPE': TYPE_SUBMAP,
+        'JMS_TEXTMESSAGE_TYPE': {'text': ['',
+                                          'Hello, world',
+                                          '"Hello, world"',
+                                          "Charlie's \"peach\"",
+                                          'Charlie\'s "peach"',
+                                          'The quick brown fox jumped over the 
lazy dog 0123456789.' * 10
+                                         ]
+                                },
+        # TODO: Add Object messages when other (non-JMS clients) can generate 
Java class strings used in this message
+        # type
+        #'JMS_OBJECTMESSAGE_TYPE': {
+        #    'java.lang.Boolean': ['true',
+        #                          'false'],
+        #    'java.lang.Byte': ['-128',
+        #                       '0',
+        #                       '127'],
+        #    'java.lang.Character': [u'a',
+        #                            u'Z'],
+        #    'java.lang.Double': ['0.0',
+        #                         '3.141592654',
+        #                         '-2.71828182846'],
+        #    'java.lang.Float': ['0.0',
+        #                        '3.14159',
+        #                        '-2.71828'],
+        #    'java.lang.Integer': ['-2147483648',
+        #                          '-129',
+        #                          '-128',
+        #                          '-1',
+        #                          '0',
+        #                          '127',
+        #                          '128',
+        #                          '2147483647'],
+        #    'java.lang.Long' : ['-9223372036854775808',
+        #                        '-129',
+        #                        '-128',
+        #                        '-1',
+        #                        '0',
+        #                        '127',
+        #                        '128',
+        #                        '9223372036854775807'],
+        #    'java.lang.Short': ['-32768',
+        #                        '-129',
+        #                        '-128',
+        #                        '-1',
+        #                        '0',
+        #                        '127',
+        #                        '128',
+        #                        '32767'],
+        #    'java.lang.String': [u'',
+        #                         u'Hello, world',
+        #                         u'"Hello, world"',
+        #                         u"Charlie's \"peach\"",
+        #                         u'Charlie\'s "peach"']
+        #    },
+        }
+
+    BROKER_SKIP = {}
+
+
+class JmsMessageTypeTestCase(unittest.TestCase):
+    """
+    Abstract base class for JMS message type test cases
+    """
+
+    def run_test(self, broker_addr, jms_message_type, test_values, msg_hdrs, 
msg_props, send_shim, receive_shim):
+        """
+        Run this test by invoking the shim send method to send the test 
values, followed by the shim receive method
+        to receive the values. Finally, compare the sent values with the 
received values.
+        """
+        queue_name = 'jms.queue.qpid-interop.jms_message_type_tests.%s.%s.%s' 
% (jms_message_type, send_shim.NAME,
+                                                                               
  receive_shim.NAME)
+
+        # First create a map containing the numbers of expected mesasges for 
each JMS message type
+        num_test_values_map = {}
+        if len(test_values) > 0:
+            for index in test_values.keys():
+                num_test_values_map[index] = len(test_values[index])
+        # Create a map of flags which indicate to the receiver the details of 
some of the messages so that it can
+        # be correctly handled (as these require some prior knowledge)
+        flags_map = {}
+        if 'JMS_CORRELATIONID_HEADER' in msg_hdrs and 'bytes' in 
msg_hdrs['JMS_CORRELATIONID_HEADER']:
+            flags_map['JMS_CORRELATIONID_AS_BYTES'] = True
+        if 'JMS_REPLYTO_HEADER' in msg_hdrs and 'topic' in 
msg_hdrs['JMS_REPLYTO_HEADER']:
+            flags_map['JMS_REPLYTO_AS_TOPIC'] = True
+        # Start the receiver shim
+        receiver = receive_shim.create_receiver(broker_addr, queue_name, 
jms_message_type,
+                                                dumps([num_test_values_map, 
flags_map]))
+        receiver.start()
+
+        # Start the send shim
+        sender = send_shim.create_sender(broker_addr, queue_name, 
jms_message_type,
+                                         dumps([test_values, msg_hdrs, 
msg_props]))
+        sender.start()
+
+        # Wait for both shims to finish
+        sender.join_or_kill(shims.THREAD_TIMEOUT)
+        receiver.join_or_kill(shims.THREAD_TIMEOUT)
+
+        # Process return string from sender
+        send_obj = sender.get_return_object()
+        if send_obj is not None:
+            if isinstance(send_obj, str) and len(send_obj) > 0:
+                self.fail('Send shim \'%s\':\n%s' % (send_shim.NAME, send_obj))
+            else:
+                self.fail('Send shim \'%s\':\n%s' % str(send_obj))
+
+        # Process return string from receiver
+        receive_obj = receiver.get_return_object()
+        if receive_obj is None:
+            self.fail('JmsReceiver shim returned None')
+        else:
+            if isinstance(receive_obj, tuple):
+                if len(receive_obj) == 4:
+                    return_jms_message_type, return_test_values, 
return_msg_hdrs, return_msg_props = receive_obj
+                    self.assertEqual(return_jms_message_type, jms_message_type,
+                                     msg='JMS message type error:\n\n    
sent:%s\n\n    received:%s' % \
+                                     (jms_message_type, 
return_jms_message_type))
+                    self.assertEqual(return_test_values, test_values,
+                                     msg='JMS message body error:\n\n    
sent:%s\n\n    received:%s' % \
+                                     (test_values, return_test_values))
+                    self.assertEqual(return_msg_hdrs, msg_hdrs,
+                                     msg='JMS message headers error:\n\n    
sent:%s\n\n    received:%s' % \
+                                     (msg_hdrs, return_msg_hdrs))
+                    self.assertEqual(return_msg_props, msg_props,
+                                     msg='JMS message properties error:\n\n    
sent:%s\n\n    received:%s' % \
+                                     (msg_props, return_msg_props))
+            else:
+                self.fail(str(receive_obj))
+
+
+def create_testcase_class(broker_name, types, broker_addr, jms_message_type, 
shim_product):
+    """
+    Class factory function which creates new subclasses to 
JmsMessageTypeTestCase. Each call creates a single new
+    test case named and based on the parameters supplied to the method
+    """
+
+    def __repr__(self):
+        """Print the class name"""
+        return self.__class__.__name__
+
+    def add_test_method(cls, hdrs, props, send_shim, receive_shim):
+        """Function which creates a new test method in class cls"""
+
+        @unittest.skipIf(types.skip_test(jms_message_type, broker_name),
+                         types.skip_test_message(jms_message_type, 
broker_name))
+        def inner_test_method(self):
+            self.run_test(self.broker_addr,
+                          self.jms_message_type,
+                          self.test_values,
+                          hdrs[1],
+                          props[1],
+                          send_shim,
+                          receive_shim)
+
+        inner_test_method.__name__ = 'test_%s%s%s_%s->%s' % 
(jms_message_type[4:-5], hdrs[0], props[0], send_shim.NAME,
+                                                             receive_shim.NAME)
+        setattr(cls, inner_test_method.__name__, inner_test_method)
+
+    class_name = jms_message_type[4:-5].title() + 'TestCase'
+    class_dict = {'__name__': class_name,
+                  '__repr__': __repr__,
+                  '__doc__': 'Test case for JMS message type \'%s\'' % 
jms_message_type,
+                  'jms_message_type': jms_message_type,
+                  'broker_addr': broker_addr,
+                  'test_values': types.get_test_values(jms_message_type)} # 
tuple (tot_size, {...}
+    new_class = type(class_name, (JmsMessageTypeTestCase,), class_dict)
+    for send_shim, receive_shim in shim_product:
+        # Message without any headers or properties
+        add_test_method(new_class, ('', {}), ('', {}), send_shim, receive_shim)
+
+        # Iterate through message headers, add one test per header value, no 
combinations
+        # Structure: {HEADER_NAME_1; {header_type_1: [val_1_1, val_1_2, 
val_1_3, ...],
+        #                             header_type_2: [val_2_1, val_2_2, 
val_2_3, ...],
+        #                             ...
+        #                            },
+        #             ...
+        #            }
+        for msg_header, header_type_dict in types.HEADERS_MAP.iteritems():
+            for header_type, header_val_list in header_type_dict.iteritems():
+                hdr_val_cnt = 0
+                for header_val in header_val_list:
+                    hdr_val_cnt += 1
+                    test_name = '_hdr.%s.%s.%02d' % (msg_header[4:-7], 
header_type, hdr_val_cnt)
+                    add_test_method(new_class,
+                                    (test_name, {msg_header: {header_type: 
header_val}}),
+                                    ('', {}),
+                                    send_shim,
+                                    receive_shim)
+
+        # One message with all the headers together using type[0] and val[0]
+        all_hdrs = {}
+        for msg_header in types.HEADERS_MAP.iterkeys():
+            header_type_dict = types.HEADERS_MAP[msg_header]
+            header_type, header_val_list = header_type_dict.iteritems().next()
+            header_val = header_val_list[0]
+            all_hdrs[msg_header] = {header_type: header_val}
+        add_test_method(new_class, ('_hdrs', all_hdrs), ('', {}), send_shim, 
receive_shim)
+
+        # Properties tests disabled until PROTON-1284 fixed
+        ## Iterate through properties
+        ## Structure: {prop_type_1: [val_1_1, val_1_2, ...],
+        ##             prop_type_2: [val_2_1, val_2_2, ...],
+        ##             ...
+        ##            }
+        #all_props = {}
+        #for prop_type, prop_val_list in types.PROPERTIES_MAP.iteritems():
+        #    prop_val_cnt = 0
+        #    for prop_val in prop_val_list:
+        #        prop_val_cnt += 1
+        #        all_props['%s_%02d' % (prop_type, prop_val_cnt)] = 
{prop_type: prop_val}
+
+        ## One message with all properties together
+        #add_test_method(new_class, ('', {}), ('_props', all_props), 
send_shim, receive_shim)
+
+        ## One message with all headers and all properties together
+        #add_test_method(new_class, ('_hdrs', all_hdrs), ('_props', 
all_props), send_shim, receive_shim)
+
+    return new_class
+
+
+PROTON_CPP_RECEIVER_SHIM = path.join(QPID_INTEROP_TEST_HOME, 'shims', 
'qpid-proton-cpp', 'build', 'jms_messages_test',
+                                     'Receiver')
+PROTON_CPP_SENDER_SHIM = path.join(QPID_INTEROP_TEST_HOME, 'shims', 
'qpid-proton-cpp', 'build', 'jms_messages_test',
+                                   'Sender')
+PROTON_PYTHON_RECEIVER_SHIM = path.join(QPID_INTEROP_TEST_HOME, 'shims', 
'qpid-proton-python', 'src', 'jms_messages_test',
+                                        'Receiver.py')
+PROTON_PYTHON_SENDER_SHIM = path.join(QPID_INTEROP_TEST_HOME, 'shims', 
'qpid-proton-python', 'src', 'jms_messages_test',
+                                      'Sender.py')
+QIT_JMS_CLASSPATH_FILE = path.join(QPID_INTEROP_TEST_HOME, 'shims', 
'qpid-jms', 'cp.txt')
+with open(QIT_JMS_CLASSPATH_FILE, 'r') as classpath_file:
+    QIT_JMS_CLASSPATH = classpath_file.read()
+QPID_JMS_RECEIVER_SHIM = 
'org.apache.qpid.interop_test.jms_messages_test.Receiver'
+QPID_JMS_SENDER_SHIM = 'org.apache.qpid.interop_test.jms_messages_test.Sender'
+
+# SHIM_MAP contains an instance of each client language shim that is to be 
tested as a part of this test. For
+# every shim in this list, a test is dynamically constructed which tests it 
against itself as well as every
+# other shim in the list.
+#
+# As new shims are added, add them into this map to have them included in the 
test cases.
+SHIM_MAP = {shims.ProtonCppShim.NAME: 
shims.ProtonCppShim(PROTON_CPP_SENDER_SHIM, PROTON_CPP_RECEIVER_SHIM),
+            shims.ProtonPythonShim.NAME: 
shims.ProtonPythonShim(PROTON_PYTHON_SENDER_SHIM, PROTON_PYTHON_RECEIVER_SHIM),
+            shims.QpidJmsShim.NAME: shims.QpidJmsShim(QIT_JMS_CLASSPATH, 
QPID_JMS_SENDER_SHIM, QPID_JMS_RECEIVER_SHIM),
+           }
+
+# TODO: Complete the test options to give fine control over running tests
+class TestOptions(object):
+    """
+    Class controlling command-line arguments used to control the test.
+    """
+    def __init__(self,):
+        parser = argparse.ArgumentParser(description='Qpid-interop AMQP client 
interoparability test suite '
+                                         'for JMS message types')
+        parser.add_argument('--broker', action='store', 
default='localhost:5672', metavar='BROKER:PORT',
+                            help='Broker against which to run test suite.')
+#        test_group = parser.add_mutually_exclusive_group()
+#        test_group.add_argument('--include-test', action='append', 
metavar='TEST-NAME',
+#                                help='Name of test to include')
+#        test_group.add_argument('--exclude-test', action='append', 
metavar='TEST-NAME',
+#                                help='Name of test to exclude')
+#        type_group = test_group.add_mutually_exclusive_group()
+#        type_group.add_argument('--include-type', action='append', 
metavar='AMQP-TYPE',
+#                                help='Name of AMQP type to include. Supported 
types:\n%s' %
+#                                sorted(JmsMessageTypes.TYPE_MAP.keys()))
+        parser.add_argument('--exclude-type', action='append', 
metavar='JMS-MESSAGE-TYPE',
+                            help='Name of JMS message type to exclude. 
Supported types:\n%s' %
+                            sorted(JmsMessageTypes.TYPE_MAP.keys()))
+#        shim_group = test_group.add_mutually_exclusive_group()
+#        shim_group.add_argument('--include-shim', action='append', 
metavar='SHIM-NAME',
+#                                help='Name of shim to include. Supported 
shims:\n%s' % sorted(SHIM_MAP.keys()))
+        parser.add_argument('--exclude-shim', action='append', 
metavar='SHIM-NAME',
+                            help='Name of shim to exclude. Supported 
shims:\n%s' % sorted(SHIM_MAP.keys()))
+        self.args = parser.parse_args()
+
+
+#--- Main program start ---
+
+if __name__ == '__main__':
+    ARGS = TestOptions().args
+    #print 'ARGS:', ARGS # debug
+
+    # Connect to broker to find broker type
+    CONNECTION_PROPS = broker_properties.getBrokerProperties(ARGS.broker)
+    if CONNECTION_PROPS is None:
+        print 'WARNING: Unable to get connection properties - unknown broker'
+        BROKER = 'unknown'
+    else:
+        BROKER = CONNECTION_PROPS[symbol(u'product')] if symbol(u'product') in 
CONNECTION_PROPS \
+                 else '<product not found>'
+        BROKER_VERSION = CONNECTION_PROPS[symbol(u'version')] if 
symbol(u'version') in CONNECTION_PROPS \
+                         else '<version not found>'
+        BROKER_PLATFORM = CONNECTION_PROPS[symbol(u'platform')] if 
symbol(u'platform') in CONNECTION_PROPS \
+                          else '<platform not found>'
+        print 'Test Broker: %s v.%s on %s' % (BROKER, BROKER_VERSION, 
BROKER_PLATFORM)
+        print
+        stdout.flush()
+
+    TYPES = JmsMessageTypes()
+
+    # TEST_CASE_CLASSES is a list that collects all the test classes that are 
constructed. One class is constructed
+    # per AMQP type used as the key in map JmsMessageTypes.TYPE_MAP.
+    TEST_CASE_CLASSES = []
+
+    # TEST_SUITE is the final suite of tests that will be run and which 
contains all the dynamically created
+    # type classes, each of which contains a test for the combinations of 
client shims
+    TEST_SUITE = unittest.TestSuite()
+
+    # Remove shims excluded from the command-line
+    if ARGS.exclude_shim is not None:
+        for shim in ARGS.exclude_shim:
+            SHIM_MAP.pop(shim)
+    # Create test classes dynamically
+    for jmt in sorted(TYPES.get_type_list()):
+        if ARGS.exclude_type is None or jmt not in ARGS.exclude_type:
+            test_case_class = create_testcase_class(BROKER,
+                                                    TYPES,
+                                                    ARGS.broker,
+                                                    jmt,
+                                                    product(SHIM_MAP.values(), 
repeat=2))
+            TEST_CASE_CLASSES.append(test_case_class)
+            TEST_SUITE.addTest(unittest.makeSuite(test_case_class))
+
+    # Finally, run all the dynamically created tests
+    RES = unittest.TextTestRunner(verbosity=2).run(TEST_SUITE)
+    if not RES.wasSuccessful():
+        sys.exit(1)


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to