You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by kp...@apache.org on 2016/10/07 16:50:40 UTC
[1/5] qpid-interop-test git commit: QPIDIT-41: Reorganized dir
structure and tidied up the test code. Copied the old jms_messages_test to a
new jms_hdrs_props_test and simplified the jms_messages_test to include only
message body tests. Simplified parame
Repository: qpid-interop-test
Updated Branches:
refs/heads/master 83b89fe40 -> 514bac751
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/src/python/qpid_interop_test/jms_hdrs_props_test.py
----------------------------------------------------------------------
diff --git a/src/python/qpid_interop_test/jms_hdrs_props_test.py b/src/python/qpid_interop_test/jms_hdrs_props_test.py
new file mode 100755
index 0000000..134f465
--- /dev/null
+++ b/src/python/qpid_interop_test/jms_hdrs_props_test.py
@@ -0,0 +1,520 @@
+#!/usr/bin/env python
+
+"""
+Module to test JMS headers and properties
+"""
+
+#
+# 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 proton import symbol
+import qpid_interop_test.broker_properties
+import qpid_interop_test.shims
+from qpid_interop_test.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(qpid_interop_test.shims.THREAD_TIMEOUT)
+ receiver.join_or_kill(qpid_interop_test.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' % (send_shim.NAME, 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) == 2:
+ return_jms_message_type, return_list = receive_obj
+ if (len(return_list) == 3):
+ return_test_values = return_list[0]
+ return_msg_hdrs = return_list[1]
+ return_msg_props = return_list[2]
+ 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('Return value list needs 3 items, found %d items: %s' % (len(return_list),
+ str(return_list)))
+ 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_hdrs_props_test',
+ 'Receiver')
+PROTON_CPP_SENDER_SHIM = path.join(QPID_INTEROP_TEST_HOME, 'shims', 'qpid-proton-cpp', 'build', 'jms_hdrs_props_test',
+ 'Sender')
+PROTON_PYTHON_RECEIVER_SHIM = path.join(QPID_INTEROP_TEST_HOME, 'shims', 'qpid-proton-python', 'src',
+ 'jms_hdrs_props_test', 'Receiver.py')
+PROTON_PYTHON_SENDER_SHIM = path.join(QPID_INTEROP_TEST_HOME, 'shims', 'qpid-proton-python', 'src',
+ 'jms_hdrs_props_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_hdrs_props_test.Receiver'
+QPID_JMS_SENDER_SHIM = 'org.apache.qpid.interop_test.jms_hdrs_props_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 = {qpid_interop_test.shims.ProtonCppShim.NAME: \
+ qpid_interop_test.shims.ProtonCppShim(PROTON_CPP_SENDER_SHIM, PROTON_CPP_RECEIVER_SHIM),
+ qpid_interop_test.shims.ProtonPythonShim.NAME: \
+ qpid_interop_test.shims.ProtonPythonShim(PROTON_PYTHON_SENDER_SHIM, PROTON_PYTHON_RECEIVER_SHIM),
+ qpid_interop_test.shims.QpidJmsShim.NAME: \
+ qpid_interop_test.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 = qpid_interop_test.broker_properties.get_broker_properties(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
+ sys.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/514bac75/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..8de22b2
--- /dev/null
+++ b/src/python/qpid_interop_test/jms_messages_test.py
@@ -0,0 +1,402 @@
+#!/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 proton import symbol
+import qpid_interop_test.broker_properties
+import qpid_interop_test.shims
+from qpid_interop_test.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)
+
+ 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, 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])
+ # Start the receiver shim
+ receiver = receive_shim.create_receiver(broker_addr, queue_name, jms_message_type, dumps(num_test_values_map))
+ receiver.start()
+
+ # Start the send shim
+ sender = send_shim.create_sender(broker_addr, queue_name, jms_message_type, dumps(test_values))
+ sender.start()
+
+ # Wait for both shims to finish
+ sender.join_or_kill(qpid_interop_test.shims.THREAD_TIMEOUT)
+ receiver.join_or_kill(qpid_interop_test.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' % (send_shim.NAME, 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) == 2:
+ return_jms_message_type, return_test_values = 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))
+ else:
+ self.fail('Received incorrect tuple format: %s' % str(receive_obj))
+ else:
+ self.fail('Received non-tuple: %s' % 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, 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,
+ send_shim,
+ receive_shim)
+
+ inner_test_method.__name__ = 'test_%s_%s->%s' % (jms_message_type[4:-5], 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:
+ add_test_method(new_class, 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 = {qpid_interop_test.shims.ProtonCppShim.NAME: \
+ qpid_interop_test.shims.ProtonCppShim(PROTON_CPP_SENDER_SHIM, PROTON_CPP_RECEIVER_SHIM),
+ qpid_interop_test.shims.ProtonPythonShim.NAME: \
+ qpid_interop_test.shims.ProtonPythonShim(PROTON_PYTHON_SENDER_SHIM, PROTON_PYTHON_RECEIVER_SHIM),
+ qpid_interop_test.shims.QpidJmsShim.NAME: \
+ qpid_interop_test.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 = qpid_interop_test.broker_properties.get_broker_properties(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
+ sys.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/514bac75/src/python/qpid_interop_test/shims.py
----------------------------------------------------------------------
diff --git a/src/python/qpid_interop_test/shims.py b/src/python/qpid_interop_test/shims.py
new file mode 100644
index 0000000..f6d019e
--- /dev/null
+++ b/src/python/qpid_interop_test/shims.py
@@ -0,0 +1,227 @@
+"""
+Module containing worker thread classes and shims
+"""
+#
+# 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.
+#
+
+from json import loads
+from os import getenv, getpgid, killpg, path, setsid
+from signal import SIGKILL, SIGTERM
+from subprocess import Popen, PIPE, CalledProcessError
+from sys import stdout
+from threading import Thread
+from time import sleep
+
+
+THREAD_TIMEOUT = 10.0 # seconds to complete before join is forced
+
+
+class ShimWorkerThread(Thread):
+ """Parent class for shim worker threads and return a string once the thread has ended"""
+ def __init__(self, thread_name):
+ super(ShimWorkerThread, self).__init__(name=thread_name)
+ self.arg_list = []
+ self.return_obj = None
+ self.proc = None
+
+ def get_return_object(self):
+ """Get the return object from the completed thread"""
+ return self.return_obj
+
+ def join_or_kill(self, timeout):
+ """
+ Wait for thread to join after timeout (seconds). If still alive, it is then terminated, then if still alive,
+ killed
+ """
+ self.join(timeout)
+ if self.is_alive():
+ if self.proc is not None:
+ if self._terminate_pg_loop():
+ if self._kill_pg_loop():
+ print '\n ERROR: Thread %s (pid=%d) alive after kill' % (self.name, self.proc.pid)
+ else:
+ print 'Killed'
+ stdout.flush()
+ else:
+ print 'Terminated'
+ stdout.flush()
+ else:
+ print 'ERROR: shims.join_or_kill(): Process joined and is alive, yet proc is None.'
+
+ def _terminate_pg_loop(self, num_attempts=2, wait_time=2):
+ cnt = 0
+ while cnt < num_attempts and self.is_alive():
+ cnt += 1
+ print '\n Thread %s (pid=%d) alive after timeout, terminating (try #%d)...' % (self.name, self.proc.pid,
+ cnt),
+ stdout.flush()
+ killpg(getpgid(self.proc.pid), SIGTERM)
+ sleep(wait_time)
+ return self.is_alive()
+
+ def _kill_pg_loop(self, num_attempts=2, wait_time=5):
+ cnt = 0
+ while cnt < num_attempts and self.is_alive():
+ cnt += 1
+ print '\n Thread %s (pid=%d) alive after terminate, killing (try #%d)...' % (self.name, self.proc.pid,
+ cnt),
+ stdout.flush()
+ killpg(getpgid(self.proc.pid), SIGKILL)
+ sleep(wait_time)
+ return self.is_alive()
+
+
+class Sender(ShimWorkerThread):
+ """Sender class for multi-threaded send"""
+ def __init__(self, use_shell_flag, send_shim_args, broker_addr, queue_name, msg_type, json_test_str):
+ super(Sender, self).__init__('sender_thread_%s' % queue_name)
+ if send_shim_args is None:
+ print 'ERROR: Sender: send_shim_args == None'
+ self.use_shell_flag = use_shell_flag
+ self.arg_list.extend(send_shim_args)
+ self.arg_list.extend([broker_addr, queue_name, msg_type, json_test_str])
+
+ def run(self):
+ """Thread starts here"""
+ try:
+ #print '\n>>>', self.arg_list # DEBUG - useful to see command-line sent to shim
+ self.proc = Popen(self.arg_list, stdout=PIPE, stderr=PIPE, shell=self.use_shell_flag, preexec_fn=setsid)
+ (stdoutdata, stderrdata) = self.proc.communicate()
+ if len(stdoutdata) > 0 or len(stderrdata) > 0:
+ self.return_obj = (stdoutdata, stderrdata)
+ except CalledProcessError as exc:
+ self.return_obj = str(exc) + '\n\nOutput:\n' + exc.output
+
+
+class Receiver(ShimWorkerThread):
+ """Receiver class for multi-threaded receive"""
+ def __init__(self, receive_shim_args, broker_addr, queue_name, msg_type, json_test_str):
+ super(Receiver, self).__init__('receiver_thread_%s' % queue_name)
+ if receive_shim_args is None:
+ print 'ERROR: Receiver: receive_shim_args == None'
+ self.arg_list.extend(receive_shim_args)
+ self.arg_list.extend([broker_addr, queue_name, msg_type, json_test_str])
+
+ def run(self):
+ """Thread starts here"""
+ try:
+ #print '\n>>>', self.arg_list # DEBUG - useful to see command-line sent to shim
+ self.proc = Popen(self.arg_list, stdout=PIPE, stderr=PIPE, preexec_fn=setsid)
+ (stdoutdata, stderrdata) = self.proc.communicate()
+ if len(stderrdata) > 0:
+ self.return_obj = (stdoutdata, stderrdata)
+ else:
+ #print '<<<', stdoutdata # DEBUG - useful to see text received from shim
+ str_tvl = stdoutdata.split('\n')[0:-1] # remove trailing \n
+ #if len(str_tvl) == 1:
+ # self.return_obj = output
+ if len(str_tvl) == 2:
+ self.return_obj = (str_tvl[0], loads(str_tvl[1]))
+ else: # Make a single line of all the bits and return that
+ #self.return_obj = loads("".join(str_tvl[1:]))
+ self.return_obj = stdoutdata
+ except CalledProcessError as exc:
+ self.return_obj = str(exc) + '\n\n' + exc.output
+
+class Shim(object):
+ """Abstract shim class, parent of all shims."""
+ NAME = None
+ def __init__(self, sender_shim, receiver_shim):
+ self.sender_shim = sender_shim
+ self.receiver_shim = receiver_shim
+ self.send_params = None
+ self.receive_params = None
+ self.use_shell_flag = False
+
+ def create_sender(self, broker_addr, queue_name, msg_type, json_test_str):
+ """Create a new sender instance"""
+ return Sender(self.use_shell_flag, self.send_params, broker_addr, queue_name, msg_type, json_test_str)
+
+ def create_receiver(self, broker_addr, queue_name, msg_type, json_test_str):
+ """Create a new receiver instance"""
+ return Receiver(self.receive_params, broker_addr, queue_name, msg_type, json_test_str)
+
+class ProtonPythonShim(Shim):
+ """Shim for qpid-proton Python client"""
+ NAME = 'ProtonPython'
+ def __init__(self, sender_shim, receiver_shim):
+ super(ProtonPythonShim, self).__init__(sender_shim, receiver_shim)
+ self.send_params = [self.sender_shim]
+ self.receive_params = [self.receiver_shim]
+
+
+class ProtonCppShim(Shim):
+ """Shim for qpid-proton C++ client"""
+ NAME = 'ProtonCpp'
+ def __init__(self, sender_shim, receiver_shim):
+ super(ProtonCppShim, self).__init__(sender_shim, receiver_shim)
+ self.send_params = [self.sender_shim]
+ self.receive_params = [self.receiver_shim]
+
+
+class QpidJmsShim(Shim):
+ """Shim for qpid-jms JMS client"""
+ NAME = 'QpidJms'
+
+ # Installed versions
+ # TODO: Automate this - it gets out of date quickly
+ # Maven works out all the deps, should use that
+ QPID_JMS_SHIM_VER = '0.1.0-SNAPSHOT'
+ QPID_JMS_VER = '0.20.0-SNAPSHOT'
+ QPID_PROTON_J_VER = '0.15.0-SNAPSHOT'
+ JMS_API_VER = '1.1.1'
+ LOGGER_API_VER = '1.7.21'
+ LOGGER_IMPL_VER = '1.7.21'
+ NETTY_VER = '4.0.40.Final'
+
+ # Classpath components
+ #QPID_INTEROP_TEST_SHIM_JAR = path.join(QPID_INTEROP_TEST_HOME, 'shims', 'qpid-jms', 'target', 'qpid-jms-shim.jar')
+ MAVEN_REPO_PATH = path.join(getenv('HOME'), '.m2', 'repository')
+ JMS_API_JAR = path.join(MAVEN_REPO_PATH, 'org', 'apache', 'geronimo', 'specs', 'geronimo-jms_1.1_spec', JMS_API_VER,
+ 'geronimo-jms_1.1_spec-%s.jar' % JMS_API_VER)
+ JMS_IMPL_JAR = path.join(MAVEN_REPO_PATH, 'org', 'apache', 'qpid', 'qpid-jms-client', QPID_JMS_VER,
+ 'qpid-jms-client-%s.jar' % QPID_JMS_VER)
+ LOGGER_API_JAR = path.join(MAVEN_REPO_PATH, 'org', 'slf4j', 'slf4j-api', LOGGER_API_VER,
+ 'slf4j-api-%s.jar' % LOGGER_API_VER)
+ LOGGER_IMPL_JAR = path.join(MAVEN_REPO_PATH, 'org', 'slf4j', 'slf4j-nop', LOGGER_IMPL_VER,
+ 'slf4j-nop-%s.jar' % LOGGER_IMPL_VER)
+ PROTON_J_JAR = path.join(MAVEN_REPO_PATH, 'org', 'apache', 'qpid', 'proton-j', QPID_PROTON_J_VER,
+ 'proton-j-%s.jar' % QPID_PROTON_J_VER)
+ NETTY_JAR = path.join(MAVEN_REPO_PATH, 'io', 'netty', 'netty-all', NETTY_VER, 'netty-all-%s.jar' % NETTY_VER)
+ QPID_JMS_SHIM_JAR = path.join(MAVEN_REPO_PATH, 'org', 'apache', 'qpid', 'qpid-interop-test-jms-shim',
+ QPID_JMS_SHIM_VER, 'qpid-interop-test-jms-shim-%s.jar' % QPID_JMS_SHIM_VER)
+
+ JAVA_HOME = getenv('JAVA_HOME', '/usr/bin') # Default only works in Linux
+ JAVA_EXEC = path.join(JAVA_HOME, 'java')
+
+ def __init__(self, dependency_class_path, sender_shim, receiver_shim):
+ super(QpidJmsShim, self).__init__(sender_shim, receiver_shim)
+ self.dependency_class_path = dependency_class_path
+ self.send_params = [self.JAVA_EXEC, '-cp', self.get_java_class_path(), self.sender_shim]
+ self.receive_params = [self.JAVA_EXEC, '-cp', self.get_java_class_path(), self.receiver_shim]
+
+ def get_java_class_path(self):
+ """Method to construct and return the Java class path necessary to run the shim"""
+ return ':'.join([self.QPID_JMS_SHIM_JAR, self.dependency_class_path])
+ # self.JMS_API_JAR,
+ # self.JMS_IMPL_JAR,
+ # self.LOGGER_API_JAR,
+ # self.LOGGER_IMPL_JAR,
+ # self.PROTON_J_JAR,
+ # self.NETTY_JAR])
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/src/python/qpid_interop_test/test_type_map.py
----------------------------------------------------------------------
diff --git a/src/python/qpid_interop_test/test_type_map.py b/src/python/qpid_interop_test/test_type_map.py
new file mode 100644
index 0000000..0fd4552
--- /dev/null
+++ b/src/python/qpid_interop_test/test_type_map.py
@@ -0,0 +1,86 @@
+"""
+Module containing Error classes for interop testing
+"""
+#
+# 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.
+#
+
+class TestTypeMap(object):
+ """
+ Class which contains all the described types and the test values to be used in testing against those types.
+ """
+
+ # TYPE_MAP: Map containing all described types as the indecies, and a list of values to be used in testing
+ # that type as a list of values.
+ #
+ # Format: {'type_1' : [val_1_1, val_1_2, ...],
+ # 'type_2' : [val_2_1, val_2_2, ...],
+ # ...
+ # }
+ TYPE_MAP = {}
+
+ # BROKER_SKIP: For know broker issues where a type would cause a test to fail or hang,
+ # entries in BROKER_SKIP will cause the test to be skipped with a message.
+ # This is a map containing AMQP types as a key, and a list of brokers for which this
+ # type should be skipped.
+ # Format: {'jms_msg_type_1' : {'broker_1' : 'skip msg for broker_1',
+ # 'broker_2' : 'skip msg for broker_2',
+ # ...
+ # },
+ # 'jms_msg_type_2' : {'broker_1' : 'skip msg for broker_1',
+ # 'broker_2' : 'skip msg for broker_2',
+ # ...
+ # },
+ # ...
+ # }
+ # where broker_1, broker_2, ... are broker product names as defined by the
+ # connection property string it returns.
+ BROKER_SKIP = {}
+
+ def __init__(self):
+ pass
+
+ def get_type_list(self):
+ """Return a list of types which this test suite supports"""
+ return self.TYPE_MAP.keys()
+
+ def get_test_values(self, test_type):
+ """Return test values to use when testing the supplied type."""
+ if test_type not in self.TYPE_MAP.keys():
+ return None
+ return self.TYPE_MAP[test_type]
+
+ def skip_test_message(self, test_type, broker_name):
+ """Return the message to use if a test is skipped"""
+ if test_type in self.BROKER_SKIP.keys():
+ if broker_name in self.BROKER_SKIP[test_type]:
+ return str(self.BROKER_SKIP[test_type][broker_name])
+ return None
+
+ def skip_test(self, test_type, broker_name):
+ """Return boolean True if test should be skipped"""
+ return test_type in self.BROKER_SKIP.keys() and \
+ broker_name in self.BROKER_SKIP[test_type]
+
+ @staticmethod
+ def merge_dicts(*dict_args):
+ """Static method to merge two or more dictionaries"""
+ res = {}
+ for this_dict in dict_args:
+ res.update(this_dict)
+ return res
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[4/5] qpid-interop-test git commit: QPIDIT-41: Reorganized dir
structure and tidied up the test code. Copied the old jms_messages_test to a
new jms_hdrs_props_test and simplified the jms_messages_test to include only
message body tests. Simplified parame
Posted by kp...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/shims/qpid-proton-cpp/src/qpidit/jms_hdrs_props_test/Receiver.cpp
----------------------------------------------------------------------
diff --git a/shims/qpid-proton-cpp/src/qpidit/jms_hdrs_props_test/Receiver.cpp b/shims/qpid-proton-cpp/src/qpidit/jms_hdrs_props_test/Receiver.cpp
new file mode 100644
index 0000000..19a40ed
--- /dev/null
+++ b/shims/qpid-proton-cpp/src/qpidit/jms_hdrs_props_test/Receiver.cpp
@@ -0,0 +1,396 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "qpidit/jms_hdrs_props_test/Receiver.hpp"
+
+#include <iostream>
+#include <json/json.h>
+#include "proton/connection.hpp"
+#include "proton/default_container.hpp"
+#include "proton/delivery.hpp"
+#include "proton/transport.hpp"
+#include "qpidit/QpidItErrors.hpp"
+
+namespace qpidit
+{
+ namespace jms_hdrs_props_test
+ {
+ Receiver::Receiver(const std::string& brokerUrl,
+ const std::string& jmsMessageType,
+ const Json::Value& testNumberMap,
+ const Json::Value& flagMap):
+ _brokerUrl(brokerUrl),
+ _jmsMessageType(jmsMessageType),
+ _testNumberMap(testNumberMap),
+ _flagMap(flagMap),
+ _subTypeList(testNumberMap.getMemberNames()),
+ _subTypeIndex(0),
+ _expected(getTotalNumExpectedMsgs(testNumberMap)),
+ _received(0UL),
+ _receivedSubTypeList(Json::arrayValue),
+ _receivedValueMap(Json::objectValue),
+ _receivedHeadersMap(Json::objectValue),
+ _receivedPropertiesMap(Json::objectValue)
+ {}
+
+ Receiver::~Receiver() {}
+
+ Json::Value& Receiver::getReceivedValueMap() {
+ return _receivedValueMap;
+ }
+
+ Json::Value& Receiver::getReceivedHeadersMap() {
+ return _receivedHeadersMap;
+ }
+
+ Json::Value& Receiver::getReceivedPropertiesMap() {
+ return _receivedPropertiesMap;
+ }
+
+ void Receiver::on_container_start(proton::container &c) {
+ c.open_receiver(_brokerUrl);
+ }
+
+ void Receiver::on_message(proton::delivery &d, proton::message &m) {
+ try {
+ if (_received < _expected) {
+ int8_t t = qpidit::JMS_MESSAGE_TYPE;
+ try {t = m.message_annotations().get(proton::symbol("x-opt-jms-msg-type")).get<int8_t>();}
+ catch (const std::exception& e) {
+ std::cout << "JmsReceiver::on_message(): Missing annotation \"x-opt-jms-msg-type\"" << std::endl;
+ throw;
+ }
+ switch (t) {
+ case qpidit::JMS_MESSAGE_TYPE:
+ receiveJmsMessage(m);
+ break;
+ case qpidit::JMS_OBJECTMESSAGE_TYPE:
+ receiveJmsObjectMessage(m);
+ break;
+ case qpidit::JMS_MAPMESSAGE_TYPE:
+ receiveJmsMapMessage(m);
+ break;
+ case qpidit::JMS_BYTESMESSAGE_TYPE:
+ receiveJmsBytesMessage(m);
+ break;
+ case qpidit::JMS_STREAMMESSAGE_TYPE:
+ receiveJmsStreamMessage(m);
+ break;
+ case qpidit::JMS_TEXTMESSAGE_TYPE:
+ receiveJmsTextMessage(m);
+ break;
+ default:;
+ // TODO: handle error - unknown JMS message type
+ }
+
+ processMessageHeaders(m);
+ processMessageProperties(m);
+
+ std::string subType(_subTypeList[_subTypeIndex]);
+ // Increment the subtype if the required number of messages have been received
+ if (_receivedSubTypeList.size() >= _testNumberMap[subType].asInt() &&
+ _subTypeIndex < _testNumberMap.size()) {
+ _receivedValueMap[subType] = _receivedSubTypeList;
+ _receivedSubTypeList.clear();
+ ++_subTypeIndex;
+ }
+ _received++;
+ if (_received >= _expected) {
+ d.receiver().close();
+ d.connection().close();
+ }
+ }
+ } catch (const std::exception&) {
+ d.receiver().close();
+ d.connection().close();
+ throw;
+ }
+ }
+
+ //static
+ uint32_t Receiver::getTotalNumExpectedMsgs(const Json::Value testNumberMap) {
+ uint32_t total(0UL);
+ for (Json::Value::const_iterator i=testNumberMap.begin(); i!=testNumberMap.end(); ++i) {
+ total += (*i).asUInt();
+ }
+ return total;
+
+ }
+
+ // protected
+
+ void Receiver::receiveJmsMessage(const proton::message& msg) {
+ _receivedSubTypeList.append(Json::Value());
+ }
+
+ void Receiver::receiveJmsObjectMessage(const proton::message& msg) {
+ // TODO
+ }
+
+ void Receiver::receiveJmsMapMessage(const proton::message& msg) {
+ if(_jmsMessageType.compare("JMS_MAPMESSAGE_TYPE") != 0) {
+ throw qpidit::IncorrectMessageBodyTypeError(_jmsMessageType, "JMS_MAPMESSAGE_TYPE");
+ }
+ std::string subType(_subTypeList[_subTypeIndex]);
+ std::map<std::string, proton::value> m;
+ msg.body().get(m);
+ for (std::map<std::string, proton::value>::const_iterator i=m.begin(); i!=m.end(); ++i) {
+ std::string key = i->first;
+ if (subType.compare(key.substr(0, key.size()-3)) != 0) {
+ throw qpidit::IncorrectJmsMapKeyPrefixError(subType, key);
+ }
+ proton::value val = i->second;
+ if (subType.compare("boolean") == 0) {
+ _receivedSubTypeList.append(val.get<bool>() ? Json::Value("True") : Json::Value("False"));
+ } else if (subType.compare("byte") == 0) {
+ _receivedSubTypeList.append(Json::Value(toHexStr<int8_t>(val.get<int8_t>())));
+ } else if (subType.compare("bytes") == 0) {
+ _receivedSubTypeList.append(Json::Value(std::string(val.get<proton::binary>())));
+ } else if (subType.compare("char") == 0) {
+ std::ostringstream oss;
+ oss << (char)val.get<wchar_t>();
+ _receivedSubTypeList.append(Json::Value(oss.str()));
+ } else if (subType.compare("double") == 0) {
+ double d = val.get<double>();
+ _receivedSubTypeList.append(Json::Value(toHexStr<int64_t>(*((int64_t*)&d), true, false)));
+ } else if (subType.compare("float") == 0) {
+ float f = val.get<float>();
+ _receivedSubTypeList.append(Json::Value(toHexStr<int32_t>(*((int32_t*)&f), true, false)));
+ } else if (subType.compare("int") == 0) {
+ _receivedSubTypeList.append(Json::Value(toHexStr<int32_t>(val.get<int32_t>())));
+ } else if (subType.compare("long") == 0) {
+ _receivedSubTypeList.append(Json::Value(toHexStr<int64_t>(val.get<int64_t>())));
+ } else if (subType.compare("short") == 0) {
+ _receivedSubTypeList.append(Json::Value(toHexStr<int16_t>(val.get<int16_t>())));
+ } else if (subType.compare("string") == 0) {
+ _receivedSubTypeList.append(Json::Value(val.get<std::string>()));
+ } else {
+ throw qpidit::UnknownJmsMessageSubTypeError(subType);
+ }
+ }
+ }
+
+ void Receiver::receiveJmsBytesMessage(const proton::message& msg) {
+ if(_jmsMessageType.compare("JMS_BYTESMESSAGE_TYPE") != 0) {
+ throw qpidit::IncorrectMessageBodyTypeError(_jmsMessageType, "JMS_BYTESMESSAGE_TYPE");
+ }
+ std::string subType(_subTypeList[_subTypeIndex]);
+ proton::binary body = msg.body().get<proton::binary>();
+ if (subType.compare("boolean") == 0) {
+ if (body.size() != 1) throw IncorrectMessageBodyLengthError("JmsReceiver::receiveJmsBytesMessage, subType=boolean", 1, body.size());
+ _receivedSubTypeList.append(body[0] ? Json::Value("True") : Json::Value("False"));
+ } else if (subType.compare("byte") == 0) {
+ if (body.size() != sizeof(int8_t)) throw IncorrectMessageBodyLengthError("JmsReceiver::receiveJmsBytesMessage, subType=byte", sizeof(int8_t), body.size());
+ int8_t val = *((int8_t*)body.data());
+ _receivedSubTypeList.append(Json::Value(toHexStr<int8_t>(val)));
+ } else if (subType.compare("bytes") == 0) {
+ _receivedSubTypeList.append(Json::Value(std::string(body)));
+ } else if (subType.compare("char") == 0) {
+ if (body.size() != sizeof(uint16_t)) throw IncorrectMessageBodyLengthError("JmsReceiver::receiveJmsBytesMessage, subType=char", sizeof(uint16_t), body.size());
+ // TODO: This is ugly: ignoring first byte - handle UTF-16 correctly
+ char c = body[1];
+ std::ostringstream oss;
+ oss << c;
+ _receivedSubTypeList.append(Json::Value(oss.str()));
+ } else if (subType.compare("double") == 0) {
+ if (body.size() != sizeof(int64_t)) throw IncorrectMessageBodyLengthError("JmsReceiver::receiveJmsBytesMessage, subType=double", sizeof(int64_t), body.size());
+ int64_t val = be64toh(*((int64_t*)body.data()));
+ _receivedSubTypeList.append(Json::Value(toHexStr<int64_t>(val, true, false)));
+ } else if (subType.compare("float") == 0) {
+ if (body.size() != sizeof(int32_t)) throw IncorrectMessageBodyLengthError("JmsReceiver::receiveJmsBytesMessage, subType=float", sizeof(int32_t), body.size());
+ int32_t val = be32toh(*((int32_t*)body.data()));
+ _receivedSubTypeList.append(Json::Value(toHexStr<int32_t>(val, true, false)));
+ } else if (subType.compare("long") == 0) {
+ if (body.size() != sizeof(int64_t)) throw IncorrectMessageBodyLengthError("JmsReceiver::receiveJmsBytesMessage, subType=long", sizeof(int64_t), body.size());
+ int64_t val = be64toh(*((int64_t*)body.data()));
+ _receivedSubTypeList.append(Json::Value(toHexStr<int64_t>(val)));
+ } else if (subType.compare("int") == 0) {
+ if (body.size() != sizeof(int32_t)) throw IncorrectMessageBodyLengthError("JmsReceiver::receiveJmsBytesMessage, subType=int", sizeof(int32_t), body.size());
+ int32_t val = be32toh(*((int32_t*)body.data()));
+ _receivedSubTypeList.append(Json::Value(toHexStr<int32_t>(val)));
+ } else if (subType.compare("short") == 0) {
+ if (body.size() != sizeof(int16_t)) throw IncorrectMessageBodyLengthError("JmsReceiver::receiveJmsBytesMessage, subType=short", sizeof(int16_t), body.size());
+ int16_t val = be16toh(*((int16_t*)body.data()));
+ _receivedSubTypeList.append(Json::Value(toHexStr<int16_t>(val)));
+ } else if (subType.compare("string") == 0) {
+ // TODO: decode string size in first two bytes and check string size
+ _receivedSubTypeList.append(Json::Value(std::string(body).substr(2)));
+ } else {
+ throw qpidit::UnknownJmsMessageSubTypeError(subType);
+ }
+ }
+
+ void Receiver::receiveJmsStreamMessage(const proton::message& msg) {
+ if(_jmsMessageType.compare("JMS_STREAMMESSAGE_TYPE") != 0) {
+ throw qpidit::IncorrectMessageBodyTypeError(_jmsMessageType, "JMS_STREAMMESSAGE_TYPE");
+ }
+ std::string subType(_subTypeList[_subTypeIndex]);
+ std::vector<proton::value> l;
+ msg.body().get(l);
+ for (std::vector<proton::value>::const_iterator i=l.begin(); i!=l.end(); ++i) {
+ if (subType.compare("boolean") == 0) {
+ _receivedSubTypeList.append(i->get<bool>() ? Json::Value("True") : Json::Value("False"));
+ } else if (subType.compare("byte") == 0) {
+ _receivedSubTypeList.append(Json::Value(toHexStr<int8_t>(i->get<int8_t>())));
+ } else if (subType.compare("bytes") == 0) {
+ _receivedSubTypeList.append(Json::Value(std::string(i->get<proton::binary>())));
+ } else if (subType.compare("char") == 0) {
+ std::ostringstream oss;
+ oss << (char)i->get<wchar_t>();
+ _receivedSubTypeList.append(Json::Value(oss.str()));
+ } else if (subType.compare("double") == 0) {
+ double d = i->get<double>();
+ _receivedSubTypeList.append(Json::Value(toHexStr<int64_t>(*((int64_t*)&d), true, false)));
+ } else if (subType.compare("float") == 0) {
+ float f = i->get<float>();
+ _receivedSubTypeList.append(Json::Value(toHexStr<int32_t>(*((int32_t*)&f), true, false)));
+ } else if (subType.compare("int") == 0) {
+ _receivedSubTypeList.append(Json::Value(toHexStr<int32_t>(i->get<int32_t>())));
+ } else if (subType.compare("long") == 0) {
+ _receivedSubTypeList.append(Json::Value(toHexStr<int64_t>(i->get<int64_t>())));
+ } else if (subType.compare("short") == 0) {
+ _receivedSubTypeList.append(Json::Value(toHexStr<int16_t>(i->get<int16_t>())));
+ } else if (subType.compare("string") == 0) {
+ _receivedSubTypeList.append(Json::Value(i->get<std::string>()));
+ } else {
+ throw qpidit::UnknownJmsMessageSubTypeError(subType);
+ }
+ }
+
+ }
+
+ void Receiver::receiveJmsTextMessage(const proton::message& msg) {
+ if(_jmsMessageType.compare("JMS_TEXTMESSAGE_TYPE") != 0) {
+ throw qpidit::IncorrectMessageBodyTypeError(_jmsMessageType, "JMS_TEXTMESSAGE_TYPE");
+ }
+ _receivedSubTypeList.append(Json::Value(msg.body().get<std::string>()));
+ }
+
+ void Receiver::processMessageHeaders(const proton::message& msg) {
+ addMessageHeaderString("JMS_TYPE_HEADER", msg.subject());
+ if (_flagMap.isMember("JMS_CORRELATIONID_AS_BYTES") && _flagMap["JMS_CORRELATIONID_AS_BYTES"].asBool()) {
+ addMessageHeaderByteArray("JMS_CORRELATIONID_HEADER", proton::get<proton::binary>(msg.correlation_id()));
+ } else {
+ try {
+ addMessageHeaderString("JMS_CORRELATIONID_HEADER", proton::get<std::string>(msg.correlation_id()));
+ } catch (const std::exception& e) {} // TODO: UGLY, how do you check if there _is_ a correlation id?
+ }
+
+ std::string reply_to = msg.reply_to();
+ // Some brokers prepend 'queue://' and 'topic://' to reply_to addresses, strip these when present
+ if (_flagMap.isMember("JMS_REPLYTO_AS_TOPIC") && _flagMap["JMS_REPLYTO_AS_TOPIC"].asBool()) {
+ if (reply_to.find("topic://") == 0) {
+ addMessageHeaderDestination("JMS_REPLYTO_HEADER", qpidit::JMS_TOPIC, reply_to.substr(8));
+ } else {
+ addMessageHeaderDestination("JMS_REPLYTO_HEADER", qpidit::JMS_TOPIC, reply_to);
+ }
+ } else {
+ if (reply_to.find("queue://") == 0) {
+ addMessageHeaderDestination("JMS_REPLYTO_HEADER", qpidit::JMS_QUEUE, reply_to.substr(8));
+ } else {
+ addMessageHeaderDestination("JMS_REPLYTO_HEADER", qpidit::JMS_QUEUE, reply_to);
+ }
+ }
+ }
+
+ void Receiver::addMessageHeaderString(const char* headerName, const std::string& value) {
+ if (!value.empty()) { // TODO: Remove this test when PROTON-1288 is fixed as empty strings are allowed in headers
+ Json::Value valueMap(Json::objectValue);
+ valueMap["string"] = value;
+ _receivedHeadersMap[headerName] = valueMap;
+ }
+ }
+
+ void Receiver::addMessageHeaderByteArray(const std::string& headerName, const proton::binary ba) {
+ if (!ba.empty()) { // TODO: Remove this test when PROTON-1288 is fixed as empty binaries are allowed in headers
+ Json::Value valueMap(Json::objectValue);
+ valueMap["bytes"] = std::string(ba);
+ _receivedHeadersMap[headerName] = valueMap;
+ }
+ }
+
+ void Receiver::addMessageHeaderDestination(const std::string& headerName, qpidit::jmsDestinationType_t dt, const std::string& d) {
+ if (!d.empty()) {
+ Json::Value valueMap(Json::objectValue);
+ switch (dt) {
+ case qpidit::JMS_QUEUE:
+ valueMap["queue"] = d;
+ break;
+ case qpidit::JMS_TOPIC:
+ valueMap["topic"] = d;
+ break;
+ default:
+ ; // TODO: Handle error: remaining JMS destinations not handled.
+ }
+ _receivedHeadersMap[headerName] = valueMap;
+ }
+ }
+
+ void Receiver::processMessageProperties(const proton::message& msg) {
+ // TODO: Add this function when PROTON-1284 is fixed
+// std::map<proton::value, proton::value> props;
+// msg.properties().value() >> props;
+ }
+
+ } /* namespace jms_hdrs_props_test */
+} /* namespace qpidit */
+
+/* --- main ---
+ * Args: 1: Broker address (ip-addr:port)
+ * 2: Queue name
+ * 3: JMS message type
+ * 4: JSON Test parameters containing 2 maps: [testValuesMap, flagMap]
+ */
+int main(int argc, char** argv) {
+ /*
+ for (int i=0; i<argc; ++i) {
+ std::cout << "*** argv[" << i << "] : " << argv[i] << std::endl;
+ }
+ */
+ // TODO: improve arg management a little...
+ if (argc != 5) {
+ throw qpidit::ArgumentError("Incorrect number of arguments");
+ }
+
+ std::ostringstream oss;
+ oss << argv[1] << "/" << argv[2];
+
+ try {
+ Json::Value testParams;
+ Json::Reader jsonReader;
+ if (not jsonReader.parse(argv[4], testParams, false)) {
+ throw qpidit::JsonParserError(jsonReader);
+ }
+
+ qpidit::jms_hdrs_props_test::Receiver receiver(oss.str(), argv[3], testParams[0], testParams[1]);
+ proton::default_container(receiver).run();
+
+ Json::FastWriter fw;
+ std::cout << argv[3] << std::endl;
+ Json::Value returnList(Json::arrayValue);
+ returnList.append(receiver.getReceivedValueMap());
+ returnList.append(receiver.getReceivedHeadersMap());
+ returnList.append(receiver.getReceivedPropertiesMap());
+ std::cout << fw.write(returnList);
+ } catch (const std::exception& e) {
+ std::cout << "JmsReceiver error: " << e.what() << std::endl;
+ }
+}
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/shims/qpid-proton-cpp/src/qpidit/jms_hdrs_props_test/Receiver.hpp
----------------------------------------------------------------------
diff --git a/shims/qpid-proton-cpp/src/qpidit/jms_hdrs_props_test/Receiver.hpp b/shims/qpid-proton-cpp/src/qpidit/jms_hdrs_props_test/Receiver.hpp
new file mode 100644
index 0000000..36db58d
--- /dev/null
+++ b/shims/qpid-proton-cpp/src/qpidit/jms_hdrs_props_test/Receiver.hpp
@@ -0,0 +1,100 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#ifndef SRC_QPIDIT_JMS_HEADERS_PROPERTIES_TEST_RECEIVER_HPP_
+#define SRC_QPIDIT_JMS_HEADERS_PROPERTIES_TEST_RECEIVER_HPP_
+
+#include <iomanip>
+#include <json/value.h>
+#include "proton/messaging_handler.hpp"
+#include "proton/types.hpp"
+#include "qpidit/JmsTestBase.hpp"
+#include <sstream>
+
+namespace qpidit
+{
+ namespace jms_hdrs_props_test
+ {
+
+ class Receiver : public qpidit::JmsTestBase
+ {
+ protected:
+ const std::string _brokerUrl;
+ const std::string _jmsMessageType;
+ const Json::Value _testNumberMap;
+ const Json::Value _flagMap;
+ Json::Value::Members _subTypeList;
+ int _subTypeIndex;
+ uint32_t _expected;
+ uint32_t _received;
+ Json::Value _receivedSubTypeList;
+ Json::Value _receivedValueMap;
+ Json::Value _receivedHeadersMap;
+ Json::Value _receivedPropertiesMap;
+ public:
+ Receiver(const std::string& brokerUrl,
+ const std::string& jmsMessageType,
+ const Json::Value& testNumberMap,
+ const Json::Value& flagMap);
+ virtual ~Receiver();
+ Json::Value& getReceivedValueMap();
+ Json::Value& getReceivedHeadersMap();
+ Json::Value& getReceivedPropertiesMap();
+ void on_container_start(proton::container &c);
+ void on_message(proton::delivery &d, proton::message &m);
+
+ static uint32_t getTotalNumExpectedMsgs(const Json::Value testNumberMap);
+
+ protected:
+ void receiveJmsMessage(const proton::message& msg);
+ void receiveJmsObjectMessage(const proton::message& msg);
+ void receiveJmsMapMessage(const proton::message& msg);
+ void receiveJmsBytesMessage(const proton::message& msg);
+ void receiveJmsStreamMessage(const proton::message& msg);
+ void receiveJmsTextMessage(const proton::message& msg);
+
+ void processMessageHeaders(const proton::message& msg);
+ void addMessageHeaderString(const char* headerName, const std::string& value);
+ void addMessageHeaderByteArray(const std::string& headerName, const proton::binary ba);
+ void addMessageHeaderDestination(const std::string& headerName, qpidit::jmsDestinationType_t dt, const std::string& d);
+ void processMessageProperties(const proton::message& msg);
+
+ // Format signed numbers in negative hex format if signedFlag is true, ie -0xNNNN, positive numbers in 0xNNNN format
+ template<typename T> static std::string toHexStr(T val, bool fillFlag = false, bool signedFlag = true) {
+ std::ostringstream oss;
+ bool neg = false;
+ if (signedFlag) {
+ neg = val < 0;
+ if (neg) val = -val;
+ }
+ oss << (neg ? "-" : "") << "0x" << std::hex;
+ if (fillFlag) {
+ oss << std::setw(sizeof(T)*2) << std::setfill('0');
+ }
+ oss << (sizeof(T) == 1 ? (int)val & 0xff : sizeof(T) == 2 ? val & 0xffff : sizeof(T) == 4 ? val & 0xffffffff : val);
+ return oss.str();
+ }
+ };
+
+ } /* namespace jms_hdrs_props_test */
+} /* namespace qpidit */
+
+#endif /* SRC_QPIDIT_JMS_HEADERS_PROPERTIES_TEST_RECEIVER_HPP_ */
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/shims/qpid-proton-cpp/src/qpidit/jms_hdrs_props_test/Sender.cpp
----------------------------------------------------------------------
diff --git a/shims/qpid-proton-cpp/src/qpidit/jms_hdrs_props_test/Sender.cpp b/shims/qpid-proton-cpp/src/qpidit/jms_hdrs_props_test/Sender.cpp
new file mode 100644
index 0000000..e3ff0e6
--- /dev/null
+++ b/shims/qpid-proton-cpp/src/qpidit/jms_hdrs_props_test/Sender.cpp
@@ -0,0 +1,451 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "qpidit/jms_hdrs_props_test/Sender.hpp"
+
+#include <cerrno>
+#include <iomanip>
+#include <iostream>
+#include <json/json.h>
+#include "proton/connection.hpp"
+#include "proton/default_container.hpp"
+#include "proton/tracker.hpp"
+#include "proton/transport.hpp"
+#include <stdio.h>
+
+namespace qpidit
+{
+ namespace jms_hdrs_props_test
+ {
+ Sender::Sender(const std::string& brokerUrl,
+ const std::string& jmsMessageType,
+ const Json::Value& testParams) :
+ _brokerUrl(brokerUrl),
+ _jmsMessageType(jmsMessageType),
+ _testValueMap(testParams[0]),
+ _testHeadersMap(testParams[1]),
+ _testPropertiesMap(testParams[2]),
+ _msgsSent(0),
+ _msgsConfirmed(0),
+ _totalMsgs(getTotalNumMessages(_testValueMap))
+ {
+ if (_testValueMap.type() != Json::objectValue) {
+ throw qpidit::InvalidJsonRootNodeError(Json::objectValue, _testValueMap.type());
+ }
+ }
+
+ Sender::~Sender() {}
+
+ void Sender::on_container_start(proton::container &c) {
+ c.open_sender(_brokerUrl);
+ }
+
+ void Sender::on_sendable(proton::sender &s) {
+ if (_totalMsgs == 0) {
+ s.connection().close();
+ } else if (_msgsSent == 0) {
+ Json::Value::Members subTypes = _testValueMap.getMemberNames();
+ std::sort(subTypes.begin(), subTypes.end());
+ for (std::vector<std::string>::const_iterator i=subTypes.begin(); i!=subTypes.end(); ++i) {
+ sendMessages(s, *i, _testValueMap[*i]);
+ }
+ }
+ }
+
+ void Sender::on_tracker_accept(proton::tracker &t) {
+ _msgsConfirmed++;
+ if (_msgsConfirmed == _totalMsgs) {
+ t.connection().close();
+ }
+ }
+
+ void Sender::on_transport_close(proton::transport &t) {
+ _msgsSent = _msgsConfirmed;
+ }
+
+ // protected
+
+ void Sender::sendMessages(proton::sender &s, const std::string& subType, const Json::Value& testValues) {
+ uint32_t valueNumber = 0;
+ for (Json::Value::const_iterator i=testValues.begin(); i!=testValues.end(); ++i) {
+ if (s.credit()) {
+ proton::message msg;
+ if (_jmsMessageType.compare("JMS_MESSAGE_TYPE") == 0) {
+ setMessage(msg, subType, (*i).asString());
+ } else if (_jmsMessageType.compare("JMS_BYTESMESSAGE_TYPE") == 0) {
+ setBytesMessage(msg, subType, (*i).asString());
+ } else if (_jmsMessageType.compare("JMS_MAPMESSAGE_TYPE") == 0) {
+ setMapMessage(msg, subType, (*i).asString(), valueNumber);
+ } else if (_jmsMessageType.compare("JMS_OBJECTMESSAGE_TYPE") == 0) {
+ setObjectMessage(msg, subType, *i);
+ } else if (_jmsMessageType.compare("JMS_STREAMMESSAGE_TYPE") == 0) {
+ setStreamMessage(msg, subType, (*i).asString());
+ } else if (_jmsMessageType.compare("JMS_TEXTMESSAGE_TYPE") == 0) {
+ setTextMessage(msg, *i);
+ } else {
+ throw qpidit::UnknownJmsMessageTypeError(_jmsMessageType);
+ }
+ addMessageHeaders(msg);
+ addMessageProperties(msg);
+ s.send(msg);
+ _msgsSent += 1;
+ valueNumber += 1;
+ }
+ }
+
+ }
+
+ proton::message& Sender::setMessage(proton::message& msg, const std::string& subType, const std::string& testValueStr) {
+ if (subType.compare("none") != 0) {
+ throw qpidit::UnknownJmsMessageSubTypeError(subType);
+ }
+ if (testValueStr.size() != 0) {
+ throw InvalidTestValueError(subType, testValueStr);
+ }
+ msg.content_type(proton::symbol("application/octet-stream"));
+ msg.message_annotations().put(proton::symbol("x-opt-jms-msg-type"), s_jmsMessageTypeAnnotationValues["JMS_MESSAGE_TYPE"]);
+ return msg;
+ }
+
+ proton::message& Sender::setBytesMessage(proton::message& msg, const std::string& subType, const std::string& testValueStr) {
+ proton::binary bin;
+ if (subType.compare("boolean") == 0) {
+ if (testValueStr.compare("False") == 0) bin.push_back(char(0));
+ else if (testValueStr.compare("True") == 0) bin.push_back(char(1));
+ else throw InvalidTestValueError(subType, testValueStr);
+ } else if (subType.compare("byte") == 0) {
+ uint8_t val = getIntegralValue<int8_t>(testValueStr);
+ bin.push_back(char(val));
+ } else if (subType.compare("bytes") == 0) {
+ bin.assign(testValueStr.begin(), testValueStr.end());
+ } else if (subType.compare("char") == 0) {
+ bin.push_back(char(0));
+ if (testValueStr[0] == '\\') { // Format: '\xNN'
+ bin.push_back(getIntegralValue<char>(testValueStr.substr(2)));
+ } else { // Format: 'c'
+ bin.push_back(testValueStr[0]);
+ }
+ } else if (subType.compare("double") == 0) {
+ uint64_t val;
+ try {
+ val = htobe64(std::strtoul(testValueStr.data(), NULL, 16));
+ } catch (const std::exception& e) { throw qpidit::InvalidTestValueError("double", testValueStr); }
+ numToBinary(val, bin);
+ //for (int i=0; i<sizeof(val); ++i) {
+ // bin.push_back(* ((char*)&val + i));
+ // }
+ } else if (subType.compare("float") == 0) {
+ uint32_t val;
+ try {
+ val = htobe32((uint32_t)std::strtoul(testValueStr.data(), NULL, 16));
+ } catch (const std::exception& e) { throw qpidit::InvalidTestValueError("float", testValueStr); }
+ numToBinary(val, bin);
+ //for (int i=0; i<sizeof(val); ++i) {
+ // bin.push_back(* ((char*)&val + i));
+ //}
+ } else if (subType.compare("long") == 0) {
+ uint64_t val = htobe64(getIntegralValue<uint64_t>(testValueStr));
+ numToBinary(val, bin);
+ //bin.assign(sizeof(val), val);
+ } else if (subType.compare("int") == 0) {
+ uint32_t val = htobe32(getIntegralValue<uint32_t>(testValueStr));
+ numToBinary(val, bin);
+ //bin.assign(sizeof(val), val);
+ } else if (subType.compare("short") == 0) {
+ uint16_t val = htobe16(getIntegralValue<int16_t>(testValueStr));
+ numToBinary(val, bin);
+ //bin.assign(sizeof(val), val);
+ } else if (subType.compare("string") == 0) {
+ std::ostringstream oss;
+ uint16_t strlen = htobe16((uint16_t)testValueStr.size());
+ oss.write((char*)&strlen, sizeof(strlen));
+ oss << testValueStr;
+ std::string os = oss.str();
+ bin.assign(os.begin(), os.end());
+ } else {
+ throw qpidit::UnknownJmsMessageSubTypeError(subType);
+ }
+ msg.body(bin);
+ msg.inferred(true);
+ msg.content_type(proton::symbol("application/octet-stream"));
+ msg.message_annotations().put(proton::symbol("x-opt-jms-msg-type"), s_jmsMessageTypeAnnotationValues["JMS_BYTESMESSAGE_TYPE"]);
+ return msg;
+ }
+
+ proton::message& Sender::setMapMessage(proton::message& msg, const std::string& subType, const std::string& testValueStr, uint32_t valueNumber) {
+ std::ostringstream oss;
+ oss << subType << std::setw(3) << std::setfill('0') << valueNumber;
+ std::string mapKey(oss.str());
+ std::map<std::string, proton::value> m;
+ if (subType.compare("boolean") == 0) {
+ if (testValueStr.compare("False") == 0) m[mapKey] = false;
+ else if (testValueStr.compare("True") == 0) m[mapKey] = true;
+ else throw InvalidTestValueError(subType, testValueStr);
+ } else if (subType.compare("byte") == 0) {
+ m[mapKey] = int8_t(getIntegralValue<int8_t>(testValueStr));
+ } else if (subType.compare("bytes") == 0) {
+ m[mapKey] = proton::binary(testValueStr);
+ } else if (subType.compare("char") == 0) {
+ wchar_t val;
+ if (testValueStr[0] == '\\') { // Format: '\xNN'
+ val = (wchar_t)getIntegralValue<wchar_t>(testValueStr.substr(2));
+ } else { // Format: 'c'
+ val = testValueStr[0];
+ }
+ m[mapKey] = val;
+ } else if (subType.compare("double") == 0) {
+ m[mapKey] = getFloatValue<double, uint64_t>(testValueStr);
+ } else if (subType.compare("float") == 0) {
+ m[mapKey] = getFloatValue<float, uint32_t>(testValueStr);
+ } else if (subType.compare("int") == 0) {
+ m[mapKey] = getIntegralValue<int32_t>(testValueStr);
+ } else if (subType.compare("long") == 0) {
+ m[mapKey] = getIntegralValue<int64_t>(testValueStr);
+ } else if (subType.compare("short") == 0) {
+ m[mapKey] = getIntegralValue<int16_t>(testValueStr);
+ } else if (subType.compare("string") == 0) {
+ m[mapKey] = testValueStr;
+ } else {
+ throw qpidit::UnknownJmsMessageSubTypeError(subType);
+ }
+ msg.inferred(false);
+ msg.body(m);
+ msg.message_annotations().put(proton::symbol("x-opt-jms-msg-type"), s_jmsMessageTypeAnnotationValues["JMS_MAPMESSAGE_TYPE"]);
+ return msg;
+ }
+
+ proton::message& Sender::setObjectMessage(proton::message& msg, const std::string& subType, const Json::Value& testValue) {
+ msg.body(getJavaObjectBinary(subType, testValue.asString()));
+ msg.inferred(true);
+ msg.content_type(proton::symbol("application/x-java-serialized-object"));
+ msg.message_annotations().put(proton::symbol("x-opt-jms-msg-type"), s_jmsMessageTypeAnnotationValues["JMS_OBJECTMESSAGE_TYPE"]);
+ return msg;
+ }
+
+ proton::message& Sender::setStreamMessage(proton::message& msg, const std::string& subType, const std::string& testValueStr) {
+ std::vector<proton::value> l;
+ if (subType.compare("boolean") == 0) {
+ if (testValueStr.compare("False") == 0) l.push_back(false);
+ else if (testValueStr.compare("True") == 0) l.push_back(true);
+ else throw InvalidTestValueError(subType, testValueStr);
+ } else if (subType.compare("byte") == 0) {
+ l.push_back(int8_t(getIntegralValue<int8_t>(testValueStr)));
+ } else if (subType.compare("bytes") == 0) {
+ l.push_back(proton::binary(testValueStr));
+ } else if (subType.compare("char") == 0) {
+ wchar_t val;
+ if (testValueStr[0] == '\\') { // Format: '\xNN'
+ val = (wchar_t)getIntegralValue<wchar_t>(testValueStr.substr(2));
+ } else { // Format: 'c'
+ val = testValueStr[0];
+ }
+ l.push_back(val);
+ } else if (subType.compare("double") == 0) {
+ l.push_back(getFloatValue<double, uint64_t>(testValueStr));
+ } else if (subType.compare("float") == 0) {
+ l.push_back(getFloatValue<float, uint32_t>(testValueStr));
+ } else if (subType.compare("int") == 0) {
+ l.push_back(getIntegralValue<int32_t>(testValueStr));
+ } else if (subType.compare("long") == 0) {
+ l.push_back(getIntegralValue<int64_t>(testValueStr));
+ } else if (subType.compare("short") == 0) {
+ l.push_back(getIntegralValue<int16_t>(testValueStr));
+ } else if (subType.compare("string") == 0) {
+ l.push_back(testValueStr);
+ } else {
+ throw qpidit::UnknownJmsMessageSubTypeError(subType);
+ }
+ msg.body(l);
+ msg.inferred(true);
+ msg.message_annotations().put(proton::symbol("x-opt-jms-msg-type"), s_jmsMessageTypeAnnotationValues["JMS_STREAMMESSAGE_TYPE"]);
+ return msg;
+ }
+
+ proton::message& Sender::setTextMessage(proton::message& msg, const Json::Value& testValue) {
+ msg.body(testValue.asString());
+ msg.inferred(false);
+ msg.message_annotations().put(proton::symbol("x-opt-jms-msg-type"), s_jmsMessageTypeAnnotationValues["JMS_TEXTMESSAGE_TYPE"]);
+ return msg;
+ }
+
+ proton::message& Sender::addMessageHeaders(proton::message& msg) {
+ Json::Value::Members headerNames = _testHeadersMap.getMemberNames();
+ for (std::vector<std::string>::const_iterator i=headerNames.begin(); i!=headerNames.end(); ++i) {
+ const Json::Value _subMap = _testHeadersMap[*i];
+ const std::string headerValueType = _subMap.getMemberNames()[0]; // There is always only one entry in map
+ std::string val = _subMap[headerValueType].asString();
+ if (i->compare("JMS_TYPE_HEADER") == 0) {
+ setJmsTypeHeader(msg, val);
+ } else if (i->compare("JMS_CORRELATIONID_HEADER") == 0) {
+ if (headerValueType.compare("bytes") == 0) {
+ setJmsCorrelationId(msg, proton::binary(val));
+ } else {
+ setJmsCorrelationId(msg, val);
+ }
+ } else if (i->compare("JMS_REPLYTO_HEADER") == 0) {
+ setJmsReplyTo(msg, headerValueType, val);
+ } else {
+ throw qpidit::UnknownJmsHeaderTypeError(*i);
+ }
+ }
+ return msg;
+ }
+
+ //static
+ proton::message& Sender::setJmsTypeHeader(proton::message& msg, const std::string& t) {
+ msg.subject(t);
+ return msg;
+ }
+
+ //static
+ proton::message& Sender::setJmsCorrelationId(proton::message& msg, const std::string& cid) {
+ proton::message_id mid(cid);
+ msg.correlation_id(mid);
+ msg.message_annotations().put(proton::symbol("x-opt-app-correlation-id"), true);
+ return msg;
+ }
+
+ //static
+ proton::message& Sender::setJmsCorrelationId(proton::message& msg, const proton::binary cid) {
+ proton::message_id mid(cid);
+ msg.correlation_id(cid);
+ msg.message_annotations().put(proton::symbol("x-opt-app-correlation-id"), true);
+ return msg;
+ }
+
+ //static
+ proton::message& Sender::setJmsReplyTo(proton::message& msg, const std::string& dts, const std::string& d) {
+ if (dts.compare("queue") == 0) {
+ msg.reply_to(/*std::string("queue://") + */d);
+ msg.message_annotations().put(proton::symbol("x-opt-jms-reply-to"), int8_t(qpidit::JMS_QUEUE));
+ } else if (dts.compare("temp_queue") == 0) {
+ msg.reply_to(/*std::string("queue://") + */d);
+ msg.message_annotations().put(proton::symbol("x-opt-jms-reply-to"), int8_t(qpidit::JMS_TMEP_QUEUE));
+ } else if (dts.compare("topic") == 0) {
+ msg.reply_to(/*std::string("topic://") + */d);
+ msg.message_annotations().put(proton::symbol("x-opt-jms-reply-to"), int8_t(qpidit::JMS_TOPIC));
+ } else if (dts.compare("temp_topic") == 0) {
+ msg.reply_to(/*std::string("topic://") + */d);
+ msg.message_annotations().put(proton::symbol("x-opt-jms-reply-to"), int8_t(qpidit::JMS_TEMP_TOPIC));
+ } else {
+ throw qpidit::UnknownJmsDestinationTypeError(dts);
+ }
+ return msg;
+ }
+
+ proton::message& Sender::addMessageProperties(proton::message& msg) {
+ Json::Value::Members propertyNames = _testPropertiesMap.getMemberNames();
+ for (std::vector<std::string>::const_iterator i=propertyNames.begin(); i!=propertyNames.end(); ++i) {
+ const Json::Value _subMap = _testPropertiesMap[*i];
+ const std::string propertyValueType = _subMap.getMemberNames()[0]; // There is always only one entry in map
+ std::string val = _subMap[propertyValueType].asString();
+ if (propertyValueType.compare("boolean") == 0) {
+ if (val.compare("False") == 0) setMessageProperty(msg, *i, false);
+ else if (val.compare("True") == 0) setMessageProperty(msg, *i, true);
+ else throw InvalidTestValueError(propertyValueType, val);
+ } else if (propertyValueType.compare("byte") == 0) {
+ setMessageProperty(msg, *i, getIntegralValue<int8_t>(val));
+ } else if (propertyValueType.compare("double") == 0) {
+ setMessageProperty(msg, *i, getFloatValue<double, uint64_t>(val));
+ } else if (propertyValueType.compare("float") == 0) {
+ setMessageProperty(msg, *i, getFloatValue<float, uint64_t>(val));
+ } else if (propertyValueType.compare("int") == 0) {
+ setMessageProperty(msg, *i, getIntegralValue<int32_t>(val));
+ } else if (propertyValueType.compare("long") == 0) {
+ setMessageProperty(msg, *i, getIntegralValue<int64_t>(val));
+ } else if (propertyValueType.compare("short") == 0) {
+ setMessageProperty(msg, *i, getIntegralValue<int16_t>(val));
+ } else if (propertyValueType.compare("string") == 0) {
+ setMessageProperty(msg, *i, val);
+ } else {
+ throw qpidit::UnknownJmsPropertyTypeError(propertyValueType);
+ }
+ }
+ return msg;
+ }
+
+ //static
+ proton::binary Sender::getJavaObjectBinary(const std::string& javaClassName, const std::string& valAsString) {
+ proton::binary javaObjectBinary;
+ char buf[1024];
+ int bytesRead;
+ FILE* fp = ::popen("java -cp target/JavaObjUtils.jar org.apache.qpid.interop_test.obj_util.JavaObjToBytes javaClassStr", "rb");
+ if (fp == NULL) { throw qpidit::PopenError(errno); }
+ do {
+ bytesRead = ::fread(buf, 1, sizeof(buf), fp);
+ javaObjectBinary.insert(javaObjectBinary.end(), &buf[0], &buf[bytesRead-1]);
+ } while (bytesRead == sizeof(buf));
+ int status = ::pclose(fp);
+ if (status == -1) {
+ throw qpidit::PcloseError(errno);
+ }
+ return javaObjectBinary;
+ }
+
+ // static
+ uint32_t Sender::getTotalNumMessages(const Json::Value& testValueMap) {
+ uint32_t tot = 0;
+ for (Json::Value::const_iterator i = testValueMap.begin(); i != testValueMap.end(); ++i) {
+ tot += (*i).size();
+ }
+ return tot;
+ }
+
+ } /* namespace jms_hdrs_props_test */
+} /* namespace qpidit */
+
+
+
+/*
+ * --- main ---
+ * Args: 1: Broker address (ip-addr:port)
+ * 2: Queue name
+ * 3: AMQP type
+ * 4: JSON Test parameters containing 3 maps: [testValueMap, testHeadersMap, testPropertiesMap]
+ */
+
+int main(int argc, char** argv) {
+/*
+ for (int i=0; i<argc; ++i) {
+ std::cout << "*** argv[" << i << "] : " << argv[i] << std::endl;
+ }
+*/
+ // TODO: improve arg management a little...
+ if (argc != 5) {
+ throw qpidit::ArgumentError("Incorrect number of arguments");
+ }
+
+ std::ostringstream oss;
+ oss << argv[1] << "/" << argv[2];
+
+ try {
+ Json::Value testParams;
+ Json::Reader jsonReader;
+ if (not jsonReader.parse(argv[4], testParams, false)) {
+ throw qpidit::JsonParserError(jsonReader);
+ }
+
+ qpidit::jms_hdrs_props_test::Sender sender(oss.str(), argv[3], testParams);
+ proton::default_container(sender).run();
+ } catch (const std::exception& e) {
+ std::cout << "JmsSender error: " << e.what() << std::endl;
+ }
+}
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/shims/qpid-proton-cpp/src/qpidit/jms_hdrs_props_test/Sender.hpp
----------------------------------------------------------------------
diff --git a/shims/qpid-proton-cpp/src/qpidit/jms_hdrs_props_test/Sender.hpp b/shims/qpid-proton-cpp/src/qpidit/jms_hdrs_props_test/Sender.hpp
new file mode 100644
index 0000000..8e3efe7
--- /dev/null
+++ b/shims/qpid-proton-cpp/src/qpidit/jms_hdrs_props_test/Sender.hpp
@@ -0,0 +1,109 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#ifndef SRC_QPIDIT_JMS_HEADERS_PROPERTIES_TEST_SENDER_HPP_
+#define SRC_QPIDIT_JMS_HEADERS_PROPERTIES_TEST_SENDER_HPP_
+
+#include "json/value.h"
+#include "proton/message.hpp"
+#include "proton/messaging_handler.hpp"
+#include "qpidit/JmsTestBase.hpp"
+#include "qpidit/QpidItErrors.hpp"
+#include <typeinfo>
+
+namespace proton {
+ class message;
+}
+
+namespace qpidit
+{
+ namespace jms_hdrs_props_test
+ {
+
+ class Sender : public qpidit::JmsTestBase
+ {
+ protected:
+ const std::string _brokerUrl;
+ const std::string _jmsMessageType;
+ const Json::Value _testValueMap;
+ const Json::Value _testHeadersMap;
+ const Json::Value _testPropertiesMap;
+ uint32_t _msgsSent;
+ uint32_t _msgsConfirmed;
+ uint32_t _totalMsgs;
+ public:
+ Sender(const std::string& brokerUrl, const std::string& jmsMessageType, const Json::Value& testParams);
+ virtual ~Sender();
+
+ void on_container_start(proton::container &c);
+ void on_sendable(proton::sender &s);
+ void on_tracker_accept(proton::tracker &t);
+ void on_transport_close(proton::transport &t);
+ protected:
+ void sendMessages(proton::sender &s, const std::string& subType, const Json::Value& testValueMap);
+ proton::message& setMessage(proton::message& msg, const std::string& subType, const std::string& testValueStr);
+ proton::message& setBytesMessage(proton::message& msg, const std::string& subType, const std::string& testValueStr);
+ proton::message& setMapMessage(proton::message& msg, const std::string& subType, const std::string& testValueStr, uint32_t valueNumber);
+ proton::message& setObjectMessage(proton::message& msg, const std::string& subType, const Json::Value& testValue);
+ proton::message& setStreamMessage(proton::message& msg, const std::string& subType, const std::string& testValue);
+ proton::message& setTextMessage(proton::message& msg, const Json::Value& testValue);
+
+ proton::message& addMessageHeaders(proton::message& msg);
+ static proton::message& setJmsTypeHeader(proton::message& msg, const std::string& t);
+ static proton::message& setJmsCorrelationId(proton::message& msg, const std::string& cid);
+ static proton::message& setJmsCorrelationId(proton::message& msg, const proton::binary cid);
+ static proton::message& setJmsReplyTo(proton::message& msg, const std::string& dt, const std::string& d);
+
+ proton::message& addMessageProperties(proton::message& msg);
+ template<typename T> proton::message& setMessageProperty(proton::message& msg, const std::string& propertyName, T val) {
+ msg.properties().put(propertyName, val);
+ return msg;
+ }
+
+ static proton::binary getJavaObjectBinary(const std::string& javaClassName, const std::string& valAsString);
+ static uint32_t getTotalNumMessages(const Json::Value& testValueMap);
+
+ template<typename T> static T numToBinary(T n, proton::binary& b) {
+ for (int i=0; i<sizeof(n); ++i) {
+ b.push_back(* ((char*)&n + i));
+ }
+ }
+
+ // Set message body to floating type T through integral type U
+ // Used to convert a hex string representation of a float or double to a float or double
+ template<typename T, typename U> T getFloatValue(const std::string& testValueStr) {
+ try {
+ U ival(std::strtoul(testValueStr.data(), NULL, 16));
+ return T(*reinterpret_cast<T*>(&ival));
+ } catch (const std::exception& e) { throw qpidit::InvalidTestValueError(typeid(T).name(), testValueStr); }
+ }
+
+ template<typename T> T getIntegralValue(const std::string& testValueStr) {
+ try {
+ return T(std::strtol(testValueStr.data(), NULL, 16));
+ } catch (const std::exception& e) { throw qpidit::InvalidTestValueError(typeid(T).name(), testValueStr); }
+ }
+ };
+
+ } /* namespace jms_hdrs_props_test */
+} /* namespace qpidit */
+
+#endif /* SRC_QPIDIT_JMS_HEADERS_PROPERTIES_TEST_SENDER_HPP_ */
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/shims/qpid-proton-cpp/src/qpidit/jms_messages_test/JmsDefinitions.hpp
----------------------------------------------------------------------
diff --git a/shims/qpid-proton-cpp/src/qpidit/jms_messages_test/JmsDefinitions.hpp b/shims/qpid-proton-cpp/src/qpidit/jms_messages_test/JmsDefinitions.hpp
deleted file mode 100644
index 6f99813..0000000
--- a/shims/qpid-proton-cpp/src/qpidit/jms_messages_test/JmsDefinitions.hpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- *
- * 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.
- *
- */
-
-#ifndef SRC_QPIDIT_JMS_MESSAGES_TEST_JMSDEFINTIONS_HPP_
-#define SRC_QPIDIT_JMS_MESSAGES_TEST_JMSDEFINTIONS_HPP_
-
-namespace qpidit
-{
- namespace jms_messages_test
- {
- typedef enum {JMS_QUEUE = 0,
- JMS_TOPIC,
- JMS_TMEP_QUEUE,
- JMS_TEMP_TOPIC}
- jmsDestinationType_t;
-
- typedef enum {JMS_MESSAGE_TYPE=0,
- JMS_OBJECTMESSAGE_TYPE,
- JMS_MAPMESSAGE_TYPE,
- JMS_BYTESMESSAGE_TYPE,
- JMS_STREAMMESSAGE_TYPE,
- JMS_TEXTMESSAGE_TYPE}
- jmsMessageType_t;
-
- }
-}
-
-#endif /* SRC_QPIDIT_JMS_MESSAGES_TEST_JMSDEFINTIONS_HPP_ */
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/shims/qpid-proton-cpp/src/qpidit/jms_messages_test/Receiver.cpp
----------------------------------------------------------------------
diff --git a/shims/qpid-proton-cpp/src/qpidit/jms_messages_test/Receiver.cpp b/shims/qpid-proton-cpp/src/qpidit/jms_messages_test/Receiver.cpp
index ed1dfa5..43bd34f 100644
--- a/shims/qpid-proton-cpp/src/qpidit/jms_messages_test/Receiver.cpp
+++ b/shims/qpid-proton-cpp/src/qpidit/jms_messages_test/Receiver.cpp
@@ -33,27 +33,18 @@ namespace qpidit
{
namespace jms_messages_test
{
- //static
- proton::symbol Receiver::s_jmsMessageTypeAnnotationKey("x-opt-jms-msg-type");
- std::map<std::string, int8_t>Receiver::s_jmsMessageTypeAnnotationValues = initializeJmsMessageTypeAnnotationMap();
-
-
Receiver::Receiver(const std::string& brokerUrl,
const std::string& jmsMessageType,
- const Json::Value& testNumberMap,
- const Json::Value& flagMap):
+ const Json::Value& testNumberMap):
_brokerUrl(brokerUrl),
_jmsMessageType(jmsMessageType),
_testNumberMap(testNumberMap),
- _flagMap(flagMap),
_subTypeList(testNumberMap.getMemberNames()),
_subTypeIndex(0),
_expected(getTotalNumExpectedMsgs(testNumberMap)),
_received(0UL),
_receivedSubTypeList(Json::arrayValue),
- _receivedValueMap(Json::objectValue),
- _receivedHeadersMap(Json::objectValue),
- _receivedPropertiesMap(Json::objectValue)
+ _receivedValueMap(Json::objectValue)
{}
Receiver::~Receiver() {}
@@ -62,14 +53,6 @@ namespace qpidit
return _receivedValueMap;
}
- Json::Value& Receiver::getReceivedHeadersMap() {
- return _receivedHeadersMap;
- }
-
- Json::Value& Receiver::getReceivedPropertiesMap() {
- return _receivedPropertiesMap;
- }
-
void Receiver::on_container_start(proton::container &c) {
c.open_receiver(_brokerUrl);
}
@@ -77,38 +60,35 @@ namespace qpidit
void Receiver::on_message(proton::delivery &d, proton::message &m) {
try {
if (_received < _expected) {
- int8_t t = JMS_MESSAGE_TYPE;
+ int8_t t = qpidit::JMS_MESSAGE_TYPE;
try {t = m.message_annotations().get(proton::symbol("x-opt-jms-msg-type")).get<int8_t>();}
catch (const std::exception& e) {
std::cout << "JmsReceiver::on_message(): Missing annotation \"x-opt-jms-msg-type\"" << std::endl;
throw;
}
switch (t) {
- case JMS_MESSAGE_TYPE:
+ case qpidit::JMS_MESSAGE_TYPE:
receiveJmsMessage(m);
break;
- case JMS_OBJECTMESSAGE_TYPE:
+ case qpidit::JMS_OBJECTMESSAGE_TYPE:
receiveJmsObjectMessage(m);
break;
- case JMS_MAPMESSAGE_TYPE:
+ case qpidit::JMS_MAPMESSAGE_TYPE:
receiveJmsMapMessage(m);
break;
- case JMS_BYTESMESSAGE_TYPE:
+ case qpidit::JMS_BYTESMESSAGE_TYPE:
receiveJmsBytesMessage(m);
break;
- case JMS_STREAMMESSAGE_TYPE:
+ case qpidit::JMS_STREAMMESSAGE_TYPE:
receiveJmsStreamMessage(m);
break;
- case JMS_TEXTMESSAGE_TYPE:
+ case qpidit::JMS_TEXTMESSAGE_TYPE:
receiveJmsTextMessage(m);
break;
default:;
// TODO: handle error - no known JMS message type
}
- processMessageHeaders(m);
- processMessageProperties(m);
-
std::string subType(_subTypeList[_subTypeIndex]);
// Increment the subtype if the required number of messages have been received
if (_receivedSubTypeList.size() >= _testNumberMap[subType].asInt() &&
@@ -130,26 +110,6 @@ namespace qpidit
}
}
- void Receiver::on_connection_error(proton::connection &c) {
- std::cerr << "JmsReceiver::on_connection_error(): " << c.error() << std::endl;
- }
-
- void Receiver::on_receiver_error(proton::receiver& r) {
- std::cerr << "JmsReceiver::on_receiver_error(): " << r.error() << std::endl;
- }
-
- void Receiver::on_session_error(proton::session &s) {
- std::cerr << "JmsReceiver::on_session_error(): " << s.error() << std::endl;
- }
-
- void Receiver::on_transport_error(proton::transport &t) {
- std::cerr << "JmsReceiver::on_transport_error(): " << t.error() << std::endl;
- }
-
- void Receiver::on_error(const proton::error_condition &ec) {
- std::cerr << "JmsReceiver::on_error(): " << ec << std::endl;
- }
-
//static
uint32_t Receiver::getTotalNumExpectedMsgs(const Json::Value testNumberMap) {
uint32_t total(0UL);
@@ -309,85 +269,6 @@ namespace qpidit
_receivedSubTypeList.append(Json::Value(msg.body().get<std::string>()));
}
- void Receiver::processMessageHeaders(const proton::message& msg) {
- addMessageHeaderString("JMS_TYPE_HEADER", msg.subject());
- if (_flagMap.isMember("JMS_CORRELATIONID_AS_BYTES") && _flagMap["JMS_CORRELATIONID_AS_BYTES"].asBool()) {
- addMessageHeaderByteArray("JMS_CORRELATIONID_HEADER", proton::get<proton::binary>(msg.correlation_id()));
- } else {
- try {
- addMessageHeaderString("JMS_CORRELATIONID_HEADER", proton::get<std::string>(msg.correlation_id()));
- } catch (const std::exception& e) {} // TODO: UGLY, how do you check if there _is_ a correlation id?
- }
-
- std::string reply_to = msg.reply_to();
- // Some brokers prepend 'queue://' and 'topic://' to reply_to addresses, strip these when present
- if (_flagMap.isMember("JMS_REPLYTO_AS_TOPIC") && _flagMap["JMS_REPLYTO_AS_TOPIC"].asBool()) {
- if (reply_to.find("topic://") == 0) {
- addMessageHeaderDestination("JMS_REPLYTO_HEADER", JMS_TOPIC, reply_to.substr(8));
- } else {
- addMessageHeaderDestination("JMS_REPLYTO_HEADER", JMS_TOPIC, reply_to);
- }
- } else {
- if (reply_to.find("queue://") == 0) {
- addMessageHeaderDestination("JMS_REPLYTO_HEADER", JMS_QUEUE, reply_to.substr(8));
- } else {
- addMessageHeaderDestination("JMS_REPLYTO_HEADER", JMS_QUEUE, reply_to);
- }
- }
- }
-
- void Receiver::addMessageHeaderString(const char* headerName, const std::string& value) {
- if (!value.empty()) { // TODO: Remove this test when PROTON-1288 is fixed as empty strings are allowed in headers
- Json::Value valueMap(Json::objectValue);
- valueMap["string"] = value;
- _receivedHeadersMap[headerName] = valueMap;
- }
- }
-
- void Receiver::addMessageHeaderByteArray(const std::string& headerName, const proton::binary ba) {
- if (!ba.empty()) { // TODO: Remove this test when PROTON-1288 is fixed as empty binaries are allowed in headers
- Json::Value valueMap(Json::objectValue);
- valueMap["bytes"] = std::string(ba);
- _receivedHeadersMap[headerName] = valueMap;
- }
- }
-
- void Receiver::addMessageHeaderDestination(const std::string& headerName, jmsDestinationType_t dt, const std::string& d) {
- if (!d.empty()) {
- Json::Value valueMap(Json::objectValue);
- switch (dt) {
- case JMS_QUEUE:
- valueMap["queue"] = d;
- break;
- case JMS_TOPIC:
- valueMap["topic"] = d;
- break;
- default:
- ; // TODO: Handle error: remaining JMS destinations not handled.
- }
- _receivedHeadersMap[headerName] = valueMap;
- }
- }
-
- void Receiver::processMessageProperties(const proton::message& msg) {
- // TODO: Add this function when PROTON-1284 is fixed
-// std::map<proton::value, proton::value> props;
-// msg.properties().value() >> props;
- }
-
- //static
- std::map<std::string, int8_t> Receiver::initializeJmsMessageTypeAnnotationMap() {
- std::map<std::string, int8_t> m;
- m["JMS_MESSAGE_TYPE"] = JMS_MESSAGE_TYPE;
- m["JMS_OBJECTMESSAGE_TYPE"] = JMS_OBJECTMESSAGE_TYPE;
- m["JMS_MAPMESSAGE_TYPE"] = JMS_MAPMESSAGE_TYPE;
- m["JMS_BYTESMESSAGE_TYPE"] = JMS_BYTESMESSAGE_TYPE;
- m["JMS_STREAMMESSAGE_TYPE"] = JMS_STREAMMESSAGE_TYPE;
- m["JMS_TEXTMESSAGE_TYPE"] = JMS_TEXTMESSAGE_TYPE;
- return m;
- }
-
-
} /* namespace jms_messages_test */
} /* namespace qpidit */
@@ -418,14 +299,12 @@ int main(int argc, char** argv) {
throw qpidit::JsonParserError(jsonReader);
}
- qpidit::jms_messages_test::Receiver receiver(oss.str(), argv[3], testParams[0], testParams[1]);
+ qpidit::jms_messages_test::Receiver receiver(oss.str(), argv[3], testParams);
proton::default_container(receiver).run();
Json::FastWriter fw;
std::cout << argv[3] << std::endl;
std::cout << fw.write(receiver.getReceivedValueMap());
- std::cout << fw.write(receiver.getReceivedHeadersMap());
- std::cout << fw.write(receiver.getReceivedPropertiesMap());
} catch (const std::exception& e) {
std::cout << "JmsReceiver error: " << e.what() << std::endl;
}
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/shims/qpid-proton-cpp/src/qpidit/jms_messages_test/Receiver.hpp
----------------------------------------------------------------------
diff --git a/shims/qpid-proton-cpp/src/qpidit/jms_messages_test/Receiver.hpp b/shims/qpid-proton-cpp/src/qpidit/jms_messages_test/Receiver.hpp
index 696b9dd..d7c183b 100644
--- a/shims/qpid-proton-cpp/src/qpidit/jms_messages_test/Receiver.hpp
+++ b/shims/qpid-proton-cpp/src/qpidit/jms_messages_test/Receiver.hpp
@@ -26,7 +26,7 @@
#include <json/value.h>
#include "proton/messaging_handler.hpp"
#include "proton/types.hpp"
-#include "qpidit/jms_messages_test/JmsDefinitions.hpp"
+#include "qpidit/JmsTestBase.hpp"
#include <sstream>
namespace qpidit
@@ -34,42 +34,28 @@ namespace qpidit
namespace jms_messages_test
{
- class Receiver : public proton::messaging_handler
+ class Receiver : public qpidit::JmsTestBase
{
protected:
- static proton::symbol s_jmsMessageTypeAnnotationKey;
- static std::map<std::string, int8_t>s_jmsMessageTypeAnnotationValues;
-
const std::string _brokerUrl;
const std::string _jmsMessageType;
const Json::Value _testNumberMap;
- const Json::Value _flagMap;
Json::Value::Members _subTypeList;
int _subTypeIndex;
uint32_t _expected;
uint32_t _received;
Json::Value _receivedSubTypeList;
Json::Value _receivedValueMap;
- Json::Value _receivedHeadersMap;
- Json::Value _receivedPropertiesMap;
+
public:
Receiver(const std::string& brokerUrl,
const std::string& jmsMessageType,
- const Json::Value& testNumberMap,
- const Json::Value& flagMap);
+ const Json::Value& testNumberMap);
virtual ~Receiver();
Json::Value& getReceivedValueMap();
- Json::Value& getReceivedHeadersMap();
- Json::Value& getReceivedPropertiesMap();
void on_container_start(proton::container &c);
void on_message(proton::delivery &d, proton::message &m);
- void on_connection_error(proton::connection &c);
- void on_receiver_error(proton::receiver& r);
- void on_session_error(proton::session &s);
- void on_transport_error(proton::transport &t);
- void on_error(const proton::error_condition &c);
-
static uint32_t getTotalNumExpectedMsgs(const Json::Value testNumberMap);
protected:
@@ -80,14 +66,6 @@ namespace qpidit
void receiveJmsStreamMessage(const proton::message& msg);
void receiveJmsTextMessage(const proton::message& msg);
- void processMessageHeaders(const proton::message& msg);
- void addMessageHeaderString(const char* headerName, const std::string& value);
- void addMessageHeaderByteArray(const std::string& headerName, const proton::binary ba);
- void addMessageHeaderDestination(const std::string& headerName, jmsDestinationType_t dt, const std::string& d);
- void processMessageProperties(const proton::message& msg);
-
- static std::map<std::string, int8_t> initializeJmsMessageTypeAnnotationMap();
-
// Format signed numbers in negative hex format if signedFlag is true, ie -0xNNNN, positive numbers in 0xNNNN format
template<typename T> static std::string toHexStr(T val, bool fillFlag = false, bool signedFlag = true) {
std::ostringstream oss;
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/shims/qpid-proton-cpp/src/qpidit/jms_messages_test/Sender.cpp
----------------------------------------------------------------------
diff --git a/shims/qpid-proton-cpp/src/qpidit/jms_messages_test/Sender.cpp b/shims/qpid-proton-cpp/src/qpidit/jms_messages_test/Sender.cpp
index dbe2c0d..42ba558 100644
--- a/shims/qpid-proton-cpp/src/qpidit/jms_messages_test/Sender.cpp
+++ b/shims/qpid-proton-cpp/src/qpidit/jms_messages_test/Sender.cpp
@@ -35,18 +35,12 @@ namespace qpidit
{
namespace jms_messages_test
{
- //static
- proton::symbol Sender::s_jmsMessageTypeAnnotationKey("x-opt-jms-msg-type");
- std::map<std::string, int8_t>Sender::s_jmsMessageTypeAnnotationValues = initializeJmsMessageTypeAnnotationMap();
-
Sender::Sender(const std::string& brokerUrl,
const std::string& jmsMessageType,
const Json::Value& testParams) :
_brokerUrl(brokerUrl),
_jmsMessageType(jmsMessageType),
- _testValueMap(testParams[0]),
- _testHeadersMap(testParams[1]),
- _testPropertiesMap(testParams[2]),
+ _testValueMap(testParams),
_msgsSent(0),
_msgsConfirmed(0),
_totalMsgs(getTotalNumMessages(_testValueMap))
@@ -85,26 +79,6 @@ namespace qpidit
_msgsSent = _msgsConfirmed;
}
- void Sender::on_connection_error(proton::connection &c) {
- std::cerr << "JmsSender::on_connection_error(): " << c.error() << std::endl;
- }
-
- void Sender::on_sender_error(proton::sender &s) {
- std::cerr << "JmsSender::on_sender_error(): " << s.error() << std::endl;
- }
-
- void Sender::on_session_error(proton::session &s) {
- std::cerr << "JmsSender::on_session_error(): " << s.error() << std::endl;
- }
-
- void Sender::on_transport_error(proton::transport &t) {
- std::cerr << "JmsSender::on_transport_error(): " << t.error() << std::endl;
- }
-
- void Sender::on_error(const proton::error_condition &ec) {
- std::cerr << "JmsSender::on_error(): " << ec << std::endl;
- }
-
// protected
void Sender::sendMessages(proton::sender &s, const std::string& subType, const Json::Value& testValues) {
@@ -127,8 +101,6 @@ namespace qpidit
} else {
throw qpidit::UnknownJmsMessageTypeError(_jmsMessageType);
}
- addMessageHeaders(msg);
- addMessageProperties(msg);
s.send(msg);
_msgsSent += 1;
valueNumber += 1;
@@ -310,102 +282,6 @@ namespace qpidit
return msg;
}
- proton::message& Sender::addMessageHeaders(proton::message& msg) {
- Json::Value::Members headerNames = _testHeadersMap.getMemberNames();
- for (std::vector<std::string>::const_iterator i=headerNames.begin(); i!=headerNames.end(); ++i) {
- const Json::Value _subMap = _testHeadersMap[*i];
- const std::string headerValueType = _subMap.getMemberNames()[0]; // There is always only one entry in map
- std::string val = _subMap[headerValueType].asString();
- if (i->compare("JMS_TYPE_HEADER") == 0) {
- setJmsTypeHeader(msg, val);
- } else if (i->compare("JMS_CORRELATIONID_HEADER") == 0) {
- if (headerValueType.compare("bytes") == 0) {
- setJmsCorrelationId(msg, proton::binary(val));
- } else {
- setJmsCorrelationId(msg, val);
- }
- } else if (i->compare("JMS_REPLYTO_HEADER") == 0) {
- setJmsReplyTo(msg, headerValueType, val);
- } else {
- throw qpidit::UnknownJmsHeaderTypeError(*i);
- }
- }
- return msg;
- }
-
- //static
- proton::message& Sender::setJmsTypeHeader(proton::message& msg, const std::string& t) {
- msg.subject(t);
- return msg;
- }
-
- //static
- proton::message& Sender::setJmsCorrelationId(proton::message& msg, const std::string& cid) {
- proton::message_id mid(cid);
- msg.correlation_id(mid);
- msg.message_annotations().put(proton::symbol("x-opt-app-correlation-id"), true);
- return msg;
- }
-
- //static
- proton::message& Sender::setJmsCorrelationId(proton::message& msg, const proton::binary cid) {
- proton::message_id mid(cid);
- msg.correlation_id(cid);
- msg.message_annotations().put(proton::symbol("x-opt-app-correlation-id"), true);
- return msg;
- }
-
- //static
- proton::message& Sender::setJmsReplyTo(proton::message& msg, const std::string& dts, const std::string& d) {
- if (dts.compare("queue") == 0) {
- msg.reply_to(/*std::string("queue://") + */d);
- msg.message_annotations().put(proton::symbol("x-opt-jms-reply-to"), int8_t(JMS_QUEUE));
- } else if (dts.compare("temp_queue") == 0) {
- msg.reply_to(/*std::string("queue://") + */d);
- msg.message_annotations().put(proton::symbol("x-opt-jms-reply-to"), int8_t(JMS_TMEP_QUEUE));
- } else if (dts.compare("topic") == 0) {
- msg.reply_to(/*std::string("topic://") + */d);
- msg.message_annotations().put(proton::symbol("x-opt-jms-reply-to"), int8_t(JMS_TOPIC));
- } else if (dts.compare("temp_topic") == 0) {
- msg.reply_to(/*std::string("topic://") + */d);
- msg.message_annotations().put(proton::symbol("x-opt-jms-reply-to"), int8_t(JMS_TEMP_TOPIC));
- } else {
- throw qpidit::UnknownJmsDestinationTypeError(dts);
- }
- return msg;
- }
-
- proton::message& Sender::addMessageProperties(proton::message& msg) {
- Json::Value::Members propertyNames = _testPropertiesMap.getMemberNames();
- for (std::vector<std::string>::const_iterator i=propertyNames.begin(); i!=propertyNames.end(); ++i) {
- const Json::Value _subMap = _testPropertiesMap[*i];
- const std::string propertyValueType = _subMap.getMemberNames()[0]; // There is always only one entry in map
- std::string val = _subMap[propertyValueType].asString();
- if (propertyValueType.compare("boolean") == 0) {
- if (val.compare("False") == 0) setMessageProperty(msg, *i, false);
- else if (val.compare("True") == 0) setMessageProperty(msg, *i, true);
- else throw InvalidTestValueError(propertyValueType, val);
- } else if (propertyValueType.compare("byte") == 0) {
- setMessageProperty(msg, *i, getIntegralValue<int8_t>(val));
- } else if (propertyValueType.compare("double") == 0) {
- setMessageProperty(msg, *i, getFloatValue<double, uint64_t>(val));
- } else if (propertyValueType.compare("float") == 0) {
- setMessageProperty(msg, *i, getFloatValue<float, uint64_t>(val));
- } else if (propertyValueType.compare("int") == 0) {
- setMessageProperty(msg, *i, getIntegralValue<int32_t>(val));
- } else if (propertyValueType.compare("long") == 0) {
- setMessageProperty(msg, *i, getIntegralValue<int64_t>(val));
- } else if (propertyValueType.compare("short") == 0) {
- setMessageProperty(msg, *i, getIntegralValue<int16_t>(val));
- } else if (propertyValueType.compare("string") == 0) {
- setMessageProperty(msg, *i, val);
- } else {
- throw qpidit::UnknownJmsPropertyTypeError(propertyValueType);
- }
- }
- return msg;
- }
-
//static
proton::binary Sender::getJavaObjectBinary(const std::string& javaClassName, const std::string& valAsString) {
proton::binary javaObjectBinary;
@@ -433,18 +309,6 @@ namespace qpidit
return tot;
}
- //static
- std::map<std::string, int8_t> Sender::initializeJmsMessageTypeAnnotationMap() {
- std::map<std::string, int8_t> m;
- m["JMS_MESSAGE_TYPE"] = JMS_MESSAGE_TYPE;
- m["JMS_OBJECTMESSAGE_TYPE"] = JMS_OBJECTMESSAGE_TYPE;
- m["JMS_MAPMESSAGE_TYPE"] = JMS_MAPMESSAGE_TYPE;
- m["JMS_BYTESMESSAGE_TYPE"] = JMS_BYTESMESSAGE_TYPE;
- m["JMS_STREAMMESSAGE_TYPE"] = JMS_STREAMMESSAGE_TYPE;
- m["JMS_TEXTMESSAGE_TYPE"] = JMS_TEXTMESSAGE_TYPE;
- return m;
- }
-
} /* namespace jms_messages_test */
} /* namespace qpidit */
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/shims/qpid-proton-cpp/src/qpidit/jms_messages_test/Sender.hpp
----------------------------------------------------------------------
diff --git a/shims/qpid-proton-cpp/src/qpidit/jms_messages_test/Sender.hpp b/shims/qpid-proton-cpp/src/qpidit/jms_messages_test/Sender.hpp
index 5e41120..551edbf 100644
--- a/shims/qpid-proton-cpp/src/qpidit/jms_messages_test/Sender.hpp
+++ b/shims/qpid-proton-cpp/src/qpidit/jms_messages_test/Sender.hpp
@@ -25,8 +25,8 @@
#include "json/value.h"
#include "proton/message.hpp"
#include "proton/messaging_handler.hpp"
+#include "qpidit/JmsTestBase.hpp"
#include "qpidit/QpidItErrors.hpp"
-#include "qpidit/jms_messages_test/JmsDefinitions.hpp"
#include <typeinfo>
namespace proton {
@@ -38,17 +38,12 @@ namespace qpidit
namespace jms_messages_test
{
- class Sender : public proton::messaging_handler
+ class Sender : public qpidit::JmsTestBase
{
protected:
- static proton::symbol s_jmsMessageTypeAnnotationKey;
- static std::map<std::string, int8_t>s_jmsMessageTypeAnnotationValues;
-
const std::string _brokerUrl;
const std::string _jmsMessageType;
const Json::Value _testValueMap;
- const Json::Value _testHeadersMap;
- const Json::Value _testPropertiesMap;
uint32_t _msgsSent;
uint32_t _msgsConfirmed;
uint32_t _totalMsgs;
@@ -60,12 +55,6 @@ namespace qpidit
void on_sendable(proton::sender &s);
void on_tracker_accept(proton::tracker &t);
void on_transport_close(proton::transport &t);
-
- void on_connection_error(proton::connection &c);
- void on_session_error(proton::session &s);
- void on_sender_error(proton::sender& s);
- void on_transport_error(proton::transport &t);
- void on_error(const proton::error_condition &c);
protected:
void sendMessages(proton::sender &s, const std::string& subType, const Json::Value& testValueMap);
proton::message& setMessage(proton::message& msg, const std::string& subType, const std::string& testValueStr);
@@ -75,23 +64,9 @@ namespace qpidit
proton::message& setStreamMessage(proton::message& msg, const std::string& subType, const std::string& testValue);
proton::message& setTextMessage(proton::message& msg, const Json::Value& testValue);
- proton::message& addMessageHeaders(proton::message& msg);
- static proton::message& setJmsTypeHeader(proton::message& msg, const std::string& t);
- static proton::message& setJmsCorrelationId(proton::message& msg, const std::string& cid);
- static proton::message& setJmsCorrelationId(proton::message& msg, const proton::binary cid);
- static proton::message& setJmsReplyTo(proton::message& msg, const std::string& dt, const std::string& d);
-
- proton::message& addMessageProperties(proton::message& msg);
- template<typename T> proton::message& setMessageProperty(proton::message& msg, const std::string& propertyName, T val) {
- msg.properties().put(propertyName, val);
- return msg;
- }
-
static proton::binary getJavaObjectBinary(const std::string& javaClassName, const std::string& valAsString);
static uint32_t getTotalNumMessages(const Json::Value& testValueMap);
- static std::map<std::string, int8_t> initializeJmsMessageTypeAnnotationMap();
-
template<typename T> static T numToBinary(T n, proton::binary& b) {
for (int i=0; i<sizeof(n); ++i) {
b.push_back(* ((char*)&n + i));
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/shims/qpid-proton-python/src/amqp_types_test/Receiver.py
----------------------------------------------------------------------
diff --git a/shims/qpid-proton-python/src/amqp_types_test/Receiver.py b/shims/qpid-proton-python/src/amqp_types_test/Receiver.py
index 2876f51..7bb6355 100755
--- a/shims/qpid-proton-python/src/amqp_types_test/Receiver.py
+++ b/shims/qpid-proton-python/src/amqp_types_test/Receiver.py
@@ -26,13 +26,14 @@ AMQP type test receiver shim for qpid-interop-test
# Issues:
# * Capturing errors from client or broker
-import sys
from json import dumps
-from proton.handlers import MessagingHandler
-from proton.reactor import Container
-from traceback import format_exc
from string import digits, letters, punctuation
from struct import pack, unpack
+import sys
+from traceback import format_exc
+
+from proton.handlers import MessagingHandler
+from proton.reactor import Container
class AmqpTypesReceiverShim(MessagingHandler):
"""
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/shims/qpid-proton-python/src/amqp_types_test/Sender.py
----------------------------------------------------------------------
diff --git a/shims/qpid-proton-python/src/amqp_types_test/Sender.py b/shims/qpid-proton-python/src/amqp_types_test/Sender.py
index 19d183f..b760467 100755
--- a/shims/qpid-proton-python/src/amqp_types_test/Sender.py
+++ b/shims/qpid-proton-python/src/amqp_types_test/Sender.py
@@ -26,16 +26,17 @@ AMQP type test sender shim for qpid-interop-test
# Issues:
# * Capturing errors from client or broker
-import sys
-import os.path
from json import loads
+import os.path
+from struct import unpack
+import sys
+from traceback import format_exc
+from uuid import UUID
+
from proton import byte, char, decimal32, decimal64, decimal128, float32, int32, Message, short, symbol, timestamp, \
ubyte, uint, ulong, ushort
from proton.handlers import MessagingHandler
from proton.reactor import Container
-from struct import unpack
-from traceback import format_exc
-from uuid import UUID
class AmqpTypesSenderShim(MessagingHandler):
"""
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[5/5] qpid-interop-test git commit: QPIDIT-41: Reorganized dir
structure and tidied up the test code. Copied the old jms_messages_test to a
new jms_hdrs_props_test and simplified the jms_messages_test to include only
message body tests. Simplified parame
Posted by kp...@apache.org.
QPIDIT-41: Reorganized dir structure and tidied up the test code. Copied the old jms_messages_test to a new jms_hdrs_props_test and simplified the jms_messages_test to include only message body tests. Simplified parameters sent to shims to the same format for all shims, only one JSON string to and returned from receiver shim.
Project: http://git-wip-us.apache.org/repos/asf/qpid-interop-test/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-interop-test/commit/514bac75
Tree: http://git-wip-us.apache.org/repos/asf/qpid-interop-test/tree/514bac75
Diff: http://git-wip-us.apache.org/repos/asf/qpid-interop-test/diff/514bac75
Branch: refs/heads/master
Commit: 514bac7511be39c2ceb25eb31c3234ccd9c1ae74
Parents: 83b89fe
Author: Kim van der Riet <kp...@apache.org>
Authored: Fri Oct 7 12:49:53 2016 -0400
Committer: Kim van der Riet <kp...@apache.org>
Committed: Fri Oct 7 12:49:53 2016 -0400
----------------------------------------------------------------------
.pydevproject | 5 +-
.../jms_hdrs_props_test/Receiver.java | 525 +++++++++++++++++++
.../jms_hdrs_props_test/Sender.java | 508 ++++++++++++++++++
.../jms_messages_test/Receiver.java | 126 +----
.../jms_messages_test/Sender.java | 109 +---
shims/qpid-proton-cpp/src/CMakeLists.txt | 44 ++
.../qpid-proton-cpp/src/qpidit/JmsTestBase.cpp | 69 +++
.../qpid-proton-cpp/src/qpidit/JmsTestBase.hpp | 64 +++
.../src/qpidit/jms_hdrs_props_test/Receiver.cpp | 396 ++++++++++++++
.../src/qpidit/jms_hdrs_props_test/Receiver.hpp | 100 ++++
.../src/qpidit/jms_hdrs_props_test/Sender.cpp | 451 ++++++++++++++++
.../src/qpidit/jms_hdrs_props_test/Sender.hpp | 109 ++++
.../qpidit/jms_messages_test/JmsDefinitions.hpp | 46 --
.../src/qpidit/jms_messages_test/Receiver.cpp | 141 +----
.../src/qpidit/jms_messages_test/Receiver.hpp | 30 +-
.../src/qpidit/jms_messages_test/Sender.cpp | 138 +----
.../src/qpidit/jms_messages_test/Sender.hpp | 29 +-
.../src/amqp_types_test/Receiver.py | 9 +-
.../src/amqp_types_test/Sender.py | 11 +-
.../src/jms_hdrs_props_test/Receiver.py | 357 +++++++++++++
.../src/jms_hdrs_props_test/Sender.py | 388 ++++++++++++++
.../src/jms_messages_test/Receiver.py | 84 +--
.../src/jms_messages_test/Sender.py | 105 +---
src/python/qpid-interop-test/.gitignore | 4 -
src/python/qpid-interop-test/__init__.py | 26 -
src/python/qpid-interop-test/amqp_types_test.py | 435 ---------------
.../qpid-interop-test/broker_properties.py | 54 --
.../qpid-interop-test/interop_test_errors.py | 29 -
.../qpid-interop-test/jms_messages_test.py | 511 ------------------
src/python/qpid-interop-test/shims.py | 229 --------
src/python/qpid-interop-test/test_type_map.py | 85 ---
src/python/qpid_interop_test/.gitignore | 4 +
src/python/qpid_interop_test/__init__.py | 23 +
src/python/qpid_interop_test/amqp_types_test.py | 443 ++++++++++++++++
.../qpid_interop_test/broker_properties.py | 55 ++
.../qpid_interop_test/interop_test_errors.py | 29 +
.../qpid_interop_test/jms_hdrs_props_test.py | 520 ++++++++++++++++++
.../qpid_interop_test/jms_messages_test.py | 402 ++++++++++++++
src/python/qpid_interop_test/shims.py | 227 ++++++++
src/python/qpid_interop_test/test_type_map.py | 86 +++
40 files changed, 4852 insertions(+), 2154 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/.pydevproject
----------------------------------------------------------------------
diff --git a/.pydevproject b/.pydevproject
index 037bd25..a279738 100644
--- a/.pydevproject
+++ b/.pydevproject
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?eclipse-pydev version="1.0"?><pydev_project>
-<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
-<path>/${PROJECT_DIR_NAME}</path>
-</pydev_pathproperty>
+
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
+
</pydev_project>
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/shims/qpid-jms/src/main/java/org/apache/qpid/qpid_interop_test/jms_hdrs_props_test/Receiver.java
----------------------------------------------------------------------
diff --git a/shims/qpid-jms/src/main/java/org/apache/qpid/qpid_interop_test/jms_hdrs_props_test/Receiver.java b/shims/qpid-jms/src/main/java/org/apache/qpid/qpid_interop_test/jms_hdrs_props_test/Receiver.java
new file mode 100644
index 0000000..27b5e7e
--- /dev/null
+++ b/shims/qpid-jms/src/main/java/org/apache/qpid/qpid_interop_test/jms_hdrs_props_test/Receiver.java
@@ -0,0 +1,525 @@
+/**
+ * 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.
+ */
+package org.apache.qpid.interop_test.jms_hdrs_props_test;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+import javax.jms.BytesMessage;
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.ObjectMessage;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.StreamMessage;
+import javax.jms.TextMessage;
+import javax.jms.Topic;
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+import javax.json.JsonReader;
+import javax.json.JsonWriter;
+import org.apache.qpid.jms.JmsConnectionFactory;
+
+public class Receiver {
+ private static final String USER = "guest";
+ private static final String PASSWORD = "guest";
+ private static final int TIMEOUT = 1000;
+ private static final String[] SUPPORTED_JMS_MESSAGE_TYPES = {"JMS_MESSAGE_TYPE",
+ "JMS_BYTESMESSAGE_TYPE",
+ "JMS_MAPMESSAGE_TYPE",
+ "JMS_OBJECTMESSAGE_TYPE",
+ "JMS_STREAMMESSAGE_TYPE",
+ "JMS_TEXTMESSAGE_TYPE"};
+ private static enum JMS_DESTINATION_TYPE {JMS_QUEUE, JMS_TEMPORARY_QUEUE, JMS_TOPIC, JMS_TEMPORARY_TOPIC};
+
+ Connection _connection;
+ Session _session;
+ Queue _queue;
+ MessageConsumer _messageConsumer;
+ JsonObjectBuilder _jsonTestValueMapBuilder;
+ JsonObjectBuilder _jsonMessageHeaderMapBuilder;
+ JsonObjectBuilder _jsonMessagePropertiesMapBuilder;
+
+ // args[0]: Broker URL
+ // args[1]: Queue name
+ // args[2]: JMS message type
+ // args[3]: JSON Test parameters containing 2 maps: [testValuesMap, flagMap]
+ public static void main(String[] args) throws Exception {
+ if (args.length != 4) {
+ System.out.println("JmsReceiverShim: Incorrect number of arguments");
+ System.out.println("JmsReceiverShim: Expected arguments: broker_address, queue_name, JMS_msg_type, JSON_receive_params");
+ System.exit(1);
+ }
+ String brokerAddress = "amqp://" + args[0];
+ String queueName = args[1];
+ String jmsMessageType = args[2];
+ if (!isSupportedJmsMessageType(jmsMessageType)) {
+ System.out.println("ERROR: JmsReceiverShim: Unknown or unsupported JMS message type \"" + jmsMessageType + "\"");
+ System.exit(1);
+ }
+
+ JsonReader jsonReader = Json.createReader(new StringReader(args[3]));
+ JsonArray testParamsList = jsonReader.readArray();
+ jsonReader.close();
+
+ if (testParamsList.size() != 2) {
+ System.err.println("ERROR: Incorrect number of JSON parameters: Expected 2, got " + Integer.toString(testParamsList.size()));
+ System.exit(1);
+ }
+
+ JsonObject numTestValuesMap = testParamsList.getJsonObject(0);
+ JsonObject flagMap = testParamsList.getJsonObject(1);
+
+ Receiver shim = new Receiver(brokerAddress, queueName);
+ shim.run(jmsMessageType, numTestValuesMap, flagMap);
+ }
+
+ public Receiver(String brokerAddress, String queueName) {
+ try {
+ _connection = null;
+ ConnectionFactory factory = (ConnectionFactory)new JmsConnectionFactory(brokerAddress);
+ _connection = factory.createConnection(USER, PASSWORD);
+ _connection.setExceptionListener(new MyExceptionListener());
+ _connection.start();
+
+ _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ _queue = _session.createQueue(queueName);
+
+ _messageConsumer = _session.createConsumer(_queue);
+
+ _jsonTestValueMapBuilder = Json.createObjectBuilder();
+ _jsonMessageHeaderMapBuilder = Json.createObjectBuilder();
+ _jsonMessagePropertiesMapBuilder = Json.createObjectBuilder();
+ } catch (Exception exc) {
+ if (_connection != null)
+ try { _connection.close(); } catch (JMSException e) {}
+ System.out.println("Caught exception, exiting.");
+ exc.printStackTrace(System.out);
+ System.exit(1);
+ }
+ }
+
+ public void run(String jmsMessageType, JsonObject numTestValuesMap, JsonObject flagMap) {
+ try {
+ List<String> subTypeKeyList = new ArrayList<String>(numTestValuesMap.keySet());
+ Collections.sort(subTypeKeyList);
+
+ Message message = null;
+
+ for (String subType: subTypeKeyList) {
+ JsonArrayBuilder jasonTestValuesArrayBuilder = Json.createArrayBuilder();
+ for (int i=0; i<numTestValuesMap.getJsonNumber(subType).intValue(); ++i) {
+ message = _messageConsumer.receive(TIMEOUT);
+ if (message == null) break;
+ switch (jmsMessageType) {
+ case "JMS_MESSAGE_TYPE":
+ processJMSMessage(jasonTestValuesArrayBuilder);
+ break;
+ case "JMS_BYTESMESSAGE_TYPE":
+ processJMSBytesMessage(jmsMessageType, subType, message, jasonTestValuesArrayBuilder);
+ break;
+ case "JMS_STREAMMESSAGE_TYPE":
+ processJMSStreamMessage(jmsMessageType, subType, message, jasonTestValuesArrayBuilder);
+ break;
+ case "JMS_MAPMESSAGE_TYPE":
+ processJMSMapMessage(jmsMessageType, subType, i, message, jasonTestValuesArrayBuilder);
+ break;
+ case "JMS_OBJECTMESSAGE_TYPE":
+ processJMSObjectMessage(subType, message, jasonTestValuesArrayBuilder);
+ break;
+ case "JMS_TEXTMESSAGE_TYPE":
+ processJMSTextMessage(message, jasonTestValuesArrayBuilder);
+ break;
+ default:
+ _connection.close();
+ throw new Exception("JmsReceiverShim: Internal error: Unknown or unsupported JMS message type \"" + jmsMessageType + "\"");
+ }
+
+ processMessageHeaders(message, flagMap);
+ processMessageProperties(message);
+ }
+ _jsonTestValueMapBuilder.add(subType, jasonTestValuesArrayBuilder);
+ }
+ _connection.close();
+
+ System.out.println(jmsMessageType);
+ StringWriter out = new StringWriter();
+ JsonArrayBuilder returnList = Json.createArrayBuilder();
+ returnList.add(_jsonTestValueMapBuilder);
+ returnList.add(_jsonMessageHeaderMapBuilder);
+ returnList.add(_jsonMessagePropertiesMapBuilder);
+ writeJsonArray(returnList, out);
+ System.out.println(out.toString());
+ } catch (Exception exp) {
+ try { _connection.close(); } catch (JMSException e) {}
+ System.out.println("Caught exception, exiting.");
+ exp.printStackTrace(System.out);
+ System.exit(1);
+ }
+ }
+
+ protected void processJMSMessage(JsonArrayBuilder jasonTestValuesArrayBuilder) {
+ jasonTestValuesArrayBuilder.addNull();
+ }
+
+ protected void processJMSBytesMessage(String jmsMessageType, String subType, Message message, JsonArrayBuilder jasonTestValuesArrayBuilder) throws Exception, JMSException, IOException, ClassNotFoundException {
+ switch (subType) {
+ case "boolean":
+ jasonTestValuesArrayBuilder.add(((BytesMessage)message).readBoolean()?"True":"False");
+ break;
+ case "byte":
+ jasonTestValuesArrayBuilder.add(formatByte(((BytesMessage)message).readByte()));
+ break;
+ case "bytes":
+ {
+ byte[] bytesBuff = new byte[65536];
+ int numBytesRead = ((BytesMessage)message).readBytes(bytesBuff);
+ if (numBytesRead >= 0) {
+ jasonTestValuesArrayBuilder.add(new String(Arrays.copyOfRange(bytesBuff, 0, numBytesRead)));
+ } else {
+ // NOTE: For this case, an empty byte array has nothing to return
+ jasonTestValuesArrayBuilder.add(new String());
+ }
+ }
+ break;
+ case "char":
+ jasonTestValuesArrayBuilder.add(formatChar(((BytesMessage)message).readChar()));
+ break;
+ case "double":
+ long l = Double.doubleToRawLongBits(((BytesMessage)message).readDouble());
+ jasonTestValuesArrayBuilder.add(String.format("0x%16s", Long.toHexString(l)).replace(' ', '0'));
+ break;
+ case "float":
+ int i0 = Float.floatToRawIntBits(((BytesMessage)message).readFloat());
+ jasonTestValuesArrayBuilder.add(String.format("0x%8s", Integer.toHexString(i0)).replace(' ', '0'));
+ break;
+ case "int":
+ jasonTestValuesArrayBuilder.add(formatInt(((BytesMessage)message).readInt()));
+ break;
+ case "long":
+ jasonTestValuesArrayBuilder.add(formatLong(((BytesMessage)message).readLong()));
+ break;
+ case "object":
+ {
+ byte[] bytesBuff = new byte[65536];
+ int numBytesRead = ((BytesMessage)message).readBytes(bytesBuff);
+ if (numBytesRead >= 0) {
+ ByteArrayInputStream bais = new ByteArrayInputStream(Arrays.copyOfRange(bytesBuff, 0, numBytesRead));
+ ObjectInputStream ois = new ObjectInputStream(bais);
+ Object obj = ois.readObject();
+ jasonTestValuesArrayBuilder.add(obj.getClass().getName() + ":" + obj.toString());
+ } else {
+ jasonTestValuesArrayBuilder.add("<object error>");
+ }
+ }
+ break;
+ case "short":
+ jasonTestValuesArrayBuilder.add(formatShort(((BytesMessage)message).readShort()));
+ break;
+ case "string":
+ jasonTestValuesArrayBuilder.add(((BytesMessage)message).readUTF());
+ break;
+ default:
+ throw new Exception("JmsReceiverShim: Unknown subtype for " + jmsMessageType + ": \"" + subType + "\"");
+ }
+ }
+
+ protected void processJMSMapMessage(String jmsMessageType, String subType, int count, Message message, JsonArrayBuilder jasonTestValuesArrayBuilder) throws Exception, JMSException {
+ String name = String.format("%s%03d", subType, count);
+ switch (subType) {
+ case "boolean":
+ jasonTestValuesArrayBuilder.add(((MapMessage)message).getBoolean(name)?"True":"False");
+ break;
+ case "byte":
+ jasonTestValuesArrayBuilder.add(formatByte(((MapMessage)message).getByte(name)));
+ break;
+ case "bytes":
+ jasonTestValuesArrayBuilder.add(new String(((MapMessage)message).getBytes(name)));
+ break;
+ case "char":
+ jasonTestValuesArrayBuilder.add(formatChar(((MapMessage)message).getChar(name)));
+ break;
+ case "double":
+ long l = Double.doubleToRawLongBits(((MapMessage)message).getDouble(name));
+ jasonTestValuesArrayBuilder.add(String.format("0x%16s", Long.toHexString(l)).replace(' ', '0'));
+ break;
+ case "float":
+ int i0 = Float.floatToRawIntBits(((MapMessage)message).getFloat(name));
+ jasonTestValuesArrayBuilder.add(String.format("0x%8s", Integer.toHexString(i0)).replace(' ', '0'));
+ break;
+ case "int":
+ jasonTestValuesArrayBuilder.add(formatInt(((MapMessage)message).getInt(name)));
+ break;
+ case "long":
+ jasonTestValuesArrayBuilder.add(formatLong(((MapMessage)message).getLong(name)));
+ break;
+ case "object":
+ Object obj = ((MapMessage)message).getObject(name);
+ jasonTestValuesArrayBuilder.add(obj.getClass().getName() + ":" + obj.toString());
+ break;
+ case "short":
+ jasonTestValuesArrayBuilder.add(formatShort(((MapMessage)message).getShort(name)));
+ break;
+ case "string":
+ jasonTestValuesArrayBuilder.add(((MapMessage)message).getString(name));
+ break;
+ default:
+ throw new Exception("JmsReceiverShim: Unknown subtype for " + jmsMessageType + ": \"" + subType + "\"");
+ }
+ }
+
+ protected void processJMSObjectMessage(String subType, Message message, JsonArrayBuilder jasonTestValuesArrayBuilder) throws JMSException {
+ jasonTestValuesArrayBuilder.add(((ObjectMessage)message).getObject().toString());
+ }
+
+ protected void processJMSStreamMessage(String jmsMessageType, String subType, Message message, JsonArrayBuilder jasonTestValuesArrayBuilder) throws Exception, JMSException {
+ switch (subType) {
+ case "boolean":
+ jasonTestValuesArrayBuilder.add(((StreamMessage)message).readBoolean()?"True":"False");
+ break;
+ case "byte":
+ jasonTestValuesArrayBuilder.add(formatByte(((StreamMessage)message).readByte()));
+ break;
+ case "bytes":
+ byte[] bytesBuff = new byte[65536];
+ int numBytesRead = ((StreamMessage)message).readBytes(bytesBuff);
+ if (numBytesRead >= 0) {
+ jasonTestValuesArrayBuilder.add(new String(Arrays.copyOfRange(bytesBuff, 0, numBytesRead)));
+ } else {
+ System.out.println("StreamMessage.readBytes() returned " + numBytesRead);
+ jasonTestValuesArrayBuilder.add("<bytes error>");
+ }
+ break;
+ case "char":
+ jasonTestValuesArrayBuilder.add(formatChar(((StreamMessage)message).readChar()));
+ break;
+ case "double":
+ long l = Double.doubleToRawLongBits(((StreamMessage)message).readDouble());
+ jasonTestValuesArrayBuilder.add(String.format("0x%16s", Long.toHexString(l)).replace(' ', '0'));
+ break;
+ case "float":
+ int i0 = Float.floatToRawIntBits(((StreamMessage)message).readFloat());
+ jasonTestValuesArrayBuilder.add(String.format("0x%8s", Integer.toHexString(i0)).replace(' ', '0'));
+ break;
+ case "int":
+ jasonTestValuesArrayBuilder.add(formatInt(((StreamMessage)message).readInt()));
+ break;
+ case "long":
+ jasonTestValuesArrayBuilder.add(formatLong(((StreamMessage)message).readLong()));
+ break;
+ case "object":
+ Object obj = ((StreamMessage)message).readObject();
+ jasonTestValuesArrayBuilder.add(obj.getClass().getName() + ":" + obj.toString());
+ break;
+ case "short":
+ jasonTestValuesArrayBuilder.add(formatShort(((StreamMessage)message).readShort()));
+ break;
+ case "string":
+ jasonTestValuesArrayBuilder.add(((StreamMessage)message).readString());
+ break;
+ default:
+ throw new Exception("JmsReceiverShim: Unknown subtype for " + jmsMessageType + ": \"" + subType + "\"");
+ }
+ }
+
+ protected void processJMSTextMessage(Message message, JsonArrayBuilder jasonTestValuesArrayBuilder) throws JMSException {
+ jasonTestValuesArrayBuilder.add(((TextMessage)message).getText());
+ }
+
+ protected void processMessageHeaders(Message message, JsonObject flagMap) throws Exception, JMSException {
+ addMessageHeaderString("JMS_TYPE_HEADER", message.getJMSType());
+ if (flagMap.containsKey("JMS_CORRELATIONID_AS_BYTES") && flagMap.getBoolean("JMS_CORRELATIONID_AS_BYTES")) {
+ addMessageHeaderByteArray("JMS_CORRELATIONID_HEADER", message.getJMSCorrelationIDAsBytes());
+ } else {
+ addMessageHeaderString("JMS_CORRELATIONID_HEADER", message.getJMSCorrelationID());
+ }
+ if (flagMap.containsKey("JMS_REPLYTO_AS_TOPIC") && flagMap.getBoolean("JMS_REPLYTO_AS_TOPIC")) {
+ addMessageHeaderDestination("JMS_REPLYTO_HEADER", JMS_DESTINATION_TYPE.JMS_TOPIC, message.getJMSReplyTo());
+ } else {
+ addMessageHeaderDestination("JMS_REPLYTO_HEADER", JMS_DESTINATION_TYPE.JMS_QUEUE, message.getJMSReplyTo());
+ }
+ }
+
+ protected void addMessageHeaderString(String headerName, String value) {
+ if (value != null) {
+ JsonObjectBuilder valueMap = Json.createObjectBuilder();
+ valueMap.add("string", value);
+ _jsonMessageHeaderMapBuilder.add(headerName, valueMap);
+ }
+ }
+
+ protected void addMessageHeaderByteArray(String headerName, byte[] value) {
+ if (value != null) {
+ JsonObjectBuilder valueMap = Json.createObjectBuilder();
+ valueMap.add("bytes", new String(value));
+ _jsonMessageHeaderMapBuilder.add(headerName, valueMap);
+ }
+ }
+
+ protected void addMessageHeaderDestination(String headerName, JMS_DESTINATION_TYPE destinationType, Destination destination) throws Exception {
+ if (destination != null) {
+ JsonObjectBuilder valueMap = Json.createObjectBuilder();
+ switch (destinationType) {
+ case JMS_QUEUE:
+ valueMap.add("queue", ((Queue)destination).getQueueName());
+ break;
+ case JMS_TOPIC:
+ valueMap.add("topic", ((Topic)destination).getTopicName());
+ break;
+ default:
+ throw new Exception("Internal error: JMSDestination type not supported");
+ }
+ _jsonMessageHeaderMapBuilder.add(headerName, valueMap);
+ }
+ }
+
+ protected void processMessageProperties(Message message) throws Exception, JMSException {
+ Enumeration<String> propertyNames = message.getPropertyNames();
+ while (propertyNames.hasMoreElements()) {
+ JsonObjectBuilder valueMap = Json.createObjectBuilder();
+ String propertyName = propertyNames.nextElement();
+ int underscoreIndex = propertyName.indexOf('_');
+ if (underscoreIndex >= 0) {
+ String propType = propertyName.substring(0, underscoreIndex);
+ switch (propType) {
+ case "boolean":
+ valueMap.add(propType, message.getBooleanProperty(propertyName) ? "True" : "False");
+ _jsonMessagePropertiesMapBuilder.add(propertyName, valueMap);
+ break;
+ case "byte":
+ valueMap.add(propType, formatByte(message.getByteProperty(propertyName)));
+ _jsonMessagePropertiesMapBuilder.add(propertyName, valueMap);
+ break;
+ case "double":
+ long l = Double.doubleToRawLongBits(message.getDoubleProperty(propertyName));
+ valueMap.add(propType, String.format("0x%16s", Long.toHexString(l)).replace(' ', '0'));
+ _jsonMessagePropertiesMapBuilder.add(propertyName, valueMap);
+ break;
+ case "float":
+ int i = Float.floatToRawIntBits(message.getFloatProperty(propertyName));
+ valueMap.add(propType, String.format("0x%8s", Integer.toHexString(i)).replace(' ', '0'));
+ _jsonMessagePropertiesMapBuilder.add(propertyName, valueMap);
+ break;
+ case "int":
+ valueMap.add(propType, formatInt(message.getIntProperty(propertyName)));
+ _jsonMessagePropertiesMapBuilder.add(propertyName, valueMap);
+ break;
+ case "long":
+ valueMap.add(propType, formatLong(message.getLongProperty(propertyName)));
+ _jsonMessagePropertiesMapBuilder.add(propertyName, valueMap);
+ break;
+ case "short":
+ valueMap.add(propType, formatShort(message.getShortProperty(propertyName)));
+ _jsonMessagePropertiesMapBuilder.add(propertyName, valueMap);
+ break;
+ case "string":
+ valueMap.add(propType, message.getStringProperty(propertyName));
+ _jsonMessagePropertiesMapBuilder.add(propertyName, valueMap);
+ break;
+ default:
+ ; // Ignore any other property the broker may add
+ }
+ } else {
+ // TODO: handle other non-test properties that might exist here
+ }
+ }
+ }
+
+ protected static void writeJsonArray(JsonArrayBuilder builder, StringWriter out) {
+ JsonWriter jsonWriter = Json.createWriter(out);
+ jsonWriter.writeArray(builder.build());
+ jsonWriter.close();
+ }
+
+ protected static String formatByte(byte b) {
+ boolean neg = false;
+ if (b < 0) {
+ neg = true;
+ b = (byte)-b;
+ }
+ return String.format("%s0x%x", neg?"-":"", b);
+ }
+
+ protected static String formatChar(char c) {
+ if (Character.isLetterOrDigit(c)) {
+ return String.format("%c", c);
+ }
+ char[] ca = {c};
+ return new String(ca);
+ }
+
+ protected static String formatInt(int i) {
+ boolean neg = false;
+ if (i < 0) {
+ neg = true;
+ i = -i;
+ }
+ return String.format("%s0x%x", neg?"-":"", i);
+ }
+
+ protected static String formatLong(long l) {
+ boolean neg = false;
+ if (l < 0) {
+ neg = true;
+ l = -l;
+ }
+ return String.format("%s0x%x", neg?"-":"", l);
+ }
+
+ protected static String formatShort(int s) {
+ boolean neg = false;
+ if (s < 0) {
+ neg = true;
+ s = -s;
+ }
+ return String.format("%s0x%x", neg?"-":"", s);
+ }
+
+ protected static boolean isSupportedJmsMessageType(String jmsMessageType) {
+ for (String supportedJmsMessageType: SUPPORTED_JMS_MESSAGE_TYPES) {
+ if (jmsMessageType.equals(supportedJmsMessageType))
+ return true;
+ }
+ return false;
+ }
+
+ private static class MyExceptionListener implements ExceptionListener {
+ @Override
+ public void onException(JMSException exception) {
+ System.out.println("Connection ExceptionListener fired, exiting.");
+ exception.printStackTrace(System.out);
+ System.exit(1);
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/shims/qpid-jms/src/main/java/org/apache/qpid/qpid_interop_test/jms_hdrs_props_test/Sender.java
----------------------------------------------------------------------
diff --git a/shims/qpid-jms/src/main/java/org/apache/qpid/qpid_interop_test/jms_hdrs_props_test/Sender.java b/shims/qpid-jms/src/main/java/org/apache/qpid/qpid_interop_test/jms_hdrs_props_test/Sender.java
new file mode 100644
index 0000000..2f38991
--- /dev/null
+++ b/shims/qpid-jms/src/main/java/org/apache/qpid/qpid_interop_test/jms_hdrs_props_test/Sender.java
@@ -0,0 +1,508 @@
+/**
+ * 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.
+ */
+package org.apache.qpid.interop_test.jms_hdrs_props_test;
+
+import java.io.Serializable;
+import java.io.StringReader;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import javax.jms.BytesMessage;
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.DeliveryMode;
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.Message;
+import javax.jms.MessageProducer;
+import javax.jms.ObjectMessage;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.StreamMessage;
+import javax.jms.TextMessage;
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonObject;
+import javax.json.JsonReader;
+import org.apache.qpid.jms.JmsConnectionFactory;
+
+public class Sender {
+ private static final String USER = "guest";
+ private static final String PASSWORD = "guest";
+ private static final String[] SUPPORTED_JMS_MESSAGE_TYPES = {"JMS_MESSAGE_TYPE",
+ "JMS_BYTESMESSAGE_TYPE",
+ "JMS_MAPMESSAGE_TYPE",
+ "JMS_OBJECTMESSAGE_TYPE",
+ "JMS_STREAMMESSAGE_TYPE",
+ "JMS_TEXTMESSAGE_TYPE"};
+ Connection _connection;
+ Session _session;
+ Queue _queue;
+ MessageProducer _messageProducer;
+ int _msgsSent;
+
+
+ // args[0]: Broker URL
+ // args[1]: Queue name
+ // args[2]: JMS message type
+ // args[3]: JSON Test parameters containing 3 maps: [testValueMap, testHeadersMap, testPropertiesMap]
+ public static void main(String[] args) throws Exception {
+ if (args.length != 4) {
+ System.out.println("JmsSenderShim: Incorrect number of arguments");
+ System.out.println("JmsSenderShim: Expected arguments: broker_address, queue_name, JMS_msg_type, JSON_send_params");
+ System.exit(1);
+ }
+ String brokerAddress = "amqp://" + args[0];
+ String queueName = args[1];
+ String jmsMessageType = args[2];
+ if (!isSupportedJmsMessageType(jmsMessageType)) {
+ System.err.println("ERROR: JmsSender: Unknown or unsupported JMS message type \"" + jmsMessageType + "\"");
+ System.exit(1);
+ }
+
+ JsonReader jsonReader = Json.createReader(new StringReader(args[3]));
+ JsonArray testParamsList = jsonReader.readArray();
+ jsonReader.close();
+
+ if (testParamsList.size() != 3) {
+ System.err.println("ERROR: Incorrect number of JSON parameters: Expected 3, got " + Integer.toString(testParamsList.size()));
+ System.err.println(" JSON parameters found: \"" + testParamsList + "\"");
+ System.exit(1);
+ }
+ JsonObject testValuesMap = testParamsList.getJsonObject(0);
+ JsonObject testHeadersMap = testParamsList.getJsonObject(1);
+ JsonObject testPropertiesMap = testParamsList.getJsonObject(2);
+
+ Sender shim = new Sender(brokerAddress, queueName);
+ shim.runTests(jmsMessageType, testValuesMap, testHeadersMap, testPropertiesMap);
+ }
+
+ public Sender(String brokerAddress, String queueName) {
+ try {
+ ConnectionFactory factory = (ConnectionFactory)new JmsConnectionFactory(brokerAddress);
+
+ _connection = factory.createConnection();
+ _connection.setExceptionListener(new MyExceptionListener());
+ _connection.start();
+
+ _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ _queue = _session.createQueue(queueName);
+
+ _messageProducer = _session.createProducer(_queue);
+
+ _msgsSent = 0;
+ } catch (Exception exp) {
+ System.out.println("Caught exception, exiting.");
+ exp.printStackTrace(System.out);
+ System.exit(1);
+ }
+ }
+
+ public void runTests(String jmsMessageType, JsonObject testValuesMap, JsonObject testHeadersMap, JsonObject testPropertiesMap) throws Exception {
+ List<String> testValuesKeyList = new ArrayList<String>(testValuesMap.keySet());
+ Collections.sort(testValuesKeyList);
+ for (String key: testValuesKeyList) {
+ JsonArray testValues = testValuesMap.getJsonArray(key);
+ for (int i=0; i<testValues.size(); ++i) {
+ String testValue = "";
+ if (!testValues.isNull(i)) {
+ testValue = testValues.getJsonString(i).getString();
+ }
+
+ // Send message
+ Message msg = createMessage(jmsMessageType, key, testValue, i);
+ addMessageHeaders(msg, testHeadersMap);
+ addMessageProperties(msg, testPropertiesMap);
+ _messageProducer.send(msg, DeliveryMode.NON_PERSISTENT, Message.DEFAULT_PRIORITY, Message.DEFAULT_TIME_TO_LIVE);
+ _msgsSent++;
+ }
+ }
+ _connection.close();
+ }
+
+ protected Message createMessage(String jmsMessageType, String key, String testValue, int i) throws Exception {
+ Message message = null;
+ switch (jmsMessageType) {
+ case "JMS_MESSAGE_TYPE":
+ message = createJMSMessage(key, testValue);
+ break;
+ case "JMS_BYTESMESSAGE_TYPE":
+ message = createJMSBytesMessage(key, testValue);
+ break;
+ case "JMS_MAPMESSAGE_TYPE":
+ message = createJMSMapMessage(key, testValue, i);
+ break;
+ case "JMS_OBJECTMESSAGE_TYPE":
+ message = createJMSObjectMessage(key, testValue);
+ break;
+ case "JMS_STREAMMESSAGE_TYPE":
+ message = createJMSStreamMessage(key, testValue);
+ break;
+ case "JMS_TEXTMESSAGE_TYPE":
+ message = createTextMessage(testValue);
+ break;
+ default:
+ throw new Exception("Internal exception: Unexpected JMS message type \"" + jmsMessageType + "\"");
+ }
+ return message;
+ }
+
+
+ protected void addMessageHeaders(Message msg, JsonObject testHeadersMap) throws Exception, JMSException {
+ List<String> testHeadersKeyList = new ArrayList<String>(testHeadersMap.keySet());
+ for (String key: testHeadersKeyList) {
+ JsonObject subMap = testHeadersMap.getJsonObject(key);
+ List<String> subMapKeyList = new ArrayList<String>(subMap.keySet());
+ String subMapKey = subMapKeyList.get(0); // There is always only one entry in map
+ String subMapVal = subMap.getString(subMapKey);
+ switch (key) {
+ case "JMS_TYPE_HEADER":
+ if (subMapKey.compareTo("string") == 0) {
+ msg.setJMSType(subMapVal);
+ } else {
+ throw new Exception("Internal exception: Invalid message header type \"" + subMapKey + "\" for message header \"" + key + "\"");
+ }
+ break;
+ case "JMS_CORRELATIONID_HEADER":
+ if (subMapKey.compareTo("string") == 0) {
+ msg.setJMSCorrelationID(subMapVal);
+ } else if (subMapKey.compareTo("bytes") == 0) {
+ msg.setJMSCorrelationIDAsBytes(subMapVal.getBytes());
+ } else {
+ throw new Exception("Internal exception: Invalid message header type \"" + subMapKey + "\" for message header \"" + key + "\"");
+ }
+ break;
+ case "JMS_REPLYTO_HEADER":
+ switch (subMapKey) {
+ case "queue":
+ msg.setJMSReplyTo(_session.createQueue(subMapVal));
+ break;
+ case "temp_queue":
+ msg.setJMSReplyTo(_session.createTemporaryQueue());
+ break;
+ case "topic":
+ msg.setJMSReplyTo(_session.createTopic(subMapVal));
+ break;
+ case "temp_topic":
+ msg.setJMSReplyTo(_session.createTemporaryTopic());
+ break;
+ default:
+ throw new Exception("Internal exception: Invalid message header type \"" + subMapKey + "\" for message header \"" + key + "\"");
+ }
+ break;
+ default:
+ throw new Exception("Internal exception: Unknown or unsupported message header \"" + key + "\"");
+ }
+ }
+ }
+
+ protected void addMessageProperties(Message msg, JsonObject testPropertiesMap) throws Exception, JMSException {
+ List<String> testPropertiesKeyList = new ArrayList<String>(testPropertiesMap.keySet());
+ for (String key: testPropertiesKeyList) {
+ JsonObject subMap = testPropertiesMap.getJsonObject(key);
+ List<String> subMapKeyList = new ArrayList<String>(subMap.keySet());
+ String subMapKey = subMapKeyList.get(0); // There is always only one entry in map
+ String subMapVal = subMap.getString(subMapKey);
+ switch (subMapKey) {
+ case "boolean":
+ msg.setBooleanProperty(key, Boolean.parseBoolean(subMapVal));
+ break;
+ case "byte":
+ msg.setByteProperty(key, Byte.decode(subMapVal));
+ break;
+ case "double":
+ Long l1 = Long.parseLong(subMapVal.substring(2, 3), 16) << 60;
+ Long l2 = Long.parseLong(subMapVal.substring(3), 16);
+ msg.setDoubleProperty(key, Double.longBitsToDouble(l1 | l2));
+ break;
+ case "float":
+ Long i = Long.parseLong(subMapVal.substring(2), 16);
+ msg.setFloatProperty(key, Float.intBitsToFloat(i.intValue()));
+ break;
+ case "int":
+ msg.setIntProperty(key, Integer.decode(subMapVal));
+ break;
+ case "long":
+ msg.setLongProperty(key, Long.decode(subMapVal));
+ break;
+ case "short":
+ msg.setShortProperty(key, Short.decode(subMapVal));
+ break;
+ case "string":
+ msg.setStringProperty(key, subMapVal);
+ break;
+ default:
+ throw new Exception("Internal exception: Unknown or unsupported message property type \"" + subMapKey + "\"");
+ }
+ }
+ }
+
+ protected Message createJMSMessage(String testValueType, String testValue) throws Exception, JMSException {
+ if (testValueType.compareTo("none") != 0) {
+ throw new Exception("Internal exception: Unexpected JMS message sub-type \"" + testValueType + "\"");
+ }
+ if (testValue.length() > 0) {
+ throw new Exception("Internal exception: Unexpected JMS message value \"" + testValue + "\" for sub-type \"" + testValueType + "\"");
+ }
+ return _session.createMessage();
+ }
+
+ protected BytesMessage createJMSBytesMessage(String testValueType, String testValue) throws Exception, JMSException {
+ BytesMessage message = _session.createBytesMessage();
+ switch (testValueType) {
+ case "boolean":
+ message.writeBoolean(Boolean.parseBoolean(testValue));
+ break;
+ case "byte":
+ message.writeByte(Byte.decode(testValue));
+ break;
+ case "bytes":
+ message.writeBytes(testValue.getBytes());
+ break;
+ case "char":
+ if (testValue.length() == 1) { // Char format: "X" or "\xNN"
+ message.writeChar(testValue.charAt(0));
+ } else {
+ throw new Exception("JmsSenderShim.createJMSBytesMessage() Malformed char string: \"" + testValue + "\" of length " + testValue.length());
+ }
+ break;
+ case "double":
+ Long l1 = Long.parseLong(testValue.substring(2, 3), 16) << 60;
+ Long l2 = Long.parseLong(testValue.substring(3), 16);
+ message.writeDouble(Double.longBitsToDouble(l1 | l2));
+ break;
+ case "float":
+ Long i = Long.parseLong(testValue.substring(2), 16);
+ message.writeFloat(Float.intBitsToFloat(i.intValue()));
+ break;
+ case "int":
+ message.writeInt(Integer.decode(testValue));
+ break;
+ case "long":
+ message.writeLong(Long.decode(testValue));
+ break;
+ case "object":
+ Object obj = (Object)createObject(testValue);
+ message.writeObject(obj);
+ break;
+ case "short":
+ message.writeShort(Short.decode(testValue));
+ break;
+ case "string":
+ message.writeUTF(testValue);
+ break;
+ default:
+ throw new Exception("Internal exception: Unexpected JMS message sub-type \"" + testValueType + "\"");
+ }
+ return message;
+ }
+
+ protected MapMessage createJMSMapMessage(String testValueType, String testValue, int testValueNum) throws Exception, JMSException {
+ MapMessage message = _session.createMapMessage();
+ String name = String.format("%s%03d", testValueType, testValueNum);
+ switch (testValueType) {
+ case "boolean":
+ message.setBoolean(name, Boolean.parseBoolean(testValue));
+ break;
+ case "byte":
+ message.setByte(name, Byte.decode(testValue));
+ break;
+ case "bytes":
+ message.setBytes(name, testValue.getBytes());
+ break;
+ case "char":
+ if (testValue.length() == 1) { // Char format: "X"
+ message.setChar(name, testValue.charAt(0));
+ } else if (testValue.length() == 6) { // Char format: "\xNNNN"
+ message.setChar(name, (char)Integer.parseInt(testValue.substring(2), 16));
+ } else {
+ throw new Exception("JmsSenderShim.createJMSMapMessage() Malformed char string: \"" + testValue + "\"");
+ }
+ break;
+ case "double":
+ Long l1 = Long.parseLong(testValue.substring(2, 3), 16) << 60;
+ Long l2 = Long.parseLong(testValue.substring(3), 16);
+ message.setDouble(name, Double.longBitsToDouble(l1 | l2));
+ break;
+ case "float":
+ Long i = Long.parseLong(testValue.substring(2), 16);
+ message.setFloat(name, Float.intBitsToFloat(i.intValue()));
+ break;
+ case "int":
+ message.setInt(name, Integer.decode(testValue));
+ break;
+ case "long":
+ message.setLong(name, Long.decode(testValue));
+ break;
+ case "object":
+ Object obj = (Object)createObject(testValue);
+ message.setObject(name, obj);
+ break;
+ case "short":
+ message.setShort(name, Short.decode(testValue));
+ break;
+ case "string":
+ message.setString(name, testValue);
+ break;
+ default:
+ throw new Exception("Internal exception: Unexpected JMS message sub-type \"" + testValueType + "\"");
+ }
+ return message;
+ }
+
+ protected ObjectMessage createJMSObjectMessage(String className, String testValue) throws Exception, JMSException {
+ Serializable obj = createJavaObject(className, testValue);
+ if (obj == null) {
+ // TODO: Handle error here
+ System.out.println("JmsSenderShim.createJMSObjectMessage: obj == null");
+ return null;
+ }
+ ObjectMessage message = _session.createObjectMessage();
+ message.setObject(obj);
+ return message;
+ }
+
+ protected StreamMessage createJMSStreamMessage(String testValueType, String testValue) throws Exception, JMSException {
+ StreamMessage message = _session.createStreamMessage();
+ switch (testValueType) {
+ case "boolean":
+ message.writeBoolean(Boolean.parseBoolean(testValue));
+ break;
+ case "byte":
+ message.writeByte(Byte.decode(testValue));
+ break;
+ case "bytes":
+ message.writeBytes(testValue.getBytes());
+ break;
+ case "char":
+ if (testValue.length() == 1) { // Char format: "X"
+ message.writeChar(testValue.charAt(0));
+ } else if (testValue.length() == 6) { // Char format: "\xNNNN"
+ message.writeChar((char)Integer.parseInt(testValue.substring(2), 16));
+ } else {
+ throw new Exception("JmsSenderShim.createJMSStreamMessage() Malformed char string: \"" + testValue + "\"");
+ }
+ break;
+ case "double":
+ Long l1 = Long.parseLong(testValue.substring(2, 3), 16) << 60;
+ Long l2 = Long.parseLong(testValue.substring(3), 16);
+ message.writeDouble(Double.longBitsToDouble(l1 | l2));
+ break;
+ case "float":
+ Long i = Long.parseLong(testValue.substring(2), 16);
+ message.writeFloat(Float.intBitsToFloat(i.intValue()));
+ break;
+ case "int":
+ message.writeInt(Integer.decode(testValue));
+ break;
+ case "long":
+ message.writeLong(Long.decode(testValue));
+ break;
+ case "object":
+ Object obj = (Object)createObject(testValue);
+ message.writeObject(obj);
+ break;
+ case "short":
+ message.writeShort(Short.decode(testValue));
+ break;
+ case "string":
+ message.writeString(testValue);
+ break;
+ default:
+ throw new Exception("JmsSenderShim.createJMSStreamMessage(): Unexpected JMS message sub-type \"" + testValueType + "\"");
+ }
+ return message;
+ }
+
+ protected static Serializable createJavaObject(String className, String testValue) throws Exception {
+ Serializable obj = null;
+ try {
+ Class<?> c = Class.forName(className);
+ if (className.compareTo("java.lang.Character") == 0) {
+ Constructor ctor = c.getConstructor(char.class);
+ if (testValue.length() == 1) {
+ // Use first character of string
+ obj = (Serializable)ctor.newInstance(testValue.charAt(0));
+ } else if (testValue.length() == 4 || testValue.length() == 6) {
+ // Format '\xNN' or '\xNNNN'
+ obj = (Serializable)ctor.newInstance((char)Integer.parseInt(testValue.substring(2), 16));
+ } else {
+ throw new Exception("JmsSenderShim.createJavaObject(): Malformed char string: \"" + testValue + "\"");
+ }
+ } else {
+ // Use string constructor
+ Constructor ctor = c.getConstructor(String.class);
+ obj = (Serializable)ctor.newInstance(testValue);
+ }
+ }
+ catch (ClassNotFoundException e) {
+ e.printStackTrace(System.out);
+ }
+ catch (NoSuchMethodException e) {
+ e.printStackTrace(System.out);
+ }
+ catch (InstantiationException e) {
+ e.printStackTrace(System.out);
+ }
+ catch (IllegalAccessException e) {
+ e.printStackTrace(System.out);
+ }
+ catch (InvocationTargetException e) {
+ e.printStackTrace(System.out);
+ }
+ return obj;
+ }
+
+ // value has format "classname:ctorstrvalue"
+ protected static Serializable createObject(String value) throws Exception {
+ Serializable obj = null;
+ int colonIndex = value.indexOf(":");
+ if (colonIndex >= 0) {
+ String className = value.substring(0, colonIndex);
+ String testValue = value.substring(colonIndex+1);
+ obj = createJavaObject(className, testValue);
+ } else {
+ throw new Exception("createObject(): Malformed value string");
+ }
+ return obj;
+ }
+
+ protected TextMessage createTextMessage(String valueStr) throws JMSException {
+ return _session.createTextMessage(valueStr);
+ }
+
+ protected static boolean isSupportedJmsMessageType(String jmsMessageType) {
+ for (String supportedJmsMessageType: SUPPORTED_JMS_MESSAGE_TYPES) {
+ if (jmsMessageType.equals(supportedJmsMessageType))
+ return true;
+ }
+ return false;
+ }
+
+ private static class MyExceptionListener implements ExceptionListener {
+ @Override
+ public void onException(JMSException exception) {
+ System.out.println("Connection ExceptionListener fired, exiting.");
+ exception.printStackTrace(System.out);
+ System.exit(1);
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/shims/qpid-jms/src/main/java/org/apache/qpid/qpid_interop_test/jms_messages_test/Receiver.java
----------------------------------------------------------------------
diff --git a/shims/qpid-jms/src/main/java/org/apache/qpid/qpid_interop_test/jms_messages_test/Receiver.java b/shims/qpid-jms/src/main/java/org/apache/qpid/qpid_interop_test/jms_messages_test/Receiver.java
index 29e8ddc..46b6baf 100644
--- a/shims/qpid-jms/src/main/java/org/apache/qpid/qpid_interop_test/jms_messages_test/Receiver.java
+++ b/shims/qpid-jms/src/main/java/org/apache/qpid/qpid_interop_test/jms_messages_test/Receiver.java
@@ -67,13 +67,11 @@ public class Receiver {
Queue _queue;
MessageConsumer _messageConsumer;
JsonObjectBuilder _jsonTestValueMapBuilder;
- JsonObjectBuilder _jsonMessageHeaderMapBuilder;
- JsonObjectBuilder _jsonMessagePropertiesMapBuilder;
// args[0]: Broker URL
// args[1]: Queue name
// args[2]: JMS message type
- // args[3]: JSON Test parameters containing 2 maps: [testValuesMap, flagMap]
+ // args[3]: JSON Test parameters containing testValuesMap
public static void main(String[] args) throws Exception {
if (args.length != 4) {
System.out.println("JmsReceiverShim: Incorrect number of arguments");
@@ -89,19 +87,11 @@ public class Receiver {
}
JsonReader jsonReader = Json.createReader(new StringReader(args[3]));
- JsonArray testParamsList = jsonReader.readArray();
+ JsonObject numTestValuesMap = jsonReader.readObject();
jsonReader.close();
-
- if (testParamsList.size() != 2) {
- System.err.println("ERROR: Incorrect number of JSON parameters: Expected 2, got " + Integer.toString(testParamsList.size()));
- System.exit(1);
- }
-
- JsonObject numTestValuesMap = testParamsList.getJsonObject(0);
- JsonObject flagMap = testParamsList.getJsonObject(1);
Receiver shim = new Receiver(brokerAddress, queueName);
- shim.run(jmsMessageType, numTestValuesMap, flagMap);
+ shim.run(jmsMessageType, numTestValuesMap);
}
public Receiver(String brokerAddress, String queueName) {
@@ -119,8 +109,6 @@ public class Receiver {
_messageConsumer = _session.createConsumer(_queue);
_jsonTestValueMapBuilder = Json.createObjectBuilder();
- _jsonMessageHeaderMapBuilder = Json.createObjectBuilder();
- _jsonMessagePropertiesMapBuilder = Json.createObjectBuilder();
} catch (Exception exc) {
if (_connection != null)
try { _connection.close(); } catch (JMSException e) {}
@@ -130,7 +118,7 @@ public class Receiver {
}
}
- public void run(String jmsMessageType, JsonObject numTestValuesMap, JsonObject flagMap) {
+ public void run(String jmsMessageType, JsonObject numTestValuesMap) {
try {
List<String> subTypeKeyList = new ArrayList<String>(numTestValuesMap.keySet());
Collections.sort(subTypeKeyList);
@@ -165,9 +153,6 @@ public class Receiver {
_connection.close();
throw new Exception("JmsReceiverShim: Internal error: Unknown or unsupported JMS message type \"" + jmsMessageType + "\"");
}
-
- processMessageHeaders(message, flagMap);
- processMessageProperties(message);
}
_jsonTestValueMapBuilder.add(subType, jasonTestValuesArrayBuilder);
}
@@ -176,10 +161,6 @@ public class Receiver {
System.out.println(jmsMessageType);
StringWriter out = new StringWriter();
writeJsonObject(_jsonTestValueMapBuilder, out);
- out.append('\n');
- writeJsonObject(_jsonMessageHeaderMapBuilder, out);
- out.append('\n');
- writeJsonObject(_jsonMessagePropertiesMapBuilder, out);
System.out.println(out.toString());
} catch (Exception exp) {
try { _connection.close(); } catch (JMSException e) {}
@@ -357,105 +338,6 @@ public class Receiver {
jasonTestValuesArrayBuilder.add(((TextMessage)message).getText());
}
- protected void processMessageHeaders(Message message, JsonObject flagMap) throws Exception, JMSException {
- addMessageHeaderString("JMS_TYPE_HEADER", message.getJMSType());
- if (flagMap.containsKey("JMS_CORRELATIONID_AS_BYTES") && flagMap.getBoolean("JMS_CORRELATIONID_AS_BYTES")) {
- addMessageHeaderByteArray("JMS_CORRELATIONID_HEADER", message.getJMSCorrelationIDAsBytes());
- } else {
- addMessageHeaderString("JMS_CORRELATIONID_HEADER", message.getJMSCorrelationID());
- }
- if (flagMap.containsKey("JMS_REPLYTO_AS_TOPIC") && flagMap.getBoolean("JMS_REPLYTO_AS_TOPIC")) {
- addMessageHeaderDestination("JMS_REPLYTO_HEADER", JMS_DESTINATION_TYPE.JMS_TOPIC, message.getJMSReplyTo());
- } else {
- addMessageHeaderDestination("JMS_REPLYTO_HEADER", JMS_DESTINATION_TYPE.JMS_QUEUE, message.getJMSReplyTo());
- }
- }
-
- protected void addMessageHeaderString(String headerName, String value) {
- if (value != null) {
- JsonObjectBuilder valueMap = Json.createObjectBuilder();
- valueMap.add("string", value);
- _jsonMessageHeaderMapBuilder.add(headerName, valueMap);
- }
- }
-
- protected void addMessageHeaderByteArray(String headerName, byte[] value) {
- if (value != null) {
- JsonObjectBuilder valueMap = Json.createObjectBuilder();
- valueMap.add("bytes", new String(value));
- _jsonMessageHeaderMapBuilder.add(headerName, valueMap);
- }
- }
-
- protected void addMessageHeaderDestination(String headerName, JMS_DESTINATION_TYPE destinationType, Destination destination) throws Exception {
- if (destination != null) {
- JsonObjectBuilder valueMap = Json.createObjectBuilder();
- switch (destinationType) {
- case JMS_QUEUE:
- valueMap.add("queue", ((Queue)destination).getQueueName());
- break;
- case JMS_TOPIC:
- valueMap.add("topic", ((Topic)destination).getTopicName());
- break;
- default:
- throw new Exception("Internal error: JMSDestination type not supported");
- }
- _jsonMessageHeaderMapBuilder.add(headerName, valueMap);
- }
- }
-
- protected void processMessageProperties(Message message) throws Exception, JMSException {
- Enumeration<String> propertyNames = message.getPropertyNames();
- while (propertyNames.hasMoreElements()) {
- JsonObjectBuilder valueMap = Json.createObjectBuilder();
- String propertyName = propertyNames.nextElement();
- int underscoreIndex = propertyName.indexOf('_');
- if (underscoreIndex >= 0) {
- String propType = propertyName.substring(0, underscoreIndex);
- switch (propType) {
- case "boolean":
- valueMap.add(propType, message.getBooleanProperty(propertyName) ? "True" : "False");
- _jsonMessagePropertiesMapBuilder.add(propertyName, valueMap);
- break;
- case "byte":
- valueMap.add(propType, formatByte(message.getByteProperty(propertyName)));
- _jsonMessagePropertiesMapBuilder.add(propertyName, valueMap);
- break;
- case "double":
- long l = Double.doubleToRawLongBits(message.getDoubleProperty(propertyName));
- valueMap.add(propType, String.format("0x%16s", Long.toHexString(l)).replace(' ', '0'));
- _jsonMessagePropertiesMapBuilder.add(propertyName, valueMap);
- break;
- case "float":
- int i = Float.floatToRawIntBits(message.getFloatProperty(propertyName));
- valueMap.add(propType, String.format("0x%8s", Integer.toHexString(i)).replace(' ', '0'));
- _jsonMessagePropertiesMapBuilder.add(propertyName, valueMap);
- break;
- case "int":
- valueMap.add(propType, formatInt(message.getIntProperty(propertyName)));
- _jsonMessagePropertiesMapBuilder.add(propertyName, valueMap);
- break;
- case "long":
- valueMap.add(propType, formatLong(message.getLongProperty(propertyName)));
- _jsonMessagePropertiesMapBuilder.add(propertyName, valueMap);
- break;
- case "short":
- valueMap.add(propType, formatShort(message.getShortProperty(propertyName)));
- _jsonMessagePropertiesMapBuilder.add(propertyName, valueMap);
- break;
- case "string":
- valueMap.add(propType, message.getStringProperty(propertyName));
- _jsonMessagePropertiesMapBuilder.add(propertyName, valueMap);
- break;
- default:
- ; // Ignore any other property the broker may add
- }
- } else {
- // TODO: handle other non-test properties that might exist here
- }
- }
- }
-
protected static void writeJsonObject(JsonObjectBuilder builder, StringWriter out) {
JsonWriter jsonWriter = Json.createWriter(out);
jsonWriter.writeObject(builder.build());
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/shims/qpid-jms/src/main/java/org/apache/qpid/qpid_interop_test/jms_messages_test/Sender.java
----------------------------------------------------------------------
diff --git a/shims/qpid-jms/src/main/java/org/apache/qpid/qpid_interop_test/jms_messages_test/Sender.java b/shims/qpid-jms/src/main/java/org/apache/qpid/qpid_interop_test/jms_messages_test/Sender.java
index 0a0539c..0cccc97 100644
--- a/shims/qpid-jms/src/main/java/org/apache/qpid/qpid_interop_test/jms_messages_test/Sender.java
+++ b/shims/qpid-jms/src/main/java/org/apache/qpid/qpid_interop_test/jms_messages_test/Sender.java
@@ -62,7 +62,7 @@ public class Sender {
// args[0]: Broker URL
// args[1]: Queue name
// args[2]: JMS message type
- // args[3]: JSON Test parameters containing 3 maps: [testValueMap, testHeadersMap, testPropertiesMap]
+ // args[3]: JSON Test parameters containing testValueMap
public static void main(String[] args) throws Exception {
if (args.length != 4) {
System.out.println("JmsSenderShim: Incorrect number of arguments");
@@ -78,20 +78,11 @@ public class Sender {
}
JsonReader jsonReader = Json.createReader(new StringReader(args[3]));
- JsonArray testParamsList = jsonReader.readArray();
+ JsonObject testValuesMap = jsonReader.readObject();
jsonReader.close();
- if (testParamsList.size() != 3) {
- System.err.println("ERROR: Incorrect number of JSON parameters: Expected 3, got " + Integer.toString(testParamsList.size()));
- System.err.println(" JSON parameters found: \"" + testParamsList + "\"");
- System.exit(1);
- }
- JsonObject testValuesMap = testParamsList.getJsonObject(0);
- JsonObject testHeadersMap = testParamsList.getJsonObject(1);
- JsonObject testPropertiesMap = testParamsList.getJsonObject(2);
-
Sender shim = new Sender(brokerAddress, queueName);
- shim.runTests(jmsMessageType, testValuesMap, testHeadersMap, testPropertiesMap);
+ shim.runTests(jmsMessageType, testValuesMap);
}
public Sender(String brokerAddress, String queueName) {
@@ -116,7 +107,7 @@ public class Sender {
}
}
- public void runTests(String jmsMessageType, JsonObject testValuesMap, JsonObject testHeadersMap, JsonObject testPropertiesMap) throws Exception {
+ public void runTests(String jmsMessageType, JsonObject testValuesMap) throws Exception {
List<String> testValuesKeyList = new ArrayList<String>(testValuesMap.keySet());
Collections.sort(testValuesKeyList);
for (String key: testValuesKeyList) {
@@ -129,8 +120,6 @@ public class Sender {
// Send message
Message msg = createMessage(jmsMessageType, key, testValue, i);
- addMessageHeaders(msg, testHeadersMap);
- addMessageProperties(msg, testPropertiesMap);
_messageProducer.send(msg, DeliveryMode.NON_PERSISTENT, Message.DEFAULT_PRIORITY, Message.DEFAULT_TIME_TO_LIVE);
_msgsSent++;
}
@@ -165,96 +154,6 @@ public class Sender {
return message;
}
-
- protected void addMessageHeaders(Message msg, JsonObject testHeadersMap) throws Exception, JMSException {
- List<String> testHeadersKeyList = new ArrayList<String>(testHeadersMap.keySet());
- for (String key: testHeadersKeyList) {
- JsonObject subMap = testHeadersMap.getJsonObject(key);
- List<String> subMapKeyList = new ArrayList<String>(subMap.keySet());
- String subMapKey = subMapKeyList.get(0); // There is always only one entry in map
- String subMapVal = subMap.getString(subMapKey);
- switch (key) {
- case "JMS_TYPE_HEADER":
- if (subMapKey.compareTo("string") == 0) {
- msg.setJMSType(subMapVal);
- } else {
- throw new Exception("Internal exception: Invalid message header type \"" + subMapKey + "\" for message header \"" + key + "\"");
- }
- break;
- case "JMS_CORRELATIONID_HEADER":
- if (subMapKey.compareTo("string") == 0) {
- msg.setJMSCorrelationID(subMapVal);
- } else if (subMapKey.compareTo("bytes") == 0) {
- msg.setJMSCorrelationIDAsBytes(subMapVal.getBytes());
- } else {
- throw new Exception("Internal exception: Invalid message header type \"" + subMapKey + "\" for message header \"" + key + "\"");
- }
- break;
- case "JMS_REPLYTO_HEADER":
- switch (subMapKey) {
- case "queue":
- msg.setJMSReplyTo(_session.createQueue(subMapVal));
- break;
- case "temp_queue":
- msg.setJMSReplyTo(_session.createTemporaryQueue());
- break;
- case "topic":
- msg.setJMSReplyTo(_session.createTopic(subMapVal));
- break;
- case "temp_topic":
- msg.setJMSReplyTo(_session.createTemporaryTopic());
- break;
- default:
- throw new Exception("Internal exception: Invalid message header type \"" + subMapKey + "\" for message header \"" + key + "\"");
- }
- break;
- default:
- throw new Exception("Internal exception: Unknown or unsupported message header \"" + key + "\"");
- }
- }
- }
-
- protected void addMessageProperties(Message msg, JsonObject testPropertiesMap) throws Exception, JMSException {
- List<String> testPropertiesKeyList = new ArrayList<String>(testPropertiesMap.keySet());
- for (String key: testPropertiesKeyList) {
- JsonObject subMap = testPropertiesMap.getJsonObject(key);
- List<String> subMapKeyList = new ArrayList<String>(subMap.keySet());
- String subMapKey = subMapKeyList.get(0); // There is always only one entry in map
- String subMapVal = subMap.getString(subMapKey);
- switch (subMapKey) {
- case "boolean":
- msg.setBooleanProperty(key, Boolean.parseBoolean(subMapVal));
- break;
- case "byte":
- msg.setByteProperty(key, Byte.decode(subMapVal));
- break;
- case "double":
- Long l1 = Long.parseLong(subMapVal.substring(2, 3), 16) << 60;
- Long l2 = Long.parseLong(subMapVal.substring(3), 16);
- msg.setDoubleProperty(key, Double.longBitsToDouble(l1 | l2));
- break;
- case "float":
- Long i = Long.parseLong(subMapVal.substring(2), 16);
- msg.setFloatProperty(key, Float.intBitsToFloat(i.intValue()));
- break;
- case "int":
- msg.setIntProperty(key, Integer.decode(subMapVal));
- break;
- case "long":
- msg.setLongProperty(key, Long.decode(subMapVal));
- break;
- case "short":
- msg.setShortProperty(key, Short.decode(subMapVal));
- break;
- case "string":
- msg.setStringProperty(key, subMapVal);
- break;
- default:
- throw new Exception("Internal exception: Unknown or unsupported message property type \"" + subMapKey + "\"");
- }
- }
- }
-
protected Message createJMSMessage(String testValueType, String testValue) throws Exception, JMSException {
if (testValueType.compareTo("none") != 0) {
throw new Exception("Internal exception: Unexpected JMS message sub-type \"" + testValueType + "\"");
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/shims/qpid-proton-cpp/src/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/shims/qpid-proton-cpp/src/CMakeLists.txt b/shims/qpid-proton-cpp/src/CMakeLists.txt
index 4f58163..f6b11a0 100644
--- a/shims/qpid-proton-cpp/src/CMakeLists.txt
+++ b/shims/qpid-proton-cpp/src/CMakeLists.txt
@@ -31,6 +31,11 @@ set(Common_SOURCES
qpidit/QpidItErrors.cpp
)
+set(Common_Jms_SOURCES
+ qpidit/JmsTestBase.hpp
+ qpidit/JmsTestBase.cpp
+)
+
set(Common_LIBS
qpid-proton-cpp
jsoncpp
@@ -72,6 +77,43 @@ set_target_properties(amqp_types_test_Receiver PROPERTIES
)
+# ---------------------------
+# --- jms_hdrs_props_test ---
+# ---------------------------
+
+# --- Sender ---
+
+set(jms_hdrs_props_test_Sender_SOURCES
+ ${Common_SOURCES}
+ ${Common_Jms_SOURCES}
+ qpidit/jms_hdrs_props_test/Sender.hpp
+ qpidit/jms_hdrs_props_test/Sender.cpp
+)
+
+add_executable(jms_hdrs_props_test_Sender ${jms_hdrs_props_test_Sender_SOURCES})
+target_link_libraries(jms_hdrs_props_test_Sender ${Common_LIBS})
+set_target_properties(jms_hdrs_props_test_Sender PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/jms_hdrs_props_test"
+ OUTPUT_NAME Sender
+)
+
+# --- Receiver ---
+
+set(jms_hdrs_props_test_Receiver_SOURCES
+ ${Common_SOURCES}
+ ${Common_Jms_SOURCES}
+ qpidit/jms_hdrs_props_test/Receiver.hpp
+ qpidit/jms_hdrs_props_test/Receiver.cpp
+)
+
+add_executable(jms_hdrs_props_test_Receiver ${jms_hdrs_props_test_Receiver_SOURCES})
+target_link_libraries(jms_hdrs_props_test_Receiver ${Common_LIBS})
+set_target_properties(jms_hdrs_props_test_Receiver PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/jms_hdrs_props_test"
+ OUTPUT_NAME Receiver
+)
+
+
# -------------------------
# --- jms_messages_test ---
# -------------------------
@@ -80,6 +122,7 @@ set_target_properties(amqp_types_test_Receiver PROPERTIES
set(jms_messages_test_Sender_SOURCES
${Common_SOURCES}
+ ${Common_Jms_SOURCES}
qpidit/jms_messages_test/Sender.hpp
qpidit/jms_messages_test/Sender.cpp
)
@@ -95,6 +138,7 @@ set_target_properties(jms_messages_test_Sender PROPERTIES
set(jms_messages_test_Receiver_SOURCES
${Common_SOURCES}
+ ${Common_Jms_SOURCES}
qpidit/jms_messages_test/Receiver.hpp
qpidit/jms_messages_test/Receiver.cpp
)
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/shims/qpid-proton-cpp/src/qpidit/JmsTestBase.cpp
----------------------------------------------------------------------
diff --git a/shims/qpid-proton-cpp/src/qpidit/JmsTestBase.cpp b/shims/qpid-proton-cpp/src/qpidit/JmsTestBase.cpp
new file mode 100644
index 0000000..010e8ba
--- /dev/null
+++ b/shims/qpid-proton-cpp/src/qpidit/JmsTestBase.cpp
@@ -0,0 +1,69 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "JmsTestBase.hpp"
+
+#include <iostream>
+#include "proton/connection.hpp"
+
+namespace qpidit {
+
+ // static
+ proton::symbol JmsTestBase::s_jmsMessageTypeAnnotationKey("x-opt-jms-msg-type");
+ std::map<std::string, int8_t>JmsTestBase::s_jmsMessageTypeAnnotationValues = initializeJmsMessageTypeAnnotationMap();
+
+ JmsTestBase::JmsTestBase() {
+
+ }
+
+ void JmsTestBase::on_connection_error(proton::connection &c) {
+ std::cerr << "JmsSender::on_connection_error(): " << c.error() << std::endl;
+ }
+
+ void JmsTestBase::on_sender_error(proton::sender &s) {
+ std::cerr << "JmsSender::on_sender_error(): " << s.error() << std::endl;
+ }
+
+ void JmsTestBase::on_session_error(proton::session &s) {
+ std::cerr << "JmsSender::on_session_error(): " << s.error() << std::endl;
+ }
+
+ void JmsTestBase::on_transport_error(proton::transport &t) {
+ std::cerr << "JmsSender::on_transport_error(): " << t.error() << std::endl;
+ }
+
+ void JmsTestBase::on_error(const proton::error_condition &ec) {
+ std::cerr << "JmsSender::on_error(): " << ec << std::endl;
+ }
+
+ // static
+ std::map<std::string, int8_t> JmsTestBase::initializeJmsMessageTypeAnnotationMap() {
+ std::map<std::string, int8_t> m;
+ m["JMS_MESSAGE_TYPE"] = JMS_MESSAGE_TYPE;
+ m["JMS_OBJECTMESSAGE_TYPE"] = JMS_OBJECTMESSAGE_TYPE;
+ m["JMS_MAPMESSAGE_TYPE"] = JMS_MAPMESSAGE_TYPE;
+ m["JMS_BYTESMESSAGE_TYPE"] = JMS_BYTESMESSAGE_TYPE;
+ m["JMS_STREAMMESSAGE_TYPE"] = JMS_STREAMMESSAGE_TYPE;
+ m["JMS_TEXTMESSAGE_TYPE"] = JMS_TEXTMESSAGE_TYPE;
+ return m;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/shims/qpid-proton-cpp/src/qpidit/JmsTestBase.hpp
----------------------------------------------------------------------
diff --git a/shims/qpid-proton-cpp/src/qpidit/JmsTestBase.hpp b/shims/qpid-proton-cpp/src/qpidit/JmsTestBase.hpp
new file mode 100644
index 0000000..7352ca2
--- /dev/null
+++ b/shims/qpid-proton-cpp/src/qpidit/JmsTestBase.hpp
@@ -0,0 +1,64 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#ifndef SRC_QPIDIT_JMS_JMSDEFINTIONS_HPP_
+#define SRC_QPIDIT_JMS_JMSDEFINTIONS_HPP_
+
+#include <map>
+#include "proton/messaging_handler.hpp"
+#include "proton/symbol.hpp"
+#include "proton/transport.hpp"
+
+namespace qpidit
+{
+ typedef enum {JMS_QUEUE = 0,
+ JMS_TOPIC,
+ JMS_TMEP_QUEUE,
+ JMS_TEMP_TOPIC}
+ jmsDestinationType_t;
+
+ typedef enum {JMS_MESSAGE_TYPE=0,
+ JMS_OBJECTMESSAGE_TYPE,
+ JMS_MAPMESSAGE_TYPE,
+ JMS_BYTESMESSAGE_TYPE,
+ JMS_STREAMMESSAGE_TYPE,
+ JMS_TEXTMESSAGE_TYPE}
+ jmsMessageType_t;
+
+ class JmsTestBase: public proton::messaging_handler {
+ protected:
+ static proton::symbol s_jmsMessageTypeAnnotationKey;
+ static std::map<std::string, int8_t>s_jmsMessageTypeAnnotationValues;
+
+ void on_connection_error(proton::connection &c);
+ void on_session_error(proton::session &s);
+ void on_sender_error(proton::sender& s);
+ void on_transport_error(proton::transport &t);
+ void on_error(const proton::error_condition &c);
+ public:
+ JmsTestBase();
+ protected:
+ static std::map<std::string, int8_t> initializeJmsMessageTypeAnnotationMap();
+ };
+
+}
+
+#endif /* SRC_QPIDIT_JMS_JMSDEFINTIONS_HPP_ */
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[3/5] qpid-interop-test git commit: QPIDIT-41: Reorganized dir
structure and tidied up the test code. Copied the old jms_messages_test to a
new jms_hdrs_props_test and simplified the jms_messages_test to include only
message body tests. Simplified parame
Posted by kp...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/shims/qpid-proton-python/src/jms_hdrs_props_test/Receiver.py
----------------------------------------------------------------------
diff --git a/shims/qpid-proton-python/src/jms_hdrs_props_test/Receiver.py b/shims/qpid-proton-python/src/jms_hdrs_props_test/Receiver.py
new file mode 100755
index 0000000..5740c16
--- /dev/null
+++ b/shims/qpid-proton-python/src/jms_hdrs_props_test/Receiver.py
@@ -0,0 +1,357 @@
+#!/usr/bin/env python
+
+"""
+JMS message headers and properties test receiver shim for qpid-interop-test
+"""
+
+#
+# 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.
+#
+
+from json import dumps, loads
+from struct import pack, unpack
+from subprocess import check_output
+import sys
+from traceback import format_exc
+
+from qpid_interop_test.interop_test_errors import InteropTestError
+from proton import byte, symbol
+from proton.handlers import MessagingHandler
+from proton.reactor import Container
+
+# These values must tie in with the Qpid-JMS client values found in
+# org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport
+QPID_JMS_TYPE_ANNOTATION_NAME = symbol(u'x-opt-jms-msg-type')
+
+class JmsReceiverShim(MessagingHandler):
+ """
+ Receiver shim: This shim receives JMS messages sent by the Sender shim and prints the contents of the received
+ messages onto the terminal in JSON format for retrieval by the test harness. The JMS messages type and, where
+ applicable, body values, as well as the combinations of JMS headers and properties which may be attached to
+ the message are received on the command-line in JSON format when this program is launched.
+ """
+ def __init__(self, url, jms_msg_type, test_parameters_list):
+ super(JmsReceiverShim, self).__init__()
+ self.url = url
+ self.jms_msg_type = jms_msg_type
+ self.expteced_msg_map = test_parameters_list[0]
+ self.flag_map = test_parameters_list[1]
+ self.subtype_itr = iter(sorted(self.expteced_msg_map.keys()))
+ self.expected = self._get_tot_num_messages()
+ self.received = 0
+ self.received_value_map = {}
+ self.current_subtype = None
+ self.current_subtype_msg_list = None
+ self.jms_header_map = {}
+ self.jms_property_map = {}
+
+ def get_received_value_map(self):
+ """"Return the collected message values received"""
+ return self.received_value_map
+
+ def get_jms_header_map(self):
+ """Return the collected message headers received"""
+ return self.jms_header_map
+
+ def get_jms_property_map(self):
+ """Return the collected message properties received"""
+ return self.jms_property_map
+
+ def on_start(self, event):
+ """Event callback for when the client starts"""
+ event.container.create_receiver(self.url)
+
+ def on_message(self, event):
+ """Event callback when a message is received by the client"""
+ if event.message.id and event.message.id < self.received:
+ return # ignore duplicate message
+ if self.expected == 0 or self.received < self.expected:
+ if self.current_subtype is None:
+ self.current_subtype = self.subtype_itr.next()
+ self.current_subtype_msg_list = []
+ self.current_subtype_msg_list.append(self._handle_message(event.message))
+ self._process_jms_headers(event.message)
+ self._process_jms_properties(event.message)
+ if len(self.current_subtype_msg_list) >= self.expteced_msg_map[self.current_subtype]:
+ self.received_value_map[self.current_subtype] = self.current_subtype_msg_list
+ self.current_subtype = None
+ self.current_subtype_msg_list = []
+ self.received += 1
+ if self.received == self.expected:
+ event.receiver.close()
+ event.connection.close()
+
+ def on_connection_error(self, event):
+ print 'JmsReceiverShim.on_connection_error'
+
+ def on_session_error(self, event):
+ print 'JmsReceiverShim.on_session_error'
+
+ def on_link_error(self, event):
+ print 'JmsReceiverShim.on_link_error'
+
+ def _handle_message(self, message):
+ """Handles the analysis of a received message"""
+ if self.jms_msg_type == 'JMS_MESSAGE_TYPE':
+ return self._receive_jms_message(message)
+ if self.jms_msg_type == 'JMS_BYTESMESSAGE_TYPE':
+ return self._receive_jms_bytesmessage(message)
+ if self.jms_msg_type == 'JMS_MAPMESSAGE_TYPE':
+ return self._recieve_jms_mapmessage(message)
+ if self.jms_msg_type == 'JMS_OBJECTMESSAGE_TYPE':
+ return self._recieve_jms_objectmessage(message)
+ if self.jms_msg_type == 'JMS_STREAMMESSAGE_TYPE':
+ return self._receive_jms_streammessage(message)
+ if self.jms_msg_type == 'JMS_TEXTMESSAGE_TYPE':
+ return self._receive_jms_textmessage(message)
+ print 'jms-receive: Unsupported JMS message type "%s"' % self.jms_msg_type
+ return None
+
+ def _get_tot_num_messages(self):
+ """"Counts up the total number of messages which should be received from the expected message map"""
+ total = 0
+ for key in self.expteced_msg_map:
+ total += int(self.expteced_msg_map[key])
+ return total
+
+ def _receive_jms_message(self, message):
+ """"Receives a JMS message (without a body)"""
+ assert self.jms_msg_type == 'JMS_MESSAGE_TYPE'
+ assert message.annotations[QPID_JMS_TYPE_ANNOTATION_NAME] == byte(0)
+ if message.body is not None:
+ raise InteropTestError('_receive_jms_message: Invalid body for type JMS_MESSAGE_TYPE: %s' %
+ str(message.body))
+ return None
+
+ def _receive_jms_bytesmessage(self, message):
+ """"Receives a JMS bytes message"""
+ assert self.jms_msg_type == 'JMS_BYTESMESSAGE_TYPE'
+ assert message.annotations[QPID_JMS_TYPE_ANNOTATION_NAME] == byte(3)
+ if self.current_subtype == 'boolean':
+ if message.body == b'\x00':
+ return 'False'
+ if message.body == b'\x01':
+ return 'True'
+ raise InteropTestError('_receive_jms_bytesmessage: Invalid encoding for subtype boolean: %s' %
+ str(message.body))
+ if self.current_subtype == 'byte':
+ return hex(unpack('b', message.body)[0])
+ if self.current_subtype == 'bytes':
+ return str(message.body)
+ if self.current_subtype == 'char':
+ if len(message.body) == 2: # format 'a' or '\xNN'
+ return str(message.body[1]) # strip leading '\x00' char
+ raise InteropTestError('Unexpected strring length for type char: %d' % len(message.body))
+ if self.current_subtype == 'double':
+ return '0x%016x' % unpack('!Q', message.body)[0]
+ if self.current_subtype == 'float':
+ return '0x%08x' % unpack('!L', message.body)[0]
+ if self.current_subtype == 'int':
+ return hex(unpack('!i', message.body)[0])
+ if self.current_subtype == 'long':
+ return hex(unpack('!q', message.body)[0])
+ if self.current_subtype == 'short':
+ return hex(unpack('!h', message.body)[0])
+ if self.current_subtype == 'string':
+ # NOTE: first 2 bytes are string length, must be present
+ if len(message.body) >= 2:
+ str_len = unpack('!H', message.body[:2])[0]
+ str_body = str(message.body[2:])
+ if len(str_body) != str_len:
+ raise InteropTestError('String length mismatch: size=%d, but len(\'%s\')=%d' %
+ (str_len, str_body, len(str_body)))
+ return str_body
+ else:
+ raise InteropTestError('Malformed string binary: len(\'%s\')=%d' %
+ (repr(message.body), len(message.body)))
+ raise InteropTestError('JMS message type %s: Unknown or unsupported subtype \'%s\'' %
+ (self.jms_msg_type, self.current_subtype))
+
+ def _recieve_jms_mapmessage(self, message):
+ """"Receives a JMS map message"""
+ assert self.jms_msg_type == 'JMS_MAPMESSAGE_TYPE'
+ assert message.annotations[QPID_JMS_TYPE_ANNOTATION_NAME] == byte(2)
+ key, value = message.body.items()[0]
+ assert key[:-3] == self.current_subtype
+ if self.current_subtype == 'boolean':
+ return str(value)
+ if self.current_subtype == 'byte':
+ return hex(value)
+ if self.current_subtype == 'bytes':
+ return str(value)
+ if self.current_subtype == 'char':
+ return str(value)
+ if self.current_subtype == 'double':
+ return '0x%016x' % unpack('!Q', pack('!d', value))[0]
+ if self.current_subtype == 'float':
+ return '0x%08x' % unpack('!L', pack('!f', value))[0]
+ if self.current_subtype == 'int':
+ return hex(value)
+ if self.current_subtype == 'long':
+ return hex(int(value))
+ if self.current_subtype == 'short':
+ return hex(value)
+ if self.current_subtype == 'string':
+ return str(value)
+ raise InteropTestError('JMS message type %s: Unknown or unsupported subtype \'%s\'' %
+ (self.jms_msg_type, self.current_subtype))
+
+ def _recieve_jms_objectmessage(self, message):
+ """"Receives a JMS Object message"""
+ assert self.jms_msg_type == 'JMS_OBJECTMESSAGE_TYPE'
+ assert message.annotations[QPID_JMS_TYPE_ANNOTATION_NAME] == byte(1)
+ return self._get_java_obj(message.body)
+
+ def _get_java_obj(self, java_obj_bytes):
+ """
+ Take bytes from serialized Java object and construct a Java object, then return its toString() value. The
+ work of 'translating' the bytes to a Java object and obtaining its class and value is done in a Java
+ utility org.apache.qpid.interop_test.obj_util.BytesToJavaObj located in jar JavaObjUtils.jar.
+ java_obj_bytes: hex string representation of bytes from Java object (eg 'aced00057372...')
+ returns: string containing Java class value as returned by the toString() method
+ """
+ java_obj_bytes_str = ''.join(["%02x" % ord(x) for x in java_obj_bytes]).strip()
+ out_str = check_output(['java',
+ '-cp',
+ 'target/JavaObjUtils.jar',
+ 'org.apache.qpid.interop_test.obj_util.BytesToJavaObj',
+ java_obj_bytes_str])
+ out_str_list = out_str.split('\n')[:-1] # remove trailing \n
+ if len(out_str_list) > 1:
+ raise InteropTestError('Unexpected return from JavaObjUtils: %s' % out_str)
+ colon_index = out_str_list[0].index(':')
+ if colon_index < 0:
+ raise InteropTestError('Unexpected format from JavaObjUtils: %s' % out_str)
+ java_class_name = out_str_list[0][:colon_index]
+ java_class_value_str = out_str_list[0][colon_index+1:]
+ if java_class_name != self.current_subtype:
+ raise InteropTestError('Unexpected class name from JavaObjUtils: expected %s, recieved %s' %
+ (self.current_subtype, java_class_name))
+ return java_class_value_str
+
+ def _receive_jms_streammessage(self, message):
+ """Receives a JMS stream message"""
+ assert self.jms_msg_type == 'JMS_STREAMMESSAGE_TYPE'
+ assert message.annotations[QPID_JMS_TYPE_ANNOTATION_NAME] == byte(4)
+ # Every message is a list with one item [value]
+ assert len(message.body) == 1
+ value = message.body[0]
+ if self.current_subtype == 'boolean':
+ return str(value)
+ if self.current_subtype == 'byte':
+ return hex(value)
+ if self.current_subtype == 'bytes':
+ return str(value)
+ if self.current_subtype == 'char':
+ return str(value)
+ if self.current_subtype == 'double':
+ return '0x%016x' % unpack('!Q', pack('!d', value))[0]
+ if self.current_subtype == 'float':
+ return '0x%08x' % unpack('!L', pack('!f', value))[0]
+ if self.current_subtype == 'int':
+ return hex(value)
+ if self.current_subtype == 'long':
+ return hex(int(value))
+ if self.current_subtype == 'short':
+ return hex(value)
+ if self.current_subtype == 'string':
+ return str(value)
+ raise InteropTestError('JmsRecieverShim._receive_jms_streammessage(): ' +
+ 'JMS message type %s: Unknown or unsupported subtype \'%s\'' %
+ (self.jms_msg_type, self.current_subtype))
+
+ def _receive_jms_textmessage(self, message):
+ """"Receives a JMS text message"""
+ assert self.jms_msg_type == 'JMS_TEXTMESSAGE_TYPE'
+ assert message.annotations[QPID_JMS_TYPE_ANNOTATION_NAME] == byte(5)
+ return message.body
+
+ def _process_jms_headers(self, message):
+ """"Checks the supplied message for three JMS headers: message type, correlation-id and reply-to"""
+ # JMS message type header
+ message_type_header = message._get_subject()
+ if message_type_header is not None:
+ self.jms_header_map['JMS_TYPE_HEADER'] = {'string': message_type_header}
+
+ # JMS correlation ID
+ correlation_id = message._get_correlation_id()
+ if correlation_id is not None:
+ if 'JMS_CORRELATIONID_AS_BYTES' in self.flag_map and self.flag_map['JMS_CORRELATIONID_AS_BYTES']:
+ self.jms_header_map['JMS_CORRELATIONID_HEADER'] = {'bytes': correlation_id}
+ else:
+ self.jms_header_map['JMS_CORRELATIONID_HEADER'] = {'string': correlation_id}
+
+ # JMS reply-to
+ reply_to = message._get_reply_to()
+ if reply_to is not None:
+ if 'JMS_REPLYTO_AS_TOPIC' in self.flag_map and self.flag_map['JMS_REPLYTO_AS_TOPIC']:
+ # Some brokers prepend 'queue://' and 'topic://' to reply_to addresses, strip these when present
+ if len(reply_to) > 8 and reply_to[0:8] == 'topic://':
+ reply_to = reply_to[8:]
+ self.jms_header_map['JMS_REPLYTO_HEADER'] = {'topic': reply_to}
+ else:
+ if len(reply_to) > 8 and reply_to[0:8] == 'queue://':
+ reply_to = reply_to[8:]
+ self.jms_header_map['JMS_REPLYTO_HEADER'] = {'queue': reply_to}
+
+ def _process_jms_properties(self, message):
+ """"Checks the supplied message for JMS message properties and decodes them"""
+ if message.properties is not None:
+ for jms_property_name in message.properties:
+ underscore_index = jms_property_name.find('_')
+ if underscore_index >= 0: # Ignore any other properties without '_'
+ jms_property_type = jms_property_name[0:underscore_index]
+ value = message.properties[jms_property_name]
+ if jms_property_type == 'boolean':
+ self.jms_property_map[jms_property_name] = {'boolean': str(value)}
+ elif jms_property_type == 'byte':
+ self.jms_property_map[jms_property_name] = {'byte': hex(value)}
+ elif jms_property_type == 'double':
+ self.jms_property_map[jms_property_name] = {'double': '0x%016x' %
+ unpack('!Q', pack('!d', value))[0]}
+ elif jms_property_type == 'float':
+ self.jms_property_map[jms_property_name] = {'float': '0x%08x' %
+ unpack('!L', pack('!f', value))[0]}
+ elif jms_property_type == 'int':
+ self.jms_property_map[jms_property_name] = {'int': hex(value)}
+ elif jms_property_type == 'long':
+ self.jms_property_map[jms_property_name] = {'long': hex(int(value))}
+ elif jms_property_type == 'short':
+ self.jms_property_map[jms_property_name] = {'short': hex(value)}
+ elif jms_property_type == 'string':
+ self.jms_property_map[jms_property_name] = {'string': str(value)}
+ else:
+ pass # Ignore any other properties, brokers can add them and we don't know what they may be
+
+
+# --- main ---
+# Args: 1: Broker address (ip-addr:port)
+# 2: Queue name
+# 3: JMS message type
+# 4: JSON Test parameters containing 2 maps: [testValuesMap, flagMap]
+#print '#### sys.argv=%s' % sys.argv
+try:
+ RECEIVER = JmsReceiverShim('%s/%s' % (sys.argv[1], sys.argv[2]), sys.argv[3], loads(sys.argv[4]))
+ Container(RECEIVER).run()
+ print sys.argv[3]
+ print dumps([RECEIVER.get_received_value_map(), RECEIVER.get_jms_header_map(), RECEIVER.get_jms_property_map()])
+except KeyboardInterrupt:
+ pass
+except Exception as exc:
+ print 'jms-receiver-shim EXCEPTION:', exc
+ print format_exc()
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/shims/qpid-proton-python/src/jms_hdrs_props_test/Sender.py
----------------------------------------------------------------------
diff --git a/shims/qpid-proton-python/src/jms_hdrs_props_test/Sender.py b/shims/qpid-proton-python/src/jms_hdrs_props_test/Sender.py
new file mode 100755
index 0000000..89abf25
--- /dev/null
+++ b/shims/qpid-proton-python/src/jms_hdrs_props_test/Sender.py
@@ -0,0 +1,388 @@
+#!/usr/bin/env python
+
+"""
+JMS message headers and properties test sender shim for qpid-interop-test
+"""
+
+#
+# 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.
+#
+
+from json import loads
+from struct import pack, unpack
+from subprocess import check_output
+import sys
+from traceback import format_exc
+
+from proton import byte, char, float32, int32, Message, short, symbol
+from proton.handlers import MessagingHandler
+from proton.reactor import Container
+from qpid_interop_test.interop_test_errors import InteropTestError
+from qpid_interop_test.test_type_map import TestTypeMap
+
+# These values must tie in with the Qpid-JMS client values found in
+# org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport
+QPID_JMS_TYPE_ANNOTATION_NAME = symbol(u'x-opt-jms-msg-type')
+QPID_JMS_TYPE_ANNOTATIONS = {
+ 'JMS_MESSAGE_TYPE': byte(0),
+ 'JMS_BYTESMESSAGE_TYPE': byte(3),
+ 'JMS_MAPMESSAGE_TYPE': byte(2),
+ 'JMS_OBJECTMESSAGE_TYPE': byte(1),
+ 'JMS_STREAMMESSAGE_TYPE': byte(4),
+ 'JMS_TEXTMESSAGE_TYPE': byte(5)
+ }
+def create_annotation(jms_msg_type):
+ """Function which creates a message annotation for JMS message type as used by the Qpid JMS client"""
+ return {QPID_JMS_TYPE_ANNOTATION_NAME: QPID_JMS_TYPE_ANNOTATIONS[jms_msg_type]}
+
+class JmsSenderShim(MessagingHandler):
+ """
+ This shim sends JMS messages of a particular JMS message type according to the test parameters list. This list
+ contains three maps:
+ 0: The test value map, which contains test value types as keys, and lists of values of that type;
+ 1. The test headers map, which contains the JMS headers as keys and a submap conatining types and values;
+ 2. The test proprties map, which contains the name of the properties as keys, and a submap containing types
+ and values
+ This shim takes the combinations of the above map and creates test cases, each of which sends a single message
+ with (or without) JMS headers and properties.
+ """
+ def __init__(self, broker_ip_addr, queue_name, jms_msg_type, test_parameters_list):
+ super(JmsSenderShim, self).__init__()
+ self.broker_ip_addr = broker_ip_addr
+ self.queue_name = queue_name
+ self.jms_msg_type = jms_msg_type
+ self.test_value_map = test_parameters_list[0]
+ self.test_headers_map = test_parameters_list[1]
+ self.test_properties_map = test_parameters_list[2]
+ self.sent = 0
+ self.confirmed = 0
+ self.total = self._get_total_num_msgs()
+
+ def on_start(self, event):
+ """Event callback for when the client starts"""
+ event.container.create_sender('%s/%s' % (self.broker_ip_addr, self.queue_name))
+
+ def on_sendable(self, event):
+ """Event callback for when send credit is received, allowing the sending of messages"""
+ if self.sent == 0:
+ # These types expect a test_values Python string representation of a map: '{type:[val, val, val], ...}'
+ for sub_type in sorted(self.test_value_map.keys()):
+ if self._send_test_values(event, sub_type, self.test_value_map[sub_type]):
+ return
+
+ def on_connection_error(self, event):
+ print 'JmsSenderShim.on_connection_error'
+
+ def on_session_error(self, event):
+ print 'JmsSenderShim.on_session_error'
+
+ def on_link_error(self, event):
+ print 'JmsSenderShim.on_link_error'
+
+ def on_accepted(self, event):
+ """Event callback for when a sent message is accepted by the broker"""
+ self.confirmed += 1
+ if self.confirmed == self.total:
+ event.connection.close()
+
+ def on_disconnected(self, event):
+ """Event callback for when the broker disconnects with the client"""
+ self.sent = self.confirmed
+
+ def _get_total_num_msgs(self):
+ """
+ Calculates the total number of messages to be sent based on the message parameters received on the command-line
+ """
+ total = 0
+ for key in self.test_value_map.keys():
+ total += len(self.test_value_map[key])
+ return total
+
+ def _send_test_values(self, event, test_value_type, test_values):
+ """Method which loops through recieved parameters and sends the corresponding messages"""
+ value_num = 0
+ for test_value in test_values:
+ if event.sender.credit:
+ hdr_kwargs, hdr_annotations = self._get_jms_message_header_kwargs()
+ message = self._create_message(test_value_type, test_value, value_num, hdr_kwargs, hdr_annotations)
+ # TODO: set message to address
+ if message is not None:
+ #self._add_jms_message_headers(message)
+ self._add_jms_message_properties(message)
+ event.sender.send(message)
+ self.sent += 1
+ value_num += 1
+ else:
+ event.connection.close()
+ return True
+ return False
+
+ # TODO: Change this to return a list of messages. That way each test can return more than one message
+ def _create_message(self, test_value_type, test_value, value_num, hdr_kwargs, hdr_annotations):
+ """Create a single message of the appropriate JMS message type"""
+ if self.jms_msg_type == 'JMS_MESSAGE_TYPE':
+ return self._create_jms_message(test_value_type, test_value, hdr_kwargs, hdr_annotations)
+ elif self.jms_msg_type == 'JMS_BYTESMESSAGE_TYPE':
+ return self._create_jms_bytesmessage(test_value_type, test_value, hdr_kwargs, hdr_annotations)
+ elif self.jms_msg_type == 'JMS_MAPMESSAGE_TYPE':
+ return self._create_jms_mapmessage(test_value_type, test_value, "%s%03d" % (test_value_type, value_num),
+ hdr_kwargs, hdr_annotations)
+ elif self.jms_msg_type == 'JMS_OBJECTMESSAGE_TYPE':
+ return self._create_jms_objectmessage('%s:%s' % (test_value_type, test_value), hdr_kwargs, hdr_annotations)
+ elif self.jms_msg_type == 'JMS_STREAMMESSAGE_TYPE':
+ return self._create_jms_streammessage(test_value_type, test_value, hdr_kwargs, hdr_annotations)
+ elif self.jms_msg_type == 'JMS_TEXTMESSAGE_TYPE':
+ return self._create_jms_textmessage(test_value, hdr_kwargs, hdr_annotations)
+ else:
+ print 'jms-send: Unsupported JMS message type "%s"' % self.jms_msg_type
+ return None
+
+ def _create_jms_message(self, test_value_type, test_value, hdr_kwargs, hdr_annotations):
+ """Create a JMS message type (without message body)"""
+ if test_value_type != 'none':
+ raise InteropTestError('JmsSenderShim._create_jms_message: Unknown or unsupported subtype "%s"' %
+ test_value_type)
+ if test_value is not None:
+ raise InteropTestError('JmsSenderShim._create_jms_message: Invalid value "%s" for subtype "%s"' %
+ (test_value, test_value_type))
+ return Message(id=(self.sent+1),
+ content_type='application/octet-stream',
+ annotations=TestTypeMap.merge_dicts(create_annotation('JMS_MESSAGE_TYPE'),
+ hdr_annotations),
+ **hdr_kwargs)
+
+ def _create_jms_bytesmessage(self, test_value_type, test_value, hdr_kwargs, hdr_annotations):
+ """Create a JMS bytes message"""
+ # NOTE: test_value contains all unicode strings u'...' as returned by json
+ body_bytes = None
+ if test_value_type == 'boolean':
+ body_bytes = b'\x01' if test_value == 'True' else b'\x00'
+ elif test_value_type == 'byte':
+ body_bytes = pack('b', int(test_value, 16))
+ elif test_value_type == 'bytes':
+ body_bytes = str(test_value) # remove unicode
+ elif test_value_type == 'char':
+ # JMS expects two-byte chars, ASCII chars can be prefixed with '\x00'
+ body_bytes = '\x00' + str(test_value) # remove unicode
+ elif test_value_type == 'double' or test_value_type == 'float':
+ body_bytes = test_value[2:].decode('hex')
+ elif test_value_type == 'int':
+ body_bytes = pack('!i', int(test_value, 16))
+ elif test_value_type == 'long':
+ body_bytes = pack('!q', long(test_value, 16))
+ elif test_value_type == 'short':
+ body_bytes = pack('!h', short(test_value, 16))
+ elif test_value_type == 'string':
+ # NOTE: First two bytes must be string length
+ test_value_str = str(test_value) # remove unicode
+ body_bytes = pack('!H', len(test_value_str)) + test_value_str
+ else:
+ raise InteropTestError('JmsSenderShim._create_jms_bytesmessage: Unknown or unsupported subtype "%s"' %
+ test_value_type)
+ return Message(id=(self.sent+1),
+ body=body_bytes,
+ inferred=True,
+ content_type='application/octet-stream',
+ annotations=TestTypeMap.merge_dicts(create_annotation('JMS_BYTESMESSAGE_TYPE'),
+ hdr_annotations),
+ **hdr_kwargs)
+
+ def _create_jms_mapmessage(self, test_value_type, test_value, name, hdr_kwargs, hdr_annotations):
+ """Create a JMS map message"""
+ if test_value_type == 'boolean':
+ value = test_value == 'True'
+ elif test_value_type == 'byte':
+ value = byte(int(test_value, 16))
+ elif test_value_type == 'bytes':
+ value = str(test_value) # remove unicode
+ elif test_value_type == 'char':
+ value = char(test_value)
+ elif test_value_type == 'double':
+ value = unpack('!d', test_value[2:].decode('hex'))[0]
+ elif test_value_type == 'float':
+ value = float32(unpack('!f', test_value[2:].decode('hex'))[0])
+ elif test_value_type == 'int':
+ value = int32(int(test_value, 16))
+ elif test_value_type == 'long':
+ value = long(test_value, 16)
+ elif test_value_type == 'short':
+ value = short(int(test_value, 16))
+ elif test_value_type == 'string':
+ value = test_value
+ else:
+ raise InteropTestError('JmsSenderShim._create_jms_mapmessage: Unknown or unsupported subtype "%s"' %
+ test_value_type)
+ return Message(id=(self.sent+1),
+ body={name: value},
+ inferred=False,
+ annotations=TestTypeMap.merge_dicts(create_annotation('JMS_MAPMESSAGE_TYPE'),
+ hdr_annotations),
+ **hdr_kwargs)
+
+ def _create_jms_objectmessage(self, test_value, hdr_kwargs, hdr_annotations):
+ """Create a JMS object message"""
+ java_binary = self._s_get_java_obj_binary(test_value)
+ return Message(id=(self.sent+1),
+ body=java_binary,
+ inferred=True,
+ content_type='application/x-java-serialized-object',
+ annotations=TestTypeMap.merge_dicts(create_annotation('JMS_MAPMESSAGE_TYPE'),
+ hdr_annotations),
+ **hdr_kwargs)
+
+ @staticmethod
+ def _s_get_java_obj_binary(java_class_str):
+ """Call external utility to create Java object and stringify it, returning the string representation"""
+ out_str = check_output(['java',
+ '-cp',
+ 'target/JavaObjUtils.jar',
+ 'org.apache.qpid.interop_test.obj_util.JavaObjToBytes',
+ java_class_str])
+ out_str_list = out_str.split('\n')[:-1] # remove trailing \n
+ if out_str_list[0] != java_class_str:
+ raise InteropTestError('JmsSenderShim._s_get_java_obj_binary(): Call to JavaObjToBytes failed\n%s' %
+ out_str)
+ return out_str_list[1].decode('hex')
+
+ def _create_jms_streammessage(self, test_value_type, test_value, hdr_kwargs, hdr_annotations):
+ """Create a JMS stream message"""
+ if test_value_type == 'boolean':
+ body_list = [test_value == 'True']
+ elif test_value_type == 'byte':
+ body_list = [byte(int(test_value, 16))]
+ elif test_value_type == 'bytes':
+ body_list = [str(test_value)]
+ elif test_value_type == 'char':
+ body_list = [char(test_value)]
+ elif test_value_type == 'double':
+ body_list = [unpack('!d', test_value[2:].decode('hex'))[0]]
+ elif test_value_type == 'float':
+ body_list = [float32(unpack('!f', test_value[2:].decode('hex'))[0])]
+ elif test_value_type == 'int':
+ body_list = [int32(int(test_value, 16))]
+ elif test_value_type == 'long':
+ body_list = [long(test_value, 16)]
+ elif test_value_type == 'short':
+ body_list = [short(int(test_value, 16))]
+ elif test_value_type == 'string':
+ body_list = [test_value]
+ else:
+ raise InteropTestError('JmsSenderShim._create_jms_streammessage: Unknown or unsupported subtype "%s"' %
+ test_value_type)
+ return Message(id=(self.sent+1),
+ body=body_list,
+ inferred=True,
+ annotations=TestTypeMap.merge_dicts(create_annotation('JMS_STREAMMESSAGE_TYPE'),
+ hdr_annotations),
+ **hdr_kwargs)
+
+ def _create_jms_textmessage(self, test_value_text, hdr_kwargs, hdr_annotations):
+ """Create a JMS text message"""
+ return Message(id=(self.sent+1),
+ body=unicode(test_value_text),
+ annotations=TestTypeMap.merge_dicts(create_annotation('JMS_TEXTMESSAGE_TYPE'),
+ hdr_annotations),
+ **hdr_kwargs)
+
+ def _get_jms_message_header_kwargs(self):
+ hdr_kwargs = {}
+ hdr_annotations = {}
+ for jms_header in self.test_headers_map.iterkeys():
+ value_map = self.test_headers_map[jms_header]
+ value_type = value_map.keys()[0] # There is only ever one value in map
+ value = value_map[value_type]
+ if jms_header == 'JMS_TYPE_HEADER':
+ if value_type == 'string':
+ hdr_kwargs['subject'] = value
+ else:
+ raise InteropTestError('JmsSenderShim._get_jms_message_header_kwargs(): ' +
+ 'JMS_TYPE_HEADER requires value type "string", type "%s" found' %
+ value_type)
+ elif jms_header == 'JMS_CORRELATIONID_HEADER':
+ if value_type == 'string':
+ hdr_kwargs['correlation_id'] = value
+ elif value_type == 'bytes':
+ hdr_kwargs['correlation_id'] = str(value)
+ else:
+ raise InteropTestError('JmsSenderShim._get_jms_message_header_kwargs(): ' +
+ 'JMS_CORRELATIONID_HEADER requires value type "string" or "bytes", ' +
+ 'type "%s" found' % value_type)
+ hdr_annotations[symbol(u'x-opt-app-correlation-id')] = True
+ elif jms_header == 'JMS_REPLYTO_HEADER':
+ if value_type == 'queue':
+ hdr_kwargs['reply_to'] = value
+ hdr_annotations[symbol(u'x-opt-jms-reply-to')] = byte(0)
+ elif value_type == 'topic':
+ hdr_kwargs['reply_to'] = value
+ hdr_annotations[symbol(u'x-opt-jms-reply-to')] = byte(1)
+ elif value_type == 'temp_queue' or value_type == 'temp_topic':
+ raise InteropTestError('JmsSenderShim._get_jms_message_header_kwargs(): ' +
+ 'JMS_REPLYTO_HEADER type "temp_queue" or "temp_topic" not handled')
+ else:
+ raise InteropTestError('JmsSenderShim._get_jms_message_header_kwargs(): ' +
+ 'JMS_REPLYTO_HEADER requires value type "queue" or "topic", ' +
+ 'type "%s" found' % value_type)
+ else:
+ raise InteropTestError('JmsSenderShim._add_jms_message_headers(): Invalid JMS message header "%s"' %
+ jms_header)
+ return (hdr_kwargs, hdr_annotations)
+
+ def _add_jms_message_properties(self, message):
+ """Adds message properties to the supplied message from self.test_properties_map"""
+ for property_name in self.test_properties_map.iterkeys():
+ value_map = self.test_properties_map[property_name]
+ value_type = value_map.keys()[0] # There is only ever one value in map
+ value = value_map[value_type]
+ if message.properties is None:
+ message.properties = {}
+ if value_type == 'boolean':
+ message.properties[property_name] = value == 'True'
+ elif value_type == 'byte':
+ message.properties[property_name] = byte(int(value, 16))
+ elif value_type == 'double':
+ message.properties[property_name] = unpack('!d', value[2:].decode('hex'))[0]
+ elif value_type == 'float':
+ message.properties[property_name] = float32(unpack('!f', value[2:].decode('hex'))[0])
+ elif value_type == 'int':
+ message.properties[property_name] = int(value, 16)
+ elif value_type == 'long':
+ message.properties[property_name] = long(value, 16)
+ elif value_type == 'short':
+ message.properties[property_name] = short(int(value, 16))
+ elif value_type == 'string':
+ message.properties[property_name] = value
+ else:
+ raise InteropTestError('JmsSenderShim._add_jms_message_properties: ' +
+ 'Unknown or unhandled message property type ?%s"' % value_type)
+
+
+
+# --- main ---
+# Args: 1: Broker address (ip-addr:port)
+# 2: Queue name
+# 3: JMS message type
+# 4: JSON Test parameters containing 3 maps: [testValueMap, testHeadersMap, testPropertiesMap]
+#print '#### sys.argv=%s' % sys.argv
+#print '>>> test_values=%s' % loads(sys.argv[4])
+try:
+ Container(JmsSenderShim(sys.argv[1], sys.argv[2], sys.argv[3], loads(sys.argv[4]))).run()
+except KeyboardInterrupt:
+ pass
+except Exception as exc:
+ print 'jms-sender-shim EXCEPTION:', exc
+ print format_exc()
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/shims/qpid-proton-python/src/jms_messages_test/Receiver.py
----------------------------------------------------------------------
diff --git a/shims/qpid-proton-python/src/jms_messages_test/Receiver.py b/shims/qpid-proton-python/src/jms_messages_test/Receiver.py
index 9140db1..eff67c1 100755
--- a/shims/qpid-proton-python/src/jms_messages_test/Receiver.py
+++ b/shims/qpid-proton-python/src/jms_messages_test/Receiver.py
@@ -23,16 +23,17 @@ JMS receiver shim for qpid-interop-test
# under the License.
#
-import sys
-from interop_test_errors import InteropTestError
from json import dumps, loads
-from proton import byte, symbol
-from proton.handlers import MessagingHandler
-from proton.reactor import Container
from struct import pack, unpack
from subprocess import check_output
+import sys
from traceback import format_exc
+from proton import byte, symbol
+from proton.handlers import MessagingHandler
+from proton.reactor import Container
+from qpid_interop_test.interop_test_errors import InteropTestError
+
# These values must tie in with the Qpid-JMS client values found in
# org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport
QPID_JMS_TYPE_ANNOTATION_NAME = symbol(u'x-opt-jms-msg-type')
@@ -48,29 +49,18 @@ class JmsReceiverShim(MessagingHandler):
super(JmsReceiverShim, self).__init__()
self.url = url
self.jms_msg_type = jms_msg_type
- self.expteced_msg_map = test_parameters_list[0]
- self.flag_map = test_parameters_list[1]
+ self.expteced_msg_map = test_parameters_list
self.subtype_itr = iter(sorted(self.expteced_msg_map.keys()))
self.expected = self._get_tot_num_messages()
self.received = 0
self.received_value_map = {}
self.current_subtype = None
self.current_subtype_msg_list = None
- self.jms_header_map = {}
- self.jms_property_map = {}
def get_received_value_map(self):
""""Return the collected message values received"""
return self.received_value_map
- def get_jms_header_map(self):
- """Return the collected message headers received"""
- return self.jms_header_map
-
- def get_jms_property_map(self):
- """Return the collected message properties received"""
- return self.jms_property_map
-
def on_start(self, event):
"""Event callback for when the client starts"""
event.container.create_receiver(self.url)
@@ -84,8 +74,6 @@ class JmsReceiverShim(MessagingHandler):
self.current_subtype = self.subtype_itr.next()
self.current_subtype_msg_list = []
self.current_subtype_msg_list.append(self._handle_message(event.message))
- self._process_jms_headers(event.message)
- self._process_jms_properties(event.message)
if len(self.current_subtype_msg_list) >= self.expteced_msg_map[self.current_subtype]:
self.received_value_map[self.current_subtype] = self.current_subtype_msg_list
self.current_subtype = None
@@ -280,62 +268,6 @@ class JmsReceiverShim(MessagingHandler):
assert message.annotations[QPID_JMS_TYPE_ANNOTATION_NAME] == byte(5)
return message.body
- def _process_jms_headers(self, message):
- """"Checks the supplied message for three JMS headers: message type, correlation-id and reply-to"""
- # JMS message type header
- message_type_header = message._get_subject()
- if message_type_header is not None:
- self.jms_header_map['JMS_TYPE_HEADER'] = {'string': message_type_header}
-
- # JMS correlation ID
- correlation_id = message._get_correlation_id()
- if correlation_id is not None:
- if 'JMS_CORRELATIONID_AS_BYTES' in self.flag_map and self.flag_map['JMS_CORRELATIONID_AS_BYTES']:
- self.jms_header_map['JMS_CORRELATIONID_HEADER'] = {'bytes': correlation_id}
- else:
- self.jms_header_map['JMS_CORRELATIONID_HEADER'] = {'string': correlation_id}
-
- # JMS reply-to
- reply_to = message._get_reply_to()
- if reply_to is not None:
- if 'JMS_REPLYTO_AS_TOPIC' in self.flag_map and self.flag_map['JMS_REPLYTO_AS_TOPIC']:
- # Some brokers prepend 'queue://' and 'topic://' to reply_to addresses, strip these when present
- if len(reply_to) > 8 and reply_to[0:8] == 'topic://':
- reply_to = reply_to[8:]
- self.jms_header_map['JMS_REPLYTO_HEADER'] = {'topic': reply_to}
- else:
- if len(reply_to) > 8 and reply_to[0:8] == 'queue://':
- reply_to = reply_to[8:]
- self.jms_header_map['JMS_REPLYTO_HEADER'] = {'queue': reply_to}
-
- def _process_jms_properties(self, message):
- """"Checks the supplied message for JMS message properties and decodes them"""
- if message.properties is not None:
- for jms_property_name in message.properties:
- underscore_index = jms_property_name.find('_')
- if underscore_index >= 0: # Ignore any other properties without '_'
- jms_property_type = jms_property_name[0:underscore_index]
- value = message.properties[jms_property_name]
- if jms_property_type == 'boolean':
- self.jms_property_map[jms_property_name] = {'boolean': str(value)}
- elif jms_property_type == 'byte':
- self.jms_property_map[jms_property_name] = {'byte': hex(value)}
- elif jms_property_type == 'double':
- self.jms_property_map[jms_property_name] = {'double': '0x%016x' %
- unpack('!Q', pack('!d', value))[0]}
- elif jms_property_type == 'float':
- self.jms_property_map[jms_property_name] = {'float': '0x%08x' %
- unpack('!L', pack('!f', value))[0]}
- elif jms_property_type == 'int':
- self.jms_property_map[jms_property_name] = {'int': hex(value)}
- elif jms_property_type == 'long':
- self.jms_property_map[jms_property_name] = {'long': hex(int(value))}
- elif jms_property_type == 'short':
- self.jms_property_map[jms_property_name] = {'short': hex(value)}
- elif jms_property_type == 'string':
- self.jms_property_map[jms_property_name] = {'string': str(value)}
- else:
- pass # Ignore any other properties, brokers can add them and we don't know what they may be
# --- main ---
@@ -349,8 +281,6 @@ try:
Container(RECEIVER).run()
print sys.argv[3]
print dumps(RECEIVER.get_received_value_map())
- print dumps(RECEIVER.get_jms_header_map())
- print dumps(RECEIVER.get_jms_property_map())
except KeyboardInterrupt:
pass
except Exception as exc:
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/shims/qpid-proton-python/src/jms_messages_test/Sender.py
----------------------------------------------------------------------
diff --git a/shims/qpid-proton-python/src/jms_messages_test/Sender.py b/shims/qpid-proton-python/src/jms_messages_test/Sender.py
index 5a1108a..33a6acd 100755
--- a/shims/qpid-proton-python/src/jms_messages_test/Sender.py
+++ b/shims/qpid-proton-python/src/jms_messages_test/Sender.py
@@ -23,16 +23,17 @@ JMS sender shim for qpid-interop-test
# under the License.
#
-import sys
from json import loads
-from proton import byte, char, float32, int32, Message, short, symbol
-from proton.handlers import MessagingHandler
-from proton.reactor import Container
-from interop_test_errors import InteropTestError
from subprocess import check_output
from struct import pack, unpack
+import sys
from traceback import format_exc
+from proton import byte, char, float32, int32, Message, short, symbol
+from proton.handlers import MessagingHandler
+from proton.reactor import Container
+from qpid_interop_test.interop_test_errors import InteropTestError
+
# These values must tie in with the Qpid-JMS client values found in
# org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport
QPID_JMS_TYPE_ANNOTATION_NAME = symbol(u'x-opt-jms-msg-type')
@@ -64,9 +65,7 @@ class JmsSenderShim(MessagingHandler):
self.broker_ip_addr = broker_ip_addr
self.queue_name = queue_name
self.jms_msg_type = jms_msg_type
- self.test_value_map = test_parameters_list[0]
- self.test_headers_map = test_parameters_list[1]
- self.test_properties_map = test_parameters_list[2]
+ self.test_value_map = test_parameters_list
self.sent = 0
self.confirmed = 0
self.total = self._get_total_num_msgs()
@@ -119,8 +118,6 @@ class JmsSenderShim(MessagingHandler):
message = self._create_message(test_value_type, test_value, value_num)
# TODO: set message to address
if message is not None:
- self._add_jms_message_headers(message)
- self._add_jms_message_properties(message)
event.sender.send(message)
self.sent += 1
value_num += 1
@@ -283,94 +280,6 @@ class JmsSenderShim(MessagingHandler):
body=unicode(test_value_text),
annotations=create_annotation('JMS_TEXTMESSAGE_TYPE'))
- def _add_jms_message_headers(self, message):
- """Add JMS headers to the supplied message from self.test_headers_map"""
- for jms_header in self.test_headers_map.iterkeys():
- value_map = self.test_headers_map[jms_header]
- value_type = value_map.keys()[0] # There is only ever one value in map
- value = value_map[value_type]
- if jms_header == 'JMS_TYPE_HEADER':
- if value_type == 'string':
- self._s_set_jms_type_header(message, value)
- else:
- raise InteropTestError('JmsSenderShim._add_jms_message_headers(): ' +
- 'JMS_TYPE_HEADER requires value type "string", type "%s" found' %
- value_type)
- elif jms_header == 'JMS_CORRELATIONID_HEADER':
- if value_type == 'string':
- self._s_set_jms_correlation_id(message, value)
- elif value_type == 'bytes':
- self._s_set_jms_correlation_id(message, str(value))
- else:
- raise InteropTestError('JmsSenderShim._add_jms_message_headers(): ' +
- 'JMS_CORRELATIONID_HEADER requires value type "string" or "bytes", ' +
- 'type "%s" found' % value_type)
- elif jms_header == 'JMS_REPLYTO_HEADER':
- if value_type == 'queue' or value_type == 'topic':
- self._s_set_jms_reply_to(message, value_type, value)
- elif value_type == 'temp_queue' or value_type == 'temp_topic':
- raise InteropTestError('JmsSenderShim._add_jms_message_headers(): ' +
- 'JMS_REPLYTO_HEADER type "temp_queue" or "temp_topic" not handled')
- else:
- raise InteropTestError('JmsSenderShim._add_jms_message_headers(): ' +
- 'JMS_REPLYTO_HEADER requires value type "queue" or "topic", ' +
- 'type "%s" found' % value_type)
- else:
- raise InteropTestError('JmsSenderShim._add_jms_message_headers(): Invalid JMS message header "%s"' %
- jms_header)
-
-
- @staticmethod
- def _s_set_jms_type_header(message, message_type):
- """Adds a JMS message type header"""
- message._set_subject(message_type)
-
- @staticmethod
- def _s_set_jms_correlation_id(message, correlation_id):
- """Adds a JMS correlation id header"""
- message._set_correlation_id(correlation_id)
- message.annotations[symbol(u'x-opt-app-correlation-id')] = True
-
- @staticmethod
- def _s_set_jms_reply_to(message, jms_destination_type_str, destination):
- """Adds a JMS reply-to header"""
- if jms_destination_type_str == 'queue':
- message._set_reply_to(destination)
- message.annotations[symbol(u'x-opt-jms-reply-to')] = byte(0)
- elif jms_destination_type_str == 'topic':
- message._set_reply_to(destination)
- message.annotations[symbol(u'x-opt-jms-reply-to')] = byte(1)
- else:
- raise InteropTestError('JmsSenderShim._s_set_jms_reply_to(): ' +
- 'Invalid value for jms_destination_type_str "%s"' % jms_destination_type_str)
-
- def _add_jms_message_properties(self, message):
- """Adds message properties to the supplied message from self.test_properties_map"""
- for property_name in self.test_properties_map.iterkeys():
- value_map = self.test_properties_map[property_name]
- value_type = value_map.keys()[0] # There is only ever one value in map
- value = value_map[value_type]
- if message.properties is None:
- message.properties = {}
- if value_type == 'boolean':
- message.properties[property_name] = value == 'True'
- elif value_type == 'byte':
- message.properties[property_name] = byte(int(value, 16))
- elif value_type == 'double':
- message.properties[property_name] = unpack('!d', value[2:].decode('hex'))[0]
- elif value_type == 'float':
- message.properties[property_name] = float32(unpack('!f', value[2:].decode('hex'))[0])
- elif value_type == 'int':
- message.properties[property_name] = int(value, 16)
- elif value_type == 'long':
- message.properties[property_name] = long(value, 16)
- elif value_type == 'short':
- message.properties[property_name] = short(int(value, 16))
- elif value_type == 'string':
- message.properties[property_name] = value
- else:
- raise InteropTestError('JmsSenderShim._add_jms_message_properties: ' +
- 'Unknown or unhandled message property type ?%s"' % value_type)
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/src/python/qpid-interop-test/.gitignore
----------------------------------------------------------------------
diff --git a/src/python/qpid-interop-test/.gitignore b/src/python/qpid-interop-test/.gitignore
deleted file mode 100644
index 835fca3..0000000
--- a/src/python/qpid-interop-test/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-/interop_test_errors.pyc
-/shim_utils.pyc
-/broker_properties.pyc
-/test_type_map.pyc
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/src/python/qpid-interop-test/__init__.py
----------------------------------------------------------------------
diff --git a/src/python/qpid-interop-test/__init__.py b/src/python/qpid-interop-test/__init__.py
deleted file mode 100644
index a94c993..0000000
--- a/src/python/qpid-interop-test/__init__.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#
-# 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 broker_properties
-import interop_test_errors
-import shims
-import test_type_map
-import types
-import jms
-
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/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
deleted file mode 100755
index 30d0577..0000000
--- a/src/python/qpid-interop-test/amqp_types_test.py
+++ /dev/null
@@ -1,435 +0,0 @@
-#!/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/514bac75/src/python/qpid-interop-test/broker_properties.py
----------------------------------------------------------------------
diff --git a/src/python/qpid-interop-test/broker_properties.py b/src/python/qpid-interop-test/broker_properties.py
deleted file mode 100644
index 08cc9cc..0000000
--- a/src/python/qpid-interop-test/broker_properties.py
+++ /dev/null
@@ -1,54 +0,0 @@
-"""
-Module containing a small client which connects to the broker and
-gets the broker connection properties so as to identify the broker.
-"""
-
-#
-# 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.
-#
-
-from proton.handlers import MessagingHandler
-from proton.reactor import Container
-
-class Client(MessagingHandler):
- """
- Client to connect to broker and collect connection properties, used to identify the test broker
- """
- def __init__(self, url):
- super(Client, self).__init__()
- self.url = url
- self.remote_properties = None
-
- def on_connection_remote_open(self, event):
- self.remote_properties = event.connection.remote_properties
- event.connection.close()
-
- def on_start(self, event):
- """Event loop start"""
- event.container.connect(url=self.url)
-
- def get_connection_properties(self):
- """Return the connection properties"""
- return self.remote_properties
-
-
-def getBrokerProperties(broker_url):
- """Start client, then return its connection properties"""
- MSG_HANDLER = Client(broker_url)
- Container(MSG_HANDLER).run()
- return MSG_HANDLER.get_connection_properties()
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/src/python/qpid-interop-test/interop_test_errors.py
----------------------------------------------------------------------
diff --git a/src/python/qpid-interop-test/interop_test_errors.py b/src/python/qpid-interop-test/interop_test_errors.py
deleted file mode 100644
index 6be8959..0000000
--- a/src/python/qpid-interop-test/interop_test_errors.py
+++ /dev/null
@@ -1,29 +0,0 @@
-"""
-Module containing Error classes for interop testing
-"""
-
-#
-# 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.
-#
-
-class InteropTestError(StandardError):
- """
- Generic simple error class for use in interop tests
- """
- def __init__(self, error_message):
- super(InteropTestError, self).__init__(error_message)
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[2/5] qpid-interop-test git commit: QPIDIT-41: Reorganized dir
structure and tidied up the test code. Copied the old jms_messages_test to a
new jms_hdrs_props_test and simplified the jms_messages_test to include only
message body tests. Simplified parame
Posted by kp...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/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
deleted file mode 100755
index 56cb203..0000000
--- a/src/python/qpid-interop-test/jms_messages_test.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', '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)
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/src/python/qpid-interop-test/shims.py
----------------------------------------------------------------------
diff --git a/src/python/qpid-interop-test/shims.py b/src/python/qpid-interop-test/shims.py
deleted file mode 100644
index 5e94d2d..0000000
--- a/src/python/qpid-interop-test/shims.py
+++ /dev/null
@@ -1,229 +0,0 @@
-"""
-Module containing worker thread classes and shims
-"""
-#
-# 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.
-#
-
-from json import loads
-from os import getenv, getpgid, killpg, path, setsid
-from signal import SIGKILL, SIGTERM
-from subprocess import Popen, PIPE, CalledProcessError
-from sys import stdout
-from threading import Thread
-from time import sleep
-
-
-THREAD_TIMEOUT = 10.0 # seconds to complete before join is forced
-
-
-class ShimWorkerThread(Thread):
- """Parent class for shim worker threads and return a string once the thread has ended"""
- def __init__(self, thread_name):
- super(ShimWorkerThread, self).__init__(name=thread_name)
- self.arg_list = []
- self.return_obj = None
- self.proc = None
-
- def get_return_object(self):
- """Get the return object from the completed thread"""
- return self.return_obj
-
- def join_or_kill(self, timeout):
- """
- Wait for thread to join after timeout (seconds). If still alive, it is then terminated, then if still alive,
- killed
- """
- self.join(timeout)
- if self.is_alive():
- if self.proc is not None:
- if self._terminate_pg_loop():
- if self._kill_pg_loop():
- print '\n ERROR: Thread %s (pid=%d) alive after kill' % (self.name, self.proc.pid)
- else:
- print 'Killed'
- stdout.flush()
- else:
- print 'Terminated'
- stdout.flush()
- else:
- print 'ERROR: shims.join_or_kill(): Process joined and is alive, yet proc is None.'
-
- def _terminate_pg_loop(self, num_attempts=2, wait_time=2):
- cnt = 0
- while cnt < num_attempts and self.is_alive():
- cnt += 1
- print '\n Thread %s (pid=%d) alive after timeout, terminating (try #%d)...' % (self.name, self.proc.pid,
- cnt),
- stdout.flush()
- killpg(getpgid(self.proc.pid), SIGTERM)
- sleep(wait_time)
- return self.is_alive()
-
- def _kill_pg_loop(self, num_attempts=2, wait_time=5):
- cnt = 0
- while cnt < num_attempts and self.is_alive():
- cnt += 1
- print '\n Thread %s (pid=%d) alive after terminate, killing (try #%d)...' % (self.name, self.proc.pid,
- cnt),
- stdout.flush()
- killpg(getpgid(self.proc.pid), SIGKILL)
- sleep(wait_time)
- return self.is_alive()
-
-
-class Sender(ShimWorkerThread):
- """Sender class for multi-threaded send"""
- def __init__(self, use_shell_flag, send_shim_args, broker_addr, queue_name, msg_type, json_test_str):
- super(Sender, self).__init__('sender_thread_%s' % queue_name)
- if send_shim_args is None:
- print 'ERROR: Sender: send_shim_args == None'
- self.use_shell_flag = use_shell_flag
- self.arg_list.extend(send_shim_args)
- self.arg_list.extend([broker_addr, queue_name, msg_type, json_test_str])
-
- def run(self):
- """Thread starts here"""
- try:
- #print '\n>>>', self.arg_list # DEBUG - useful to see command-line sent to shim
- self.proc = Popen(self.arg_list, stdout=PIPE, stderr=PIPE, shell=self.use_shell_flag, preexec_fn=setsid)
- (stdoutdata, stderrdata) = self.proc.communicate()
- if len(stdoutdata) > 0 or len(stderrdata) > 0:
- self.return_obj = (stdoutdata, stderrdata)
- except CalledProcessError as exc:
- self.return_obj = str(exc) + '\n\nOutput:\n' + exc.output
-
-
-class Receiver(ShimWorkerThread):
- """Receiver class for multi-threaded receive"""
- def __init__(self, receive_shim_args, broker_addr, queue_name, msg_type, json_test_str):
- super(Receiver, self).__init__('receiver_thread_%s' % queue_name)
- if receive_shim_args is None:
- print 'ERROR: Receiver: receive_shim_args == None'
- self.arg_list.extend(receive_shim_args)
- self.arg_list.extend([broker_addr, queue_name, msg_type, json_test_str])
-
- def run(self):
- """Thread starts here"""
- try:
- #print '\n>>>', self.arg_list # DEBUG - useful to see command-line sent to shim
- self.proc = Popen(self.arg_list, stdout=PIPE, stderr=PIPE, preexec_fn=setsid)
- (stdoutdata, stderrdata) = self.proc.communicate()
- if len(stderrdata) > 0:
- self.return_obj = (stdoutdata, stderrdata)
- else:
- #print '<<<', stdoutdata # DEBUG - useful to see text received from shim
- str_tvl = stdoutdata.split('\n')[0:-1] # remove trailing \n
- #if len(str_tvl) == 1:
- # self.return_obj = output
- if len(str_tvl) == 2: # AMQP type test return
- self.return_obj = loads(str_tvl[1])
- elif len(str_tvl) == 4: # JMS test return
- self.return_obj = (str_tvl[0], loads(str_tvl[1]), loads(str_tvl[2]), loads(str_tvl[3]))
- else: # Make a single line of all the bits and return that
- #self.return_obj = loads("".join(str_tvl[1:]))
- self.return_obj = stdoutdata
- except CalledProcessError as exc:
- self.return_obj = str(exc) + '\n\n' + exc.output
-
-class Shim(object):
- """Abstract shim class, parent of all shims."""
- NAME = None
- def __init__(self, sender_shim, receiver_shim):
- self.sender_shim = sender_shim
- self.receiver_shim = receiver_shim
- self.send_params = None
- self.receive_params = None
- self.use_shell_flag = False
-
- def create_sender(self, broker_addr, queue_name, msg_type, json_test_str):
- """Create a new sender instance"""
- return Sender(self.use_shell_flag, self.send_params, broker_addr, queue_name, msg_type, json_test_str)
-
- def create_receiver(self, broker_addr, queue_name, msg_type, json_test_str):
- """Create a new receiver instance"""
- return Receiver(self.receive_params, broker_addr, queue_name, msg_type, json_test_str)
-
-class ProtonPythonShim(Shim):
- """Shim for qpid-proton Python client"""
- NAME = 'ProtonPython'
- def __init__(self, sender_shim, receiver_shim):
- super(ProtonPythonShim, self).__init__(sender_shim, receiver_shim)
- self.send_params = [self.sender_shim]
- self.receive_params = [self.receiver_shim]
-
-
-class ProtonCppShim(Shim):
- """Shim for qpid-proton C++ client"""
- NAME = 'ProtonCpp'
- def __init__(self, sender_shim, receiver_shim):
- super(ProtonCppShim, self).__init__(sender_shim, receiver_shim)
- self.send_params = [self.sender_shim]
- self.receive_params = [self.receiver_shim]
-
-
-class QpidJmsShim(Shim):
- """Shim for qpid-jms JMS client"""
- NAME = 'QpidJms'
-
- # Installed versions
- # TODO: Automate this - it gets out of date quickly
- # Maven works out all the deps, should use that
- QPID_JMS_SHIM_VER = '0.1.0-SNAPSHOT'
- QPID_JMS_VER = '0.20.0-SNAPSHOT'
- QPID_PROTON_J_VER = '0.15.0-SNAPSHOT'
- JMS_API_VER = '1.1.1'
- LOGGER_API_VER = '1.7.21'
- LOGGER_IMPL_VER = '1.7.21'
- NETTY_VER = '4.0.40.Final'
-
- # Classpath components
- #QPID_INTEROP_TEST_SHIM_JAR = path.join(QPID_INTEROP_TEST_HOME, 'shims', 'qpid-jms', 'target', 'qpid-jms-shim.jar')
- MAVEN_REPO_PATH = path.join(getenv('HOME'), '.m2', 'repository')
- JMS_API_JAR = path.join(MAVEN_REPO_PATH, 'org', 'apache', 'geronimo', 'specs', 'geronimo-jms_1.1_spec', JMS_API_VER,
- 'geronimo-jms_1.1_spec-%s.jar' % JMS_API_VER)
- JMS_IMPL_JAR = path.join(MAVEN_REPO_PATH, 'org', 'apache', 'qpid', 'qpid-jms-client', QPID_JMS_VER,
- 'qpid-jms-client-%s.jar' % QPID_JMS_VER)
- LOGGER_API_JAR = path.join(MAVEN_REPO_PATH, 'org', 'slf4j', 'slf4j-api', LOGGER_API_VER,
- 'slf4j-api-%s.jar' % LOGGER_API_VER)
- LOGGER_IMPL_JAR = path.join(MAVEN_REPO_PATH, 'org', 'slf4j', 'slf4j-nop', LOGGER_IMPL_VER,
- 'slf4j-nop-%s.jar' % LOGGER_IMPL_VER)
- PROTON_J_JAR = path.join(MAVEN_REPO_PATH, 'org', 'apache', 'qpid', 'proton-j', QPID_PROTON_J_VER,
- 'proton-j-%s.jar' % QPID_PROTON_J_VER)
- NETTY_JAR = path.join(MAVEN_REPO_PATH, 'io', 'netty', 'netty-all', NETTY_VER, 'netty-all-%s.jar' % NETTY_VER)
- QPID_JMS_SHIM_JAR = path.join(MAVEN_REPO_PATH, 'org', 'apache', 'qpid', 'qpid-interop-test-jms-shim',
- QPID_JMS_SHIM_VER, 'qpid-interop-test-jms-shim-%s.jar' % QPID_JMS_SHIM_VER)
-
- JAVA_HOME = getenv('JAVA_HOME', '/usr/bin') # Default only works in Linux
- JAVA_EXEC = path.join(JAVA_HOME, 'java')
-
- def __init__(self, dependency_class_path, sender_shim, receiver_shim):
- super(QpidJmsShim, self).__init__(sender_shim, receiver_shim)
- self.dependency_class_path = dependency_class_path
- self.send_params = [self.JAVA_EXEC, '-cp', self.get_java_class_path(), self.sender_shim]
- self.receive_params = [self.JAVA_EXEC, '-cp', self.get_java_class_path(), self.receiver_shim]
-
- def get_java_class_path(self):
- """Method to construct and return the Java class path necessary to run the shim"""
- return ':'.join([self.QPID_JMS_SHIM_JAR, self.dependency_class_path])
- # self.JMS_API_JAR,
- # self.JMS_IMPL_JAR,
- # self.LOGGER_API_JAR,
- # self.LOGGER_IMPL_JAR,
- # self.PROTON_J_JAR,
- # self.NETTY_JAR])
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/src/python/qpid-interop-test/test_type_map.py
----------------------------------------------------------------------
diff --git a/src/python/qpid-interop-test/test_type_map.py b/src/python/qpid-interop-test/test_type_map.py
deleted file mode 100644
index b571ac8..0000000
--- a/src/python/qpid-interop-test/test_type_map.py
+++ /dev/null
@@ -1,85 +0,0 @@
-"""
-Module containing Error classes for interop testing
-"""
-#
-# 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.
-#
-
-class TestTypeMap(object):
- """
- Class which contains all the described types and the test values to be used in testing against those types.
- """
-
- # TYPE_MAP: Map containing all described types as the indecies, and a list of values to be used in testing
- # that type as a list of values.
- #
- # Format: {'type_1' : [val_1_1, val_1_2, ...],
- # 'type_2' : [val_2_1, val_2_2, ...],
- # ...
- # }
- TYPE_MAP = {}
-
- # BROKER_SKIP: For know broker issues where a type would cause a test to fail or hang,
- # entries in BROKER_SKIP will cause the test to be skipped with a message.
- # This is a map containing AMQP types as a key, and a list of brokers for which this
- # type should be skipped.
- # Format: {'jms_msg_type_1' : {'broker_1' : 'skip msg for broker_1',
- # 'broker_2' : 'skip msg for broker_2',
- # ...
- # },
- # 'jms_msg_type_2' : {'broker_1' : 'skip msg for broker_1',
- # 'broker_2' : 'skip msg for broker_2',
- # ...
- # },
- # ...
- # }
- # where broker_1, broker_2, ... are broker product names as defined by the
- # connection property string it returns.
- BROKER_SKIP = {}
-
- def __init__(self):
- pass
-
- def get_type_list(self):
- """Return a list of types which this test suite supports"""
- return self.TYPE_MAP.keys()
-
- def get_test_values(self, test_type):
- """Return test values to use when testing the supplied type."""
- if test_type not in self.TYPE_MAP.keys():
- return None
- return self.TYPE_MAP[test_type]
-
- def skip_test_message(self, test_type, broker_name):
- """Return the message to use if a test is skipped"""
- if test_type in self.BROKER_SKIP.keys():
- if broker_name in self.BROKER_SKIP[test_type]:
- return str(self.BROKER_SKIP[test_type][broker_name])
- return None
-
- def skip_test(self, test_type, broker_name):
- """Return boolean True if test should be skipped"""
- return test_type in self.BROKER_SKIP.keys() and \
- broker_name in self.BROKER_SKIP[test_type]
-
- @staticmethod
- def merge_dicts(*dict_args):
- res = {}
- for d in dict_args:
- res.update(d)
- return res
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/src/python/qpid_interop_test/.gitignore
----------------------------------------------------------------------
diff --git a/src/python/qpid_interop_test/.gitignore b/src/python/qpid_interop_test/.gitignore
new file mode 100644
index 0000000..835fca3
--- /dev/null
+++ b/src/python/qpid_interop_test/.gitignore
@@ -0,0 +1,4 @@
+/interop_test_errors.pyc
+/shim_utils.pyc
+/broker_properties.pyc
+/test_type_map.pyc
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/src/python/qpid_interop_test/__init__.py
----------------------------------------------------------------------
diff --git a/src/python/qpid_interop_test/__init__.py b/src/python/qpid_interop_test/__init__.py
new file mode 100644
index 0000000..70204e4
--- /dev/null
+++ b/src/python/qpid_interop_test/__init__.py
@@ -0,0 +1,23 @@
+#
+# 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 broker_properties
+import interop_test_errors
+import shims
+import test_type_map
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/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..bde21f3
--- /dev/null
+++ b/src/python/qpid_interop_test/amqp_types_test.py
@@ -0,0 +1,443 @@
+#!/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 time import mktime, time
+from uuid import UUID, uuid4
+
+from proton import symbol
+import qpid_interop_test.broker_properties
+import qpid_interop_test.shims
+from qpid_interop_test.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 sent byte reversed: PROTON-1160',
+ 'qpid-cpp': 'decimal32 not supported on qpid-cpp broker: QPIDIT-5, QPID-6328',
+ 'apache-activemq-artemis': 'decimal32 and decimal64 sent byte reversed: PROTON-1160',
+ 'qpid-dispatch-router': 'decimal32 and decimal64 sent byte reversed: PROTON-1160'},
+ 'decimal64': {'ActiveMQ': 'decimal32 and decimal64 sent byte reversed: PROTON-1160',
+ 'qpid-cpp': 'decimal64 not supported on qpid-cpp broker: QPIDIT-6, QPID-6328',
+ 'apache-activemq-artemis': 'decimal32 and decimal64 sent byte reversed: PROTON-1160',
+ 'qpid-dispatch-router': 'decimal32 and decimal64 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(qpid_interop_test.shims.THREAD_TIMEOUT)
+ receiver.join_or_kill(qpid_interop_test.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, tuple):
+ if len(receive_obj) == 2:
+ return_amqp_type, return_test_value_list = receive_obj
+ self.assertEqual(return_amqp_type, amqp_type,
+ msg='AMQP type error:\n\n sent:%s\n\n received:%s' % \
+ (amqp_type, return_amqp_type))
+ self.assertEqual(return_test_value_list, test_value_list, msg='\n sent:%s\nreceived:%s' % \
+ (test_value_list, return_test_value_list))
+ else:
+ self.fail('Received incorrect tuple format: %s' % str(receive_obj))
+ else:
+ self.fail('Received non-tuple: %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 = {qpid_interop_test.shims.ProtonCppShim.NAME: \
+ qpid_interop_test.shims.ProtonCppShim(PROTON_CPP_SENDER_SHIM, PROTON_CPP_RECEIVER_SHIM),
+ qpid_interop_test.shims.ProtonPythonShim.NAME: \
+ qpid_interop_test.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 = qpid_interop_test.broker_properties.get_broker_properties(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
+ sys.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/514bac75/src/python/qpid_interop_test/broker_properties.py
----------------------------------------------------------------------
diff --git a/src/python/qpid_interop_test/broker_properties.py b/src/python/qpid_interop_test/broker_properties.py
new file mode 100644
index 0000000..01a090f
--- /dev/null
+++ b/src/python/qpid_interop_test/broker_properties.py
@@ -0,0 +1,55 @@
+"""
+Module containing a small client which connects to the broker and
+gets the broker connection properties so as to identify the broker.
+"""
+
+#
+# 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.
+#
+
+from proton.handlers import MessagingHandler
+from proton.reactor import Container
+
+class Client(MessagingHandler):
+ """
+ Client to connect to broker and collect connection properties, used to identify the test broker
+ """
+ def __init__(self, url):
+ super(Client, self).__init__()
+ self.url = url
+ self.remote_properties = None
+
+ def on_connection_remote_open(self, event):
+ """Callback for remote connection open"""
+ self.remote_properties = event.connection.remote_properties
+ event.connection.close()
+
+ def on_start(self, event):
+ """Event loop start"""
+ event.container.connect(url=self.url)
+
+ def get_connection_properties(self):
+ """Return the connection properties"""
+ return self.remote_properties
+
+
+def get_broker_properties(broker_url):
+ """Start client, then return its connection properties"""
+ msg_handler = Client(broker_url)
+ Container(msg_handler).run()
+ return msg_handler.get_connection_properties()
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/514bac75/src/python/qpid_interop_test/interop_test_errors.py
----------------------------------------------------------------------
diff --git a/src/python/qpid_interop_test/interop_test_errors.py b/src/python/qpid_interop_test/interop_test_errors.py
new file mode 100644
index 0000000..6be8959
--- /dev/null
+++ b/src/python/qpid_interop_test/interop_test_errors.py
@@ -0,0 +1,29 @@
+"""
+Module containing Error classes for interop testing
+"""
+
+#
+# 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.
+#
+
+class InteropTestError(StandardError):
+ """
+ Generic simple error class for use in interop tests
+ """
+ def __init__(self, error_message):
+ super(InteropTestError, self).__init__(error_message)
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org