Repository: qpid-interop-test Updated Branches: refs/heads/master 899a9a863 -> 6c8ab3b0a
QPIDIT-20: Added ability to detect broker and automatically exclude tests that fail for that broker 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/6c8ab3b0 Tree: http://git-wip-us.apache.org/repos/asf/qpid-interop-test/tree/6c8ab3b0 Diff: http://git-wip-us.apache.org/repos/asf/qpid-interop-test/diff/6c8ab3b0 Branch: refs/heads/master Commit: 6c8ab3b0a25b549de355a85f09e83dde6aa5cd19 Parents: 899a9a8 Author: Kim van der Riet <[email protected]> Authored: Wed Nov 11 15:00:58 2015 -0500 Committer: Kim van der Riet <[email protected]> Committed: Wed Nov 11 15:00:58 2015 -0500 ---------------------------------------------------------------------- src/py/qpid-interop-test/__init__.py | 4 +- src/py/qpid-interop-test/broker_properties.py | 55 +++ .../qpid-interop-test/jms/jms_message_tests.py | 49 ++- src/py/qpid-interop-test/shim_utils.py | 388 ------------------- src/py/qpid-interop-test/test_type_map.py | 80 ++++ .../types/simple_type_tests.py | 53 ++- 6 files changed, 199 insertions(+), 430 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/6c8ab3b0/src/py/qpid-interop-test/__init__.py ---------------------------------------------------------------------- diff --git a/src/py/qpid-interop-test/__init__.py b/src/py/qpid-interop-test/__init__.py index 404056b..7b8aee3 100644 --- a/src/py/qpid-interop-test/__init__.py +++ b/src/py/qpid-interop-test/__init__.py @@ -17,7 +17,9 @@ # under the License. # -import shim_utils +import broker_properties +import interop_test_errors +import test_type_map import types import jms http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/6c8ab3b0/src/py/qpid-interop-test/broker_properties.py ---------------------------------------------------------------------- diff --git a/src/py/qpid-interop-test/broker_properties.py b/src/py/qpid-interop-test/broker_properties.py new file mode 100644 index 0000000..86b092a --- /dev/null +++ b/src/py/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 BrokerClient(MessagingHandler): + """ + Client to connect to broker and collect connection properties, used to identify the test broker + """ + def __init__(self, url): + super(BrokerClient, self).__init__() + self.url = url + self.remote_properties = None + + def on_start(self, event): + """Event loop start""" + event.container.create_sender(self.url) + + def on_sendable(self, event): + """Sender link has credit, can send messages. Get connection properties, then close connection""" + self.remote_properties = event.sender.connection.remote_properties + event.sender.connection.close() + + 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 = BrokerClient(broker_url) + Container(MSG_HANDLER).run() + return MSG_HANDLER.get_connection_properties() http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/6c8ab3b0/src/py/qpid-interop-test/jms/jms_message_tests.py ---------------------------------------------------------------------- diff --git a/src/py/qpid-interop-test/jms/jms_message_tests.py b/src/py/qpid-interop-test/jms/jms_message_tests.py index 1e53145..7ba2854 100755 --- a/src/py/qpid-interop-test/jms/jms_message_tests.py +++ b/src/py/qpid-interop-test/jms/jms_message_tests.py @@ -31,10 +31,15 @@ from json import dumps, loads from os import getenv, path from subprocess import check_output, CalledProcessError +from proton import symbol +from test_type_map import TestTypeMap +import broker_properties + + # TODO - propose a sensible default when installation details are worked out QPID_INTEROP_TEST_HOME = getenv('QPID_INTEROP_TEST_HOME') -class JmsMessageTypes(object): +class JmsMessageTypes(TestTypeMap): """ Class which contains all the described JMS message types and the test values to be used in testing. """ @@ -113,6 +118,7 @@ class JmsMessageTypes(object): 'Charlie\'s "peach"', 'The quick brown fox jumped over the lazy dog 0123456789.' * 100] } + TYPE_MAP = { 'JMS_BYTESMESSAGE_TYPE': TYPE_SUBMAP, 'JMS_MAPMESSAGE_TYPE': TYPE_SUBMAP, @@ -169,17 +175,7 @@ class JmsMessageTypes(object): 'The quick brown fox jumped over the lazy dog 0123456789.' * 100]} } - @staticmethod - def get_type_list(): - """Return a list of JMS message types which this test suite supports""" - return JmsMessageTypes.TYPE_MAP.keys() - - @staticmethod - def get_test_value_map(jms_messagae_type): - """Return a list of test values to use when testing the supplied JMS message type.""" - if jms_messagae_type not in JmsMessageTypes.TYPE_MAP.keys(): - return None - return JmsMessageTypes.TYPE_MAP[jms_messagae_type] + BROKER_SKIP = {} class JmsMessageTypeTestCase(unittest.TestCase): @@ -211,7 +207,7 @@ class JmsMessageTypeTestCase(unittest.TestCase): self.fail('Type %s has no test values' % jms_message_type) -def create_testcase_class(broker_addr, jms_message_type, test_values, shim_product): +def create_testcase_class(broker_name, types, broker_addr, jms_message_type, shim_product): """ Class factory function which creates new subclasses to JmsMessageTypeTestCase. """ @@ -223,6 +219,8 @@ def create_testcase_class(broker_addr, jms_message_type, test_values, shim_produ 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) @@ -237,7 +235,7 @@ def create_testcase_class(broker_addr, jms_message_type, test_values, shim_produ '__doc__': 'Test case for JMS message type \'%s\'' % jms_message_type, 'jms_message_type': jms_message_type, 'broker_addr': broker_addr, - 'test_values': test_values} + 'test_values': types.get_test_values(jms_message_type)} 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) @@ -391,7 +389,17 @@ class TestOptions(object): if __name__ == '__main__': ARGS = TestOptions().args - #print 'ARGS:', ARGS # DEBUG + #print 'ARGS:', ARGS # debug + + # Connect to broker to find broker type + CONNECTION_PROPS = broker_properties.getBrokerProperties(ARGS.broker) + print 'Test Broker: %s v.%s on %s' % (CONNECTION_PROPS[symbol(u'product')], + CONNECTION_PROPS[symbol(u'version')], + CONNECTION_PROPS[symbol(u'platform')]) + print + BROKER = CONNECTION_PROPS[symbol(u'product')] + + 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. @@ -406,11 +414,12 @@ if __name__ == '__main__': for shim in ARGS.exclude_shim: SHIM_MAP.pop(shim) # Create test classes dynamically - for at in sorted(JmsMessageTypes.get_type_list()): - if ARGS.exclude_type is None or at not in ARGS.exclude_type: - test_case_class = create_testcase_class(ARGS.broker, - at, - JmsMessageTypes.get_test_value_map(at), + 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)) http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/6c8ab3b0/src/py/qpid-interop-test/shim_utils.py ---------------------------------------------------------------------- diff --git a/src/py/qpid-interop-test/shim_utils.py b/src/py/qpid-interop-test/shim_utils.py deleted file mode 100755 index 14d3a96..0000000 --- a/src/py/qpid-interop-test/shim_utils.py +++ /dev/null @@ -1,388 +0,0 @@ -#!/usr/bin/env python - -""" -Module containing utilities for the shims used in qpid-interop. -""" - -# -# 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 sys -import proton -from ast import literal_eval -from uuid import UUID - -class StrToObj(object): - """ - Class StrObj consumes the characters from a string iterator str_itr - and interprets the string so as to create the equivalent python - object(s) in a manner similar to ast.leteral_eval(). The difference - is that this version supports proton types as a part of the - interpretation, so that a string such as - - '[1, char('a'), timestamp(1234567)]' - - can be parsed. - - The following compound python types can be handled: - [...] list - (...) tuple - {...} dict - which may contain any legal combination of simple python types - including strings, embedded lists, tuples and dicts, and the - supported proton types. All of the simple types must be supported - by ast.leteral_eval() to be supported in this class. - - The following proton types are handled: - proton.char - proton.symbol - proton.timestamp - proton.ulong - - Typical usage: - ------------- - For a python string object str containing the string to be parsed, - it is necessary to obtain an iterator to the individual characters - of the string. This can be done as follows: - - obj = StrToObj(list(str).__iter__()).run() - - where obj will contain an instance of the object described in the - string. The run() method starts the process of consuming characters - from the iterator and interpreting them. - - This class is also the parent class of a number of more specialized - subclasses for handling sub-sections of the string interpretation: - - StrToObj (this class) - ^ - | - +----------+-------------+ - | | | - StrToStr StrToType StrToSeq - ^ - | - +-------------+-----------+ - | | | - StrToList StrToTuple StrToDict - - and which make up all the elements of the composite types needed - for this application. Simple types are handled by calling - ast.literal_evel(), and the types that can be handled are - determined by that function. - """ - - def __init__(self, str_itr): - self._str_itr = str_itr - self._done = False - self._obj = None - self._str_buff = '' - - def get_obj(self): - """ - Return object created as a result of parsing the string - supplied to the constructor and using the run() method. - """ - return self._obj - - def run(self): - """ - Starts the process of 'consuming' characters from the supplied - string iterator and of interpreting them in the context of the - previous characters. - """ - try: - while not self._done: - char = self._str_itr.next() - if not self._process_char(char): - self._str_buff += char - except StopIteration: - if len(self._str_buff) > 0 and self._obj is None: - self._obj = literal_eval(self._str_buff) - self._str_buff = '' - return self._obj - - def _add_elt(self, elt): - """ - Sets the object itself to parameter elt. This function is - frequently overloaded by its subclasses. - """ - self._obj = elt - - def _process_char(self, char): - """ - Consume and process a single character in the context of those - that have passed before. This function is overloaded by its - subclasses to provide either additional or alternative - processing. - - This function checks for the characters that start a list - ('['), a dict ('{'), a tuple ('(' when preceded only by - whitespace), a string ('\'' or '"') or special proton types - ('(' when preceded by a constructor string). - - If any of these chars are found, a new object of the - appropriate class is constructed to handle the processing of - that type, and when its run() function completes, a constructed - object will be returned. - """ - if char == '[': - self._add_elt(StrToList(char, self._str_itr).run()) - return True - if char == '{': - self._add_elt(StrToDict(char, self._str_itr).run()) - return True - if char == '(': - if len(self._str_buff.strip()) == 0: - self._add_elt(StrToTuple(char, self._str_itr).run()) - else: - self._add_elt(StrToType(char, self._str_itr, - self._str_buff).run()) - self._str_buff = '' - return True - if char == '\'' or char == '"': - str_prefix = None - if len(self._str_buff.strip()) > 0: - str_prefix = self._str_buff.strip() - self._add_elt(StrToStr(char, self._str_itr, str_prefix).run()) - self._str_buff = '' - return True - return False - - -class StrToStr(StrToObj): - """ - Class to consume a string delimited by either ' or " chars. - """ - - def __init__(self, delim_char, str_itr, str_prefix): - super(StrToStr, self).__init__(str_itr) - self._delim_char = delim_char - self._str_prefix = str_prefix - self._escape_flag = False - - def _process_char(self, char): - """ - This function processes a python string type, and continues - consuming characters until another matching delimiter character - ('\'' or '"') is encountered. A delimiter character that is - preceded by an escape character ('\\') is excluded. - - The entire string may have a prefix of one or more characters. - Only the u prefix (eg u'hello') has any effect; the b prefix - has no effect in Python 2.x but paves the way for Python 3.x - where it does have significance, and the r prefix affects the - display or printing of strings only. - """ - if char == '\\': - self._escape_flag = not self._escape_flag - elif char == self._delim_char and not self._escape_flag: - if self._str_prefix is None: - self._obj = self._str_buff - elif 'u' in self._str_prefix or 'U' in self._str_prefix: - self._obj = unicode(self._str_buff) - else: - self._obj = self._str_buff # Ignore other prefixes (b, B, r, R) - self._str_buff = '' - self._done = True - return True - else: - self._escape_flag = False - return False - - -class StrToType(StrToObj): - """ - Class for processing special proton python types. - """ - - def __init__(self, _, str_itr, type_str): - super(StrToType, self).__init__(str_itr) - self._type_str = type_str.strip() - self._val = None - - def _add_elt(self, elt): - """ - Sets the value portion of the type to elt. This is then used - in the constructor of the type. - """ - self._val = elt - - def _process_char(self, char): - """ - Process characters to identify the value to the constructor of - the proton type being processed. The proton type string is - passed to the constructor, and when the '(' char is encountered, - this function is used until the matching ')' char is reached. - - The parent StrToObj._process_char() is called first to process - any compound types and strings which may be present as a - constructor value. - """ - if super(StrToType, self)._process_char(char): - return True - if char == ')': - if len(self._str_buff.strip()) > 0: - if self._val is not None: - # This condition should not ever arise, either - # self._val is set OR self._str_buff contains a - # value, but not both. - raise RuntimeError('self._val=%s and self._str_buff=%s' % - (self._val, self._str_buff)) - self._val = literal_eval( - self._str_buff[self._str_buff.find('(')+1:]) - if self._type_str == 'ubyte': - self._obj = proton.ubyte(self._val) - elif self._type_str == 'ushort': - self._obj = proton.ushort(self._val) - elif self._type_str == 'uint': - self._obj = proton.uint(self._val) - elif self._type_str == 'ulong': - self._obj = proton.ulong(self._val) - elif self._type_str == 'byte': - self._obj = proton.byte(self._val) - elif self._type_str == 'short': - self._obj = proton.short(self._val) - elif self._type_str == 'int32': - self._obj = proton.int32(self._val) - elif self._type_str == 'float32': - self._obj = proton.float32(self._val) - elif self._type_str == 'decimal32': - self._obj = proton.decimal32(self._val) - elif self._type_str == 'decimal64': - self._obj = proton.decimal64(self._val) - elif self._type_str == 'decimal128': - self._obj = proton.decimal128(self._val) - elif self._type_str == 'char': - self._obj = proton.char(self._val) - elif self._type_str == 'symbol': - self._obj = proton.symbol(self._val) - elif self._type_str == 'timestamp': - self._obj = proton.timestamp(self._val) - elif self._type_str == 'UUID': - self._obj = UUID(self._val) - else: - raise ValueError('StrToType: unknown type \'%s\'' % self._type_str) - self._str_buff = '' - self._done = True - return True - - -class StrToSeq(StrToObj): - """ - Class which consumes comma-delimited sequence types such as lists, - dicts and tuples. - """ - - def __init__(self, _, str_itr, close_char, seq_type): - super(StrToSeq, self).__init__(str_itr) - self._close_char = close_char - self._obj = seq_type() - - def _process_char(self, char): - """ - Processing for container sequence types that use a ',' - character as an element delimiter. Individual elements may be - any legal type, including proton types and nested containers. - """ - if super(StrToSeq, self)._process_char(char): - return True - if char == ',' or char == self._close_char: - if char == self._close_char: - self._done = True - if len(self._str_buff.strip()) > 0: - self._add_elt(literal_eval(self._str_buff.strip())) - self._str_buff = '' - return True - return False - -class StrToList(StrToSeq): - """ - Class which consumes a list of the form '[...]'. - """ - - def __init__(self, char, str_itr): - super(StrToList, self).__init__(char, str_itr, ']', list) - - def _add_elt(self, elt): - """ - Adds an additional element into the list object. - """ - self._obj.append(elt) - -class StrToTuple(StrToSeq): - """ - Class which consumes a tuple of the form '(...)'. Tuples without - the enclosing braces are not currently supported, however. - """ - - def __init__(self, char, str_itr): - super(StrToTuple, self).__init__(char, str_itr, ')', tuple) - - def _add_elt(self, elt): - """ - Adds an additional element into the tuple object. - """ - self._obj = self._obj + (elt,) - -class StrToDict(StrToSeq): - """ - Class which consumed a dict of the form '{...}'. - """ - - def __init__(self, c, str_itr): - super(StrToDict, self).__init__(c, str_itr, '}', dict) - self._key = None - - def _add_elt(self, elt): - """ - Called twice for dicts; the first call sets the key object, - and the second call sets the value object and then inserts - the entire key:value pair into the map. - """ - if self._key is None: - self._key = elt - else: - self._obj[self._key] = elt - self._key = None - - def _process_char(self, c): - """ - Processing of characters for the python dict type using the - 'key:value' syntax. The key and value may be any legal python - or proton type, including embedded containers. - """ - if super(StrToDict, self)._process_char(c): - return True - if c == ':': - if len(self._str_buff.strip()) > 0: - self._add_elt(literal_eval(self._str_buff.strip())) - self._str_buff = '' - return True - return False - -# --- main --- - -# This command-line entry point is for testing only, it does not -# provide any useful functionality on its own. - -#if len(sys.argv) == 2: -# print '%r' % StrToObj(list(sys.argv[1]).__iter__()).run() -#else: -# print 'Usage: shim_utils <string>' http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/6c8ab3b0/src/py/qpid-interop-test/test_type_map.py ---------------------------------------------------------------------- diff --git a/src/py/qpid-interop-test/test_type_map.py b/src/py/qpid-interop-test/test_type_map.py new file mode 100644 index 0000000..33894fc --- /dev/null +++ b/src/py/qpid-interop-test/test_type_map.py @@ -0,0 +1,80 @@ +""" +Module containing Error classes for interop testing +""" +from reportlab.lib.randomtext import BLAH + +# +# 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] http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/6c8ab3b0/src/py/qpid-interop-test/types/simple_type_tests.py ---------------------------------------------------------------------- diff --git a/src/py/qpid-interop-test/types/simple_type_tests.py b/src/py/qpid-interop-test/types/simple_type_tests.py index 59d2790..cc8fbf2 100755 --- a/src/py/qpid-interop-test/types/simple_type_tests.py +++ b/src/py/qpid-interop-test/types/simple_type_tests.py @@ -33,10 +33,16 @@ from subprocess import check_output, CalledProcessError from time import mktime, time from uuid import UUID, uuid4 +from proton import symbol +from test_type_map import TestTypeMap +import broker_properties + + # TODO - propose a sensible default when installation details are worked out QPID_INTEROP_TEST_HOME = getenv('QPID_INTEROP_TEST_HOME') -class AmqpPrimitiveTypes(object): + +class AmqpPrimitiveTypes(TestTypeMap): """ Class which contains all the described AMQP primitive types and the test values to be used in testing. """ @@ -121,8 +127,6 @@ class AmqpPrimitiveTypes(object): # 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. - # Note that IEE-754 allows for two binary encodings of these numbers without any way to determine which - # of them is in use. Thus the encoding used must be by convention or agreed upon in advance by the clients. 'decimal32': ['0x00000000', '0x40490fdb', '0xc02df854', @@ -137,8 +141,7 @@ class AmqpPrimitiveTypes(object): 'Z', '\x01', '\x7f'], - # timestamp - # Must be in milliseconds since the unix epoch + # timestamp: Must be in milliseconds since the Unix epoch 'timestamp': ['0', '%d' % int(mktime((2000, 1, 1, 0, 0, 0, 5, 1, 0))*1000), '%d' % int(time()*1000)], @@ -183,17 +186,12 @@ class AmqpPrimitiveTypes(object): #'array': [[], [1,2,3], ['Hello', 'world']] # TODO: Not yet implemented } - @staticmethod - def get_type_list(): - """Return a list of simple AMQP types which this test suite supports""" - return AmqpPrimitiveTypes.TYPE_MAP.keys() + BROKER_SKIP = {'decimal32': {'qpid-cpp': 'decimal32 not supported on qpid-cpp broker: QPIDIT-5, QPID-6328',}, + 'decimal64': {'qpid-cpp': 'decimal64 not supported on qpid-cpp broker: QPIDIT-6, QPID-6328',}, + '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',}, + } - @staticmethod - def get_test_value_list(amqp_type): - """Return a list of test values to use when testing the supplied AMQP type.""" - if amqp_type not in AmqpPrimitiveTypes.TYPE_MAP.keys(): - return None - return AmqpPrimitiveTypes.TYPE_MAP[amqp_type] class AmqpTypeTestCase(unittest.TestCase): @@ -221,7 +219,7 @@ class AmqpTypeTestCase(unittest.TestCase): self.fail('Type %s has no test values' % amqp_type) -def create_testcase_class(broker_addr, amqp_type, test_value_list, shim_product): +def create_testcase_class(broker_name, types, broker_addr, amqp_type, shim_product): """ Class factory function which creates new subclasses to AmqpTypeTestCase. """ @@ -233,6 +231,8 @@ def create_testcase_class(broker_addr, amqp_type, test_value_list, shim_product) 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) @@ -247,7 +247,7 @@ def create_testcase_class(broker_addr, amqp_type, test_value_list, shim_product) '__doc__': 'Test case for AMQP 1.0 simple type \'%s\'' % amqp_type, 'amqp_type': amqp_type, 'broker_addr': broker_addr, - 'test_value_list': test_value_list} + '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) @@ -395,7 +395,17 @@ class TestOptions(object): if __name__ == '__main__': ARGS = TestOptions().args - #print 'ARGS:', ARGS + #print 'ARGS:', ARGS # debug + + # Connect to broker to find broker type + CONNECTION_PROPS = broker_properties.getBrokerProperties(ARGS.broker) + print 'Test Broker: %s v.%s on %s' % (CONNECTION_PROPS[symbol(u'product')], + CONNECTION_PROPS[symbol(u'version')], + CONNECTION_PROPS[symbol(u'platform')]) + print + BROKER = CONNECTION_PROPS[symbol(u'product')] + + 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. @@ -410,11 +420,12 @@ if __name__ == '__main__': for shim in ARGS.exclude_shim: SHIM_MAP.pop(shim) # Create test classes dynamically - for at in sorted(AmqpPrimitiveTypes.get_type_list()): + 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(ARGS.broker, + test_case_class = create_testcase_class(BROKER, + TYPES, + ARGS.broker, at, - AmqpPrimitiveTypes.get_test_value_list(at), product(SHIM_MAP.values(), repeat=2)) TEST_CASE_CLASSES.append(test_case_class) TEST_SUITE.addTest(unittest.makeSuite(test_case_class)) --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
