PROTON-1885: [python] move tests/python to python/tests

Consistent with other bindings


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/9778eda8
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/9778eda8
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/9778eda8

Branch: refs/heads/master
Commit: 9778eda8e9387caa8a207fbb6fedfa09ac0e298a
Parents: b41f60d
Author: Alan Conway <acon...@redhat.com>
Authored: Wed Jul 4 14:52:06 2018 -0400
Committer: Alan Conway <acon...@redhat.com>
Committed: Fri Jul 6 12:20:32 2018 -0400

----------------------------------------------------------------------
 CMakeLists.txt                                  |   64 -
 misc/config.sh.in                               |    4 +-
 misc/tox.ini.in                                 |   26 -
 python/CMakeLists.txt                           |   59 +
 python/tests/interop-generate                   |  150 +
 python/tests/proton-test                        |  711 +++++
 python/tests/proton_tests/__init__.py           |   31 +
 python/tests/proton_tests/codec.py              |  401 +++
 python/tests/proton_tests/common.py             |  510 ++++
 python/tests/proton_tests/engine.py             | 2714 ++++++++++++++++++
 python/tests/proton_tests/handler.py            |  123 +
 python/tests/proton_tests/interop.py            |  147 +
 python/tests/proton_tests/message.py            |  275 ++
 python/tests/proton_tests/reactor.py            |  485 ++++
 python/tests/proton_tests/sasl.py               |  587 ++++
 python/tests/proton_tests/soak.py               |  334 +++
 python/tests/proton_tests/ssl.py                |  936 ++++++
 python/tests/proton_tests/ssl_db/README.txt     |   79 +
 .../ssl_db/bad-server-certificate.p12           |  Bin 0 -> 1490 bytes
 .../ssl_db/bad-server-certificate.pem           |   22 +
 .../ssl_db/bad-server-private-key.pem           |   15 +
 .../tests/proton_tests/ssl_db/bad-server.pkcs12 |  Bin 0 -> 1524 bytes
 .../proton_tests/ssl_db/ca-certificate.p12      |  Bin 0 -> 992 bytes
 .../proton_tests/ssl_db/ca-certificate.pem      |   24 +
 python/tests/proton_tests/ssl_db/ca.pkcs12      |  Bin 0 -> 1572 bytes
 .../proton_tests/ssl_db/client-certificate.p12  |  Bin 0 -> 1546 bytes
 .../proton_tests/ssl_db/client-certificate.pem  |   18 +
 .../proton_tests/ssl_db/client-certificate1.p12 |  Bin 0 -> 1604 bytes
 .../proton_tests/ssl_db/client-certificate1.pem |   19 +
 .../proton_tests/ssl_db/client-private-key.pem  |   15 +
 .../proton_tests/ssl_db/client-private-key1.pem |   15 +
 .../proton_tests/ssl_db/client-request.pem      |   15 +
 .../proton_tests/ssl_db/client-request1.pem     |   16 +
 python/tests/proton_tests/ssl_db/client.pkcs12  |  Bin 0 -> 1532 bytes
 python/tests/proton_tests/ssl_db/client1.pkcs12 |  Bin 0 -> 1646 bytes
 .../proton_tests/ssl_db/server-certificate.p12  |  Bin 0 -> 1562 bytes
 .../proton_tests/ssl_db/server-certificate.pem  |   18 +
 .../proton_tests/ssl_db/server-private-key.pem  |   15 +
 .../proton_tests/ssl_db/server-request.pem      |   15 +
 .../ssl_db/server-wc-certificate.p12            |  Bin 0 -> 1624 bytes
 .../ssl_db/server-wc-certificate.pem            |   19 +
 .../ssl_db/server-wc-private-key.pem            |   15 +
 .../proton_tests/ssl_db/server-wc-request.pem   |   16 +
 .../tests/proton_tests/ssl_db/server-wc.pkcs12  |  Bin 0 -> 1626 bytes
 python/tests/proton_tests/ssl_db/server.pkcs12  |  Bin 0 -> 1572 bytes
 python/tests/proton_tests/transport.py          |  393 +++
 python/tests/proton_tests/url.py                |  147 +
 python/tests/proton_tests/utils.py              |  163 ++
 python/tests/tox-blacklist                      |   12 +
 python/tox.ini.in                               |   26 +
 scripts/jenkins-proton-c-build.sh               |    2 +-
 tests/python/interop-generate                   |  150 -
 tests/python/proton-test                        |  711 -----
 tests/python/proton_tests/__init__.py           |   31 -
 tests/python/proton_tests/codec.py              |  401 ---
 tests/python/proton_tests/common.py             |  510 ----
 tests/python/proton_tests/engine.py             | 2714 ------------------
 tests/python/proton_tests/handler.py            |  123 -
 tests/python/proton_tests/interop.py            |  147 -
 tests/python/proton_tests/message.py            |  275 --
 tests/python/proton_tests/reactor.py            |  485 ----
 tests/python/proton_tests/sasl.py               |  587 ----
 tests/python/proton_tests/soak.py               |  334 ---
 tests/python/proton_tests/ssl.py                |  936 ------
 tests/python/proton_tests/ssl_db/README.txt     |   79 -
 .../ssl_db/bad-server-certificate.p12           |  Bin 1490 -> 0 bytes
 .../ssl_db/bad-server-certificate.pem           |   22 -
 .../ssl_db/bad-server-private-key.pem           |   15 -
 .../proton_tests/ssl_db/bad-server.pkcs12       |  Bin 1524 -> 0 bytes
 .../proton_tests/ssl_db/ca-certificate.p12      |  Bin 992 -> 0 bytes
 .../proton_tests/ssl_db/ca-certificate.pem      |   24 -
 tests/python/proton_tests/ssl_db/ca.pkcs12      |  Bin 1572 -> 0 bytes
 .../proton_tests/ssl_db/client-certificate.p12  |  Bin 1546 -> 0 bytes
 .../proton_tests/ssl_db/client-certificate.pem  |   18 -
 .../proton_tests/ssl_db/client-certificate1.p12 |  Bin 1604 -> 0 bytes
 .../proton_tests/ssl_db/client-certificate1.pem |   19 -
 .../proton_tests/ssl_db/client-private-key.pem  |   15 -
 .../proton_tests/ssl_db/client-private-key1.pem |   15 -
 .../proton_tests/ssl_db/client-request.pem      |   15 -
 .../proton_tests/ssl_db/client-request1.pem     |   16 -
 tests/python/proton_tests/ssl_db/client.pkcs12  |  Bin 1532 -> 0 bytes
 tests/python/proton_tests/ssl_db/client1.pkcs12 |  Bin 1646 -> 0 bytes
 .../proton_tests/ssl_db/server-certificate.p12  |  Bin 1562 -> 0 bytes
 .../proton_tests/ssl_db/server-certificate.pem  |   18 -
 .../proton_tests/ssl_db/server-private-key.pem  |   15 -
 .../proton_tests/ssl_db/server-request.pem      |   15 -
 .../ssl_db/server-wc-certificate.p12            |  Bin 1624 -> 0 bytes
 .../ssl_db/server-wc-certificate.pem            |   19 -
 .../ssl_db/server-wc-private-key.pem            |   15 -
 .../proton_tests/ssl_db/server-wc-request.pem   |   16 -
 .../python/proton_tests/ssl_db/server-wc.pkcs12 |  Bin 1626 -> 0 bytes
 tests/python/proton_tests/ssl_db/server.pkcs12  |  Bin 1572 -> 0 bytes
 tests/python/proton_tests/transport.py          |  393 ---
 tests/python/proton_tests/url.py                |  147 -
 tests/python/proton_tests/utils.py              |  163 --
 tests/python/tox-blacklist                      |   13 -
 96 files changed, 8543 insertions(+), 8549 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c2f17c9..b7ea06c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -134,9 +134,6 @@ endif()
 
 message(STATUS "PN_VERSION: ${PN_VERSION} (${PN_VERSION_QUALIFIER})")
 
-set (pn_test_root "${CMAKE_CURRENT_SOURCE_DIR}/tests")
-set (pn_test_bin "${CMAKE_CURRENT_BINARY_DIR}/tests")
-
 # In rpm builds the build sets some variables:
 #  CMAKE_INSTALL_PREFIX - this is a standard cmake variable
 #  INCLUDE_INSTALL_DIR
@@ -343,67 +340,6 @@ endforeach(BINDING)
 
 unset(BUILD_BINDINGS CACHE) # Remove from cache, only relevant when creating 
the initial cache.
 
-# python test: tests/python/proton-test
-if (BUILD_PYTHON)
-  set (py_root "${pn_test_root}/python")
-  set (py_src "${CMAKE_CURRENT_SOURCE_DIR}/python")
-  set (py_bin "${CMAKE_CURRENT_BINARY_DIR}/python")
-  set (py_dll "$<TARGET_FILE_DIR:_cproton>")
-  set (py_bld "$<TARGET_FILE_DIR:qpid-proton>") # For windows
-  set (app_path $<TARGET_FILE_DIR:msgr-send> 
"${pn_test_root}/tools/apps/python")
-  set (py_path ${py_bld} ${app_path} $ENV{PATH})
-  set (py_pythonpath ${py_root} ${py_src} ${py_bin} ${py_dll} $ENV{PYTHONPATH})
-  to_native_path ("${py_pythonpath}" py_pythonpath)
-  to_native_path ("${py_path}" py_path)
-
-  if (CMAKE_BUILD_TYPE MATCHES "Coverage")
-    set (python_coverage_options -m coverage run)
-  endif(CMAKE_BUILD_TYPE MATCHES "Coverage")
-
-  add_test (NAME python-test
-            COMMAND ${PN_ENV_SCRIPT}
-              "PATH=${py_path}" "PYTHONPATH=${py_pythonpath}"
-              "SASLPASSWD=${CyrusSASL_Saslpasswd_EXECUTABLE}"
-              ${VALGRIND_ENV}
-              ${PYTHON_EXECUTABLE} -- ${python_coverage_options} 
"${py_root}/proton-test")
-  set_tests_properties(python-test PROPERTIES PASS_REGULAR_EXPRESSION "Totals: 
.* 0 failed")
-
-  check_python_module("tox" TOX_MODULE_FOUND)
-  if (NOT TOX_MODULE_FOUND)
-    message(STATUS "The tox tool is not available; skipping the 
python-tox-tests")
-  else ()
-    option(ENABLE_TOX_TEST "Enable multi-version python testing with TOX" ON)
-
-    set(tox_default "py26,py27,py34,py35,py36")
-    set(TOX_ENVLIST ${tox_default} CACHE STRING "List of python environments 
for TOX tests" )
-    mark_as_advanced(TOX_ENVLIST)
-
-    if (NOT (TOX_ENVLIST STREQUAL tox_default))
-      message(WARNING "non-default TOX test set '${TOX_ENVLIST}' (default 
'${tox_default}')")
-    endif()
-    if (ENABLE_TOX_TEST)
-      if (CMAKE_BUILD_TYPE MATCHES "Coverage")
-        message(STATUS "Building for coverage analysis; skipping the 
python-tox-tests")
-      else ()
-        configure_file(
-          "${CMAKE_CURRENT_SOURCE_DIR}/misc/tox.ini.in"
-          "${CMAKE_CURRENT_BINARY_DIR}/tox.ini")
-        add_test (NAME python-tox-test
-                  COMMAND ${PN_ENV_SCRIPT}
-                  "PATH=${py_path}"
-                  "SASLPASSWD=${CyrusSASL_Saslpasswd_EXECUTABLE}"
-                  "SWIG=${SWIG_EXECUTABLE}"
-                  ${VALGRIND_ENV} --
-                  ${PYTHON_EXECUTABLE} -m tox)
-        set_tests_properties(python-tox-test
-                             PROPERTIES
-                               PASS_REGULAR_EXPRESSION "Totals: .* ignored, 0 
failed"
-                               FAIL_REGULAR_EXPRESSION "ERROR:[ ]+py[0-9]*: 
commands failed")
-      endif ()
-    endif (ENABLE_TOX_TEST)
-  endif (NOT TOX_MODULE_FOUND)
-endif (BUILD_PYTHON)
-
 install (FILES LICENSE.txt README.md
          DESTINATION ${PROTON_SHARE})
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/misc/config.sh.in
----------------------------------------------------------------------
diff --git a/misc/config.sh.in b/misc/config.sh.in
old mode 100644
new mode 100755
index 8b3475f..a61c757
--- a/misc/config.sh.in
+++ b/misc/config.sh.in
@@ -34,7 +34,7 @@ PROTON_BUILD=@CMAKE_BINARY_DIR@
 PYTHON_BINDING=$PROTON_BUILD/python
 
 # Python
-COMMON_PYPATH=$PROTON_HOME/tests/python:$PROTON_HOME/python:$PROTON_HOME/tools/python
+COMMON_PYPATH=$PROTON_HOME/python/tests:$PROTON_HOME/python:$PROTON_HOME/tools/python
 export PYTHONPATH=$COMMON_PYPATH:$PYTHON_BINDING
 
 # Ruby
@@ -50,7 +50,7 @@ export LIBRARY_PATH="$(merge_paths $PROTON_BUILD 
$LIBRARY_PATH)"
 export LD_LIBRARY_PATH="$(merge_paths $PROTON_BUILD $LD_LIBRARY_PATH)"
 
 # Test applications
-export PATH="$(merge_paths $PATH $PROTON_BUILD/c/tools 
$PROTON_HOME/tests/python)"
+export PATH="$(merge_paths $PATH $PROTON_BUILD/c/tools 
$PROTON_HOME/python/tests)"
 
 # Can the test harness use valgrind?
 if [[ -x "$(type -p valgrind)" && "@ENABLE_VALGRIND@" == "ON" ]] ; then

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/misc/tox.ini.in
----------------------------------------------------------------------
diff --git a/misc/tox.ini.in b/misc/tox.ini.in
deleted file mode 100644
index 1000282..0000000
--- a/misc/tox.ini.in
+++ /dev/null
@@ -1,26 +0,0 @@
-[tox]
-envlist = @TOX_ENVLIST@
-minversion = 1.4
-skipdist = True
-setupdir = @py_bin@/dist
-
-[testenv]
-usedevelop = False
-setenv =
-    VIRTUAL_ENV={envdir}
-    DEBUG=True
-passenv =
-    PKG_CONFIG_PATH
-    CFLAGS
-    SASLPASSWD
-    VALGRIND
-commands =
-    @CMAKE_SOURCE_DIR@/tests/python/proton-test 
'{posargs:--ignore-file=@CMAKE_SOURCE_DIR@/tests/python/tox-blacklist}'
-deps =
-    unittest2
-
-[testenv:pep8]
-commands = flake8
-
-[testenv:docs]
-commands = python setup.py build_sphinx

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
index 037552e..31fcfba 100644
--- a/python/CMakeLists.txt
+++ b/python/CMakeLists.txt
@@ -184,3 +184,62 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/README.rst.in
                ${py_dist_dir}/README.rst
 )
+
+# python test: python/tests/proton-test
+set (py_src "${CMAKE_CURRENT_SOURCE_DIR}")
+set (py_bin "${CMAKE_CURRENT_BINARY_DIR}")
+set (py_dll "$<TARGET_FILE_DIR:_cproton>")
+set (py_bld "$<TARGET_FILE_DIR:qpid-proton>") # For windows
+set (py_tests "${py_src}/tests")
+
+set (py_path ${CMAKE_BINARY_DIR}/c/tools ${py_bld} $ENV{PATH})
+set (py_pythonpath ${py_tests} ${py_src} ${py_bin} ${py_dll} $ENV{PYTHONPATH})
+to_native_path ("${py_pythonpath}" py_pythonpath)
+to_native_path ("${py_path}" py_path)
+
+if (CMAKE_BUILD_TYPE MATCHES "Coverage")
+  set (python_coverage_options -m coverage run)
+endif(CMAKE_BUILD_TYPE MATCHES "Coverage")
+
+add_test (NAME python-test
+  COMMAND ${PN_ENV_SCRIPT}
+  "PATH=${py_path}" "PYTHONPATH=${py_pythonpath}"
+  "SASLPASSWD=${CyrusSASL_Saslpasswd_EXECUTABLE}"
+  ${VALGRIND_ENV}
+  ${PYTHON_EXECUTABLE} -- ${python_coverage_options} "${py_tests}/proton-test")
+set_tests_properties(python-test PROPERTIES PASS_REGULAR_EXPRESSION "Totals: 
.* 0 failed")
+
+check_python_module("tox" TOX_MODULE_FOUND)
+if (NOT TOX_MODULE_FOUND)
+  message(STATUS "The tox tool is not available; skipping the 
python-tox-tests")
+else ()
+  option(ENABLE_TOX_TEST "Enable multi-version python testing with TOX" ON)
+
+  set(tox_default "py26,py27,py34,py35,py36")
+  set(TOX_ENVLIST ${tox_default} CACHE STRING "List of python environments for 
TOX tests" )
+  mark_as_advanced(TOX_ENVLIST)
+
+  if (NOT (TOX_ENVLIST STREQUAL tox_default))
+    message(WARNING "non-default TOX test set '${TOX_ENVLIST}' (default 
'${tox_default}')")
+  endif()
+  if (ENABLE_TOX_TEST)
+    if (CMAKE_BUILD_TYPE MATCHES "Coverage")
+      message(STATUS "Building for coverage analysis; skipping the 
python-tox-tests")
+    else ()
+      configure_file(
+        "${CMAKE_CURRENT_SOURCE_DIR}/tox.ini.in"
+        "${CMAKE_CURRENT_BINARY_DIR}/tox.ini")
+      add_test (NAME python-tox-test
+        COMMAND ${PN_ENV_SCRIPT}
+        "PATH=${py_path}"
+        "SASLPASSWD=${CyrusSASL_Saslpasswd_EXECUTABLE}"
+        "SWIG=${SWIG_EXECUTABLE}"
+        ${VALGRIND_ENV} --
+        ${PYTHON_EXECUTABLE} -m tox)
+      set_tests_properties(python-tox-test
+        PROPERTIES
+        PASS_REGULAR_EXPRESSION "Totals: .* ignored, 0 failed"
+        FAIL_REGULAR_EXPRESSION "ERROR:[ ]+py[0-9]*: commands failed")
+    endif ()
+  endif (ENABLE_TOX_TEST)
+endif (NOT TOX_MODULE_FOUND)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/interop-generate
----------------------------------------------------------------------
diff --git a/python/tests/interop-generate b/python/tests/interop-generate
new file mode 100755
index 0000000..9c360a6
--- /dev/null
+++ b/python/tests/interop-generate
@@ -0,0 +1,150 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+
+# Generate encoded  AMQP fragments for interop testing.
+
+import logging, optparse, os, struct, sys, time, traceback, types, cgi
+from proton import *
+
+def main(argv):
+
+    def write(data, filename):
+        f = open(filename+".amqp", 'w')
+        f.write(data.encode())
+        f.close()
+
+    # message
+    m = Message()
+    d = Data()
+    d.put_string("hello")
+    m.body = d.encode()
+    write(m, "message")
+
+    # null
+    d = Data()
+    d.put_null()
+    write(d, "null")
+
+    # primitive types
+    d = Data()
+    d.put_bool(True)
+    d.put_bool(False)
+    d.put_ubyte(42)
+    d.put_ushort(42)
+    d.put_short(-42)
+    d.put_uint(12345)
+    d.put_int(-12345)
+    d.put_ulong(12345)
+    d.put_long(-12345)
+    d.put_float(0.125)
+    d.put_double(0.125)
+    write(d, "primitives")
+
+    # string types
+    d = Data()
+    d.put_binary("abc\0defg")
+    d.put_string("abcdefg")
+    d.put_symbol("abcdefg")
+    d.put_binary("")
+    d.put_string("")
+    d.put_symbol("")
+    write(d, "strings")
+
+    # described types
+    d = Data()
+    d.put_described()
+    d.enter()
+    d.put_symbol("foo-descriptor")
+    d.put_string("foo-value")
+    d.exit()
+
+    d.put_described()
+    d.enter()
+    d.put_int(12)
+    d.put_int(13)
+    d.exit()
+
+    write(d, "described")
+
+    # described array
+    d = Data()
+    d.put_array(True, Data.INT)
+    d.enter()
+    d.put_symbol("int-array")
+    for i in xrange(0,10): d.put_int(i)
+    d.exit()
+    write(d, "described_array")
+
+
+    # Arrays
+
+    # Integer array
+    d = Data()
+    d.put_array(False, Data.INT)
+    d.enter()
+    for i in xrange(0,100): d.put_int(i)
+    d.exit()
+
+    # String array
+    d.put_array(False, Data.STRING)
+    d.enter()
+    for i in ["a", "b", "c"]: d.put_string(i)
+    d.exit()
+
+    # empty array
+    d.put_array(False, Data.INT)
+
+    write(d, "arrays")
+
+    # List - mixed types
+    d = Data()
+    d.put_list()
+    d.enter()
+    d.put_int(32)
+    d.put_string("foo")
+    d.put_bool(True)
+    d.exit()
+
+    d.put_list()                # Empty list
+    write(d, "lists")
+
+    # Maps
+    d = Data()
+    d.put_map()
+    d.enter()
+    for k,v in {"one":1, "two":2, "three":3}.items():
+        d.put_string(k)
+        d.put_int(v)
+    d.exit()
+
+    d.put_map()
+    d.enter()
+    for k,v in {1:"one", 2:"two", 3:"three"}.items():
+        d.put_int(k)
+        d.put_string(v)
+    d.exit()
+
+    d.put_map()                 # Empty map
+    write(d, "maps")
+
+    return 0
+
+if __name__ == "__main__":
+    sys.exit(main(sys.argv))

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton-test
----------------------------------------------------------------------
diff --git a/python/tests/proton-test b/python/tests/proton-test
new file mode 100755
index 0000000..6280556
--- /dev/null
+++ b/python/tests/proton-test
@@ -0,0 +1,711 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+
+# TODO: summarize, test harness preconditions (e.g. broker is alive)
+
+import logging, optparse, os, struct, sys, time, traceback, types, cgi
+from fnmatch import fnmatchcase as match
+from getopt import GetoptError
+from logging import getLogger, StreamHandler, Formatter, Filter, \
+    WARN, DEBUG, ERROR
+import unittest
+from proton_tests.common import SkipTest
+
+if sys.version_info[0] == 3:
+    CLASS_TYPES = (type,)
+else:
+    CLASS_TYPES = (type, types.ClassType)
+
+levels = {
+  "DEBUG": DEBUG,
+  "WARN": WARN,
+  "ERROR": ERROR
+  }
+
+sorted_levels = [(v, k) for k, v in list(levels.items())]
+sorted_levels.sort()
+sorted_levels = [v for k, v in sorted_levels]
+
+parser = optparse.OptionParser(usage="usage: %prog [options] PATTERN ...",
+                               description="Run tests matching the specified 
PATTERNs.")
+parser.add_option("-l", "--list", action="store_true", default=False,
+                  help="list tests instead of executing them")
+parser.add_option("-f", "--log-file", metavar="FILE", help="log output to 
FILE")
+parser.add_option("-v", "--log-level", metavar="LEVEL", default="WARN",
+                  help="only display log messages of LEVEL or higher severity: 
"
+                  "%s (default %%default)" % ", ".join(sorted_levels))
+parser.add_option("-c", "--log-category", metavar="CATEGORY", action="append",
+                  dest="log_categories", default=[],
+                  help="log only categories matching CATEGORY pattern")
+parser.add_option("-m", "--module", action="append", default=[],
+                  dest="modules", help="add module to test search path")
+parser.add_option("-i", "--ignore", action="append", default=[],
+                  help="ignore tests matching IGNORE pattern")
+parser.add_option("-I", "--ignore-file", metavar="IFILE", action="append",
+                  default=[],
+                  help="ignore tests matching patterns in IFILE")
+parser.add_option("-H", "--halt-on-error", action="store_true", default=False,
+                  dest="hoe", help="halt if an error is encountered")
+parser.add_option("-t", "--time", action="store_true", default=False,
+                  help="report timing information on test run")
+parser.add_option("-D", "--define", metavar="DEFINE", dest="defines",
+                  action="append", default=[], help="define test parameters")
+parser.add_option("-x", "--xml", metavar="XML", dest="xml",
+                  help="write test results in Junit style xml suitable for use 
by CI tools etc")
+parser.add_option("-a", "--always-colorize", action="store_true", 
dest="always_colorize", default=False,
+                  help="always colorize the test results rather than relying 
on terminal tty detection. Useful when invoked from Jython/Maven.")
+parser.add_option("-n", metavar="count", dest="count", type=int, default=1,
+                  help="run the tests <count> times")
+parser.add_option("-b", "--bare", action="store_true", default=False,
+                  help="Run bare, i.e. don't capture stack traces. This is 
useful under Jython as " +
+                  "captured stack traces do not include the Java portion of 
the stack," +
+                  "whereas non captured stack traces do.")
+parser.add_option("-j", "--javatrace", action="store_true", default=False,
+                  help="Show the full java stack trace. This disables 
heuristics to eliminate the " +
+                  "jython portion of java stack traces.")
+
+class Config:
+
+  def __init__(self):
+    self.defines = {}
+    self.log_file = None
+    self.log_level = WARN
+    self.log_categories = []
+
+opts, args = parser.parse_args()
+
+# Known bad tests, skipped unless specifically matched on the command line
+known_bad = ["proton_tests.messenger.*"]
+
+includes = []
+excludes = ["*__*__"]
+config = Config()
+list_only = opts.list
+for d in opts.defines:
+  try:
+    idx = d.index("=")
+    name = d[:idx]
+    value = d[idx+1:]
+    config.defines[name] = value
+  except ValueError:
+    config.defines[d] = None
+config.log_file = opts.log_file
+config.log_level = levels[opts.log_level.upper()]
+config.log_categories = opts.log_categories
+excludes.extend([v.strip() for v in opts.ignore])
+for v in opts.ignore_file:
+  f = open(v)
+  for line in f:
+    line = line.strip()
+    if line.startswith("#"):
+      continue
+    excludes.append(line)
+  f.close()
+
+for a in args:
+  includes.append(a.strip())
+
+def is_ignored(path):
+  for p in excludes:
+    if match(path, p):
+      return True
+  return False
+
+def is_included(path):
+  if is_ignored(path):
+    return False
+  for p in includes:
+    if match(path, p):
+      return True
+  for p in known_bad:
+    if match(path, p):
+      return False
+  return not includes           # If includes is empty, include everything
+
+def is_smart():
+  return sys.stdout.isatty() and os.environ.get("TERM", "dumb") != "dumb"
+
+try:
+  import fcntl, termios
+
+  def width():
+    if is_smart():
+      s = struct.pack("HHHH", 0, 0, 0, 0)
+      fd_stdout = sys.stdout.fileno()
+      x = fcntl.ioctl(fd_stdout, termios.TIOCGWINSZ, s)
+      rows, cols, xpx, ypx = struct.unpack("HHHH", x)
+      return cols
+    else:
+      try:
+        return int(os.environ.get("COLUMNS", "80"))
+      except ValueError:
+        return 80
+
+  WIDTH = width()
+
+  def resize(sig, frm):
+    global WIDTH
+    WIDTH = width()
+
+  import signal
+  signal.signal(signal.SIGWINCH, resize)
+
+except ImportError:
+  WIDTH = 80
+
+def vt100_attrs(*attrs):
+  return "\x1B[%sm" % ";".join(map(str, attrs))
+
+vt100_reset = vt100_attrs(0)
+
+KEYWORDS = {"pass": (32,),
+            "skip": (33,),
+            "fail": (31,),
+            "start": (34,),
+            "total": (34,),
+            "ignored": (33,),
+            "selected": (34,),
+            "elapsed": (34,),
+            "average": (34,)}
+
+def colorize_word(word, text=None):
+  if text is None:
+    text = word
+  return colorize(text, *KEYWORDS.get(word, ()))
+
+def colorize(text, *attrs):
+  if attrs and (is_smart() or opts.always_colorize):
+    return "%s%s%s" % (vt100_attrs(*attrs), text, vt100_reset)
+  else:
+    return text
+
+def indent(text):
+  lines = text.split("\n")
+  return "  %s" % "\n  ".join(lines)
+
+# Write a 'minimal' Junit xml style report file suitable for use by CI tools 
such as Jenkins.
+class JunitXmlStyleReporter:
+
+  def __init__(self, file):
+    self.f = open(file, "w");
+
+  def begin(self):
+    self.f.write('<?xml version="1.0" encoding="UTF-8" ?>\n')
+    self.f.write('<testsuite name="pythontests">\n')
+
+  def report(self, name, result):
+    parts = name.split(".")
+    method = parts[-1]
+    module = '.'.join(parts[0:-1])
+    self.f.write('<testcase classname="%s" name="%s" time="%f">\n' % (module, 
method, result.time))
+    if result.failed:
+      escaped_type = cgi.escape(str(result.exception_type))
+      escaped_message = cgi.escape(str(result.exception_message))
+      self.f.write('<failure type="%s" message="%s">\n' % (escaped_type, 
escaped_message))
+      self.f.write('<![CDATA[\n')
+      self.f.write(result.formatted_exception_trace)
+      self.f.write(']]>\n')
+      self.f.write('</failure>\n')
+    if result.skipped:
+      self.f.write('<skipped/>\n')
+    self.f.write('</testcase>\n')
+
+  def end(self):
+      self.f.write('</testsuite>\n')
+      self.f.close()
+
+class Interceptor:
+
+  def __init__(self):
+    self.newline = False
+    self.indent = False
+    self.passthrough = True
+    self.dirty = False
+    self.last = None
+
+  def begin(self):
+    self.newline = True
+    self.indent = True
+    self.passthrough = False
+    self.dirty = False
+    self.last = None
+
+  def reset(self):
+    self.newline = False
+    self.indent = False
+    self.passthrough = True
+
+class StreamWrapper:
+
+  def __init__(self, interceptor, stream, prefix="  "):
+    self.interceptor = interceptor
+    self.stream = stream
+    self.prefix = prefix
+
+  def fileno(self):
+    return self.stream.fileno()
+
+  def isatty(self):
+    return self.stream.isatty()
+
+  def write(self, s):
+    if self.interceptor.passthrough:
+      self.stream.write(s)
+      return
+
+    if s:
+      self.interceptor.dirty = True
+
+    if self.interceptor.newline:
+      self.interceptor.newline = False
+      self.stream.write(" %s\n" % colorize_word("start"))
+      self.interceptor.indent = True
+    if self.interceptor.indent:
+      self.stream.write(self.prefix)
+    if s.endswith("\n"):
+      s = s.replace("\n", "\n%s" % self.prefix)[:-2]
+      self.interceptor.indent = True
+    else:
+      s = s.replace("\n", "\n%s" % self.prefix)
+      self.interceptor.indent = False
+    self.stream.write(s)
+
+    if s:
+      self.interceptor.last = s[-1]
+
+  def flush(self):
+    self.stream.flush()
+
+interceptor = Interceptor()
+
+out_wrp = StreamWrapper(interceptor, sys.stdout)
+err_wrp = StreamWrapper(interceptor, sys.stderr)
+
+out = sys.stdout
+err = sys.stderr
+sys.stdout = out_wrp
+sys.stderr = err_wrp
+
+class PatternFilter(Filter):
+
+  def __init__(self, *patterns):
+    Filter.__init__(self, patterns)
+    self.patterns = patterns
+
+  def filter(self, record):
+    if not self.patterns:
+      return True
+    for p in self.patterns:
+      if match(record.name, p):
+        return True
+    return False
+
+root = getLogger()
+handler = StreamHandler(sys.stdout)
+filter = PatternFilter(*config.log_categories)
+handler.addFilter(filter)
+handler.setFormatter(Formatter("%(asctime)s %(levelname)s %(message)s"))
+root.addHandler(handler)
+root.setLevel(WARN)
+
+log = getLogger("proton.test")
+
+PASS = "pass"
+SKIP = "skip"
+FAIL = "fail"
+
+class Runner:
+
+  def __init__(self):
+    self.exception = None
+    self.exception_phase_name = None
+    self.skip = False
+
+  def passed(self):
+    return not self.exception
+
+  def skipped(self):
+    return self.skip
+
+  def failed(self):
+    return self.exception and not self.skip
+
+  def halt(self):
+    """determines if the overall test execution should be allowed to continue 
to the next phase"""
+    return self.exception or self.skip
+
+  def run(self, phase_name, phase):
+    """invokes a test-phase method (which can be the test method itself or a 
setUp/tearDown
+       method).  If the method raises an exception the exception is examined 
to see if the
+       exception should be classified as a 'skipped' test"""
+    # we don't try to catch exceptions for jython because currently a
+    # jython bug will prevent the java portion of the stack being
+    # stored with the exception info in the sys module
+    if opts.bare:
+      phase()
+    else:
+      try:
+        phase()
+      except KeyboardInterrupt:
+        raise
+      except:
+        self.exception_phase_name = phase_name
+        self.exception = sys.exc_info()
+        exception_type = self.exception[0]
+        self.skip = getattr(exception_type, "skipped", False) or 
issubclass(exception_type, SkipTest)
+
+  def status(self):
+    if self.passed():
+      return PASS
+    elif self.skipped():
+      return SKIP
+    elif self.failed():
+      return FAIL
+    else:
+      return None
+
+  def get_formatted_exception_trace(self):
+    if self.exception:
+      if self.skip:
+        # format skipped tests without a traceback
+        output = 
indent("".join(traceback.format_exception_only(*self.exception[:2]))).rstrip()
+      else:
+        output = "Error during %s:" % self.exception_phase_name
+        lines = traceback.format_exception(*self.exception)
+        val = self.exception[1]
+        reflect = False
+        if val and hasattr(val, "getStackTrace"):
+          jlines = []
+          for frame in val.getStackTrace():
+            if reflect and frame.getClassName().startswith("org.python."):
+              # this is a heuristic to eliminate the jython portion of
+              # the java stack trace
+              if not opts.javatrace:
+                break
+            jlines.append("  %s\n" % frame.toString())
+            if frame.getClassName().startswith("java.lang.reflect"):
+              reflect = True
+            else:
+              reflect = False
+          lines.extend(jlines)
+        output += indent("".join(lines)).rstrip()
+      return output
+
+  def get_exception_type(self):
+    if self.exception:
+      return self.exception[0]
+    else:
+      return None
+
+  def get_exception_message(self):
+    if self.exception:
+      return self.exception[1]
+    else:
+      return None
+
+ST_WIDTH = 8
+
+def run_test(name, test, config):
+  patterns = filter.patterns
+  level = root.level
+  filter.patterns = config.log_categories
+  root.setLevel(config.log_level)
+
+  parts = name.split(".")
+  line = None
+  output = ""
+  for part in parts:
+    if line:
+      if len(line) + len(part) >= (WIDTH - ST_WIDTH - 1):
+        output += "%s. \\\n" % line
+        line = "    %s" % part
+      else:
+        line = "%s.%s" % (line, part)
+    else:
+      line = part
+
+  if line:
+    output += "%s %s" % (line, (((WIDTH - ST_WIDTH) - len(line))*"."))
+  sys.stdout.write(output)
+  sys.stdout.flush()
+  interceptor.begin()
+  start = time.time()
+  try:
+    runner = test()
+  finally:
+    interceptor.reset()
+  end = time.time()
+  if interceptor.dirty:
+    if interceptor.last != "\n":
+      sys.stdout.write("\n")
+    sys.stdout.write(output)
+  print(" %s" % colorize_word(runner.status()))
+  if runner.failed() or runner.skipped():
+    print(runner.get_formatted_exception_trace())
+  root.setLevel(level)
+  filter.patterns = patterns
+  return TestResult(end - start,
+                    runner.passed(),
+                    runner.skipped(),
+                    runner.failed(),
+                    runner.get_exception_type(),
+                    runner.get_exception_message(),
+                    runner.get_formatted_exception_trace())
+
+class TestResult:
+
+  def __init__(self, time, passed, skipped, failed, exception_type, 
exception_message, formatted_exception_trace):
+    self.time = time
+    self.passed = passed
+    self.skipped = skipped
+    self.failed = failed
+    self.exception_type =  exception_type
+    self.exception_message = exception_message
+    self.formatted_exception_trace = formatted_exception_trace
+
+class FunctionTest:
+
+  def __init__(self, test):
+    self.test = test
+
+  def name(self):
+    return "%s.%s" % (self.test.__module__, self.test.__name__)
+
+  def run(self):
+    return run_test(self.name(), self._run, config)
+
+  def _run(self):
+    runner = Runner()
+    runner.run("test", lambda: self.test(config))
+    return runner
+
+  def __repr__(self):
+    return "FunctionTest(%r)" % self.test
+
+class MethodTest:
+
+  def __init__(self, cls, method):
+    self.cls = cls
+    self.method = method
+
+  def name(self):
+    return "%s.%s.%s" % (self.cls.__module__, self.cls.__name__, self.method)
+
+  def run(self):
+    return run_test(self.name(), self._run, config)
+
+  def _run(self):
+    runner = Runner()
+    inst = self.cls(self.method)
+    test = getattr(inst, self.method)
+
+    if hasattr(inst, "configure"):
+      runner.run("configure", lambda: inst.configure(config))
+      if runner.halt(): return runner
+    if hasattr(inst, "setUp"):
+      runner.run("setup", inst.setUp)
+      if runner.halt(): return runner
+
+    runner.run("test", test)
+
+    if hasattr(inst, "tearDown"):
+      runner.run("teardown", inst.tearDown)
+
+    return runner
+
+  def __repr__(self):
+    return "MethodTest(%r, %r)" % (self.cls, self.method)
+
+class PatternMatcher:
+
+  def __init__(self, *patterns):
+    self.patterns = patterns
+
+  def matches(self, name):
+    for p in self.patterns:
+      if match(name, p):
+        return True
+    return False
+
+class FunctionScanner(PatternMatcher):
+
+  def inspect(self, obj):
+    return type(obj) == types.FunctionType and self.matches(obj.__name__)
+
+  def descend(self, func):
+    # the None is required for older versions of python
+    return; yield None
+
+  def extract(self, func):
+    yield FunctionTest(func)
+
+class ClassScanner(PatternMatcher):
+
+  def inspect(self, obj):
+    return type(obj) in CLASS_TYPES and self.matches(obj.__name__)
+
+  def descend(self, cls):
+    # the None is required for older versions of python
+    return; yield None
+
+  def extract(self, cls):
+    names = dir(cls)
+    names.sort()
+    for name in names:
+      obj = getattr(cls, name)
+      if hasattr(obj, '__call__') and name.startswith("test"):
+        yield MethodTest(cls, name)
+
+class ModuleScanner:
+
+  def inspect(self, obj):
+    return type(obj) == types.ModuleType
+
+  def descend(self, obj):
+    names = dir(obj)
+    names.sort()
+    for name in names:
+      yield getattr(obj, name)
+
+  def extract(self, obj):
+    # the None is required for older versions of python
+    return; yield None
+
+class Harness:
+
+  def __init__(self):
+    self.scanners = [
+      ModuleScanner(),
+      ClassScanner("*Test", "*Tests", "*TestCase"),
+      FunctionScanner("test_*")
+      ]
+    self.tests = []
+    self.scanned = []
+
+  def scan(self, *roots):
+    objects = list(roots)
+
+    while objects:
+      obj = objects.pop(0)
+      for s in self.scanners:
+        if s.inspect(obj):
+          self.tests.extend(s.extract(obj))
+          for child in s.descend(obj):
+            if not (child in self.scanned or child in objects):
+              objects.append(child)
+      self.scanned.append(obj)
+
+modules = opts.modules
+if not modules:
+  modules.extend(["proton_tests"])
+h = Harness()
+for name in modules:
+  m = __import__(name, None, None, ["dummy"])
+  h.scan(m)
+
+filtered = [t for t in h.tests if is_included(t.name())]
+ignored = [t for t in h.tests if is_ignored(t.name())]
+total = len(filtered) + len(ignored)
+
+if opts.xml and not list_only:
+   xmlr = JunitXmlStyleReporter(opts.xml);
+   xmlr.begin();
+else:
+   xmlr = None
+
+def runthrough():
+  passed = 0
+  failed = 0
+  skipped = 0
+  start = time.time()
+  for t in filtered:
+    if list_only:
+      print(t.name())
+    else:
+      st = t.run()
+      if xmlr:
+        xmlr.report(t.name(), st)
+      if st.passed:
+        passed += 1
+      elif st.skipped:
+        skipped += 1
+      elif st.failed:
+        failed += 1
+        if opts.hoe:
+          break
+  end = time.time()
+
+  run = passed + failed
+
+  if not list_only:
+    if passed:
+      _pass = "pass"
+    else:
+      _pass = "fail"
+    if failed:
+      outcome = "fail"
+    else:
+      outcome = "pass"
+    if ignored:
+      ign = "ignored"
+    else:
+      ign = "pass"
+    if skipped:
+      skip = "skip"
+    else:
+      skip = "pass"
+    sys.stdout.write(colorize("Totals: ", 1))
+    totals = [colorize_word("total", "%s tests" % total),
+              colorize_word(_pass, "%s passed" % passed),
+              colorize_word(skip, "%s skipped" % skipped),
+              colorize_word(ign, "%s ignored" % len(ignored)),
+              colorize_word(outcome, "%s failed" % failed)]
+    sys.stdout.write(", ".join(totals))
+    if opts.hoe and failed > 0:
+      print(" -- (halted after %s)" % run)
+    else:
+      print("")
+    if opts.time and run > 0:
+      sys.stdout.write(colorize("Timing:", 1))
+      timing = [colorize_word("elapsed", "%.2fs elapsed" % (end - start)),
+                colorize_word("average", "%.2fs average" % ((end - 
start)/run))]
+      print(", ".join(timing))
+
+  if xmlr:
+     xmlr.end()
+
+  return failed
+
+limit = opts.count
+count = 0
+failures = False
+while limit == 0 or count < limit:
+  count += 1
+  if runthrough():
+    failures = True
+    if count > 1:
+      print(" -- (failures after %s runthroughs)" % count)
+  else:
+    continue
+
+if failures:
+  sys.exit(1)
+else:
+  sys.exit(0)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/__init__.py
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/__init__.py 
b/python/tests/proton_tests/__init__.py
new file mode 100644
index 0000000..cc75c6c
--- /dev/null
+++ b/python/tests/proton_tests/__init__.py
@@ -0,0 +1,31 @@
+#
+# 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 proton_tests.codec
+import proton_tests.engine
+import proton_tests.message
+import proton_tests.handler
+import proton_tests.reactor
+import proton_tests.sasl
+import proton_tests.transport
+import proton_tests.ssl
+import proton_tests.interop
+import proton_tests.soak
+import proton_tests.url
+import proton_tests.utils

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/codec.py
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/codec.py 
b/python/tests/proton_tests/codec.py
new file mode 100644
index 0000000..43fe09a
--- /dev/null
+++ b/python/tests/proton_tests/codec.py
@@ -0,0 +1,401 @@
+#
+# 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 os, sys
+from . import common
+from proton import *
+from proton._compat import raise_
+from uuid import uuid4
+
+class Test(common.Test):
+
+  def setUp(self):
+    self.data = Data()
+
+  def tearDown(self):
+    self.data = None
+
+class DataTest(Test):
+
+  def testTopLevelNext(self):
+    assert self.data.next() is None
+    self.data.put_null()
+    self.data.put_bool(False)
+    self.data.put_int(0)
+    assert self.data.next() is None
+    self.data.rewind()
+    assert self.data.next() == Data.NULL
+    assert self.data.next() == Data.BOOL
+    assert self.data.next() == Data.INT
+    assert self.data.next() is None
+
+  def testNestedNext(self):
+    assert self.data.next() is None
+    self.data.put_null()
+    assert self.data.next() is None
+    self.data.put_list()
+    assert self.data.next() is None
+    self.data.put_bool(False)
+    assert self.data.next() is None
+    self.data.rewind()
+    assert self.data.next() is Data.NULL
+    assert self.data.next() is Data.LIST
+    self.data.enter()
+    assert self.data.next() is None
+    self.data.put_ubyte(0)
+    assert self.data.next() is None
+    self.data.put_uint(0)
+    assert self.data.next() is None
+    self.data.put_int(0)
+    assert self.data.next() is None
+    self.data.exit()
+    assert self.data.next() is Data.BOOL
+    assert self.data.next() is None
+
+    self.data.rewind()
+    assert self.data.next() is Data.NULL
+    assert self.data.next() is Data.LIST
+    assert self.data.enter()
+    assert self.data.next() is Data.UBYTE
+    assert self.data.next() is Data.UINT
+    assert self.data.next() is Data.INT
+    assert self.data.next() is None
+    assert self.data.exit()
+    assert self.data.next() is Data.BOOL
+    assert self.data.next() is None
+
+  def testEnterExit(self):
+    assert self.data.next() is None
+    assert not self.data.enter()
+    self.data.put_list()
+    assert self.data.enter()
+    assert self.data.next() is None
+    self.data.put_list()
+    assert self.data.enter()
+    self.data.put_list()
+    assert self.data.enter()
+    assert self.data.exit()
+    assert self.data.get_list() == 0
+    assert self.data.exit()
+    assert self.data.get_list() == 1
+    assert self.data.exit()
+    assert self.data.get_list() == 1
+    assert not self.data.exit()
+    assert self.data.get_list() == 1
+    assert self.data.next() is None
+
+    self.data.rewind()
+    assert self.data.next() is Data.LIST
+    assert self.data.get_list() == 1
+    assert self.data.enter()
+    assert self.data.next() is Data.LIST
+    assert self.data.get_list() == 1
+    assert self.data.enter()
+    assert self.data.next() is Data.LIST
+    assert self.data.get_list() == 0
+    assert self.data.enter()
+    assert self.data.next() is None
+    assert self.data.exit()
+    assert self.data.get_list() == 0
+    assert self.data.exit()
+    assert self.data.get_list() == 1
+    assert self.data.exit()
+    assert self.data.get_list() == 1
+    assert not self.data.exit()
+
+
+  def put(self, putter, v):
+    """More informative exception from putters, include bad value"""
+    try:
+      putter(v)
+    except Exception:
+      etype, value, trace = sys.exc_info()
+      raise_(etype, etype("%s(%r): %s" % (putter.__name__, v, value)), trace)
+    return putter
+
+  # (bits, signed) for each integer type
+  INT_TYPES = {
+    "byte": (8, True),
+    "ubyte": (8, False),
+    "short": (16, True),
+    "ushort": (16, False),
+    "int": (32, True),
+    "uint": (32, False),
+    "long": (64, True),
+    "ulong": (64, False)
+  }
+
+  def int_values(self, dtype):
+    """Set of test values for integer type dtype, include extreme and medial 
values"""
+    bits, signed = self.INT_TYPES[dtype]
+    values = [0, 1, 2, 5, 42]
+    if signed:
+      min, max = -2**(bits-1), 2**(bits-1)-1
+      values.append(max // 2)
+      values += [-i for i in values if i]
+      values += [min, max]
+    else:
+      max = 2**(bits) - 1
+      values += [max // 2, max]
+    return sorted(values)
+
+  def _testArray(self, dtype, descriptor, atype, *values):
+    if dtype: dTYPE = getattr(self.data, dtype.upper())
+    aTYPE = getattr(self.data, atype.upper())
+    self.data.put_array(dtype is not None, aTYPE)
+    self.data.enter()
+    if dtype is not None:
+      putter = getattr(self.data, "put_%s" % dtype)
+      self.put(putter, descriptor)
+    putter = getattr(self.data, "put_%s" % atype)
+    for v in values:
+      self.put(putter, v)
+    self.data.exit()
+    self.data.rewind()
+    assert self.data.next() == Data.ARRAY
+    count, described, type = self.data.get_array()
+    assert count == len(values), count
+    if dtype is None:
+      assert described == False
+    else:
+      assert described == True
+    assert type == aTYPE, type
+    assert self.data.enter()
+    if described:
+      assert self.data.next() == dTYPE
+      getter = getattr(self.data, "get_%s" % dtype)
+      gotten = getter()
+      assert gotten == descriptor, gotten
+    if values:
+      getter = getattr(self.data, "get_%s" % atype)
+      for v in values:
+        assert self.data.next() == aTYPE
+        gotten = getter()
+        assert gotten == v, gotten
+    assert self.data.next() is None
+    assert self.data.exit()
+
+  def testStringArray(self):
+    self._testArray(None, None, "string", "one", "two", "three")
+
+  def testDescribedStringArray(self):
+    self._testArray("symbol", "url", "string", "one", "two", "three")
+
+  def _test_int_array(self, atype):
+    self._testArray(None, None, atype, *self.int_values(atype))
+
+  def testByteArray(self): self._test_int_array("byte")
+  def testUbyteArray(self): self._test_int_array("ubyte")
+  def testShortArray(self): self._test_int_array("short")
+  def testUshortArray(self): self._test_int_array("ushort")
+  def testIntArray(self): self._test_int_array("int")
+  def testUintArray(self): self._test_int_array("uint")
+  def testLongArray(self): self._test_int_array("long")
+  def testUlongArray(self): self._test_int_array("ulong")
+
+  def testUUIDArray(self):
+    self._testArray(None, None, "uuid", uuid4(), uuid4(), uuid4())
+
+  def testEmptyArray(self):
+    self._testArray(None, None, "null")
+
+  def testDescribedEmptyArray(self):
+    self._testArray("long", 0, "null")
+
+  def _test(self, dtype, *values, **kwargs):
+    eq=kwargs.get("eq", lambda x, y: x == y)
+    ntype = getattr(Data, dtype.upper())
+    putter = getattr(self.data, "put_%s" % dtype)
+    getter = getattr(self.data, "get_%s" % dtype)
+
+    for v in values:
+      self.put(putter, v)
+      gotten = getter()
+      assert eq(gotten, v), (gotten, v)
+
+    self.data.rewind()
+
+    for v in values:
+      vtype = self.data.next()
+      assert vtype == ntype, vtype
+      gotten = getter()
+      assert eq(gotten, v), (gotten, v)
+
+    encoded = self.data.encode()
+    copy = Data(0)
+    while encoded:
+      n = copy.decode(encoded)
+      encoded = encoded[n:]
+    copy.rewind()
+
+    cgetter = getattr(copy, "get_%s" % dtype)
+
+    for v in values:
+      vtype = copy.next()
+      assert vtype == ntype, vtype
+      gotten = cgetter()
+      assert eq(gotten, v), (gotten, v)
+
+  def _test_int(self, itype):
+    self._test(itype, *self.int_values(itype))
+
+  def testByte(self): self._test_int("byte")
+  def testUbyte(self): self._test_int("ubyte")
+  def testShort(self): self._test_int("short")
+  def testUshort(self): self._test("ushort")
+  def testInt(self): self._test_int("int")
+  def testUint(self): self._test_int("uint")
+  def testLong(self): self._test_int("long")
+  def testUlong(self): self._test_int("ulong")
+
+  def testString(self):
+    self._test("string", "one", "two", "three", "this is a test", "")
+
+  def testFloat(self):
+    # we have to use a special comparison here because python
+    # internally only uses doubles and converting between floats and
+    # doubles is imprecise
+    self._test("float", 0, 1, 2, 3, 0.1, 0.2, 0.3, -1, -2, -3, -0.1, -0.2, 
-0.3,
+               eq=lambda x, y: x - y < 0.000001)
+
+  def testDouble(self):
+    self._test("double", 0, 1, 2, 3, 0.1, 0.2, 0.3, -1, -2, -3, -0.1, -0.2, 
-0.3)
+
+  def testBinary(self):
+    self._test("binary", b"this", b"is", b"a", b"test",b"of" b"b\x00inary")
+
+  def testSymbol(self):
+    self._test("symbol", symbol("this is a symbol test"), symbol("bleh"), 
symbol("blah"))
+
+  def testTimestamp(self):
+    self._test("timestamp", timestamp(0), timestamp(12345), timestamp(1000000))
+
+  def testChar(self):
+    self._test("char", char('a'), char('b'), char('c'), char(u'\u20AC'))
+
+  def testUUID(self):
+    self._test("uuid", uuid4(), uuid4(), uuid4())
+
+  def testDecimal32(self):
+    self._test("decimal32", decimal32(0), decimal32(1), decimal32(2), 
decimal32(3), decimal32(4), decimal32(2**30))
+
+  def testDecimal64(self):
+    self._test("decimal64", decimal64(0), decimal64(1), decimal64(2), 
decimal64(3), decimal64(4), decimal64(2**60))
+
+  def testDecimal128(self):
+    self._test("decimal128", decimal128(b"fdsaasdf;lkjjkl;"), 
decimal128(b"x"*16))
+
+  def testCopy(self):
+    self.data.put_described()
+    self.data.enter()
+    self.data.put_ulong(123)
+    self.data.put_map()
+    self.data.enter()
+    self.data.put_string("pi")
+    self.data.put_double(3.14159265359)
+
+    dst = Data()
+    dst.copy(self.data)
+
+    copy = dst.format()
+    orig = self.data.format()
+    assert copy == orig, (copy, orig)
+
+  def testCopyNested(self):
+    nested = [1, 2, 3, [4, 5, 6], 7, 8, 9]
+    self.data.put_object(nested)
+    dst = Data()
+    dst.copy(self.data)
+    assert dst.format() == self.data.format()
+
+  def testCopyNestedArray(self):
+    nested = [Array(UNDESCRIBED, Data.LIST,
+                    ["first", [Array(UNDESCRIBED, Data.INT, 1,2,3)]],
+                    ["second", [Array(UNDESCRIBED, Data.INT, 1,2,3)]],
+                    ["third", [Array(UNDESCRIBED, Data.INT, 1,2,3)]],
+                    ),
+              "end"]
+    self.data.put_object(nested)
+    dst = Data()
+    dst.copy(self.data)
+    assert dst.format() == self.data.format()
+
+  def testRoundTrip(self):
+    obj = {symbol("key"): timestamp(1234),
+           ulong(123): "blah",
+           char("c"): "bleh",
+           u"desc": Described(symbol("url"), u"http://example.org";),
+           u"array": Array(UNDESCRIBED, Data.INT, 1, 2, 3),
+           u"list": [1, 2, 3, None, 4],
+           u"boolean": True}
+    self.data.put_object(obj)
+    enc = self.data.encode()
+    data = Data()
+    data.decode(enc)
+    data.rewind()
+    assert data.next()
+    copy = data.get_object()
+    assert copy == obj, (copy, obj)
+
+  def testBuffer(self):
+    try:
+      self.data.put_object(buffer(b"foo"))
+    except NameError:
+      # python >= 3.0 does not have `buffer`
+      return
+    data = Data()
+    data.decode(self.data.encode())
+    data.rewind()
+    assert data.next()
+    assert data.type() == Data.BINARY
+    assert data.get_object() == b"foo"
+
+  def testMemoryView(self):
+    try:
+      self.data.put_object(memoryview(b"foo"))
+    except NameError:
+      # python <= 2.6 does not have `memoryview`
+      return
+    data = Data()
+    data.decode(self.data.encode())
+    data.rewind()
+    assert data.next()
+    assert data.type() == Data.BINARY
+    assert data.get_object() == b"foo"
+
+  def testLookup(self):
+    obj = {symbol("key"): u"value",
+           symbol("pi"): 3.14159,
+           symbol("list"): [1, 2, 3, 4]}
+    self.data.put_object(obj)
+    self.data.rewind()
+    self.data.next()
+    self.data.enter()
+    self.data.narrow()
+    assert self.data.lookup("pi")
+    assert self.data.get_object() == 3.14159
+    self.data.rewind()
+    assert self.data.lookup("key")
+    assert self.data.get_object() == u"value"
+    self.data.rewind()
+    assert self.data.lookup("list")
+    assert self.data.get_object() == [1, 2, 3, 4]
+    self.data.widen()
+    self.data.rewind()
+    assert not self.data.lookup("pi")

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/common.py
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/common.py 
b/python/tests/proton_tests/common.py
new file mode 100644
index 0000000..90ba34c
--- /dev/null
+++ b/python/tests/proton_tests/common.py
@@ -0,0 +1,510 @@
+#
+# 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 unittest import TestCase
+try:
+  from unittest import SkipTest
+except:
+  try:
+    from unittest2 import SkipTest
+  except:
+    class SkipTest(Exception):
+      pass
+
+from random import randint
+from threading import Thread
+from socket import socket, AF_INET, SOCK_STREAM
+from subprocess import Popen,PIPE,STDOUT
+import sys, os, subprocess
+from proton import SASL, SSL
+from proton.reactor import Container
+from proton.handlers import Handshaker, FlowController
+from string import Template
+
+def free_tcp_ports(count=1):
+  """ return a list of 'count' TCP ports that are free to used (ie. unbound)
+  """
+  retry = 0
+  ports = []
+  sockets = []
+  while len(ports) != count:
+    port = randint(49152, 65535)
+    sockets.append( socket( AF_INET, SOCK_STREAM ) )
+    try:
+      sockets[-1].bind( ("0.0.0.0", port ) )
+      ports.append( port )
+      retry = 0
+    except:
+      retry += 1
+      assert retry != 100, "No free sockets available for test!"
+  for s in sockets:
+    s.close()
+  return ports
+
+def free_tcp_port():
+  return free_tcp_ports(1)[0]
+
+def pump_uni(src, dst, buffer_size=1024):
+  p = src.pending()
+  c = dst.capacity()
+
+  if c < 0:
+    if p < 0:
+      return False
+    else:
+      src.close_head()
+      return True
+
+  if p < 0:
+    dst.close_tail()
+  elif p == 0 or c == 0:
+    return False
+  else:
+    binary = src.peek(min(c, buffer_size))
+    dst.push(binary)
+    src.pop(len(binary))
+
+  return True
+
+def pump(transport1, transport2, buffer_size=1024):
+  """ Transfer all pending bytes between two Proton engines
+      by repeatedly calling peek/pop and push.
+      Asserts that each engine accepts some bytes every time
+      (unless it's already closed).
+  """
+  while (pump_uni(transport1, transport2, buffer_size) or
+         pump_uni(transport2, transport1, buffer_size)):
+    pass
+
+def findfileinpath(filename, searchpath):
+    """Find filename in the searchpath
+        return absolute path to the file or None
+    """
+    paths = searchpath.split(os.pathsep)
+    for path in paths:
+        if os.path.exists(os.path.join(path, filename)):
+            return os.path.abspath(os.path.join(path, filename))
+    return None
+
+def isSSLPresent():
+    return SSL.present()
+
+createdSASLDb = False
+
+def _cyrusSetup(conf_dir):
+  """Write out simple SASL config.
+  """
+  saslpasswd = ""
+  if 'SASLPASSWD' in os.environ:
+    saslpasswd = os.environ['SASLPASSWD']
+  else:
+    saslpasswd = findfileinpath('saslpasswd2', os.getenv('PATH')) or ""
+  if os.path.exists(saslpasswd):
+    t = Template("""sasldb_path: ${db}
+mech_list: EXTERNAL DIGEST-MD5 SCRAM-SHA-1 CRAM-MD5 PLAIN ANONYMOUS
+""")
+    abs_conf_dir = os.path.abspath(conf_dir)
+    subprocess.call(args=['rm','-rf',abs_conf_dir])
+    os.mkdir(abs_conf_dir)
+    db = os.path.join(abs_conf_dir,'proton.sasldb')
+    conf = os.path.join(abs_conf_dir,'proton-server.conf')
+    f = open(conf, 'w')
+    f.write(t.substitute(db=db))
+    f.close()
+
+    cmd_template = Template("echo password | ${saslpasswd} -c -p -f ${db} -u 
proton user")
+    cmd = cmd_template.substitute(db=db, saslpasswd=saslpasswd)
+    subprocess.call(args=cmd, shell=True)
+
+    os.environ['PN_SASL_CONFIG_PATH'] = abs_conf_dir
+    global createdSASLDb
+    createdSASLDb = True
+
+# Globally initialize Cyrus SASL configuration
+if SASL.extended():
+  _cyrusSetup('sasl-conf')
+
+def ensureCanTestExtendedSASL():
+  if not SASL.extended():
+    raise Skipped('Extended SASL not supported')
+  if not createdSASLDb:
+    raise Skipped("Can't Test Extended SASL: Couldn't create auth db")
+
+class DefaultConfig:
+    defines = {}
+
+class Test(TestCase):
+  config = DefaultConfig()
+
+  def __init__(self, name):
+    super(Test, self).__init__(name)
+    self.name = name
+
+  def configure(self, config):
+    self.config = config
+
+  def default(self, name, value, **profiles):
+    default = value
+    profile = self.config.defines.get("profile")
+    if profile:
+      default = profiles.get(profile, default)
+    return self.config.defines.get(name, default)
+
+  @property
+  def delay(self):
+    return float(self.default("delay", "1", fast="0.1"))
+
+  @property
+  def timeout(self):
+    return float(self.default("timeout", "60", fast="10"))
+
+  @property
+  def verbose(self):
+    return int(self.default("verbose", 0))
+
+
+class Skipped(SkipTest):
+  skipped = True
+
+
+class TestServer(object):
+  """ Base class for creating test-specific message servers.
+  """
+  def __init__(self, **kwargs):
+    self.args = kwargs
+    self.reactor = Container(self)
+    self.host = "127.0.0.1"
+    self.port = 0
+    if "host" in kwargs:
+      self.host = kwargs["host"]
+    if "port" in kwargs:
+      self.port = kwargs["port"]
+    self.handlers = [FlowController(10), Handshaker()]
+    self.thread = Thread(name="server-thread", target=self.run)
+    self.thread.daemon = True
+    self.running = True
+    self.conditions = []
+
+  def start(self):
+    self.reactor.start()
+    retry = 0
+    if self.port == 0:
+      self.port = str(randint(49152, 65535))
+      retry = 10
+    while retry > 0:
+      try:
+        self.acceptor = self.reactor.acceptor(self.host, self.port)
+        break
+      except IOError:
+        self.port = str(randint(49152, 65535))
+        retry -= 1
+    assert retry > 0, "No free port for server to listen on!"
+    self.thread.start()
+
+  def stop(self):
+    self.running = False
+    self.reactor.wakeup()
+    self.thread.join()
+
+  # Note: all following methods all run under the thread:
+
+  def run(self):
+    self.reactor.timeout = 3.14159265359
+    while self.reactor.process():
+      if not self.running:
+        self.acceptor.close()
+        self.reactor.stop()
+        break
+
+  def on_connection_bound(self, event):
+    if "idle_timeout" in self.args:
+      event.transport.idle_timeout = self.args["idle_timeout"]
+
+  def on_connection_local_close(self, event):
+    self.conditions.append(event.connection.condition)
+
+  def on_delivery(self, event):
+    event.delivery.settle()
+
+#
+# Classes that wrap the messenger applications msgr-send and msgr-recv.
+# These applications reside in the c/tools directory
+#
+
+class MessengerApp(object):
+    """ Interface to control a MessengerApp """
+    def __init__(self):
+        self._cmdline = None
+        # options common to Receivers and Senders:
+        self.ca_db = None
+        self.certificate = None
+        self.privatekey = None
+        self.password = None
+        self._output = None
+
+    def start(self, verbose=False):
+        """ Begin executing the test """
+        cmd = self.cmdline()
+        self._verbose = verbose
+        if self._verbose:
+            print("COMMAND='%s'" % str(cmd))
+        #print("ENV='%s'" % str(os.environ.copy()))
+        try:
+            # Handle python launch by replacing script 'filename' with
+            # 'python abspath-to-filename' in cmdline arg list.
+            if cmd[0].endswith('.py'):
+                foundfile = findfileinpath(cmd[0], os.getenv('PATH'))
+                if foundfile is None:
+                    msg = "Unable to locate file '%s' in PATH" % cmd[0]
+                    raise Skipped("Skipping test - %s" % msg)
+
+                del cmd[0:1]
+                cmd.insert(0, foundfile)
+                cmd.insert(0, sys.executable)
+            self._process = Popen(cmd, stdout=PIPE, stderr=STDOUT,
+                                  bufsize=4096, universal_newlines=True)
+        except OSError:
+            e = sys.exc_info()[1]
+            print("ERROR: '%s'" % e)
+            msg = "Unable to execute command '%s', is it in your PATH?" % 
cmd[0]
+
+            # NOTE(flaper87): Skip the test if the command is not found.
+            if e.errno == 2:
+              raise Skipped("Skipping test - %s" % msg)
+            assert False, msg
+
+        self._ready()  # wait for it to initialize
+
+    def stop(self):
+        """ Signal the client to start clean shutdown """
+        pass
+
+    def wait(self):
+        """ Wait for client to complete """
+        self._output = self._process.communicate()
+        if self._verbose:
+            print("OUTPUT='%s'" % self.stdout())
+
+    def status(self):
+        """ Return status from client process """
+        return self._process.returncode
+
+    def stdout(self):
+        #self._process.communicate()[0]
+        if not self._output or not self._output[0]:
+            return "*** NO STDOUT ***"
+        return self._output[0]
+
+    def stderr(self):
+        if not self._output or not self._output[1]:
+            return "*** NO STDERR ***"
+        return self._output[1]
+
+    def cmdline(self):
+        if not self._cmdline:
+            self._build_command()
+        return self._cmdline
+
+    def _build_command(self):
+        assert False, "_build_command() needs override"
+
+    def _ready(self):
+        assert False, "_ready() needs override"
+
+    def _do_common_options(self):
+        """ Common option handling """
+        if self.ca_db is not None:
+            self._cmdline.append("-T")
+            self._cmdline.append(str(self.ca_db))
+        if self.certificate is not None:
+            self._cmdline.append("-C")
+            self._cmdline.append(str(self.certificate))
+        if self.privatekey is not None:
+            self._cmdline.append("-K")
+            self._cmdline.append(str(self.privatekey))
+        if self.password is not None:
+            self._cmdline.append("-P")
+            self._cmdline.append("pass:" + str(self.password))
+
+
+class MessengerSender(MessengerApp):
+    """ Interface to configure a sending MessengerApp """
+    def __init__(self):
+        MessengerApp.__init__(self)
+        self._command = None
+        # @todo make these properties
+        self.targets = []
+        self.send_count = None
+        self.msg_size = None
+        self.send_batch = None
+        self.outgoing_window = None
+        self.report_interval = None
+        self.get_reply = False
+        self.timeout = None
+        self.incoming_window = None
+        self.recv_count = None
+        self.name = None
+
+    # command string?
+    def _build_command(self):
+        self._cmdline = self._command
+        self._do_common_options()
+        assert self.targets, "Missing targets, required for sender!"
+        self._cmdline.append("-a")
+        self._cmdline.append(",".join(self.targets))
+        if self.send_count is not None:
+            self._cmdline.append("-c")
+            self._cmdline.append(str(self.send_count))
+        if self.msg_size is not None:
+            self._cmdline.append("-b")
+            self._cmdline.append(str(self.msg_size))
+        if self.send_batch is not None:
+            self._cmdline.append("-p")
+            self._cmdline.append(str(self.send_batch))
+        if self.outgoing_window is not None:
+            self._cmdline.append("-w")
+            self._cmdline.append(str(self.outgoing_window))
+        if self.report_interval is not None:
+            self._cmdline.append("-e")
+            self._cmdline.append(str(self.report_interval))
+        if self.get_reply:
+            self._cmdline.append("-R")
+        if self.timeout is not None:
+            self._cmdline.append("-t")
+            self._cmdline.append(str(self.timeout))
+        if self.incoming_window is not None:
+            self._cmdline.append("-W")
+            self._cmdline.append(str(self.incoming_window))
+        if self.recv_count is not None:
+            self._cmdline.append("-B")
+            self._cmdline.append(str(self.recv_count))
+        if self.name is not None:
+            self._cmdline.append("-N")
+            self._cmdline.append(str(self.name))
+
+    def _ready(self):
+        pass
+
+
+class MessengerReceiver(MessengerApp):
+    """ Interface to configure a receiving MessengerApp """
+    def __init__(self):
+        MessengerApp.__init__(self)
+        self._command = None
+        # @todo make these properties
+        self.subscriptions = []
+        self.receive_count = None
+        self.recv_count = None
+        self.incoming_window = None
+        self.timeout = None
+        self.report_interval = None
+        self.send_reply = False
+        self.outgoing_window = None
+        self.forwards = []
+        self.name = None
+
+    # command string?
+    def _build_command(self):
+        self._cmdline = self._command
+        self._do_common_options()
+        self._cmdline += ["-X", "READY"]
+        assert self.subscriptions, "Missing subscriptions, required for 
receiver!"
+        self._cmdline.append("-a")
+        self._cmdline.append(",".join(self.subscriptions))
+        if self.receive_count is not None:
+            self._cmdline.append("-c")
+            self._cmdline.append(str(self.receive_count))
+        if self.recv_count is not None:
+            self._cmdline.append("-b")
+            self._cmdline.append(str(self.recv_count))
+        if self.incoming_window is not None:
+            self._cmdline.append("-w")
+            self._cmdline.append(str(self.incoming_window))
+        if self.timeout is not None:
+            self._cmdline.append("-t")
+            self._cmdline.append(str(self.timeout))
+        if self.report_interval is not None:
+            self._cmdline.append("-e")
+            self._cmdline.append(str(self.report_interval))
+        if self.send_reply:
+            self._cmdline.append("-R")
+        if self.outgoing_window is not None:
+            self._cmdline.append("-W")
+            self._cmdline.append(str(self.outgoing_window))
+        if self.forwards:
+            self._cmdline.append("-F")
+            self._cmdline.append(",".join(self.forwards))
+        if self.name is not None:
+            self._cmdline.append("-N")
+            self._cmdline.append(str(self.name))
+
+    def _ready(self):
+        """ wait for subscriptions to complete setup. """
+        r = self._process.stdout.readline()
+        assert r.strip() == "READY", "Unexpected input while waiting for 
receiver to initialize: %s" % r
+
+class MessengerSenderC(MessengerSender):
+    def __init__(self):
+        MessengerSender.__init__(self)
+        self._command = ["msgr-send"]
+
+def setup_valgrind(self):
+    if "VALGRIND" not in os.environ:
+        raise Skipped("Skipping test - $VALGRIND not set.")
+    super(type(self), self).__init__()
+    self._command = [os.environ["VALGRIND"]] + 
os.environ["VALGRIND_ARGS"].split(' ') + self._command
+
+class MessengerSenderValgrind(MessengerSenderC):
+    """ Run the C sender under Valgrind
+    """
+    def __init__(self, suppressions=None):
+        setup_valgrind(self)
+
+class MessengerReceiverC(MessengerReceiver):
+    def __init__(self):
+        MessengerReceiver.__init__(self)
+        self._command = ["msgr-recv"]
+
+class MessengerReceiverValgrind(MessengerReceiverC):
+    """ Run the C receiver under Valgrind
+    """
+    def __init__(self, suppressions=None):
+        setup_valgrind(self)
+
+class ReactorSenderC(MessengerSender):
+    def __init__(self):
+        MessengerSender.__init__(self)
+        self._command = ["reactor-send"]
+
+class ReactorSenderValgrind(ReactorSenderC):
+    """ Run the C sender under Valgrind
+    """
+    def __init__(self, suppressions=None):
+        setup_valgrind(self)
+
+class ReactorReceiverC(MessengerReceiver):
+    def __init__(self):
+        MessengerReceiver.__init__(self)
+        self._command = ["reactor-recv"]
+
+class ReactorReceiverValgrind(ReactorReceiverC):
+    """ Run the C receiver under Valgrind
+    """
+    def __init__(self, suppressions=None):
+        setup_valgrind(self)


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@qpid.apache.org
For additional commands, e-mail: commits-h...@qpid.apache.org

Reply via email to