qpid-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From acon...@apache.org
Subject [07/11] qpid-proton git commit: PROTON-1885: [python] move tests/python to python/tests
Date Fri, 06 Jul 2018 16:59:19 GMT
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/transport.py
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/transport.py b/python/tests/proton_tests/transport.py
new file mode 100644
index 0000000..236169d
--- /dev/null
+++ b/python/tests/proton_tests/transport.py
@@ -0,0 +1,393 @@
+#
+# 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
+import sys
+from . import common
+from proton import *
+
+
+class Test(common.Test):
+  pass
+
+class ClientTransportTest(Test):
+
+  def setUp(self):
+    self.transport = Transport()
+    self.peer = Transport()
+    self.conn = Connection()
+    self.peer.bind(self.conn)
+
+  def tearDown(self):
+    self.transport = None
+    self.peer = None
+    self.conn = None
+
+  def drain(self):
+    while True:
+      p = self.transport.pending()
+      if p < 0:
+        return
+      elif p > 0:
+        data = self.transport.peek(p)
+        self.peer.push(data)
+        self.transport.pop(len(data))
+      else:
+        assert False
+
+  def assert_error(self, name):
+    assert self.conn.remote_container is None, self.conn.remote_container
+    self.drain()
+    # verify that we received an open frame
+    assert self.conn.remote_container is not None, self.conn.remote_container
+    # verify that we received a close frame
+    assert self.conn.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_CLOSED, self.conn.state
+    # verify that a framing error was reported
+    assert self.conn.remote_condition.name == name, self.conn.remote_condition
+
+  def testEOS(self):
+    self.transport.push(b"") # should be a noop
+    self.transport.close_tail() # should result in framing error
+    self.assert_error(u'amqp:connection:framing-error')
+
+  def testPartial(self):
+    self.transport.push(b"AMQ") # partial header
+    self.transport.close_tail() # should result in framing error
+    self.assert_error(u'amqp:connection:framing-error')
+
+  def testGarbage(self, garbage=b"GARBAGE_"):
+    self.transport.push(garbage)
+    self.assert_error(u'amqp:connection:framing-error')
+    assert self.transport.pending() < 0
+    self.transport.close_tail()
+    assert self.transport.pending() < 0
+
+  def testSmallGarbage(self):
+    self.testGarbage(b"XXX")
+
+  def testBigGarbage(self):
+    self.testGarbage(b"GARBAGE_XXX")
+
+  def testHeader(self):
+    self.transport.push(b"AMQP\x00\x01\x00\x00")
+    self.transport.close_tail()
+    self.assert_error(u'amqp:connection:framing-error')
+
+  def testHeaderBadDOFF1(self):
+    """Verify doff > size error"""
+    self.testGarbage(b"AMQP\x00\x01\x00\x00\x00\x00\x00\x08\x08\x00\x00\x00")
+
+  def testHeaderBadDOFF2(self):
+    """Verify doff < 2 error"""
+    self.testGarbage(b"AMQP\x00\x01\x00\x00\x00\x00\x00\x08\x01\x00\x00\x00")
+
+  def testHeaderBadSize(self):
+    """Verify size > max_frame_size error"""
+    self.transport.max_frame_size = 512
+    self.testGarbage(b"AMQP\x00\x01\x00\x00\x00\x00\x02\x01\x02\x00\x00\x00")
+
+  def testProtocolNotSupported(self):
+    self.transport.push(b"AMQP\x01\x01\x0a\x00")
+    p = self.transport.pending()
+    assert p >= 8, p
+    bytes = self.transport.peek(p)
+    assert bytes[:8] == b"AMQP\x00\x01\x00\x00"
+    self.transport.pop(p)
+    self.drain()
+    assert self.transport.closed
+
+  def testPeek(self):
+    out = self.transport.peek(1024)
+    assert out is not None
+
+  def testBindAfterOpen(self):
+    conn = Connection()
+    ssn = conn.session()
+    conn.open()
+    ssn.open()
+    conn.container = "test-container"
+    conn.hostname = "test-hostname"
+    trn = Transport()
+    trn.bind(conn)
+    out = trn.peek(1024)
+    assert b"test-container" in out, repr(out)
+    assert b"test-hostname" in out, repr(out)
+    self.transport.push(out)
+
+    c = Connection()
+    assert c.remote_container == None
+    assert c.remote_hostname == None
+    assert c.session_head(0) == None
+    self.transport.bind(c)
+    assert c.remote_container == "test-container"
+    assert c.remote_hostname == "test-hostname"
+    assert c.session_head(0) != None
+
+  def testCloseHead(self):
+    n = self.transport.pending()
+    assert n > 0, n
+    try:
+      self.transport.close_head()
+    except TransportException:
+      e = sys.exc_info()[1]
+      assert "aborted" in str(e), str(e)
+    n = self.transport.pending()
+    assert n < 0, n
+
+  def testCloseTail(self):
+    n = self.transport.capacity()
+    assert n > 0, n
+    try:
+      self.transport.close_tail()
+    except TransportException:
+      e = sys.exc_info()[1]
+      assert "aborted" in str(e), str(e)
+    n = self.transport.capacity()
+    assert n < 0, n
+
+  def testUnpairedPop(self):
+    conn = Connection()
+    self.transport.bind(conn)
+
+    conn.hostname = "hostname"
+    conn.open()
+
+    dat1 = self.transport.peek(1024)
+
+    ssn = conn.session()
+    ssn.open()
+
+    dat2 = self.transport.peek(1024)
+
+    assert dat2[:len(dat1)] == dat1
+
+    snd = ssn.sender("sender")
+    snd.open()
+
+    self.transport.pop(len(dat1))
+    self.transport.pop(len(dat2) - len(dat1))
+    dat3 = self.transport.peek(1024)
+    self.transport.pop(len(dat3))
+    assert self.transport.peek(1024) == b""
+
+    self.peer.push(dat1)
+    self.peer.push(dat2[len(dat1):])
+    self.peer.push(dat3)
+
+class ServerTransportTest(Test):
+
+  def setUp(self):
+    self.transport = Transport(Transport.SERVER)
+    self.peer = Transport()
+    self.conn = Connection()
+    self.peer.bind(self.conn)
+
+  def tearDOwn(self):
+    self.transport = None
+    self.peer = None
+    self.conn = None
+
+  def drain(self):
+    while True:
+      p = self.transport.pending()
+      if p < 0:
+        return
+      elif p > 0:
+        bytes = self.transport.peek(p)
+        self.peer.push(bytes)
+        self.transport.pop(len(bytes))
+      else:
+        assert False
+
+  def assert_error(self, name):
+    assert self.conn.remote_container is None, self.conn.remote_container
+    self.drain()
+    # verify that we received an open frame
+    assert self.conn.remote_container is not None, self.conn.remote_container
+    # verify that we received a close frame
+    assert self.conn.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_CLOSED, self.conn.state
+    # verify that a framing error was reported
+    assert self.conn.remote_condition.name == name, self.conn.remote_condition
+
+  # TODO: This may no longer be testing anything
+  def testEOS(self):
+    self.transport.push(b"") # should be a noop
+    self.transport.close_tail()
+    p = self.transport.pending()
+    self.drain()
+    assert self.transport.closed
+
+  def testPartial(self):
+    self.transport.push(b"AMQ") # partial header
+    self.transport.close_tail()
+    p = self.transport.pending()
+    assert p >= 8, p
+    bytes = self.transport.peek(p)
+    assert bytes[:8] == b"AMQP\x00\x01\x00\x00"
+    self.transport.pop(p)
+    self.drain()
+    assert self.transport.closed
+
+  def testGarbage(self, garbage=b"GARBAGE_"):
+    self.transport.push(garbage)
+    p = self.transport.pending()
+    assert p >= 8, p
+    bytes = self.transport.peek(p)
+    assert bytes[:8] == b"AMQP\x00\x01\x00\x00"
+    self.transport.pop(p)
+    self.drain()
+    assert self.transport.closed
+
+  def testSmallGarbage(self):
+    self.testGarbage(b"XXX")
+
+  def testBigGarbage(self):
+    self.testGarbage(b"GARBAGE_XXX")
+
+  def testHeader(self):
+    self.transport.push(b"AMQP\x00\x01\x00\x00")
+    self.transport.close_tail()
+    self.assert_error(u'amqp:connection:framing-error')
+
+  def testProtocolNotSupported(self):
+    self.transport.push(b"AMQP\x01\x01\x0a\x00")
+    p = self.transport.pending()
+    assert p >= 8, p
+    bytes = self.transport.peek(p)
+    assert bytes[:8] == b"AMQP\x00\x01\x00\x00"
+    self.transport.pop(p)
+    self.drain()
+    assert self.transport.closed
+
+  def testPeek(self):
+    out = self.transport.peek(1024)
+    assert out is not None
+
+  def testBindAfterOpen(self):
+    conn = Connection()
+    ssn = conn.session()
+    conn.open()
+    ssn.open()
+    conn.container = "test-container"
+    conn.hostname = "test-hostname"
+    trn = Transport()
+    trn.bind(conn)
+    out = trn.peek(1024)
+    assert b"test-container" in out, repr(out)
+    assert b"test-hostname" in out, repr(out)
+    self.transport.push(out)
+
+    c = Connection()
+    assert c.remote_container == None
+    assert c.remote_hostname == None
+    assert c.session_head(0) == None
+    self.transport.bind(c)
+    assert c.remote_container == "test-container"
+    assert c.remote_hostname == "test-hostname"
+    assert c.session_head(0) != None
+
+  def testCloseHead(self):
+    n = self.transport.pending()
+    assert n >= 0, n
+    try:
+      self.transport.close_head()
+    except TransportException:
+      e = sys.exc_info()[1]
+      assert "aborted" in str(e), str(e)
+    n = self.transport.pending()
+    assert n < 0, n
+
+  def testCloseTail(self):
+    n = self.transport.capacity()
+    assert n > 0, n
+    try:
+      self.transport.close_tail()
+    except TransportException:
+      e = sys.exc_info()[1]
+      assert "aborted" in str(e), str(e)
+    n = self.transport.capacity()
+    assert n < 0, n
+
+  def testUnpairedPop(self):
+    conn = Connection()
+    self.transport.bind(conn)
+
+    conn.hostname = "hostname"
+    conn.open()
+
+    dat1 = self.transport.peek(1024)
+
+    ssn = conn.session()
+    ssn.open()
+
+    dat2 = self.transport.peek(1024)
+
+    assert dat2[:len(dat1)] == dat1
+
+    snd = ssn.sender("sender")
+    snd.open()
+
+    self.transport.pop(len(dat1))
+    self.transport.pop(len(dat2) - len(dat1))
+    dat3 = self.transport.peek(1024)
+    self.transport.pop(len(dat3))
+    assert self.transport.peek(1024) == b""
+
+    self.peer.push(dat1)
+    self.peer.push(dat2[len(dat1):])
+    self.peer.push(dat3)
+
+  def testEOSAfterSASL(self):
+    self.transport.sasl().allowed_mechs('ANONYMOUS')
+
+    self.peer.sasl().allowed_mechs('ANONYMOUS')
+
+    # this should send over the sasl header plus a sasl-init set up
+    # for anonymous
+    p = self.peer.pending()
+    self.transport.push(self.peer.peek(p))
+    self.peer.pop(p)
+
+    # now we send EOS
+    self.transport.close_tail()
+
+    # the server may send an error back
+    p = self.transport.pending()
+    while p>0:
+      self.peer.push(self.transport.peek(p))
+      self.transport.pop(p)
+      p = self.transport.pending()
+
+    # server closed
+    assert self.transport.pending() < 0
+
+class LogTest(Test):
+
+  def testTracer(self):
+    t = Transport()
+    assert t.tracer is None
+    messages = []
+    def tracer(transport, message):
+      messages.append((transport, message))
+    t.tracer = tracer
+    assert t.tracer is tracer
+    t.log("one")
+    t.log("two")
+    t.log("three")
+    assert messages == [(t, "one"), (t, "two"), (t, "three")], messages

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/url.py
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/url.py b/python/tests/proton_tests/url.py
new file mode 100644
index 0000000..b44699a
--- /dev/null
+++ b/python/tests/proton_tests/url.py
@@ -0,0 +1,147 @@
+from __future__ import absolute_import
+#
+# 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 . import common
+from proton import Url
+
+class UrlTest(common.Test):
+    def assertEqual(self, a, b):
+        assert a == b, "%s != %s" % (a, b)
+
+    def assertNotEqual(self, a, b):
+        assert a != b, "%s == %s" % (a, b)
+
+    def assertUrl(self, u, scheme, username, password, host, port, path):
+        self.assertEqual((u.scheme, u.username, u.password, u.host, u.port, u.path),
+                         (scheme, username, password, host, port, path))
+
+    def testUrl(self):
+        url = Url('amqp://me:secret@myhost:1234/foobar')
+        self.assertEqual(str(url), "amqp://me:secret@myhost:1234/foobar")
+        self.assertUrl(url, 'amqp', 'me', 'secret', 'myhost', 1234, 'foobar')
+        self.assertEqual(str(url), "amqp://me:secret@myhost:1234/foobar")
+
+    def testDefaults(self):
+        # Check that we allow None for scheme, port
+        url = Url(username='me', password='secret', host='myhost', path='foobar', defaults=False)
+        self.assertEqual(str(url), "//me:secret@myhost/foobar")
+        self.assertUrl(url, None, 'me', 'secret', 'myhost', None, 'foobar')
+
+        self.assertEqual(str(Url("amqp://me:secret@myhost/foobar")),
+                         "amqp://me:secret@myhost:amqp/foobar")
+
+        # Empty string vs. None for path
+        self.assertEqual(Url("myhost/").path, "")
+        assert Url("myhost", defaults=False).path is None
+
+        # Expanding abbreviated url strings.
+        for s, u in [
+            ("", "amqp://0.0.0.0:amqp"),
+            ("foo", "amqp://foo:amqp"),
+            (":1234", "amqp://0.0.0.0:1234"),
+            ("/path", "amqp://0.0.0.0:amqp/path"),
+            ("user@host/topic://test", "amqp://user@host:amqp/topic://test"),
+            ("user@host:3456", "amqp://user@host:3456"),
+            ("user:pass@host/topic://test", "amqp://user:pass@host:amqp/topic://test")
+        ]: self.assertEqual(str(Url(s)), u)
+
+    def assertPort(self, port, portint, portstr):
+        self.assertEqual((port, port), (portint, portstr))
+        self.assertEqual((int(port), str(port)), (portint, portstr))
+
+    def testPort(self):
+        self.assertPort(Url.Port('amqp'), 5672, 'amqp')
+        self.assertPort(Url.Port(5672), 5672, '5672')
+        self.assertPort(Url.Port(5671), 5671, '5671')
+        self.assertEqual(Url.Port(5671)+1, 5672) # Treat as int
+        self.assertEqual(str(Url.Port(5672)), '5672')
+
+        self.assertPort(Url.Port(Url.Port('amqp')), 5672, 'amqp')
+        self.assertPort(Url.Port(Url.Port(5672)), 5672, '5672')
+
+        try:
+            Url.Port('xxx')
+            assert False, "Expected ValueError"
+        except ValueError: pass
+
+        self.assertEqual(str(Url("host:amqp", defaults=False)), "//host:amqp")
+        self.assertEqual(Url("host:amqp", defaults=False).port, 5672)
+
+    def testArgs(self):
+        u = Url("amqp://u:p@host:amqp/path", scheme='foo', host='bar', port=1234, path='garden', defaults=False)
+        self.assertUrl(u, 'foo', 'u', 'p', 'bar', 1234, 'garden')
+        u = Url(defaults=False)
+        self.assertUrl(u, None, None, None, None, None, None)
+
+    def assertRaises(self, exception, function, *args, **kwargs):
+        try:
+            function(*args, **kwargs)
+            assert False, "Expected exception %s" % exception.__name__
+        except exception: pass
+
+    def testMissing(self):
+        self.assertUrl(Url(defaults=False), None, None, None, None, None, None)
+        self.assertUrl(Url('amqp://', defaults=False), 'amqp', None, None, None, None, None)
+        self.assertUrl(Url('username@', defaults=False), None, 'username', None, None, None, None)
+        self.assertUrl(Url(':pass@', defaults=False), None, '', 'pass', None, None, None)
+        self.assertUrl(Url('host', defaults=False), None, None, None, 'host', None, None)
+        self.assertUrl(Url(':1234', defaults=False), None, None, None, None, 1234, None)
+        self.assertUrl(Url('/path', defaults=False), None, None, None, None, None, 'path')
+
+        for s, full in [
+            ('amqp://', 'amqp://'),
+            ('username@','//username@'),
+            (':pass@', '//:pass@'),
+            (':1234', '//:1234'),
+            ('/path','/path')
+        ]:
+            self.assertEqual(str(Url(s, defaults=False)), full)
+
+        for s, full in [
+                ('amqp://', 'amqp://0.0.0.0:amqp'),
+                ('username@', 'amqp://username@0.0.0.0:amqp'),
+                (':pass@', 'amqp://:pass@0.0.0.0:amqp'),
+                (':1234', 'amqp://0.0.0.0:1234'),
+                ('/path', 'amqp://0.0.0.0:amqp/path'),
+                ('foo/path', 'amqp://foo:amqp/path'),
+                (':1234/path', 'amqp://0.0.0.0:1234/path')
+        ]:
+            self.assertEqual(str(Url(s)), full)
+
+    def testAmqps(self):
+        # Scheme defaults
+        self.assertEqual(str(Url("me:secret@myhost/foobar")),
+                         "amqp://me:secret@myhost:amqp/foobar")
+        # Correct port for amqps vs. amqps
+        self.assertEqual(str(Url("amqps://me:secret@myhost/foobar")),
+                         "amqps://me:secret@myhost:amqps/foobar")
+
+        self.assertPort(Url.Port('amqps'), 5671, 'amqps')
+        self.assertEqual(str(Url("host:amqps", defaults=False)), "//host:amqps")
+        self.assertEqual(Url("host:amqps", defaults=False).port, 5671)
+
+    def testEqual(self):
+        self.assertEqual(Url("foo/path"), 'amqp://foo:amqp/path')
+        self.assertEqual('amqp://foo:amqp/path', Url("foo/path"))
+        self.assertEqual(Url("foo/path"), Url("foo/path"))
+        self.assertNotEqual(Url("foo/path"), 'xamqp://foo:amqp/path')
+        self.assertNotEqual('xamqp://foo:amqp/path', Url("foo/path"))
+        self.assertNotEqual(Url("foo/path"), Url("bar/path"))

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/utils.py
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/utils.py b/python/tests/proton_tests/utils.py
new file mode 100644
index 0000000..1f20bba
--- /dev/null
+++ b/python/tests/proton_tests/utils.py
@@ -0,0 +1,163 @@
+#
+# 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, time, sys
+from threading import Thread, Event
+from unittest import TestCase
+from proton_tests.common import Test, free_tcp_port
+from copy import copy
+from proton import Message, Url, generate_uuid, Array, UNDESCRIBED, Data, symbol, ConnectionException, ProtonException
+from proton.handlers import MessagingHandler
+from proton.reactor import Container
+from proton.utils import SyncRequestResponse, BlockingConnection
+from .common import Skipped, ensureCanTestExtendedSASL
+CONNECTION_PROPERTIES={u'connection': u'properties'}
+OFFERED_CAPABILITIES = Array(UNDESCRIBED, Data.SYMBOL, symbol("O_one"), symbol("O_two"), symbol("O_three"))
+DESIRED_CAPABILITIES = Array(UNDESCRIBED, Data.SYMBOL, symbol("D_one"), symbol("D_two"), symbol("D_three"))
+ANONYMOUS='ANONYMOUS'
+EXTERNAL='EXTERNAL'
+
+class EchoServer(MessagingHandler, Thread):
+    """
+    Simple echo server that echos messages to their reply-to. Runs in a thread.
+    Will only accept a single connection and shut down when that connection closes.
+    """
+
+    def __init__(self, url, timeout):
+        MessagingHandler.__init__(self)
+        Thread.__init__(self)
+        self.daemon = True
+        self.timeout = timeout
+        self.url = url
+        self.senders = {}
+        self.container = None
+        self.event = Event()
+
+    def on_start(self, event):
+        self.acceptor = event.container.listen(self.url)
+        self.container = event.container
+        self.event.set()
+
+    def on_link_opening(self, event):
+        if event.link.is_sender:
+            if event.link.remote_source and event.link.remote_source.dynamic:
+                event.link.source.address = str(generate_uuid())
+                self.senders[event.link.source.address] = event.link
+
+    def on_message(self, event):
+        m = event.message
+        sender = self.senders.get(m.reply_to)
+        if sender:
+            reply = Message(address=m.reply_to, body=m.body, correlation_id=m.correlation_id)
+            sender.send(reply)
+
+    def on_connection_closing(self, event):
+        self.acceptor.close()
+
+    def on_transport_error(self, event):
+        self.acceptor.close()
+
+    def run(self):
+        Container(self).run()
+
+    def wait(self):
+        self.event.wait(self.timeout)
+
+
+class ConnPropertiesServer(EchoServer):
+     def __init__(self, url, timeout):
+        EchoServer.__init__(self, url, timeout)
+        self.properties_received = False
+        self.offered_capabilities_received = False
+        self.desired_capabilities_received = False
+
+     def on_connection_opening(self, event):
+        conn = event.connection
+
+        if conn.remote_properties == CONNECTION_PROPERTIES:
+            self.properties_received = True
+        if conn.remote_offered_capabilities == OFFERED_CAPABILITIES:
+            self.offered_capabilities_received = True
+        if conn.remote_desired_capabilities == DESIRED_CAPABILITIES:
+            self.desired_capabilities_received = True
+
+class SyncRequestResponseTest(Test):
+    """Test SyncRequestResponse"""
+
+    def test_request_response(self):
+        ensureCanTestExtendedSASL()
+        def test(name, address="x"):
+            for i in range(5):
+                body="%s%s" % (name, i)
+                response = client.call(Message(address=address, body=body))
+                self.assertEquals(response.address, client.reply_to)
+                self.assertEquals(response.body, body)
+
+        server = EchoServer(Url(host="127.0.0.1", port=free_tcp_port()), self.timeout)
+        server.start()
+        server.wait()
+        connection = BlockingConnection(server.url, timeout=self.timeout)
+        client = SyncRequestResponse(connection)
+        try:
+            test("foo")         # Simple request/resposne
+        finally:
+            client.connection.close()
+        server.join(timeout=self.timeout)
+
+
+    def test_connection_properties(self):
+        ensureCanTestExtendedSASL()
+        server = ConnPropertiesServer(Url(host="127.0.0.1", port=free_tcp_port()), timeout=self.timeout)
+        server.start()
+        server.wait()
+        connection = BlockingConnection(server.url, timeout=self.timeout, properties=CONNECTION_PROPERTIES, offered_capabilities=OFFERED_CAPABILITIES, desired_capabilities=DESIRED_CAPABILITIES)
+        client = SyncRequestResponse(connection)
+        client.connection.close()
+        server.join(timeout=self.timeout)
+        self.assertEquals(server.properties_received, True)
+        self.assertEquals(server.offered_capabilities_received, True)
+        self.assertEquals(server.desired_capabilities_received, True)
+
+    def test_allowed_mechs_external(self):
+        # All this test does it make sure that if we pass allowed_mechs to BlockingConnection, it is actually used.
+        port = free_tcp_port()
+        server = ConnPropertiesServer(Url(host="127.0.0.1", port=port), timeout=self.timeout)
+        server.start()
+        server.wait()
+        try:
+            # This will cause an exception because we are specifying allowed_mechs as EXTERNAL. The SASL handshake will fail because the server is not setup to handle EXTERNAL
+            connection = BlockingConnection(server.url, timeout=self.timeout, properties=CONNECTION_PROPERTIES, offered_capabilities=OFFERED_CAPABILITIES, desired_capabilities=DESIRED_CAPABILITIES, allowed_mechs=EXTERNAL)
+            self.fail("Expected ConnectionException")
+        except ConnectionException as e:
+            self.assertTrue('amqp:unauthorized-access' in str(e), "expected unauthorized-access")
+        server.join(timeout=self.timeout)
+
+    def test_allowed_mechs_anonymous(self):
+        # All this test does it make sure that if we pass allowed_mechs to BlockingConnection, it is actually used.
+        server = ConnPropertiesServer(Url(host="127.0.0.1", port=free_tcp_port()), timeout=self.timeout)
+        server.start()
+        server.wait()
+        # An ANONYMOUS allowed_mechs will work, anonymous connections are allowed by ConnPropertiesServer
+        connection = BlockingConnection(server.url, timeout=self.timeout, properties=CONNECTION_PROPERTIES, offered_capabilities=OFFERED_CAPABILITIES, desired_capabilities=DESIRED_CAPABILITIES, allowed_mechs=ANONYMOUS)
+        client = SyncRequestResponse(connection)
+        client.connection.close()
+        server.join(timeout=self.timeout)
+        self.assertEquals(server.properties_received, True)
+        self.assertEquals(server.offered_capabilities_received, True)
+        self.assertEquals(server.desired_capabilities_received, True)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/tox-blacklist
----------------------------------------------------------------------
diff --git a/python/tests/tox-blacklist b/python/tests/tox-blacklist
new file mode 100644
index 0000000..3e31da8
--- /dev/null
+++ b/python/tests/tox-blacklist
@@ -0,0 +1,12 @@
+# Running *all* the python tests under tox is redundant as this is
+# already done by the python-test suite.
+# This file contains a list of the longer running tests that can be
+# skipped in order to speed up the tox test run
+
+proton_tests.soak.*
+proton_tests.engine.ServerTest.testIdleTimeout
+proton_tests.engine.ServerTest.testKeepalive
+proton_tests.messenger.IdleTimeoutTest.testIdleTimeout
+proton_tests.messenger.MessengerTest.testCreditBlockingRebalance
+proton_tests.messenger.NBMessengerTest.testCreditReplenish
+proton_tests.messenger.NBMessengerTest.testRecvBeforeSubscribe

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tox.ini.in
----------------------------------------------------------------------
diff --git a/python/tox.ini.in b/python/tox.ini.in
new file mode 100644
index 0000000..c514078
--- /dev/null
+++ b/python/tox.ini.in
@@ -0,0 +1,26 @@
+[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@/python/tests/proton-test '{posargs:--ignore-file=@CMAKE_SOURCE_DIR@/python/tests/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/scripts/jenkins-proton-c-build.sh
----------------------------------------------------------------------
diff --git a/scripts/jenkins-proton-c-build.sh b/scripts/jenkins-proton-c-build.sh
index 8b710c1..1af4a45 100755
--- a/scripts/jenkins-proton-c-build.sh
+++ b/scripts/jenkins-proton-c-build.sh
@@ -69,7 +69,7 @@ $RUN_TOX && ctest -V -R 'python-tox-test'
 source config.sh
 
 # proton-c tests via python
-python ../tests/python/proton-test --xml=${XMLOUTPUT}
+python ../python/tests/proton-test --xml=${XMLOUTPUT}
 
 # proton-c native c-* tests
 ctest -V -R '^c-*'

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/interop-generate
----------------------------------------------------------------------
diff --git a/tests/python/interop-generate b/tests/python/interop-generate
deleted file mode 100755
index 9c360a6..0000000
--- a/tests/python/interop-generate
+++ /dev/null
@@ -1,150 +0,0 @@
-#!/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/tests/python/proton-test
----------------------------------------------------------------------
diff --git a/tests/python/proton-test b/tests/python/proton-test
deleted file mode 100755
index 951fea8..0000000
--- a/tests/python/proton-test
+++ /dev/null
@@ -1,711 +0,0 @@
-#!/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/tests/python/proton_tests/__init__.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/__init__.py b/tests/python/proton_tests/__init__.py
deleted file mode 100644
index 66792f5..0000000
--- a/tests/python/proton_tests/__init__.py
+++ /dev/null
@@ -1,31 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-# 
-#   http://www.apache.org/licenses/LICENSE-2.0
-# 
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-import 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/tests/python/proton_tests/codec.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/codec.py b/tests/python/proton_tests/codec.py
deleted file mode 100644
index e13dcfe..0000000
--- a/tests/python/proton_tests/codec.py
+++ /dev/null
@@ -1,401 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-# 
-#   http://www.apache.org/licenses/LICENSE-2.0
-# 
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-import 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/tests/python/proton_tests/common.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/common.py b/tests/python/proton_tests/common.py
deleted file mode 100644
index 90ba34c..0000000
--- a/tests/python/proton_tests/common.py
+++ /dev/null
@@ -1,510 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-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-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


Mime
View raw message