You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ac...@apache.org on 2018/07/06 16:59:13 UTC
[01/11] qpid-proton git commit: PROTON-1798: [c,
cpp] self-contained test scripts.
Repository: qpid-proton
Updated Branches:
refs/heads/master ea315ff04 -> 9778eda8e
PROTON-1798: [c,cpp] self-contained test scripts.
Simplify python test scripts for C and C++, get rid of the proctest.py common
library. Each test script is now self-contained using only standard python 2.7.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/e2858e6a
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/e2858e6a
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/e2858e6a
Branch: refs/heads/master
Commit: e2858e6afd15581d8f8b029ce76a175bb5ea41da
Parents: ea315ff
Author: Alan Conway <ac...@redhat.com>
Authored: Wed Jul 4 15:43:16 2018 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Fri Jul 6 12:16:32 2018 -0400
----------------------------------------------------------------------
c/examples/CMakeLists.txt | 6 +-
c/examples/broker.c | 4 +-
c/examples/direct.c | 4 +-
c/examples/example_test.py | 77 ++++++-------
c/examples/receive.c | 2 +-
c/tests/CMakeLists.txt | 2 -
c/tests/fdlimit.py | 44 +++-----
cpp/examples/CMakeLists.txt | 6 +-
cpp/examples/broker.cpp | 13 +--
cpp/examples/example_test.py | 167 +++++++++++-----------------
tools/python/proctest.py | 227 --------------------------------------
11 files changed, 121 insertions(+), 431 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/e2858e6a/c/examples/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/c/examples/CMakeLists.txt b/c/examples/CMakeLists.txt
index 6f732a6..17438d0 100644
--- a/c/examples/CMakeLists.txt
+++ b/c/examples/CMakeLists.txt
@@ -53,12 +53,8 @@ macro(set_search_path result)
file(TO_NATIVE_PATH "${${result}}" ${result}) # native slash separators
endmacro()
-# Add the tools directory for the 'proctest' module
-set_search_path(EXAMPLE_PYTHONPATH "${CMAKE_SOURCE_DIR}/tools/python" "$ENV{PYTHON_PATH}")
-set(EXAMPLE_ENV "PYTHONPATH=${EXAMPLE_PYTHONPATH}")
-
add_test(
NAME c-example-tests
- COMMAND ${PN_ENV_SCRIPT} ${EXAMPLE_ENV} "PATH=${test_path}" ${VALGRIND_ENV} --
+ COMMAND ${PN_ENV_SCRIPT} "PATH=${test_path}" ${VALGRIND_ENV} --
${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example_test.py -v
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/e2858e6a/c/examples/broker.c
----------------------------------------------------------------------
diff --git a/c/examples/broker.c b/c/examples/broker.c
index dcb0158..d2591df 100644
--- a/c/examples/broker.c
+++ b/c/examples/broker.c
@@ -364,8 +364,8 @@ static void handle(broker_t* b, pn_event_t* e) {
m->start = (char*)realloc(m->start, m->size);
recv = pn_link_recv(l, m->start, m->size);
if (recv == PN_ABORTED) { /* */
- fprintf(stderr, "Message aborted\n");
- fflush(stderr);
+ printf("Message aborted\n");
+ fflush(stdout);
m->size = 0; /* Forget the data we accumulated */
pn_delivery_settle(d); /* Free the delivery so we can receive the next message */
pn_link_flow(l, WINDOW - pn_link_credit(l)); /* Replace credit for the aborted message */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/e2858e6a/c/examples/direct.c
----------------------------------------------------------------------
diff --git a/c/examples/direct.c b/c/examples/direct.c
index fd0c3a4..a990663 100644
--- a/c/examples/direct.c
+++ b/c/examples/direct.c
@@ -132,8 +132,8 @@ static void handle_receive(app_data_t *app, pn_event_t* event) {
m->start = (char*)realloc(m->start, m->size);
recv = pn_link_recv(l, m->start, m->size);
if (recv == PN_ABORTED) {
- fprintf(stderr, "Message aborted\n");
- fflush(stderr);
+ printf("Message aborted\n");
+ fflush(stdout);
m->size = 0; /* Forget the data we accumulated */
pn_delivery_settle(d); /* Free the delivery so we can receive the next message */
pn_link_flow(l, 1); /* Replace credit for aborted message */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/e2858e6a/c/examples/example_test.py
----------------------------------------------------------------------
diff --git a/c/examples/example_test.py b/c/examples/example_test.py
index 25a089b..f7aa911 100644
--- a/c/examples/example_test.py
+++ b/c/examples/example_test.py
@@ -17,112 +17,99 @@
# under the License
#
-# This is a test script to run the examples and verify that they behave as expected.
+# Run the C examples and verify that they behave as expected.
+# Example executables must be in PATH
-import unittest, sys, time
-from proctest import *
-
-def python_cmd(name):
- dir = os.path.dirname(__file__)
- return [sys.executable, os.path.join(dir, "..", "..", "python", name)]
+import unittest, sys, time, re
+from subprocess import Popen, PIPE, check_output, CalledProcessError, STDOUT
MESSAGES=10
def receive_expect_messages(n=MESSAGES): return ''.join(['{"sequence"=%s}\n'%i for i in range(1, n+1)])
def receive_expect_total(n=MESSAGES): return "%s messages received\n"%n
def receive_expect(n=MESSAGES): return receive_expect_messages(n)+receive_expect_total(n)
-
def send_expect(n=MESSAGES): return "%s messages sent and acknowledged\n" % n
def send_abort_expect(n=MESSAGES): return "%s messages started and aborted\n" % n
-def wait_listening(proc):
- m = proc.wait_re("listening on ([0-9]+)$")
- return m.group(1), m.group(0)+"\n" # Return (port, line)
+def wait_listening(p):
+ return re.search("listening on ([0-9]+)$", p.stdout.readline()).group(1)
-class Broker(object):
- def __init__(self, test):
- self.test = test
+class Broker(Popen):
+ def __init__(self):
+ super(Broker, self).__init__(["broker", "", "0"], stdout=PIPE)
def __enter__(self):
- self.proc = self.test.proc(["broker", "", "0"])
- self.port, _ = wait_listening(self.proc)
+ self.port = wait_listening(self)
return self
def __exit__(self, *args):
- b = getattr(self, "proc")
- if b:
- if b.poll() != None: # Broker crashed
- raise ProcError(b, "broker crash")
- b.kill()
+ self.kill()
-class CExampleTest(ProcTestCase):
+class ExampleTest(unittest.TestCase):
def runex(self, name, port, messages=MESSAGES):
"""Run an example with standard arguments, return output"""
- return self.proc([name, "", str(port), "xtest", str(messages)]).wait_exit()
+ return check_output([name, "", str(port), "xtest", str(messages)], stderr=STDOUT)
def test_send_receive(self):
"""Send first then receive"""
- with Broker(self) as b:
+ with Broker() as b:
self.assertEqual(send_expect(), self.runex("send", b.port))
self.assertMultiLineEqual(receive_expect(), self.runex("receive", b.port))
def test_receive_send(self):
"""Start receiving first, then send."""
- with Broker(self) as b:
+ with Broker() as b:
self.assertEqual(send_expect(), self.runex("send", b.port))
self.assertMultiLineEqual(receive_expect(), self.runex("receive", b.port))
def test_send_direct(self):
"""Send to direct server"""
- d = self.proc(["direct", "", "0"])
- port, line = wait_listening(d)
+ d = Popen(["direct", "", "0"], stdout=PIPE)
+ port = wait_listening(d)
self.assertEqual(send_expect(), self.runex("send", port))
- self.assertMultiLineEqual(line+receive_expect(), d.wait_exit())
+ self.assertMultiLineEqual(receive_expect(), d.communicate()[0])
def test_receive_direct(self):
"""Receive from direct server"""
- d = self.proc(["direct", "", "0"])
- port, line = wait_listening(d)
+ d = Popen(["direct", "", "0"], stdout=PIPE)
+ port = wait_listening(d)
self.assertMultiLineEqual(receive_expect(), self.runex("receive", port))
- self.assertEqual(line+"10 messages sent and acknowledged\n", d.wait_exit())
+ self.assertEqual("10 messages sent and acknowledged\n", d.communicate()[0])
def test_send_abort_broker(self):
"""Sending aborted messages to a broker"""
- with Broker(self) as b:
+ with Broker() as b:
self.assertEqual(send_expect(), self.runex("send", b.port))
self.assertEqual(send_abort_expect(), self.runex("send-abort", b.port))
- b.proc.wait_re("Message aborted\n"*MESSAGES)
+ for i in xrange(MESSAGES):
+ self.assertEqual("Message aborted\n", b.stdout.readline())
self.assertEqual(send_expect(), self.runex("send", b.port))
expect = receive_expect_messages(MESSAGES)+receive_expect_messages(MESSAGES)+receive_expect_total(20)
self.assertMultiLineEqual(expect, self.runex("receive", b.port, "20"))
def test_send_abort_direct(self):
"""Send aborted messages to the direct server"""
- d = self.proc(["direct", "", "0", "examples", "20"])
- port, line = wait_listening(d)
- expect = line
+ d = Popen(["direct", "", "0", "examples", "20"], stdout=PIPE)
+ port = wait_listening(d)
self.assertEqual(send_expect(), self.runex("send", port))
- expect += receive_expect_messages()
- d.wait_re(expect)
self.assertEqual(send_abort_expect(), self.runex("send-abort", port))
- expect += "Message aborted\n"*MESSAGES
- d.wait_re(expect)
self.assertEqual(send_expect(), self.runex("send", port))
- expect += receive_expect_messages()+receive_expect_total(20)
+ expect = receive_expect_messages() + "Message aborted\n"*MESSAGES + receive_expect_messages()+receive_expect_total(20)
self.maxDiff = None
- self.assertMultiLineEqual(expect, d.wait_exit())
+ self.assertMultiLineEqual(expect, d.communicate()[0])
def test_send_ssl_receive(self):
"""Send with SSL, then receive"""
try:
- with Broker(self) as b:
+ with Broker() as b:
got = self.runex("send-ssl", b.port)
self.assertIn("secure connection:", got)
self.assertIn(send_expect(), got)
self.assertMultiLineEqual(receive_expect(), self.runex("receive", b.port))
- except ProcError as e:
- if e.out.startswith("error initializing SSL"):
+ except CalledProcessError as e:
+ print "FIXME", e.output
+ if e.output.startswith("error initializing SSL"):
print("Skipping %s: SSL not available" % self.id())
else:
raise
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/e2858e6a/c/examples/receive.c
----------------------------------------------------------------------
diff --git a/c/examples/receive.c b/c/examples/receive.c
index 8280345..c70e0d8 100644
--- a/c/examples/receive.c
+++ b/c/examples/receive.c
@@ -105,7 +105,7 @@ static bool handle(app_data_t* app, pn_event_t* event) {
m->start = (char*)realloc(m->start, m->size);
recv = pn_link_recv(l, m->start + oldsize, m->size);
if (recv == PN_ABORTED) {
- fprintf(stderr, "Message aborted\n");
+ printf("Message aborted\n");
m->size = 0; /* Forget the data we accumulated */
pn_delivery_settle(d); /* Free the delivery so we can receive the next message */
pn_link_flow(l, 1); /* Replace credit for aborted message */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/e2858e6a/c/tests/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/c/tests/CMakeLists.txt b/c/tests/CMakeLists.txt
index 7283c87..c79cda4 100644
--- a/c/tests/CMakeLists.txt
+++ b/c/tests/CMakeLists.txt
@@ -78,8 +78,6 @@ if(HAS_PROACTOR)
else(WIN32)
set(path "$<TARGET_FILE_DIR:c-broker>:$ENV{PATH}")
endif(WIN32)
- # Add the tools directory for the 'proctest' module
- set_search_path(pypath "${CMAKE_SOURCE_DIR}/tools/python" "$ENV{PYTHON_PATH}")
add_test(NAME c-fdlimit-tests COMMAND ${PN_ENV_SCRIPT} -- "PATH=${path}" "PYTHONPATH=${pypath}" ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/fdlimit.py)
endif(HAS_PROACTOR)
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/e2858e6a/c/tests/fdlimit.py
----------------------------------------------------------------------
diff --git a/c/tests/fdlimit.py b/c/tests/fdlimit.py
index 57faef8..4836140 100644
--- a/c/tests/fdlimit.py
+++ b/c/tests/fdlimit.py
@@ -18,28 +18,23 @@
#
from __future__ import print_function
-from proctest import *
+import os, sys
+from subprocess import Popen, PIPE
-def wait_listening(proc):
- m = proc.wait_re("listening on ([0-9]+)$")
- return m.group(1), m.group(0)+"\n" # Return (port, line)
+def wait_listening(p):
+ return re.search("listening on ([0-9]+)$", p.stdout.readline()).group(1)
-class LimitedBroker(object):
- def __init__(self, test, fdlimit):
- self.test = test
+class LimitedBroker(Popen):
+ def __init__(self, fdlimit):
+ super(LimitedBroker, self).__init__(["broker", "", "0"], stdout=PIPE, stderr=open(os.devnull))
self.fdlimit = fdlimit
def __enter__(self):
- self.proc = self.test.proc(["broker", "", "0"])
- self.port, _ = wait_listening(self.proc)
+ self.port = wait_listening(self)
return self
def __exit__(self, *args):
- b = getattr(self, "proc")
- if b:
- if b.poll() not in [1, None]: # Broker crashed or got expected connection error
- raise ProcError(b, "broker crash")
- b.kill()
+ self.kill()
# Check if we can run prlimit to control resources
try:
@@ -50,36 +45,27 @@ except:
class FdLimitTest(ProcTestCase):
- def proc(self, *args, **kwargs):
- """Skip valgrind for all processes started by this test"""
- return super(FdLimitTest, self).proc(*args, valgrind=False, **kwargs)
-
def test_fd_limit_broker(self):
"""Check behaviour when running out of file descriptors on accept"""
# Not too many FDs but not too few either, some are used for system purposes.
fdlimit = 256
- with LimitedBroker(self, fdlimit) as b:
+ with LimitedBroker(fdlimit) as b:
receivers = []
# Start enough receivers to use all FDs, make sure the broker logs an error
for i in range(fdlimit+1):
- receivers.append(self.proc(["receive", "", b.port, str(i)]))
-
- # Note: libuv silently swallows EMFILE/ENFILE errors so there is no error reporting.
- # The epoll proactor will close the users connection with the EMFILE/ENFILE error
- if "TRANSPORT_CLOSED" in b.proc.out:
- self.assertIn("open files", b.proc.out)
+ receivers.append(Popen(["receive", "", b.port, str(i)], stdout=PIPE))
# All FDs are now in use, send attempt should fail or hang
- self.assertIn(self.proc(["send", "", b.port, "x"]).poll(), [1, None])
+ self.assertIn(Popen(["send", "", b.port, "x"], stdout=PIPE, stderr=STDOUT).poll(), [1, None])
# Kill receivers to free up FDs
for r in receivers:
r.kill()
for r in receivers:
- r.wait_exit(expect=None)
+ r.wait()
# send/receive should succeed now
- self.assertIn("10 messages sent", self.proc(["send", "", b.port]).wait_exit())
- self.assertIn("10 messages received", self.proc(["receive", "", b.port]).wait_exit())
+ self.assertIn("10 messages sent", check_output(["send", "", b.port]))
+ self.assertIn("10 messages received", check_output(["receive", "", b.port]))
if __name__ == "__main__":
main()
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/e2858e6a/cpp/examples/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt
index a9bde0a..8487a6b 100644
--- a/cpp/examples/CMakeLists.txt
+++ b/cpp/examples/CMakeLists.txt
@@ -113,10 +113,6 @@ macro(set_search_path result)
file(TO_NATIVE_PATH "${${result}}" ${result}) # native slash separators
endmacro()
-# Add the tools directory for the 'proctest' module
-set_search_path(EXAMPLE_PYTHONPATH "${CMAKE_SOURCE_DIR}/tools/python" "$ENV{PYTHON_PATH}")
-set(EXAMPLE_ENV "PYTHONPATH=${EXAMPLE_PYTHONPATH}")
-
# Add a test with the correct environment to find test executables and valgrind.
macro(add_cpp_test name)
if(WIN32)
@@ -126,7 +122,7 @@ macro(add_cpp_test name)
endif(WIN32)
add_test(
NAME ${name}
- COMMAND ${PN_ENV_SCRIPT} ${EXAMPLE_ENV} "PATH=${test_path}" ${VALGRIND_ENV}
+ COMMAND ${PN_ENV_SCRIPT} "PATH=${test_path}" ${VALGRIND_ENV}
"HAS_CPP11=$<$<BOOL:${HAS_ENOUGH_CPP11}>:1>" -- ${ARGN}
)
endmacro()
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/e2858e6a/cpp/examples/broker.cpp
----------------------------------------------------------------------
diff --git a/cpp/examples/broker.cpp b/cpp/examples/broker.cpp
index 47d6109..479ec01 100644
--- a/cpp/examples/broker.cpp
+++ b/cpp/examples/broker.cpp
@@ -44,10 +44,6 @@
#if PN_CPP_HAS_STD_THREAD
#include <thread>
-
-int hardware_concurrency() {return std::thread::hardware_concurrency();}
-#else
-int hardware_concurrency() {return 1;}
#endif
#include "fake_cpp11.hpp"
@@ -396,14 +392,9 @@ class broker {
}
void run() {
-#if PN_CPP_SUPPORTS_THREADS
- int threads = hardware_concurrency();
- std::cout << "starting " << threads << " listening threads\n";
- std::cout.flush();
- container_.run(threads);
+#if PN_CPP_HAS_STD_THREAD
+ container_.run(std::thread::hardware_concurrency());
#else
- std::cout << "no thread support - starting 1 listening thread\n";
- std::cout.flush();
container_.run();
#endif
}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/e2858e6a/cpp/examples/example_test.py
----------------------------------------------------------------------
diff --git a/cpp/examples/example_test.py b/cpp/examples/example_test.py
index b9f0621..b83540f 100644
--- a/cpp/examples/example_test.py
+++ b/cpp/examples/example_test.py
@@ -17,20 +17,13 @@
# under the License
#
-# This is a test script to run the examples and verify that they behave as expected.
-
-import unittest
-import os, sys, socket, time, re, inspect
-from proctest import *
-from random import randrange
-from subprocess import Popen, PIPE, STDOUT, call
-from copy import copy
-import platform
-from os.path import dirname as dirname
-from threading import Thread, Event
-from string import Template
+# Run the C++ examples and verify that they behave as expected.
+# Example executables must be in PATH
-createdSASLDb = False
+import unittest, sys, time, re, shutil, os
+from subprocess import Popen, PIPE, STDOUT, check_output, check_call
+from os.path import dirname
+from string import Template
def _cyrusSetup(conf_dir):
"""Write out simple SASL config.tests
@@ -41,52 +34,31 @@ def _cyrusSetup(conf_dir):
mech_list: EXTERNAL DIGEST-MD5 SCRAM-SHA-1 CRAM-MD5 PLAIN ANONYMOUS
""")
abs_conf_dir = os.path.abspath(conf_dir)
- call(args=['rm','-rf',abs_conf_dir])
+ shutil.rmtree(abs_conf_dir, True)
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()
-
+ with open(conf, 'w') as f:
+ f.write(t.substitute(db=db))
cmd_template = Template("echo password | ${saslpasswd} -c -p -f ${db} -u proton user")
cmd = cmd_template.substitute(db=db, saslpasswd=saslpasswd)
- call(args=cmd, shell=True)
-
+ check_call(args=cmd, shell=True)
os.environ['PN_SASL_CONFIG_PATH'] = abs_conf_dir
- global createdSASLDb
- createdSASLDb = True
# Globally initialize Cyrus SASL configuration
_cyrusSetup('sasl-conf')
-def wait_listening(proc):
- m = proc.wait_re(".*listening on ([0-9]+)$")
- return m.group(1), m.group(0)+"\n" # Return (port, line)
-
-class BrokerTestCase(ProcTestCase):
- """
- ExampleTest that starts a broker in setUpClass and kills it in tearDownClass.
- Subclasses must set `broker_exe` class variable with the name of the broker executable.
- """
- @classmethod
- def setUpClass(cls):
- cls.broker = None # In case Proc throws, create the attribute.
- cls.broker = Proc([cls.broker_exe, "-a", "//:0"])
- cls.port, line = wait_listening(cls.broker)
- cls.addr = "//:%s/example" % cls.port
-
- @classmethod
- def tearDownClass(cls):
- if cls.broker:
- cls.broker.kill()
-
- def tearDown(self):
- b = type(self).broker
- if b and b.poll() != None: # Broker crashed
- type(self).setUpClass() # Start another for the next test.
- raise ProcError(b, "broker crash")
- super(BrokerTestCase, self).tearDown()
+def wait_listening(p):
+ return re.search("listening on ([0-9]+)$", p.stdout.readline()).group(1)
+
+class Broker(Popen):
+ port = None
+ def __init__(self):
+ super(Broker, self).__init__(["broker", "-a", "//:0"], stdout=PIPE, stderr=open(os.devnull))
+ Broker.port = wait_listening(self)
+ Broker.addr = "amqp://:%s/example" % self.port
+ def __enter__(self): return self
+ def __exit__(self, *args): self.kill()
CLIENT_EXPECT="""Twas brillig, and the slithy toves => TWAS BRILLIG, AND THE SLITHY TOVES
@@ -98,51 +70,52 @@ And the mome raths outgrabe. => AND THE MOME RATHS OUTGRABE.
def recv_expect():
return "".join(['{"sequence"=%s}\n' % (i+1) for i in range(100)])
-class ContainerExampleTest(BrokerTestCase):
+class ContainerExampleTest(unittest.TestCase):
"""Run the container examples, verify they behave as expected."""
broker_exe = "broker"
def test_helloworld(self):
- self.assertMultiLineEqual('Hello World!\n', self.proc(["helloworld", self.addr]).wait_exit())
+ self.assertMultiLineEqual('Hello World!\n', check_output(["helloworld", Broker.addr]))
def test_simple_send_recv(self):
- self.assertMultiLineEqual("all messages confirmed\n", self.proc(["simple_send", "-a", self.addr]).wait_exit())
- self.assertMultiLineEqual(recv_expect(), self.proc(["simple_recv", "-a", self.addr]).wait_exit())
+ self.assertMultiLineEqual("all messages confirmed\n", check_output(["simple_send", "-a", Broker.addr]))
+ self.assertMultiLineEqual(recv_expect(), check_output(["simple_recv", "-a", Broker.addr]))
def test_simple_recv_send(self):
- # Start receiver first, then run sender"""
- recv = self.proc(["simple_recv", "-a", self.addr])
- self.assertMultiLineEqual("all messages confirmed\n", self.proc(["simple_send", "-a", self.addr]).wait_exit())
- self.assertMultiLineEqual(recv_expect(), recv.wait_exit())
+ recv = Popen(["simple_recv", "-a", Broker.addr], stdout=PIPE)
+ self.assertMultiLineEqual("all messages confirmed\n", check_output(["simple_send", "-a", Broker.addr]))
+ self.assertMultiLineEqual(recv_expect(), recv.communicate()[0])
def test_simple_send_direct_recv(self):
- recv = self.proc(["direct_recv", "-a", "//:0"])
- port, line = wait_listening(recv)
- addr = "//:%s/examples" % port
- self.assertMultiLineEqual("all messages confirmed\n",
- self.proc(["simple_send", "-a", addr]).wait_exit())
- self.assertMultiLineEqual(line+recv_expect(), recv.wait_exit())
+ recv = Popen(["direct_recv", "-a", "//:0"], stdout=PIPE)
+ addr = "//:%s/examples" % wait_listening(recv)
+ self.assertMultiLineEqual("all messages confirmed\n", check_output(["simple_send", "-a", addr]))
+ self.assertMultiLineEqual(recv_expect(), recv.communicate()[0])
+
def test_simple_recv_direct_send(self):
- send = self.proc(["direct_send", "-a", "//:0"])
- port, line = wait_listening(send)
- addr = "//:%s/examples" % port
- self.assertMultiLineEqual(recv_expect(), self.proc(["simple_recv", "-a", addr]).wait_exit())
- self.assertMultiLineEqual(line+"all messages confirmed\n", send.wait_exit())
+ send = Popen(["direct_send", "-a", "//:0"], stdout=PIPE)
+ addr = "//:%s/examples" % wait_listening(send)
+ self.assertMultiLineEqual(recv_expect(), check_output(["simple_recv", "-a", addr]))
+ self.assertMultiLineEqual("all messages confirmed\n", send.communicate()[0])
def test_request_response(self):
- server = self.proc(["server", self.addr, "example"]) # self.addr has the connection info
- server.wait_re("connected")
- self.assertMultiLineEqual(CLIENT_EXPECT,
- self.proc(["client", "-a", self.addr]).wait_exit())
+ server = Popen(["server", Broker.addr, "example"], stdout=PIPE)
+ self.assertIn("connected to", server.stdout.readline())
+ try:
+ self.assertMultiLineEqual(CLIENT_EXPECT, check_output(["client", "-a", Broker.addr]))
+ finally:
+ server.kill()
def test_request_response_direct(self):
- server = self.proc(["server_direct", "-a", "//:0"])
- port, line = wait_listening(server);
- addr = "//:%s/examples" % port
- self.assertMultiLineEqual(CLIENT_EXPECT, self.proc(["client", "-a", addr]).wait_exit())
+ server = Popen(["server_direct", "-a", "//:0"], stdout=PIPE)
+ addr = "//:%s/examples" % wait_listening(server);
+ try:
+ self.assertMultiLineEqual(CLIENT_EXPECT, check_output(["client", "-a", addr]))
+ finally:
+ server.kill()
def test_flow_control(self):
want="""success: Example 1: simple credit
@@ -150,7 +123,7 @@ success: Example 2: basic drain
success: Example 3: drain without credit
success: Example 4: high/low watermark
"""
- self.assertMultiLineEqual(want, self.proc(["flow_control", "--quiet"]).wait_exit())
+ self.assertMultiLineEqual(want, check_output(["flow_control", "--quiet"]))
def test_encode_decode(self):
want="""
@@ -177,17 +150,17 @@ list[int(42), boolean(0), symbol(x)]
map{string(k1):int(42), symbol(k2):boolean(0)}
"""
self.maxDiff = None
- self.assertMultiLineEqual(want, self.proc(["encode_decode"]).wait_exit())
+ self.assertMultiLineEqual(want, check_output(["encode_decode"]))
def test_scheduled_send_03(self):
# Output should be a bunch of "send" lines but can't guarantee exactly how many.
- out = self.proc(["scheduled_send_03", "-a", self.addr+"scheduled_send", "-t", "0.1", "-i", "0.001"]).wait_exit().split()
+ out = check_output(["scheduled_send_03", "-a", Broker.addr+"scheduled_send", "-t", "0.1", "-i", "0.001"]).split()
self.assertTrue(len(out) > 0);
self.assertEqual(["send"]*len(out), out)
@unittest.skipUnless(os.getenv('HAS_CPP11'), "not a C++11 build")
def test_scheduled_send(self):
- out = self.proc(["scheduled_send", "-a", self.addr+"scheduled_send", "-t", "0.1", "-i", "0.001"]).wait_exit().split()
+ out = check_output(["scheduled_send", "-a", Broker.addr+"scheduled_send", "-t", "0.1", "-i", "0.001"]).split()
self.assertTrue(len(out) > 0);
self.assertEqual(["send"]*len(out), out)
@@ -201,32 +174,25 @@ short=42 string=bar
expected conversion_error: "unexpected type, want: uint got: int"
expected conversion_error: "unexpected type, want: uint got: string"
"""
- self.assertMultiLineEqual(expect, self.proc(["message_properties"]).wait_exit())
+ self.assertMultiLineEqual(expect, check_output(["message_properties"]))
@unittest.skipUnless(os.getenv('HAS_CPP11'), "not a C++11 build")
def test_multithreaded_client(self):
- got = self.proc(["multithreaded_client", self.addr, "examples", "10"], helgrind=True).wait_exit()
+ got = check_output(["multithreaded_client", Broker.addr, "examples", "10"])
self.maxDiff = None
- self.assertRegexpMatches(got, "10 messages sent and received");
+ self.assertIn("10 messages sent and received", got);
# @unittest.skipUnless(os.getenv('HAS_CPP11'), "not a C++11 build")
@unittest.skip("Test is unstable, will enable when fixed")
def test_multithreaded_client_flow_control(self):
- got = self.proc(["multithreaded_client_flow_control", self.addr, "examples", "10", "2"], helgrind=True).wait_exit()
+ got = check_output(["multithreaded_client_flow_control", Broker.addr, "examples", "10", "2"])
self.maxDiff = None
- self.assertRegexpMatches(got, "20 messages sent and received");
+ self.assertIn("20 messages sent and received", got);
-class ContainerExampleSSLTest(BrokerTestCase):
+class ContainerExampleSSLTest(unittest.TestCase):
"""Run the SSL container examples, verify they behave as expected."""
broker_exe = "broker"
- valgrind = False # Disable for all tests, including inherited
-
- def setUp(self):
- super(ContainerExampleSSLTest, self).setUp()
-
- def tearDown(self):
- super(ContainerExampleSSLTest, self).tearDown()
def ssl_certs_dir(self):
"""Absolute path to the test SSL certificates"""
@@ -234,21 +200,18 @@ class ContainerExampleSSLTest(BrokerTestCase):
def test_ssl(self):
# SSL without SASL, VERIFY_PEER_NAME
- # Disable valgrind when using OpenSSL
- out = self.proc(["ssl", "-c", self.ssl_certs_dir()]).wait_exit()
+ out = check_output(["ssl", "-c", self.ssl_certs_dir()])
expect = "Server certificate identity CN=test_server\nHello World!"
self.assertIn(expect, out)
def test_ssl_no_name(self):
- # VERIFY_PEER
- # Disable valgrind when using OpenSSL
- out = self.proc(["ssl", "-c", self.ssl_certs_dir(), "-v", "noname"], valgrind=False).wait_exit()
+ out = check_output(["ssl", "-c", self.ssl_certs_dir(), "-v", "noname"])
expect = "Outgoing client connection connected via SSL. Server certificate identity CN=test_server\nHello World!"
self.assertIn(expect, out)
def test_ssl_bad_name(self):
# VERIFY_PEER
- out = self.proc(["ssl", "-c", self.ssl_certs_dir(), "-v", "fail"]).wait_exit()
+ out = check_output(["ssl", "-c", self.ssl_certs_dir(), "-v", "fail"])
expect = "Expected failure of connection with wrong peer name"
self.assertIn(expect, out)
@@ -258,9 +221,9 @@ class ContainerExampleSSLTest(BrokerTestCase):
Outgoing client connection connected via SSL. Server certificate identity CN=test_server
Hello World!
"""
- # Disable valgrind when using OpenSSL
- out = self.proc(["ssl_client_cert", self.ssl_certs_dir()]).wait_exit()
+ out = check_output(["ssl_client_cert", self.ssl_certs_dir()])
self.assertIn(expect, out)
if __name__ == "__main__":
- unittest.main()
+ with Broker():
+ unittest.main()
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/e2858e6a/tools/python/proctest.py
----------------------------------------------------------------------
diff --git a/tools/python/proctest.py b/tools/python/proctest.py
deleted file mode 100644
index 6445f95..0000000
--- a/tools/python/proctest.py
+++ /dev/null
@@ -1,227 +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
-#
-
-"""Unit test library to simplify tests that start, monitor, check and report
-output from sub-processes. Provides safe port allocation for processes that
-listen on a port. Allows executables to be run under a debugging tool like
-valgrind.
-"""
-
-import unittest
-import os, sys, socket, time, re, inspect, errno, threading, tempfile
-from random import randrange
-from subprocess import Popen, PIPE, STDOUT
-from copy import copy
-import platform
-from os.path import dirname as dirname
-
-DEFAULT_TIMEOUT=30 # Valgrind can be very slow.
-
-class ProcError(Exception):
- """An exception that displays failed process output"""
- def __init__(self, proc, what="bad exit status"):
- self.out = proc.out.strip()
- returncode = getattr(proc, 'returncode') # Can be missing in some cases
- msg = "%s (exit=%s) command:\n%s" % (what, returncode, " ".join(proc.args))
- if self.out:
- msg += "\nvvvvvvvvvvvvvvvv\n%s\n^^^^^^^^^^^^^^^^" % self.out
- else:
- msg += "\n<<no output>>"
- super(ProcError, self, ).__init__(msg)
-
-class NotFoundError(ProcError):
- pass
-
-class Proc(Popen):
- """Subclass of suprocess.Popen that stores its output and can scan it for a
- 'ready' pattern' Use self.out to access output (combined stdout and stderr).
- You can't set the Popen stdout and stderr arguments, they will be overwritten.
- """
-
- @property
- def out(self):
- self._out.seek(0)
- return self._out.read()
-
- def __init__(self, args, valgrind=True, helgrind=False, **kwargs):
- """Start an example process"""
- self.args = list(args)
- self.kwargs = kwargs
- self._out = tempfile.TemporaryFile(mode='w+')
- valgrind_exe = valgrind and os.getenv("VALGRIND")
- if valgrind_exe:
- # run valgrind for speed, not for detailed information
- vg = [valgrind_exe]
- if helgrind:
- vg += ["--tool=helgrind", "--quiet", "--error-exitcode=42"]
- else:
- vg += ["--tool=memcheck"] + os.getenv("VALGRIND_ARGS").split(' ')
- self.args = vg + self.args
- if os.getenv("PROCTEST_VERBOSE"):
- sys.stderr.write("\n== running == "+" ".join(self.args)+"\n")
- try:
- Popen.__init__(self, self.args, stdout=self._out, stderr=STDOUT, **kwargs)
- except OSError as e:
- if e.errno == errno.ENOENT:
- raise NotFoundError(self, str(e))
- raise ProcError(self, str(e))
- except Exception as e:
- raise ProcError(self, str(e))
-
- def __del__(self):
- self._out.close()
-
- def kill(self):
- try:
- if self.poll() is None:
- Popen.kill(self)
- except:
- pass # Already exited.
- return self.out
-
- def wait_exit(self, timeout=DEFAULT_TIMEOUT, expect=0):
- """Wait for process to exit, return output. Raise ProcError on failure."""
- t = threading.Thread(target=self.wait)
- t.start()
- t.join(timeout)
- if self.poll() is None: # Still running
- self.kill()
- raise ProcError(self, "still running after %ss" % timeout)
- if expect is not None and self.poll() != expect:
- raise ProcError(self)
- return self.out
-
- def wait_re(self, regexp, timeout=DEFAULT_TIMEOUT):
- """
- Wait for regexp to appear in the output, returns the re.search match result.
- The target process should flush() important output to ensure it appears.
- """
- if timeout:
- deadline = time.time() + timeout
- while timeout is None or time.time() < deadline:
- match = re.search(regexp, self.out)
- if match:
- return match
- if self.poll() is not None:
- raise ProcError(self, "process exited while waiting for '%s'" % (regexp))
- time.sleep(0.01) # Not very efficient
- raise ProcError(self, "gave up waiting for '%s' after %ss" % (regexp, timeout))
-
-def _tc_missing(attr):
- return not hasattr(unittest.TestCase, attr)
-
-class ProcTestCase(unittest.TestCase):
- """TestCase that manages started processes
-
- Also roughly provides setUpClass() and tearDownClass() and other features
- missing in python 2.6. If subclasses override setUp() or tearDown() they
- *must* call the superclass.
- """
-
- def setUp(self):
- super(ProcTestCase, self).setUp()
- self.procs = []
-
- def tearDown(self):
- for p in self.procs:
- p.kill()
- super(ProcTestCase, self).tearDown()
-
- # Default value for valgrind= in proc() function if not explicitly set.
- # Override by setting a "valgrind" member in subclass or instance.
- valgrind=True
-
- def proc(self, *args, **kwargs):
- """Return a Proc() that will be automatically killed on teardown"""
- if 'valgrind' in kwargs:
- p = Proc(*args, **kwargs)
- else:
- p = Proc(*args, valgrind=self.valgrind, **kwargs)
- self.procs.append(p)
- return p
-
- if _tc_missing('setUpClass') and _tc_missing('tearDownClass'):
-
- @classmethod
- def setUpClass(cls):
- pass
-
- @classmethod
- def tearDownClass(cls):
- pass
-
- def setUp(self):
- super(ProcTestCase, self).setUp()
- cls = type(self)
- if not hasattr(cls, '_setup_class_count'): # First time
- def is_test(m):
- return inspect.ismethod(m) and m.__name__.startswith('test_')
- cls._setup_class_count = len(inspect.getmembers(cls, predicate=is_test))
- cls.setUpClass()
- self.procs = []
-
- def tearDown(self):
- self.assertTrue(self._setup_class_count > 0)
- self._setup_class_count -= 1
- if self._setup_class_count == 0:
- type(self).tearDownClass()
- for p in self.procs:
- p.kill()
- super(ProcTestCase, self).tearDown()
-
- if _tc_missing('assertIn'):
- def assertIn(self, a, b):
- self.assertTrue(a in b, "%r not in %r" % (a, b))
-
- if _tc_missing('assertMultiLineEqual'):
- def assertMultiLineEqual(self, a, b):
- self.assertEqual(a, b)
-
-from functools import reduce
-
-#### Skip decorators missing in python 2.6
-
-def _id(obj):
- return obj
-
-from functools import wraps
-
-def skip(reason):
- def decorator(test):
- @wraps(test)
- def skipper(*args, **kwargs):
- print("skipped %s: %s" % (test.__name__, reason))
- return skipper
- return decorator
-
-def skipIf(cond, reason):
- if cond: return skip(reason)
- else: return _id
-
-def skipUnless(cond, reason):
- if not cond: return skip(reason)
- else: return _id
-
-if not hasattr(unittest, 'skip'): unittest.skip = skip
-if not hasattr(unittest, 'skipIf'): unittest.skipIf = skipIf
-if not hasattr(unittest, 'skipUnless'): unittest.skipUnless = skipUnless
-
-from unittest import main
-if __name__ == "__main__":
- main()
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[02/11] qpid-proton git commit: PROTON-1798: [c,
cpp] update example drivers to work with python 3
Posted by ac...@apache.org.
PROTON-1798: [c,cpp] update example drivers to work with python 3
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/b41f60d4
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/b41f60d4
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/b41f60d4
Branch: refs/heads/master
Commit: b41f60d46cb81909c349ef705c0b5ccccf402231
Parents: e2858e6
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Jul 5 14:25:40 2018 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Fri Jul 6 12:20:32 2018 -0400
----------------------------------------------------------------------
c/examples/example_test.py | 78 +++++++++++++++++++---------------
c/tests/fdlimit.py | 2 +-
cpp/examples/example_test.py | 88 ++++++++++++++++++++++-----------------
3 files changed, 94 insertions(+), 74 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b41f60d4/c/examples/example_test.py
----------------------------------------------------------------------
diff --git a/c/examples/example_test.py b/c/examples/example_test.py
index f7aa911..2cf87d8 100644
--- a/c/examples/example_test.py
+++ b/c/examples/example_test.py
@@ -21,7 +21,31 @@
# Example executables must be in PATH
import unittest, sys, time, re
-from subprocess import Popen, PIPE, check_output, CalledProcessError, STDOUT
+
+import subprocess
+
+class Server(subprocess.Popen):
+ def __init__(self, *args, **kwargs):
+ self.kill_me = kwargs.pop('kill_me', False)
+ kwargs.update({'universal_newlines': True,
+ 'stdout': subprocess.PIPE,
+ 'stderr': subprocess.STDOUT})
+ super(Server, self).__init__(*args, **kwargs)
+
+ def __enter__(self):
+ line = self.stdout.readline()
+ self.port = re.search("listening on ([0-9]+)$", line).group(1)
+ return self
+
+ def __exit__(self, *args):
+ if self.kill_me:
+ self.kill()
+ self.stdout.close() # Doesn't get closed if killed
+ self.wait()
+
+def check_output(*args, **kwargs):
+ kwargs.update({'universal_newlines': True})
+ return subprocess.check_output(*args, **kwargs)
MESSAGES=10
@@ -31,25 +55,15 @@ def receive_expect(n=MESSAGES): return receive_expect_messages(n)+receive_expect
def send_expect(n=MESSAGES): return "%s messages sent and acknowledged\n" % n
def send_abort_expect(n=MESSAGES): return "%s messages started and aborted\n" % n
-def wait_listening(p):
- return re.search("listening on ([0-9]+)$", p.stdout.readline()).group(1)
-
-class Broker(Popen):
+class Broker(Server):
def __init__(self):
- super(Broker, self).__init__(["broker", "", "0"], stdout=PIPE)
-
- def __enter__(self):
- self.port = wait_listening(self)
- return self
-
- def __exit__(self, *args):
- self.kill()
+ super(Broker, self).__init__(["broker", "", "0"], kill_me=True)
class ExampleTest(unittest.TestCase):
def runex(self, name, port, messages=MESSAGES):
"""Run an example with standard arguments, return output"""
- return check_output([name, "", str(port), "xtest", str(messages)], stderr=STDOUT)
+ return check_output([name, "", port, "xtest", str(messages)])
def test_send_receive(self):
"""Send first then receive"""
@@ -65,24 +79,22 @@ class ExampleTest(unittest.TestCase):
def test_send_direct(self):
"""Send to direct server"""
- d = Popen(["direct", "", "0"], stdout=PIPE)
- port = wait_listening(d)
- self.assertEqual(send_expect(), self.runex("send", port))
- self.assertMultiLineEqual(receive_expect(), d.communicate()[0])
+ with Server(["direct", "", "0"]) as d:
+ self.assertEqual(send_expect(), self.runex("send", d.port))
+ self.assertMultiLineEqual(receive_expect(), d.communicate()[0])
def test_receive_direct(self):
"""Receive from direct server"""
- d = Popen(["direct", "", "0"], stdout=PIPE)
- port = wait_listening(d)
- self.assertMultiLineEqual(receive_expect(), self.runex("receive", port))
- self.assertEqual("10 messages sent and acknowledged\n", d.communicate()[0])
+ with Server(["direct", "", "0"]) as d:
+ self.assertMultiLineEqual(receive_expect(), self.runex("receive", d.port))
+ self.assertEqual("10 messages sent and acknowledged\n", d.communicate()[0])
def test_send_abort_broker(self):
"""Sending aborted messages to a broker"""
with Broker() as b:
self.assertEqual(send_expect(), self.runex("send", b.port))
self.assertEqual(send_abort_expect(), self.runex("send-abort", b.port))
- for i in xrange(MESSAGES):
+ for i in range(MESSAGES):
self.assertEqual("Message aborted\n", b.stdout.readline())
self.assertEqual(send_expect(), self.runex("send", b.port))
expect = receive_expect_messages(MESSAGES)+receive_expect_messages(MESSAGES)+receive_expect_total(20)
@@ -90,14 +102,13 @@ class ExampleTest(unittest.TestCase):
def test_send_abort_direct(self):
"""Send aborted messages to the direct server"""
- d = Popen(["direct", "", "0", "examples", "20"], stdout=PIPE)
- port = wait_listening(d)
- self.assertEqual(send_expect(), self.runex("send", port))
- self.assertEqual(send_abort_expect(), self.runex("send-abort", port))
- self.assertEqual(send_expect(), self.runex("send", port))
- expect = receive_expect_messages() + "Message aborted\n"*MESSAGES + receive_expect_messages()+receive_expect_total(20)
- self.maxDiff = None
- self.assertMultiLineEqual(expect, d.communicate()[0])
+ with Server(["direct", "", "0", "examples", "20"]) as d:
+ self.assertEqual(send_expect(), self.runex("send", d.port))
+ self.assertEqual(send_abort_expect(), self.runex("send-abort", d.port))
+ self.assertEqual(send_expect(), self.runex("send", d.port))
+ expect = receive_expect_messages() + "Message aborted\n"*MESSAGES + receive_expect_messages()+receive_expect_total(20)
+ self.maxDiff = None
+ self.assertMultiLineEqual(expect, d.communicate()[0])
def test_send_ssl_receive(self):
"""Send with SSL, then receive"""
@@ -107,9 +118,8 @@ class ExampleTest(unittest.TestCase):
self.assertIn("secure connection:", got)
self.assertIn(send_expect(), got)
self.assertMultiLineEqual(receive_expect(), self.runex("receive", b.port))
- except CalledProcessError as e:
- print "FIXME", e.output
- if e.output.startswith("error initializing SSL"):
+ except subprocess.CalledProcessError as e:
+ if e.output.startswith(b"error initializing SSL"):
print("Skipping %s: SSL not available" % self.id())
else:
raise
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b41f60d4/c/tests/fdlimit.py
----------------------------------------------------------------------
diff --git a/c/tests/fdlimit.py b/c/tests/fdlimit.py
index 4836140..e5cedac 100644
--- a/c/tests/fdlimit.py
+++ b/c/tests/fdlimit.py
@@ -22,7 +22,7 @@ import os, sys
from subprocess import Popen, PIPE
def wait_listening(p):
- return re.search("listening on ([0-9]+)$", p.stdout.readline()).group(1)
+ return re.search(b"listening on ([0-9]+)$", p.stdout.readline()).group(1)
class LimitedBroker(Popen):
def __init__(self, fdlimit):
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b41f60d4/cpp/examples/example_test.py
----------------------------------------------------------------------
diff --git a/cpp/examples/example_test.py b/cpp/examples/example_test.py
index b83540f..e287ba5 100644
--- a/cpp/examples/example_test.py
+++ b/cpp/examples/example_test.py
@@ -21,10 +21,40 @@
# Example executables must be in PATH
import unittest, sys, time, re, shutil, os
-from subprocess import Popen, PIPE, STDOUT, check_output, check_call
from os.path import dirname
from string import Template
+import subprocess
+
+class Server(subprocess.Popen):
+ def __init__(self, *args, **kwargs):
+ self.port = None
+ self.kill_me = kwargs.pop('kill_me', False)
+ kwargs.update({'universal_newlines': True,
+ 'stdout': subprocess.PIPE,
+ 'stderr': subprocess.STDOUT})
+ super(Server, self).__init__(*args, **kwargs)
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *args):
+ if self.kill_me:
+ self.kill()
+ self.stdout.close() # Doesn't get closed if killed
+ self.wait()
+
+ @property
+ def addr(self):
+ if not self.port:
+ line = self.stdout.readline()
+ self.port = re.search("listening on ([0-9]+)$", line).group(1)
+ return ":%s/example" % self.port
+
+def check_output(*args, **kwargs):
+ kwargs.update({'universal_newlines': True})
+ return subprocess.check_output(*args, **kwargs)
+
def _cyrusSetup(conf_dir):
"""Write out simple SASL config.tests
"""
@@ -42,24 +72,18 @@ mech_list: EXTERNAL DIGEST-MD5 SCRAM-SHA-1 CRAM-MD5 PLAIN ANONYMOUS
f.write(t.substitute(db=db))
cmd_template = Template("echo password | ${saslpasswd} -c -p -f ${db} -u proton user")
cmd = cmd_template.substitute(db=db, saslpasswd=saslpasswd)
- check_call(args=cmd, shell=True)
+ check_output(args=cmd, shell=True)
os.environ['PN_SASL_CONFIG_PATH'] = abs_conf_dir
# Globally initialize Cyrus SASL configuration
_cyrusSetup('sasl-conf')
def wait_listening(p):
- return re.search("listening on ([0-9]+)$", p.stdout.readline()).group(1)
-
-class Broker(Popen):
- port = None
- def __init__(self):
- super(Broker, self).__init__(["broker", "-a", "//:0"], stdout=PIPE, stderr=open(os.devnull))
- Broker.port = wait_listening(self)
- Broker.addr = "amqp://:%s/example" % self.port
- def __enter__(self): return self
- def __exit__(self, *args): self.kill()
+ return re.search(b"listening on ([0-9]+)$", p.stdout.readline()).group(1)
+class Broker(Server):
+ def __init__(self):
+ super(Broker, self).__init__(["broker", "-a", "//:0"], kill_me=True)
CLIENT_EXPECT="""Twas brillig, and the slithy toves => TWAS BRILLIG, AND THE SLITHY TOVES
Did gire and gymble in the wabe. => DID GIRE AND GYMBLE IN THE WABE.
@@ -73,49 +97,36 @@ def recv_expect():
class ContainerExampleTest(unittest.TestCase):
"""Run the container examples, verify they behave as expected."""
- broker_exe = "broker"
-
def test_helloworld(self):
- self.assertMultiLineEqual('Hello World!\n', check_output(["helloworld", Broker.addr]))
+ self.assertMultiLineEqual('Hello World!\n', check_output(["helloworld", Broker.addr]))
def test_simple_send_recv(self):
self.assertMultiLineEqual("all messages confirmed\n", check_output(["simple_send", "-a", Broker.addr]))
self.assertMultiLineEqual(recv_expect(), check_output(["simple_recv", "-a", Broker.addr]))
def test_simple_recv_send(self):
- recv = Popen(["simple_recv", "-a", Broker.addr], stdout=PIPE)
+ recv = Server(["simple_recv", "-a", Broker.addr])
self.assertMultiLineEqual("all messages confirmed\n", check_output(["simple_send", "-a", Broker.addr]))
self.assertMultiLineEqual(recv_expect(), recv.communicate()[0])
-
def test_simple_send_direct_recv(self):
- recv = Popen(["direct_recv", "-a", "//:0"], stdout=PIPE)
- addr = "//:%s/examples" % wait_listening(recv)
- self.assertMultiLineEqual("all messages confirmed\n", check_output(["simple_send", "-a", addr]))
+ recv = Server(["direct_recv", "-a", "//:0"])
+ self.assertMultiLineEqual("all messages confirmed\n", check_output(["simple_send", "-a", recv.addr]))
self.assertMultiLineEqual(recv_expect(), recv.communicate()[0])
-
def test_simple_recv_direct_send(self):
- send = Popen(["direct_send", "-a", "//:0"], stdout=PIPE)
- addr = "//:%s/examples" % wait_listening(send)
- self.assertMultiLineEqual(recv_expect(), check_output(["simple_recv", "-a", addr]))
+ send = Server(["direct_send", "-a", "//:0"])
+ self.assertMultiLineEqual(recv_expect(), check_output(["simple_recv", "-a", send.addr]))
self.assertMultiLineEqual("all messages confirmed\n", send.communicate()[0])
def test_request_response(self):
- server = Popen(["server", Broker.addr, "example"], stdout=PIPE)
- self.assertIn("connected to", server.stdout.readline())
- try:
+ with Server(["server", Broker.addr, "example"], kill_me=True) as server:
+ self.assertIn("connected to", server.stdout.readline())
self.assertMultiLineEqual(CLIENT_EXPECT, check_output(["client", "-a", Broker.addr]))
- finally:
- server.kill()
def test_request_response_direct(self):
- server = Popen(["server_direct", "-a", "//:0"], stdout=PIPE)
- addr = "//:%s/examples" % wait_listening(server);
- try:
- self.assertMultiLineEqual(CLIENT_EXPECT, check_output(["client", "-a", addr]))
- finally:
- server.kill()
+ with Server(["server_direct", "-a", "//:0"], kill_me=True) as server:
+ self.assertMultiLineEqual(CLIENT_EXPECT, check_output(["client", "-a", server.addr]))
def test_flow_control(self):
want="""success: Example 1: simple credit
@@ -192,8 +203,6 @@ expected conversion_error: "unexpected type, want: uint got: string"
class ContainerExampleSSLTest(unittest.TestCase):
"""Run the SSL container examples, verify they behave as expected."""
- broker_exe = "broker"
-
def ssl_certs_dir(self):
"""Absolute path to the test SSL certificates"""
return os.path.join(dirname(sys.argv[0]), "ssl-certs")
@@ -225,5 +234,6 @@ Hello World!
self.assertIn(expect, out)
if __name__ == "__main__":
- with Broker():
- unittest.main()
+ with Broker() as b:
+ Broker.addr = b.addr
+ unittest.main()
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[09/11] qpid-proton git commit: PROTON-1885: [python] move
tests/python to python/tests
Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/interop.py
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/interop.py b/python/tests/proton_tests/interop.py
new file mode 100644
index 0000000..fe62c02
--- /dev/null
+++ b/python/tests/proton_tests/interop.py
@@ -0,0 +1,147 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from proton import *
+from . import common
+import os
+
+
+def find_test_interop_dir():
+ """Find the common tests directory relative to this script"""
+ from os.path import dirname, join, abspath, isdir
+ f = dirname(dirname(dirname(dirname(abspath(__file__)))))
+ f = join(f, "tests", "interop")
+ if not isdir(f):
+ raise Exception("Cannot find tests/interop directory from "+__file__)
+ return f
+
+test_interop_dir=find_test_interop_dir()
+
+class InteropTest(common.Test):
+
+ def setUp(self):
+ self.data = Data()
+ self.message = Message()
+
+ def tearDown(self):
+ self.data = None
+
+ def get_data(self, name):
+ filename = os.path.join(test_interop_dir, name+".amqp")
+ f = open(filename,"rb")
+ try: return f.read()
+ finally: f.close()
+
+ def decode_data(self, encoded):
+ buffer = encoded
+ while buffer:
+ n = self.data.decode(buffer)
+ buffer = buffer[n:]
+ self.data.rewind()
+
+ def decode_data_file(self, name):
+ encoded = self.get_data(name)
+ self.decode_data(encoded)
+ encoded_size = self.data.encoded_size()
+ # Re-encode and verify pre-computed and actual encoded size match.
+ reencoded = self.data.encode()
+ assert encoded_size == len(reencoded), "%d != %d" % (encoded_size, len(reencoded))
+ # verify round trip bytes
+ assert reencoded == encoded, "Value mismatch: %s != %s" % (reencoded, encoded)
+
+ def decode_message_file(self, name):
+ self.message.decode(self.get_data(name))
+ body = self.message.body
+ if str(type(body)) == "<type 'org.apache.qpid.proton.amqp.Binary'>":
+ body = body.array.tostring()
+ self.decode_data(body)
+
+ def assert_next(self, type, value):
+ next_type = self.data.next()
+ assert next_type == type, "Type mismatch: %s != %s"%(
+ Data.type_names[next_type], Data.type_names[type])
+ next_value = self.data.get_object()
+ assert next_value == value, "Value mismatch: %s != %s"%(next_value, value)
+
+ def test_message(self):
+ self.decode_message_file("message")
+ self.assert_next(Data.STRING, "hello")
+ assert self.data.next() is None
+
+ def test_primitives(self):
+ self.decode_data_file("primitives")
+ self.assert_next(Data.BOOL, True)
+ self.assert_next(Data.BOOL, False)
+ self.assert_next(Data.UBYTE, 42)
+ self.assert_next(Data.USHORT, 42)
+ self.assert_next(Data.SHORT, -42)
+ self.assert_next(Data.UINT, 12345)
+ self.assert_next(Data.INT, -12345)
+ self.assert_next(Data.ULONG, 12345)
+ self.assert_next(Data.LONG, -12345)
+ self.assert_next(Data.FLOAT, 0.125)
+ self.assert_next(Data.DOUBLE, 0.125)
+ assert self.data.next() is None
+
+ def test_strings(self):
+ self.decode_data_file("strings")
+ self.assert_next(Data.BINARY, b"abc\0defg")
+ self.assert_next(Data.STRING, "abcdefg")
+ self.assert_next(Data.SYMBOL, "abcdefg")
+ self.assert_next(Data.BINARY, b"")
+ self.assert_next(Data.STRING, "")
+ self.assert_next(Data.SYMBOL, "")
+ assert self.data.next() is None
+
+ def test_described(self):
+ self.decode_data_file("described")
+ self.assert_next(Data.DESCRIBED, Described("foo-descriptor", "foo-value"))
+ self.data.exit()
+
+ assert self.data.next() == Data.DESCRIBED
+ self.data.enter()
+ self.assert_next(Data.INT, 12)
+ self.assert_next(Data.INT, 13)
+ self.data.exit()
+
+ assert self.data.next() is None
+
+ def test_described_array(self):
+ self.decode_data_file("described_array")
+ self.assert_next(Data.ARRAY, Array("int-array", Data.INT, *range(0,10)))
+
+ def test_arrays(self):
+ self.decode_data_file("arrays")
+ self.assert_next(Data.ARRAY, Array(UNDESCRIBED, Data.INT, *range(0,100)))
+ self.assert_next(Data.ARRAY, Array(UNDESCRIBED, Data.STRING, *["a", "b", "c"]))
+ self.assert_next(Data.ARRAY, Array(UNDESCRIBED, Data.INT))
+ assert self.data.next() is None
+
+ def test_lists(self):
+ self.decode_data_file("lists")
+ self.assert_next(Data.LIST, [32, "foo", True])
+ self.assert_next(Data.LIST, [])
+ assert self.data.next() is None
+
+ def test_maps(self):
+ self.decode_data_file("maps")
+ self.assert_next(Data.MAP, {"one":1, "two":2, "three":3 })
+ self.assert_next(Data.MAP, {1:"one", 2:"two", 3:"three"})
+ self.assert_next(Data.MAP, {})
+ assert self.data.next() is None
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/message.py
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/message.py b/python/tests/proton_tests/message.py
new file mode 100644
index 0000000..26a3dd2
--- /dev/null
+++ b/python/tests/proton_tests/message.py
@@ -0,0 +1,275 @@
+#
+# 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
+from . import common
+from proton import *
+from uuid import uuid4
+
+class Test(common.Test):
+
+ def setUp(self):
+ self.msg = Message()
+
+ def tearDown(self):
+ self.msg = None
+
+
+class AccessorsTest(Test):
+
+ def _test(self, name, default, values):
+ d = getattr(self.msg, name)
+ assert d == default, (d, default)
+ for v in values:
+ setattr(self.msg, name, v)
+ gotten = getattr(self.msg, name)
+ assert gotten == v, gotten
+
+ def _test_symbol(self, name):
+ self._test(name, symbol(None), (symbol(u"abc.123.#$%"), symbol(u"hello.world")))
+
+ def _test_str(self, name):
+ self._test(name, None, (u"asdf", u"fdsa", u""))
+
+ def _test_time(self, name):
+ self._test(name, 0, (0, 123456789, 987654321))
+
+ def testId(self):
+ self._test("id", None, ("bytes", None, 123, u"string", uuid4()))
+
+ def testCorrelationId(self):
+ self._test("correlation_id", None, ("bytes", None, 123, u"string", uuid4()))
+
+ def testDurable(self):
+ self._test("durable", False, (True, False))
+
+ def testPriority(self):
+ self._test("priority", Message.DEFAULT_PRIORITY, range(0, 255))
+
+ def testTtl(self):
+ self._test("ttl", 0, range(12345, 54321))
+
+ def testFirstAcquirer(self):
+ self._test("first_acquirer", False, (True, False))
+
+ def testDeliveryCount(self):
+ self._test("delivery_count", 0, range(0, 1024))
+
+ def testUserId(self):
+ self._test("user_id", b"", (b"asdf", b"fdsa", b"asd\x00fdsa", b""))
+
+ def testAddress(self):
+ self._test_str("address")
+
+ def testSubject(self):
+ self._test_str("subject")
+
+ def testReplyTo(self):
+ self._test_str("reply_to")
+
+ def testContentType(self):
+ self._test_symbol("content_type")
+
+ def testContentEncoding(self):
+ self._test_symbol("content_encoding")
+
+ def testExpiryTime(self):
+ self._test_time("expiry_time")
+
+ def testCreationTime(self):
+ self._test_time("creation_time")
+
+ def testGroupId(self):
+ self._test_str("group_id")
+
+ def testGroupSequence(self):
+ self._test("group_sequence", 0, (0, -10, 10, 20, -20))
+
+ def testReplyToGroupId(self):
+ self._test_str("reply_to_group_id")
+
+class CodecTest(Test):
+
+ def testProperties(self):
+ self.msg.properties = {}
+ self.msg.properties['key'] = 'value'
+ data = self.msg.encode()
+
+ msg2 = Message()
+ msg2.decode(data)
+
+ assert msg2.properties['key'] == 'value', msg2.properties['key']
+
+ def testRoundTrip(self):
+ self.msg.id = "asdf"
+ self.msg.correlation_id = uuid4()
+ self.msg.ttl = 3
+ self.msg.priority = 100
+ self.msg.address = "address"
+ self.msg.subject = "subject"
+ self.msg.body = 'Hello World!'
+
+ data = self.msg.encode()
+
+ msg2 = Message()
+ msg2.decode(data)
+
+ assert self.msg.id == msg2.id, (self.msg.id, msg2.id)
+ assert self.msg.correlation_id == msg2.correlation_id, (self.msg.correlation_id, msg2.correlation_id)
+ assert self.msg.ttl == msg2.ttl, (self.msg.ttl, msg2.ttl)
+ assert self.msg.priority == msg2.priority, (self.msg.priority, msg2.priority)
+ assert self.msg.address == msg2.address, (self.msg.address, msg2.address)
+ assert self.msg.subject == msg2.subject, (self.msg.subject, msg2.subject)
+ assert self.msg.body == msg2.body, (self.msg.body, msg2.body)
+
+ def testExpiryEncodeAsNull(self):
+ self.msg.group_id = "A" # Force creation and expiry fields to be present
+ data = self.msg.encode()
+
+ decoder = Data()
+
+ # Skip past the headers
+ consumed = decoder.decode(data)
+ decoder.clear()
+ data = data[consumed:]
+
+ decoder.decode(data)
+ dproperties = decoder.get_py_described()
+ # Check we've got the correct described list
+ assert dproperties.descriptor == 0x73, (dproperties.descriptor)
+
+ properties = dproperties.value
+ assert properties[8] == None, properties[8]
+
+ def testCreationEncodeAsNull(self):
+ self.msg.group_id = "A" # Force creation and expiry fields to be present
+ data = self.msg.encode()
+
+ decoder = Data()
+
+ # Skip past the headers
+ consumed = decoder.decode(data)
+ decoder.clear()
+ data = data[consumed:]
+
+ decoder.decode(data)
+ dproperties = decoder.get_py_described()
+ # Check we've got the correct described list
+ assert dproperties.descriptor == 0x73, (dproperties.descriptor)
+
+ properties = dproperties.value
+ assert properties[9] == None, properties[9]
+
+ def testGroupSequenceEncodeAsNull(self):
+ self.msg.reply_to_group_id = "R" # Force group_id and group_sequence fields to be present
+ data = self.msg.encode()
+
+ decoder = Data()
+
+ # Skip past the headers
+ consumed = decoder.decode(data)
+ decoder.clear()
+ data = data[consumed:]
+
+ decoder.decode(data)
+ dproperties = decoder.get_py_described()
+ # Check we've got the correct described list
+ assert dproperties.descriptor == 0x73, (dproperties.descriptor)
+
+ properties = dproperties.value
+ assert properties[10] == None, properties[10]
+ assert properties[11] == None, properties[11]
+
+ def testGroupSequenceEncodeAsNonNull(self):
+ self.msg.group_id = "G"
+ self.msg.reply_to_group_id = "R" # Force group_id and group_sequence fields to be present
+ data = self.msg.encode()
+
+ decoder = Data()
+
+ # Skip past the headers
+ consumed = decoder.decode(data)
+ decoder.clear()
+ data = data[consumed:]
+
+ decoder.decode(data)
+ dproperties = decoder.get_py_described()
+ # Check we've got the correct described list
+ assert dproperties.descriptor == 0x73, (dproperties.descriptor)
+
+ properties = dproperties.value
+ assert properties[10] == 'G', properties[10]
+ assert properties[11] == 0, properties[11]
+
+ def testDefaultCreationExpiryDecode(self):
+ # This is a message with everything filled explicitly as null or zero in LIST32 HEADER and PROPERTIES lists
+ data = b'\x00\x53\x70\xd0\x00\x00\x00\x0a\x00\x00\x00\x05\x42\x40\x40\x42\x52\x00\x00\x53\x73\xd0\x00\x00\x00\x12\x00\x00\x00\x0d\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x52\x00\x40'
+ msg2 = Message()
+ msg2.decode(data)
+ assert msg2.expiry_time == 0, (msg2.expiry_time)
+ assert msg2.creation_time == 0, (msg2.creation_time)
+
+ # The same message with LIST8s instead
+ data = b'\x00\x53\x70\xc0\x07\x05\x42\x40\x40\x42\x52\x00\x00\x53\x73\xc0\x0f\x0d\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x52\x00\x40'
+ msg3 = Message()
+ msg3.decode(data)
+ assert msg2.expiry_time == 0, (msg2.expiry_time)
+ assert msg2.creation_time == 0, (msg2.creation_time)
+
+ # Minified message with zero length HEADER and PROPERTIES lists
+ data = b'\x00\x53\x70\x45' b'\x00\x53\x73\x45'
+ msg4 = Message()
+ msg4.decode(data)
+ assert msg2.expiry_time == 0, (msg2.expiry_time)
+ assert msg2.creation_time == 0, (msg2.creation_time)
+
+ def testDefaultPriorityEncode(self):
+ assert self.msg.priority == 4, (self.msg.priority)
+ self.msg.ttl = 0.003 # field after priority, so forces priority to be present
+ data = self.msg.encode()
+
+ decoder = Data()
+ decoder.decode(data)
+
+ dheaders = decoder.get_py_described()
+ # Check we've got the correct described list
+ assert dheaders.descriptor == 0x70, (dheaders.descriptor)
+
+ # Check that the priority field (second field) is encoded as null
+ headers = dheaders.value
+ assert headers[1] == None, (headers[1])
+
+ def testDefaultPriorityDecode(self):
+ # This is a message with everything filled explicitly as null or zero in LIST32 HEADER and PROPERTIES lists
+ data = b'\x00\x53\x70\xd0\x00\x00\x00\x0a\x00\x00\x00\x05\x42\x40\x40\x42\x52\x00\x00\x53\x73\xd0\x00\x00\x00\x22\x00\x00\x00\x0d\x40\x40\x40\x40\x40\x40\x40\x40\x83\x00\x00\x00\x00\x00\x00\x00\x00\x83\x00\x00\x00\x00\x00\x00\x00\x00\x40\x52\x00\x40'
+ msg2 = Message()
+ msg2.decode(data)
+ assert msg2.priority == 4, (msg2.priority)
+
+ # The same message with LIST8s instead
+ data = b'\x00\x53\x70\xc0\x07\x05\x42\x40\x40\x42\x52\x00\x00\x53\x73\xc0\x1f\x0d\x40\x40\x40\x40\x40\x40\x40\x40\x83\x00\x00\x00\x00\x00\x00\x00\x00\x83\x00\x00\x00\x00\x00\x00\x00\x00\x40\x52\x00\x40'
+ msg3 = Message()
+ msg3.decode(data)
+ assert msg3.priority == 4, (msg3.priority)
+
+ # Minified message with zero length HEADER and PROPERTIES lists
+ data = b'\x00\x53\x70\x45' b'\x00\x53\x73\x45'
+ msg4 = Message()
+ msg4.decode(data)
+ assert msg4.priority == 4, (msg4.priority)
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/reactor.py
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/reactor.py b/python/tests/proton_tests/reactor.py
new file mode 100644
index 0000000..208baa2
--- /dev/null
+++ b/python/tests/proton_tests/reactor.py
@@ -0,0 +1,485 @@
+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.
+#
+
+import time
+import sys
+from .common import Test, SkipTest, TestServer, free_tcp_port, ensureCanTestExtendedSASL
+from proton.reactor import Container, Reactor, ApplicationEvent, EventInjector
+from proton.handlers import Handshaker, MessagingHandler
+from proton import Handler, Url
+
+class Barf(Exception):
+ pass
+
+class BarfOnInit:
+
+ def on_reactor_init(self, event):
+ raise Barf()
+
+ def on_connection_init(self, event):
+ raise Barf()
+
+ def on_session_init(self, event):
+ raise Barf()
+
+ def on_link_init(self, event):
+ raise Barf()
+
+class BarfOnTask:
+
+ def on_timer_task(self, event):
+ raise Barf()
+
+class BarfOnFinal:
+ init = False
+
+ def on_reactor_init(self, event):
+ self.init = True
+
+ def on_reactor_final(self, event):
+ raise Barf()
+
+class BarfOnFinalDerived(Handshaker):
+ init = False
+
+ def on_reactor_init(self, event):
+ self.init = True
+
+ def on_reactor_final(self, event):
+ raise Barf()
+
+class ExceptionTest(Test):
+
+ def setUp(self):
+ self.reactor = Reactor()
+
+ def test_reactor_final(self):
+ self.reactor.global_handler = BarfOnFinal()
+ try:
+ self.reactor.run()
+ assert False, "expected to barf"
+ except Barf:
+ pass
+
+ def test_global_set(self):
+ self.reactor.global_handler = BarfOnInit()
+ try:
+ self.reactor.run()
+ assert False, "expected to barf"
+ except Barf:
+ pass
+
+ def test_global_add(self):
+ self.reactor.global_handler.add(BarfOnInit())
+ try:
+ self.reactor.run()
+ assert False, "expected to barf"
+ except Barf:
+ pass
+
+ def test_reactor_set(self):
+ self.reactor.handler = BarfOnInit()
+ try:
+ self.reactor.run()
+ assert False, "expected to barf"
+ except Barf:
+ pass
+
+ def test_reactor_add(self):
+ self.reactor.handler.add(BarfOnInit())
+ try:
+ self.reactor.run()
+ assert False, "expected to barf"
+ except Barf:
+ pass
+
+ def test_connection(self):
+ self.reactor.connection(BarfOnInit())
+ try:
+ self.reactor.run()
+ assert False, "expected to barf"
+ except Barf:
+ pass
+
+ def test_connection_set(self):
+ c = self.reactor.connection()
+ c.handler = BarfOnInit()
+ try:
+ self.reactor.run()
+ assert False, "expected to barf"
+ except Barf:
+ pass
+
+ def test_connection_add(self):
+ c = self.reactor.connection()
+ c.handler = object()
+ c.handler.add(BarfOnInit())
+ try:
+ self.reactor.run()
+ assert False, "expected to barf"
+ except Barf:
+ pass
+
+ def test_session_set(self):
+ c = self.reactor.connection()
+ s = c.session()
+ s.handler = BarfOnInit()
+ try:
+ self.reactor.run()
+ assert False, "expected to barf"
+ except Barf:
+ pass
+
+ def test_session_add(self):
+ c = self.reactor.connection()
+ s = c.session()
+ s.handler = object()
+ s.handler.add(BarfOnInit())
+ try:
+ self.reactor.run()
+ assert False, "expected to barf"
+ except Barf:
+ pass
+
+ def test_link_set(self):
+ c = self.reactor.connection()
+ s = c.session()
+ l = s.sender("xxx")
+ l.handler = BarfOnInit()
+ try:
+ self.reactor.run()
+ assert False, "expected to barf"
+ except Barf:
+ pass
+
+ def test_link_add(self):
+ c = self.reactor.connection()
+ s = c.session()
+ l = s.sender("xxx")
+ l.handler = object()
+ l.handler.add(BarfOnInit())
+ try:
+ self.reactor.run()
+ assert False, "expected to barf"
+ except Barf:
+ pass
+
+ def test_schedule(self):
+ self.reactor.schedule(0, BarfOnTask())
+ try:
+ self.reactor.run()
+ assert False, "expected to barf"
+ except Barf:
+ pass
+
+ def test_schedule_many_nothings(self):
+ class Nothing:
+ results = []
+ def on_timer_task(self, event):
+ self.results.append(None)
+ num = 12345
+ for a in range(num):
+ self.reactor.schedule(0, Nothing())
+ self.reactor.run()
+ assert len(Nothing.results) == num
+
+ def test_schedule_many_nothing_refs(self):
+ class Nothing:
+ results = []
+ def on_timer_task(self, event):
+ self.results.append(None)
+ num = 12345
+ tasks = []
+ for a in range(num):
+ tasks.append(self.reactor.schedule(0, Nothing()))
+ self.reactor.run()
+ assert len(Nothing.results) == num
+
+ def test_schedule_many_nothing_refs_cancel_before_run(self):
+ class Nothing:
+ results = []
+ def on_timer_task(self, event):
+ self.results.append(None)
+ num = 12345
+ tasks = []
+ for a in range(num):
+ tasks.append(self.reactor.schedule(0, Nothing()))
+ for task in tasks:
+ task.cancel()
+ self.reactor.run()
+ assert len(Nothing.results) == 0
+
+ def test_schedule_cancel(self):
+ barf = self.reactor.schedule(10, BarfOnTask())
+ class CancelBarf:
+ def __init__(self, barf):
+ self.barf = barf
+ def on_timer_task(self, event):
+ self.barf.cancel()
+ pass
+ self.reactor.schedule(0, CancelBarf(barf))
+ now = self.reactor.mark()
+ try:
+ self.reactor.run()
+ elapsed = self.reactor.mark() - now
+ assert elapsed < 10, "expected cancelled task to not delay the reactor by %s" % elapsed
+ except Barf:
+ assert False, "expected barf to be cancelled"
+
+ def test_schedule_cancel_many(self):
+ num = 12345
+ barfs = set()
+ for a in range(num):
+ barf = self.reactor.schedule(10*(a+1), BarfOnTask())
+ class CancelBarf:
+ def __init__(self, barf):
+ self.barf = barf
+ def on_timer_task(self, event):
+ self.barf.cancel()
+ barfs.discard(self.barf)
+ pass
+ self.reactor.schedule(0, CancelBarf(barf))
+ barfs.add(barf)
+ now = self.reactor.mark()
+ try:
+ self.reactor.run()
+ elapsed = self.reactor.mark() - now
+ assert elapsed < num, "expected cancelled task to not delay the reactor by %s" % elapsed
+ assert not barfs, "expected all barfs to be discarded"
+ except Barf:
+ assert False, "expected barf to be cancelled"
+
+
+class ApplicationEventTest(Test):
+ """Test application defined events and handlers."""
+
+ class MyTestServer(TestServer):
+ def __init__(self):
+ super(ApplicationEventTest.MyTestServer, self).__init__()
+
+ class MyHandler(Handler):
+ def __init__(self, test):
+ super(ApplicationEventTest.MyHandler, self).__init__()
+ self._test = test
+
+ def on_hello(self, event):
+ # verify PROTON-1056
+ self._test.hello_rcvd = str(event)
+
+ def on_goodbye(self, event):
+ self._test.goodbye_rcvd = str(event)
+
+ def setUp(self):
+ import os
+ if not hasattr(os, 'pipe'):
+ # KAG: seems like Jython doesn't have an os.pipe() method
+ raise SkipTest()
+ if os.name=="nt":
+ # Correct implementation on Windows is complicated
+ raise SkipTest("PROTON-1071")
+ self.server = ApplicationEventTest.MyTestServer()
+ self.server.reactor.handler.add(ApplicationEventTest.MyHandler(self))
+ self.event_injector = EventInjector()
+ self.hello_event = ApplicationEvent("hello")
+ self.goodbye_event = ApplicationEvent("goodbye")
+ self.server.reactor.selectable(self.event_injector)
+ self.hello_rcvd = None
+ self.goodbye_rcvd = None
+ self.server.start()
+
+ def tearDown(self):
+ self.server.stop()
+
+ def _wait_for(self, predicate, timeout=10.0):
+ deadline = time.time() + timeout
+ while time.time() < deadline:
+ if predicate():
+ break
+ time.sleep(0.1)
+ assert predicate()
+
+ def test_application_events(self):
+ self.event_injector.trigger(self.hello_event)
+ self._wait_for(lambda: self.hello_rcvd is not None)
+ self.event_injector.trigger(self.goodbye_event)
+ self._wait_for(lambda: self.goodbye_rcvd is not None)
+
+
+class AuthenticationTestHandler(MessagingHandler):
+ def __init__(self):
+ super(AuthenticationTestHandler, self).__init__()
+ port = free_tcp_port()
+ self.url = "localhost:%i" % port
+ self.verified = False
+
+ def on_start(self, event):
+ self.listener = event.container.listen(self.url)
+
+ def on_connection_opened(self, event):
+ event.connection.close()
+
+ def on_connection_opening(self, event):
+ assert event.connection.transport.user == "user@proton"
+ self.verified = True
+
+ def on_connection_closed(self, event):
+ event.connection.close()
+ self.listener.close()
+
+ def on_connection_error(self, event):
+ event.connection.close()
+ self.listener.close()
+
+class ContainerTest(Test):
+ """Test container subclass of reactor."""
+
+ def test_event_has_container_attribute(self):
+ ensureCanTestExtendedSASL()
+ class TestHandler(MessagingHandler):
+ def __init__(self):
+ super(TestHandler, self).__init__()
+ port = free_tcp_port()
+ self.url = "localhost:%i" % port
+
+ def on_start(self, event):
+ self.listener = event.container.listen(self.url)
+
+ def on_connection_closing(self, event):
+ event.connection.close()
+ self.listener.close()
+ test_handler = TestHandler()
+ container = Container(test_handler)
+ class ConnectionHandler(MessagingHandler):
+ def __init__(self):
+ super(ConnectionHandler, self).__init__()
+
+ def on_connection_opened(self, event):
+ event.connection.close()
+ assert event.container == event.reactor
+ assert event.container == container
+ container.connect(test_handler.url, handler=ConnectionHandler())
+ container.run()
+
+ def test_authentication_via_url(self):
+ ensureCanTestExtendedSASL()
+ test_handler = AuthenticationTestHandler()
+ container = Container(test_handler)
+ container.connect("%s:password@%s" % ("user%40proton", test_handler.url), reconnect=False)
+ container.run()
+ assert test_handler.verified
+
+ def test_authentication_via_container_attributes(self):
+ ensureCanTestExtendedSASL()
+ test_handler = AuthenticationTestHandler()
+ container = Container(test_handler)
+ container.user = "user@proton"
+ container.password = "password"
+ container.connect(test_handler.url, reconnect=False)
+ container.run()
+ assert test_handler.verified
+
+ def test_authentication_via_kwargs(self):
+ ensureCanTestExtendedSASL()
+ test_handler = AuthenticationTestHandler()
+ container = Container(test_handler)
+ container.connect(test_handler.url, user="user@proton", password="password", reconnect=False)
+ container.run()
+ assert test_handler.verified
+
+ class _ServerHandler(MessagingHandler):
+ def __init__(self, host):
+ super(ContainerTest._ServerHandler, self).__init__()
+ self.host = host
+ port = free_tcp_port()
+ self.port = free_tcp_port()
+ self.client_addr = None
+ self.peer_hostname = None
+
+ def on_start(self, event):
+ self.listener = event.container.listen("%s:%s" % (self.host, self.port))
+
+ def on_connection_opened(self, event):
+ self.client_addr = event.reactor.get_connection_address(event.connection)
+ self.peer_hostname = event.connection.remote_hostname
+
+ def on_connection_closing(self, event):
+ event.connection.close()
+ self.listener.close()
+
+ class _ClientHandler(MessagingHandler):
+ def __init__(self):
+ super(ContainerTest._ClientHandler, self).__init__()
+ self.server_addr = None
+
+ def on_connection_opened(self, event):
+ self.server_addr = event.reactor.get_connection_address(event.connection)
+ event.connection.close()
+
+ def test_numeric_hostname(self):
+ ensureCanTestExtendedSASL()
+ server_handler = ContainerTest._ServerHandler("127.0.0.1")
+ client_handler = ContainerTest._ClientHandler()
+ container = Container(server_handler)
+ container.connect(url=Url(host="127.0.0.1",
+ port=server_handler.port),
+ handler=client_handler)
+ container.run()
+ assert server_handler.client_addr
+ assert client_handler.server_addr
+ assert server_handler.peer_hostname == "127.0.0.1", server_handler.peer_hostname
+ assert client_handler.server_addr.rsplit(':', 1)[1] == str(server_handler.port)
+
+ def test_non_numeric_hostname(self):
+ ensureCanTestExtendedSASL()
+ server_handler = ContainerTest._ServerHandler("localhost")
+ client_handler = ContainerTest._ClientHandler()
+ container = Container(server_handler)
+ container.connect(url=Url(host="localhost",
+ port=server_handler.port),
+ handler=client_handler)
+ container.run()
+ assert server_handler.client_addr
+ assert client_handler.server_addr
+ assert server_handler.peer_hostname == "localhost", server_handler.peer_hostname
+ assert client_handler.server_addr.rsplit(':', 1)[1] == str(server_handler.port)
+
+ def test_virtual_host(self):
+ ensureCanTestExtendedSASL()
+ server_handler = ContainerTest._ServerHandler("localhost")
+ container = Container(server_handler)
+ conn = container.connect(url=Url(host="localhost",
+ port=server_handler.port),
+ handler=ContainerTest._ClientHandler(),
+ virtual_host="a.b.c.org")
+ container.run()
+ assert server_handler.peer_hostname == "a.b.c.org", server_handler.peer_hostname
+
+ def test_no_virtual_host(self):
+ # explicitly setting an empty virtual host should prevent the hostname
+ # field from being sent in the Open performative when using the
+ # Python Container.
+ server_handler = ContainerTest._ServerHandler("localhost")
+ container = Container(server_handler)
+ conn = container.connect(url=Url(host="localhost",
+ port=server_handler.port),
+ handler=ContainerTest._ClientHandler(),
+ virtual_host="")
+ container.run()
+ assert server_handler.peer_hostname is None, server_handler.peer_hostname
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/sasl.py
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/sasl.py b/python/tests/proton_tests/sasl.py
new file mode 100644
index 0000000..09b5f81
--- /dev/null
+++ b/python/tests/proton_tests/sasl.py
@@ -0,0 +1,587 @@
+#
+# 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 __future__ import absolute_import
+
+import sys, os
+from . import common
+from . import engine
+
+from proton import *
+from .common import pump, Skipped
+
+def _sslCertpath(file):
+ """ Return the full path to the certificate, keyfile, etc.
+ """
+ if os.name=="nt":
+ if file.find("private-key")!=-1:
+ # The private key is not in a separate store
+ return None
+ # Substitute pkcs#12 equivalent for the CA/key store
+ if file.endswith(".pem"):
+ file = file[:-4] + ".p12"
+ return os.path.join(os.path.dirname(__file__),
+ "ssl_db/%s" % file)
+
+def _testSaslMech(self, mech, clientUser='user@proton', authUser='user@proton', encrypted=False, authenticated=True):
+ self.s1.allowed_mechs(mech)
+ self.c1.open()
+ self.c2.open()
+
+ pump(self.t1, self.t2, 1024)
+
+ if encrypted is not None:
+ assert self.t2.encrypted == encrypted, encrypted
+ assert self.t1.encrypted == encrypted, encrypted
+
+ assert self.t2.authenticated == authenticated, authenticated
+ assert self.t1.authenticated == authenticated, authenticated
+ if authenticated:
+ # Server
+ assert self.t2.user == authUser
+ assert self.s2.user == authUser
+ assert self.s2.mech == mech.strip()
+ assert self.s2.outcome == SASL.OK, self.s2.outcome
+ assert self.c2.state & Endpoint.LOCAL_ACTIVE and self.c2.state & Endpoint.REMOTE_ACTIVE,\
+ "local_active=%s, remote_active=%s" % (self.c1.state & Endpoint.LOCAL_ACTIVE, self.c1.state & Endpoint.REMOTE_ACTIVE)
+ # Client
+ assert self.t1.user == clientUser
+ assert self.s1.user == clientUser
+ assert self.s1.mech == mech.strip()
+ assert self.s1.outcome == SASL.OK, self.s1.outcome
+ assert self.c1.state & Endpoint.LOCAL_ACTIVE and self.c1.state & Endpoint.REMOTE_ACTIVE,\
+ "local_active=%s, remote_active=%s" % (self.c1.state & Endpoint.LOCAL_ACTIVE, self.c1.state & Endpoint.REMOTE_ACTIVE)
+ else:
+ # Server
+ assert self.t2.user == None
+ assert self.s2.user == None
+ assert self.s2.outcome != SASL.OK, self.s2.outcome
+ # Client
+ assert self.t1.user == clientUser
+ assert self.s1.user == clientUser
+ assert self.s1.outcome != SASL.OK, self.s1.outcome
+
+class Test(common.Test):
+ pass
+
+def consumeAllOuput(t):
+ stops = 0
+ while stops<1:
+ out = t.peek(1024)
+ l = len(out) if out else 0
+ t.pop(l)
+ if l <= 0:
+ stops += 1
+
+class SaslTest(Test):
+
+ def setUp(self):
+ self.t1 = Transport()
+ self.s1 = SASL(self.t1)
+ self.t2 = Transport(Transport.SERVER)
+ self.t2.max_frame_size = 65536
+ self.s2 = SASL(self.t2)
+
+ def pump(self):
+ pump(self.t1, self.t2, 1024)
+
+ # We have to generate the client frames manually because proton does not
+ # generate pipelined SASL and AMQP frames together
+ def testIllegalProtocolLayering(self):
+ # Server
+ self.s2.allowed_mechs('ANONYMOUS')
+
+ c2 = Connection()
+ self.t2.bind(c2)
+
+ assert self.s2.outcome is None
+
+ # Push client bytes into server
+ self.t2.push(
+ # SASL
+ b'AMQP\x03\x01\x00\x00'
+ # @sasl-init(65) [mechanism=:ANONYMOUS, initial-response=b"anonymous@fuschia"]
+ b'\x00\x00\x002\x02\x01\x00\x00\x00SA\xd0\x00\x00\x00"\x00\x00\x00\x02\xa3\x09ANONYMOUS\xa0\x11anonymous@fuschia'
+ # SASL (again illegally)
+ b'AMQP\x03\x01\x00\x00'
+ # @sasl-init(65) [mechanism=:ANONYMOUS, initial-response=b"anonymous@fuschia"]
+ b'\x00\x00\x002\x02\x01\x00\x00\x00SA\xd0\x00\x00\x00"\x00\x00\x00\x02\xa3\x09ANONYMOUS\xa0\x11anonymous@fuschia'
+ # AMQP
+ b'AMQP\x00\x01\x00\x00'
+ # @open(16) [container-id="", channel-max=1234]
+ b'\x00\x00\x00!\x02\x00\x00\x00\x00S\x10\xd0\x00\x00\x00\x11\x00\x00\x00\x0a\xa1\x00@@`\x04\xd2@@@@@@'
+ )
+
+ consumeAllOuput(self.t2)
+
+ assert self.t2.condition
+ assert self.t2.closed
+ assert not c2.state & Endpoint.REMOTE_ACTIVE
+
+ def testPipelinedClient(self):
+ # Server
+ self.s2.allowed_mechs('ANONYMOUS')
+
+ c2 = Connection()
+ self.t2.bind(c2)
+
+ assert self.s2.outcome is None
+
+ # Push client bytes into server
+ self.t2.push(
+ # SASL
+ b'AMQP\x03\x01\x00\x00'
+ # @sasl-init(65) [mechanism=:ANONYMOUS, initial-response=b"anonymous@fuschia"]
+ b'\x00\x00\x002\x02\x01\x00\x00\x00SA\xd0\x00\x00\x00"\x00\x00\x00\x02\xa3\x09ANONYMOUS\xa0\x11anonymous@fuschia'
+ # AMQP
+ b'AMQP\x00\x01\x00\x00'
+ # @open(16) [container-id="", channel-max=1234]
+ b'\x00\x00\x00!\x02\x00\x00\x00\x00S\x10\xd0\x00\x00\x00\x11\x00\x00\x00\x0a\xa1\x00@@`\x04\xd2@@@@@@'
+ )
+
+ consumeAllOuput(self.t2)
+
+ assert not self.t2.condition
+ assert self.s2.outcome == SASL.OK
+ assert c2.state & Endpoint.REMOTE_ACTIVE
+
+ def testPipelinedServer(self):
+ # Client
+ self.s1.allowed_mechs('ANONYMOUS')
+
+ c1 = Connection()
+ self.t1.bind(c1)
+
+ assert self.s1.outcome is None
+
+ # Push server bytes into client
+ # Commented out lines in this test are where the client input processing doesn't
+ # run after output processing even though there is input waiting
+ self.t1.push(
+ # SASL
+ b'AMQP\x03\x01\x00\x00'
+ # @sasl-mechanisms(64) [sasl-server-mechanisms=@PN_SYMBOL[:ANONYMOUS]]
+ b'\x00\x00\x00\x1c\x02\x01\x00\x00\x00S@\xc0\x0f\x01\xe0\x0c\x01\xa3\tANONYMOUS'
+ # @sasl-outcome(68) [code=0]
+ b'\x00\x00\x00\x10\x02\x01\x00\x00\x00SD\xc0\x03\x01P\x00'
+ # AMQP
+ b'AMQP\x00\x01\x00\x00'
+ # @open(16) [container-id="", channel-max=1234]
+ b'\x00\x00\x00!\x02\x00\x00\x00\x00S\x10\xd0\x00\x00\x00\x11\x00\x00\x00\x0a\xa1\x00@@`\x04\xd2@@@@@@'
+ )
+
+ consumeAllOuput(self.t1)
+
+ assert self.s1.outcome == SASL.OK
+ assert c1.state & Endpoint.REMOTE_ACTIVE
+
+ def testPipelined2(self):
+ out1 = self.t1.peek(1024)
+ self.t1.pop(len(out1))
+ self.t2.push(out1)
+
+ self.s2.allowed_mechs('ANONYMOUS')
+ c2 = Connection()
+ c2.open()
+ self.t2.bind(c2)
+
+ out2 = self.t2.peek(1024)
+ self.t2.pop(len(out2))
+ self.t1.push(out2)
+
+ out1 = self.t1.peek(1024)
+ assert len(out1) > 0
+
+ def testFracturedSASL(self):
+ """ PROTON-235
+ """
+ assert self.s1.outcome is None
+
+ # self.t1.trace(Transport.TRACE_FRM)
+
+ out = self.t1.peek(1024)
+ self.t1.pop(len(out))
+ self.t1.push(b"AMQP\x03\x01\x00\x00")
+ out = self.t1.peek(1024)
+ self.t1.pop(len(out))
+ self.t1.push(b"\x00\x00\x00")
+ out = self.t1.peek(1024)
+ self.t1.pop(len(out))
+
+ self.t1.push(b"6\x02\x01\x00\x00\x00S@\xc0\x29\x01\xe0\x26\x04\xa3\x05PLAIN\x0aDIGEST-MD5\x09ANONYMOUS\x08CRAM-MD5")
+ out = self.t1.peek(1024)
+ self.t1.pop(len(out))
+ self.t1.push(b"\x00\x00\x00\x10\x02\x01\x00\x00\x00SD\xc0\x03\x01P\x00")
+ out = self.t1.peek(1024)
+ self.t1.pop(len(out))
+ while out:
+ out = self.t1.peek(1024)
+ self.t1.pop(len(out))
+
+ assert self.s1.outcome == SASL.OK, self.s1.outcome
+
+ def test_singleton(self):
+ """Verify that only a single instance of SASL can exist per Transport"""
+ transport = Transport()
+ attr = object()
+ sasl1 = SASL(transport)
+ sasl1.my_attribute = attr
+ sasl2 = transport.sasl()
+ sasl3 = SASL(transport)
+ assert sasl1 == sasl2
+ assert sasl1 == sasl3
+ assert sasl1.my_attribute == attr
+ assert sasl2.my_attribute == attr
+ assert sasl3.my_attribute == attr
+ transport = Transport()
+ sasl1 = transport.sasl()
+ sasl1.my_attribute = attr
+ sasl2 = SASL(transport)
+ assert sasl1 == sasl2
+ assert sasl1.my_attribute == attr
+ assert sasl2.my_attribute == attr
+
+ def testSaslSkipped(self):
+ """Verify that the server (with SASL) correctly handles a client without SASL"""
+ self.t1 = Transport()
+ self.t2.require_auth(False)
+ self.pump()
+ assert self.s2.outcome == None
+ assert self.t2.condition == None
+ assert self.t2.authenticated == False
+ assert self.s1.outcome == None
+ assert self.t1.condition == None
+ assert self.t1.authenticated == False
+
+ def testSaslSkippedFail(self):
+ """Verify that the server (with SASL) correctly handles a client without SASL"""
+ self.t1 = Transport()
+ self.t2.require_auth(True)
+ self.pump()
+ assert self.s2.outcome == None
+ assert self.t2.condition != None
+ assert self.s1.outcome == None
+ assert self.t1.condition != None
+
+ def testMechNotFound(self):
+ self.c1 = Connection()
+ self.c1.open()
+ self.t1.bind(self.c1)
+ self.s1.allowed_mechs('IMPOSSIBLE')
+
+ self.pump()
+
+ assert self.t2.authenticated == False
+ assert self.t1.authenticated == False
+ assert self.s1.outcome != SASL.OK
+ assert self.s2.outcome != SASL.OK
+
+class SASLMechTest(Test):
+ def setUp(self):
+ self.t1 = Transport()
+ self.s1 = SASL(self.t1)
+ self.t2 = Transport(Transport.SERVER)
+ self.s2 = SASL(self.t2)
+
+ self.c1 = Connection()
+ self.c1.user = 'user@proton'
+ self.c1.password = 'password'
+ self.c1.hostname = 'localhost'
+
+ self.c2 = Connection()
+
+ def testANON(self):
+ self.t1.bind(self.c1)
+ self.t2.bind(self.c2)
+ _testSaslMech(self, 'ANONYMOUS', authUser='anonymous')
+
+ def testCRAMMD5(self):
+ common.ensureCanTestExtendedSASL()
+
+ self.t1.bind(self.c1)
+ self.t2.bind(self.c2)
+ _testSaslMech(self, 'CRAM-MD5')
+
+ def testDIGESTMD5(self):
+ common.ensureCanTestExtendedSASL()
+
+ self.t1.bind(self.c1)
+ self.t2.bind(self.c2)
+ _testSaslMech(self, 'DIGEST-MD5')
+
+ # PLAIN shouldn't work without encryption without special setting
+ def testPLAINfail(self):
+ common.ensureCanTestExtendedSASL()
+
+ self.t1.bind(self.c1)
+ self.t2.bind(self.c2)
+ _testSaslMech(self, 'PLAIN', authenticated=False)
+
+ # Client won't accept PLAIN even if offered by server without special setting
+ def testPLAINClientFail(self):
+ common.ensureCanTestExtendedSASL()
+
+ self.s2.allow_insecure_mechs = True
+ self.t1.bind(self.c1)
+ self.t2.bind(self.c2)
+ _testSaslMech(self, 'PLAIN', authenticated=False)
+
+ # PLAIN will only work if both ends are specially set up
+ def testPLAIN(self):
+ common.ensureCanTestExtendedSASL()
+
+ self.s1.allow_insecure_mechs = True
+ self.s2.allow_insecure_mechs = True
+ self.t1.bind(self.c1)
+ self.t2.bind(self.c2)
+ _testSaslMech(self, 'PLAIN')
+
+# SCRAM not supported before Cyrus SASL 2.1.26
+# so not universal and hence need a test for support
+# to keep it in tests.
+# def testSCRAMSHA1(self):
+# common.ensureCanTestExtendedSASL()
+#
+# self.t1.bind(self.c1)
+# self.t2.bind(self.c2)
+# _testSaslMech(self, 'SCRAM-SHA-1')
+
+def _sslConnection(domain, transport, connection):
+ transport.bind(connection)
+ ssl = SSL(transport, domain, None )
+ return connection
+
+class SSLSASLTest(Test):
+ def setUp(self):
+ if not common.isSSLPresent():
+ raise Skipped("No SSL libraries found.")
+
+ self.server_domain = SSLDomain(SSLDomain.MODE_SERVER)
+ self.client_domain = SSLDomain(SSLDomain.MODE_CLIENT)
+
+ self.t1 = Transport()
+ self.s1 = SASL(self.t1)
+ self.t2 = Transport(Transport.SERVER)
+ self.s2 = SASL(self.t2)
+
+ self.c1 = Connection()
+ self.c2 = Connection()
+
+ def testSSLPlainSimple(self):
+ if not SASL.extended():
+ raise Skipped("Simple SASL server does not support PLAIN")
+ common.ensureCanTestExtendedSASL()
+
+ clientUser = 'user@proton'
+ mech = 'PLAIN'
+
+ self.c1.user = clientUser
+ self.c1.password = 'password'
+ self.c1.hostname = 'localhost'
+
+ ssl1 = _sslConnection(self.client_domain, self.t1, self.c1)
+ ssl2 = _sslConnection(self.server_domain, self.t2, self.c2)
+
+ _testSaslMech(self, mech, encrypted=True)
+
+ def testSSLPlainSimpleFail(self):
+ if not SASL.extended():
+ raise Skipped("Simple SASL server does not support PLAIN")
+ common.ensureCanTestExtendedSASL()
+
+ clientUser = 'usr@proton'
+ mech = 'PLAIN'
+
+ self.c1.user = clientUser
+ self.c1.password = 'password'
+ self.c1.hostname = 'localhost'
+
+ ssl1 = _sslConnection(self.client_domain, self.t1, self.c1)
+ ssl2 = _sslConnection(self.server_domain, self.t2, self.c2)
+
+ _testSaslMech(self, mech, clientUser='usr@proton', encrypted=True, authenticated=False)
+
+ def testSSLExternalSimple(self):
+ if os.name=="nt":
+ extUser = 'O=Client, CN=127.0.0.1'
+ else:
+ extUser = 'O=Client,CN=127.0.0.1'
+ mech = 'EXTERNAL'
+
+ self.server_domain.set_credentials(_sslCertpath("server-certificate.pem"),
+ _sslCertpath("server-private-key.pem"),
+ "server-password")
+ self.server_domain.set_trusted_ca_db(_sslCertpath("ca-certificate.pem"))
+ self.server_domain.set_peer_authentication(SSLDomain.VERIFY_PEER,
+ _sslCertpath("ca-certificate.pem") )
+ self.client_domain.set_credentials(_sslCertpath("client-certificate.pem"),
+ _sslCertpath("client-private-key.pem"),
+ "client-password")
+ self.client_domain.set_trusted_ca_db(_sslCertpath("ca-certificate.pem"))
+ self.client_domain.set_peer_authentication(SSLDomain.VERIFY_PEER)
+
+ ssl1 = _sslConnection(self.client_domain, self.t1, self.c1)
+ ssl2 = _sslConnection(self.server_domain, self.t2, self.c2)
+
+ _testSaslMech(self, mech, clientUser=None, authUser=extUser, encrypted=True)
+
+ def testSSLExternalSimpleFail(self):
+ mech = 'EXTERNAL'
+
+ self.server_domain.set_credentials(_sslCertpath("server-certificate.pem"),
+ _sslCertpath("server-private-key.pem"),
+ "server-password")
+ self.server_domain.set_trusted_ca_db(_sslCertpath("ca-certificate.pem"))
+ self.server_domain.set_peer_authentication(SSLDomain.VERIFY_PEER,
+ _sslCertpath("ca-certificate.pem") )
+ self.client_domain.set_trusted_ca_db(_sslCertpath("ca-certificate.pem"))
+ self.client_domain.set_peer_authentication(SSLDomain.VERIFY_PEER)
+
+ ssl1 = _sslConnection(self.client_domain, self.t1, self.c1)
+ ssl2 = _sslConnection(self.server_domain, self.t2, self.c2)
+
+ _testSaslMech(self, mech, clientUser=None, authUser=None, encrypted=None, authenticated=False)
+
+class SASLEventTest(engine.CollectorTest):
+ def setUp(self):
+ engine.CollectorTest.setUp(self)
+ self.t1 = Transport()
+ self.s1 = SASL(self.t1)
+ self.t2 = Transport(Transport.SERVER)
+ self.s2 = SASL(self.t2)
+
+ self.c1 = Connection()
+ self.c1.user = 'user@proton'
+ self.c1.password = 'password'
+ self.c1.hostname = 'localhost'
+
+ self.c2 = Connection()
+
+ self.collector = Collector()
+
+ def testNormalAuthenticationClient(self):
+ common.ensureCanTestExtendedSASL()
+ self.c1.collect(self.collector)
+ self.t1.bind(self.c1)
+ self.t2.bind(self.c2)
+ _testSaslMech(self, 'DIGEST-MD5')
+ self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND,
+ Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT,
+ Event.CONNECTION_REMOTE_OPEN)
+
+ def testNormalAuthenticationServer(self):
+ common.ensureCanTestExtendedSASL()
+ self.c2.collect(self.collector)
+ self.t1.bind(self.c1)
+ self.t2.bind(self.c2)
+ _testSaslMech(self, 'DIGEST-MD5')
+ self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND,
+ Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT,
+ Event.CONNECTION_REMOTE_OPEN)
+
+ def testFailedAuthenticationClient(self):
+ common.ensureCanTestExtendedSASL()
+ clientUser = "usr@proton"
+ self.c1.user = clientUser
+ self.c1.collect(self.collector)
+ self.t1.bind(self.c1)
+ self.t2.bind(self.c2)
+ _testSaslMech(self, 'DIGEST-MD5', clientUser=clientUser, authenticated=False)
+ self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND,
+ Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT,
+ Event.TRANSPORT_ERROR,
+ Event.TRANSPORT_TAIL_CLOSED,
+ Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED)
+
+ def testFailedAuthenticationServer(self):
+ common.ensureCanTestExtendedSASL()
+ clientUser = "usr@proton"
+ self.c1.user = clientUser
+ self.c2.collect(self.collector)
+ self.t1.bind(self.c1)
+ self.t2.bind(self.c2)
+ _testSaslMech(self, 'DIGEST-MD5', clientUser=clientUser, authenticated=False)
+ self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND,
+ Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT,
+ Event.TRANSPORT_ERROR,
+ Event.TRANSPORT_TAIL_CLOSED,
+ Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED)
+
+ def testNoMechClient(self):
+ common.ensureCanTestExtendedSASL()
+ self.c1.collect(self.collector)
+ self.s2.allowed_mechs('IMPOSSIBLE')
+ self.t1.bind(self.c1)
+ self.t2.bind(self.c2)
+ _testSaslMech(self, 'DIGEST-MD5', authenticated=False)
+ self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND,
+ Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT,
+ Event.TRANSPORT_ERROR,
+ Event.TRANSPORT_TAIL_CLOSED, Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED)
+
+ def testNoMechServer(self):
+ common.ensureCanTestExtendedSASL()
+ self.c2.collect(self.collector)
+ self.s2.allowed_mechs('IMPOSSIBLE')
+ self.t1.bind(self.c1)
+ self.t2.bind(self.c2)
+ _testSaslMech(self, 'DIGEST-MD5', authenticated=False)
+ self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND,
+ Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT,
+ Event.TRANSPORT_TAIL_CLOSED,
+ Event.TRANSPORT_ERROR, Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED)
+
+ def testDisallowedMechClient(self):
+ self.c1.collect(self.collector)
+ self.t1.bind(self.c1)
+ self.t2.bind(self.c2)
+ _testSaslMech(self, 'IMPOSSIBLE', authenticated=False)
+ self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND,
+ Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT,
+ Event.TRANSPORT_ERROR,
+ Event.TRANSPORT_TAIL_CLOSED, Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED)
+
+ def testDisallowedMechServer(self):
+ self.c2.collect(self.collector)
+ self.t1.bind(self.c1)
+ self.t2.bind(self.c2)
+ _testSaslMech(self, 'IMPOSSIBLE', authenticated=False)
+ self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND,
+ Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT,
+ Event.TRANSPORT_TAIL_CLOSED,
+ Event.TRANSPORT_ERROR, Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED)
+
+ def testDisallowedPlainClient(self):
+ self.c1.collect(self.collector)
+ self.t1.bind(self.c1)
+ self.t2.bind(self.c2)
+ _testSaslMech(self, 'PLAIN', authenticated=False)
+ self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND,
+ Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT,
+ Event.TRANSPORT_ERROR,
+ Event.TRANSPORT_TAIL_CLOSED, Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED)
+
+ def testDisallowedPlainServer(self):
+ self.c2.collect(self.collector)
+ self.t1.bind(self.c1)
+ self.t2.bind(self.c2)
+ _testSaslMech(self, 'PLAIN', authenticated=False)
+ self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND,
+ Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT,
+ Event.TRANSPORT_TAIL_CLOSED,
+ Event.TRANSPORT_ERROR, Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED)
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/soak.py
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/soak.py b/python/tests/proton_tests/soak.py
new file mode 100644
index 0000000..b7b521c
--- /dev/null
+++ b/python/tests/proton_tests/soak.py
@@ -0,0 +1,334 @@
+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.
+#
+import os
+import sys
+from .common import Test, Skipped, free_tcp_ports, \
+ MessengerReceiverC, MessengerSenderC, \
+ MessengerReceiverValgrind, MessengerSenderValgrind, \
+ ReactorReceiverC, ReactorSenderC, \
+ ReactorReceiverValgrind, ReactorSenderValgrind, \
+ isSSLPresent
+from proton import *
+
+#
+# Tests that run the apps
+#
+
+class AppTests(Test):
+
+ def __init__(self, *args):
+ Test.__init__(self, *args)
+ self.is_valgrind = False
+
+ def default(self, name, value, **kwargs):
+ if self.is_valgrind:
+ default = kwargs.get("valgrind", value)
+ else:
+ default = value
+ return Test.default(self, name, default, **kwargs)
+
+ @property
+ def iterations(self):
+ return int(self.default("iterations", 2, fast=1, valgrind=2))
+
+ @property
+ def send_count(self):
+ return int(self.default("send_count", 17, fast=1, valgrind=2))
+
+ @property
+ def target_count(self):
+ return int(self.default("target_count", 5, fast=1, valgrind=2))
+
+ @property
+ def send_batch(self):
+ return int(self.default("send_batch", 7, fast=1, valgrind=2))
+
+ @property
+ def forward_count(self):
+ return int(self.default("forward_count", 5, fast=1, valgrind=2))
+
+ @property
+ def port_count(self):
+ return int(self.default("port_count", 3, fast=1, valgrind=2))
+
+ @property
+ def sender_count(self):
+ return int(self.default("sender_count", 3, fast=1, valgrind=2))
+
+ def valgrind_test(self):
+ self.is_valgrind = True
+
+ def setUp(self):
+ self.senders = []
+ self.receivers = []
+
+ def tearDown(self):
+ pass
+
+ def _do_test(self, iterations=1):
+ verbose = self.verbose
+
+ for R in self.receivers:
+ R.start( verbose )
+
+ for j in range(iterations):
+ for S in self.senders:
+ S.start( verbose )
+
+ for S in self.senders:
+ S.wait()
+ #print("SENDER OUTPUT:")
+ #print( S.stdout() )
+ assert S.status() == 0, ("Command '%s' failed status=%d: '%s' '%s'"
+ % (str(S.cmdline()),
+ S.status(),
+ S.stdout(),
+ S.stderr()))
+
+ for R in self.receivers:
+ R.wait()
+ #print("RECEIVER OUTPUT")
+ #print( R.stdout() )
+ assert R.status() == 0, ("Command '%s' failed status=%d: '%s' '%s'"
+ % (str(R.cmdline()),
+ R.status(),
+ R.stdout(),
+ R.stderr()))
+
+#
+# Traffic passing tests based on the Messenger apps
+#
+
+class MessengerTests(AppTests):
+
+ _timeout = 60
+
+ def _ssl_check(self):
+ if not isSSLPresent():
+ raise Skipped("No SSL libraries found.")
+ if os.name=="nt":
+ raise Skipped("Windows SChannel lacks anonymous cipher support.")
+
+ def __init__(self, *args):
+ AppTests.__init__(self, *args)
+
+ def _do_oneway_test(self, receiver, sender, domain="amqp"):
+ """ Send N messages to a receiver.
+ Parameters:
+ iterations - repeat the senders this many times
+ target_count = # of targets to send to.
+ send_count = # messages sent to each target
+ """
+ iterations = self.iterations
+ send_count = self.send_count
+ target_count = self.target_count
+
+ send_total = send_count * target_count
+ receive_total = send_total * iterations
+
+ port = free_tcp_ports()[0]
+
+ receiver.subscriptions = ["%s://~0.0.0.0:%s" % (domain, port)]
+ receiver.receive_count = receive_total
+ receiver.timeout = MessengerTests._timeout
+ self.receivers.append( receiver )
+
+ sender.targets = ["%s://0.0.0.0:%s/X%d" % (domain, port, j) for j in range(target_count)]
+ sender.send_count = send_total
+ sender.timeout = MessengerTests._timeout
+ self.senders.append( sender )
+
+ self._do_test(iterations)
+
+ def _do_echo_test(self, receiver, sender, domain="amqp"):
+ """ Send N messages to a receiver, which responds to each.
+ Parameters:
+ iterations - repeat the senders this many times
+ target_count - # targets to send to
+ send_count = # messages sent to each target
+ send_batch - wait for replies after this many messages sent
+ """
+ iterations = self.iterations
+ send_count = self.send_count
+ target_count = self.target_count
+ send_batch = self.send_batch
+
+ send_total = send_count * target_count
+ receive_total = send_total * iterations
+
+ port = free_tcp_ports()[0]
+
+ receiver.subscriptions = ["%s://~0.0.0.0:%s" % (domain, port)]
+ receiver.receive_count = receive_total
+ receiver.send_reply = True
+ receiver.timeout = MessengerTests._timeout
+ self.receivers.append( receiver )
+
+ sender.targets = ["%s://0.0.0.0:%s/%dY" % (domain, port, j) for j in range(target_count)]
+ sender.send_count = send_total
+ sender.get_reply = True
+ sender.send_batch = send_batch
+ sender.timeout = MessengerTests._timeout
+ self.senders.append( sender )
+
+ self._do_test(iterations)
+
+ def _do_relay_test(self, receiver, relay, sender, domain="amqp"):
+ """ Send N messages to a receiver, which replies to each and forwards
+ each of them to different receiver.
+ Parameters:
+ iterations - repeat the senders this many times
+ target_count - # targets to send to
+ send_count = # messages sent to each target
+ send_batch - wait for replies after this many messages sent
+ forward_count - forward to this many targets
+ """
+ iterations = self.iterations
+ send_count = self.send_count
+ target_count = self.target_count
+ send_batch = self.send_batch
+ forward_count = self.forward_count
+
+ send_total = send_count * target_count
+ receive_total = send_total * iterations
+
+ port = free_tcp_ports()[0]
+
+ receiver.subscriptions = ["%s://~0.0.0.0:%s" % (domain, port)]
+ receiver.receive_count = receive_total
+ receiver.send_reply = True
+ # forward to 'relay' - uses two links
+ # ## THIS FAILS:
+ # receiver.forwards = ["amqp://Relay/%d" % j for j in range(forward_count)]
+ receiver.forwards = ["%s://Relay" % domain]
+ receiver.timeout = MessengerTests._timeout
+ self.receivers.append( receiver )
+
+ relay.subscriptions = ["%s://0.0.0.0:%s" % (domain, port)]
+ relay.name = "Relay"
+ relay.receive_count = receive_total
+ relay.timeout = MessengerTests._timeout
+ self.receivers.append( relay )
+
+ # send to 'receiver'
+ sender.targets = ["%s://0.0.0.0:%s/X%dY" % (domain, port, j) for j in range(target_count)]
+ sender.send_count = send_total
+ sender.get_reply = True
+ sender.timeout = MessengerTests._timeout
+ self.senders.append( sender )
+
+ self._do_test(iterations)
+
+
+ def _do_star_topology_test(self, r_factory, s_factory, domain="amqp"):
+ """
+ A star-like topology, with a central receiver at the hub, and senders at
+ the spokes. Each sender will connect to each of the ports the receiver is
+ listening on. Each sender will then create N links per each connection.
+ Each sender will send X messages per link, waiting for a response.
+ Parameters:
+ iterations - repeat the senders this many times
+ port_count - # of ports the receiver will listen on. Each sender connects
+ to all ports.
+ sender_count - # of senders
+ target_count - # of targets per connection
+ send_count - # of messages sent to each target
+ send_batch - # of messages to send before waiting for response
+ """
+ iterations = self.iterations
+ port_count = self.port_count
+ sender_count = self.sender_count
+ target_count = self.target_count
+ send_count = self.send_count
+ send_batch = self.send_batch
+
+ send_total = port_count * target_count * send_count
+ receive_total = send_total * sender_count * iterations
+
+ ports = free_tcp_ports(port_count)
+
+ receiver = r_factory()
+ receiver.subscriptions = ["%s://~0.0.0.0:%s" % (domain, port) for port in ports]
+ receiver.receive_count = receive_total
+ receiver.send_reply = True
+ receiver.timeout = MessengerTests._timeout
+ self.receivers.append( receiver )
+
+ for i in range(sender_count):
+ sender = s_factory()
+ sender.targets = ["%s://0.0.0.0:%s/%d" % (domain, port, j) for port in ports for j in range(target_count)]
+ sender.send_count = send_total
+ sender.send_batch = send_batch
+ sender.get_reply = True
+ sender.timeout = MessengerTests._timeout
+ self.senders.append( sender )
+
+ self._do_test(iterations)
+
+ def test_oneway_C(self):
+ self._do_oneway_test(MessengerReceiverC(), MessengerSenderC())
+
+ def test_oneway_C_SSL(self):
+ self._ssl_check()
+ self._do_oneway_test(MessengerReceiverC(), MessengerSenderC(), "amqps")
+
+ def test_oneway_valgrind(self):
+ self.valgrind_test()
+ self._do_oneway_test(MessengerReceiverValgrind(), MessengerSenderValgrind())
+
+ def test_echo_C(self):
+ self._do_echo_test(MessengerReceiverC(), MessengerSenderC())
+
+ def test_echo_C_SSL(self):
+ self._ssl_check()
+ self._do_echo_test(MessengerReceiverC(), MessengerSenderC(), "amqps")
+
+ def test_echo_valgrind(self):
+ self.valgrind_test()
+ self._do_echo_test(MessengerReceiverValgrind(), MessengerSenderValgrind())
+
+ def test_relay_C(self):
+ self._do_relay_test(MessengerReceiverC(), MessengerReceiverC(), MessengerSenderC())
+
+ def test_relay_C_SSL(self):
+ self._ssl_check()
+ self._do_relay_test(MessengerReceiverC(), MessengerReceiverC(), MessengerSenderC(), "amqps")
+
+ def test_relay_valgrind(self):
+ self.valgrind_test()
+ self._do_relay_test(MessengerReceiverValgrind(), MessengerReceiverValgrind(), MessengerSenderValgrind())
+
+ def test_star_topology_C(self):
+ self._do_star_topology_test( MessengerReceiverC, MessengerSenderC )
+
+ def test_star_topology_C_SSL(self):
+ self._ssl_check()
+ self._do_star_topology_test( MessengerReceiverC, MessengerSenderC, "amqps" )
+
+ def test_star_topology_valgrind(self):
+ self.valgrind_test()
+ self._do_star_topology_test( MessengerReceiverValgrind, MessengerSenderValgrind )
+
+ def test_oneway_reactor(self):
+ self._do_oneway_test(ReactorReceiverC(), ReactorSenderC())
+
+ def test_oneway_reactor_valgrind(self):
+ self.valgrind_test()
+ self._do_oneway_test(ReactorReceiverValgrind(), ReactorSenderValgrind())
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[06/11] qpid-proton git commit: PROTON-1885: [python] move
tests/python to python/tests
Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/engine.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/engine.py b/tests/python/proton_tests/engine.py
deleted file mode 100644
index c0ea31d..0000000
--- a/tests/python/proton_tests/engine.py
+++ /dev/null
@@ -1,2714 +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 __future__ import absolute_import
-
-import os, gc
-import sys
-from . import common
-from time import time, sleep
-from proton import *
-from .common import pump, Skipped
-from proton.reactor import Reactor
-
-
-# older versions of gc do not provide the garbage list
-if not hasattr(gc, "garbage"):
- gc.garbage=[]
-
-# future test areas
-# + different permutations of setup
-# - creating deliveries and calling input/output before opening the session/link
-# + shrinking output_size down to something small? should the engine buffer?
-# + resuming
-# - locally and remotely created deliveries with the same tag
-
-# Jython 2.5 needs this:
-try:
- bytes()
-except:
- bytes = str
-
-# and this...
-try:
- bytearray()
-except:
- def bytearray(x):
- return b'\x00' * x
-
-OUTPUT_SIZE = 10*1024
-
-class Test(common.Test):
-
- def __init__(self, *args):
- common.Test.__init__(self, *args)
- self._wires = []
-
- def connection(self):
- c1 = Connection()
- c2 = Connection()
- t1 = Transport()
- t1.bind(c1)
- t2 = Transport()
- t2.bind(c2)
- self._wires.append((c1, t1, c2, t2))
-
- mask1 = 0
- mask2 = 0
-
- for cat in ("TRACE_FRM", "TRACE_RAW"):
- trc = os.environ.get("PN_%s" % cat)
- if trc and trc.lower() in ("1", "2", "yes", "true"):
- mask1 = mask1 | getattr(Transport, cat)
- if trc == "2":
- mask2 = mask2 | getattr(Transport, cat)
- t1.trace(mask1)
- t2.trace(mask2)
-
- return c1, c2
-
- def link(self, name, max_frame=None, idle_timeout=None):
- c1, c2 = self.connection()
- if max_frame:
- c1.transport.max_frame_size = max_frame[0]
- c2.transport.max_frame_size = max_frame[1]
- if idle_timeout:
- # idle_timeout in seconds expressed as float
- c1.transport.idle_timeout = idle_timeout[0]
- c2.transport.idle_timeout = idle_timeout[1]
- c1.open()
- c2.open()
- ssn1 = c1.session()
- ssn1.open()
- self.pump()
- ssn2 = c2.session_head(Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE)
- ssn2.open()
- self.pump()
- snd = ssn1.sender(name)
- rcv = ssn2.receiver(name)
- return snd, rcv
-
- def cleanup(self):
- self._wires = []
-
- def pump(self, buffer_size=OUTPUT_SIZE):
- for c1, t1, c2, t2 in self._wires:
- pump(t1, t2, buffer_size)
-
-class ConnectionTest(Test):
-
- def setUp(self):
- gc.enable()
- self.c1, self.c2 = self.connection()
-
- def cleanup(self):
- # release resources created by this class
- super(ConnectionTest, self).cleanup()
- self.c1 = None
- self.c2 = None
-
- def tearDown(self):
- self.cleanup()
- gc.collect()
- assert not gc.garbage
-
- def test_open_close(self):
- assert self.c1.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
- assert self.c2.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
-
- self.c1.open()
- self.pump()
-
- assert self.c1.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT
- assert self.c2.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE
-
- self.c2.open()
- self.pump()
-
- assert self.c1.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
- assert self.c2.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
-
- self.c1.close()
- self.pump()
-
- assert self.c1.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
- assert self.c2.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED
-
- self.c2.close()
- self.pump()
-
- assert self.c1.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
- assert self.c2.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
-
- def test_simultaneous_open_close(self):
- assert self.c1.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
- assert self.c2.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
-
- self.c1.open()
- self.c2.open()
-
- self.pump()
-
- assert self.c1.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
- assert self.c2.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
-
- self.c1.close()
- self.c2.close()
-
- self.pump()
-
- assert self.c1.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
- assert self.c2.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
-
- def test_capabilities(self):
- self.c1.offered_capabilities = Array(UNDESCRIBED, Data.SYMBOL,
- symbol("O_one"),
- symbol("O_two"),
- symbol("O_three"))
-
- self.c1.desired_capabilities = Array(UNDESCRIBED, Data.SYMBOL,
- symbol("D_one"),
- symbol("D_two"),
- symbol("D_three"))
- self.c1.open()
-
- assert self.c2.remote_offered_capabilities is None
- assert self.c2.remote_desired_capabilities is None
-
- self.pump()
-
- assert self.c2.remote_offered_capabilities == self.c1.offered_capabilities, \
- (self.c2.remote_offered_capabilities, self.c1.offered_capabilities)
- assert self.c2.remote_desired_capabilities == self.c1.desired_capabilities, \
- (self.c2.remote_desired_capabilities, self.c1.desired_capabilities)
-
- def test_condition(self):
- self.c1.open()
- self.c2.open()
- self.pump()
- assert self.c1.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
- assert self.c2.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
-
- cond = Condition("blah:bleh", "this is a description", {symbol("foo"): "bar"})
- self.c1.condition = cond
- self.c1.close()
-
- self.pump()
-
- assert self.c1.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
- assert self.c2.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED
-
- rcond = self.c2.remote_condition
- assert rcond == cond, (rcond, cond)
-
- def test_properties(self, p1={symbol("key"): symbol("value")}, p2=None):
- self.c1.properties = p1
- self.c2.properties = p2
- self.c1.open()
- self.c2.open()
- self.pump()
-
- assert self.c2.remote_properties == p1, (self.c2.remote_properties, p1)
- assert self.c1.remote_properties == p2, (self.c2.remote_properties, p2)
-
- # The proton implementation limits channel_max to 32767.
- # If I set the application's limit lower than that, I should
- # get my wish. If I set it higher -- not.
- def test_channel_max_low(self, value=1234):
- self.c1.transport.channel_max = value
- self.c1.open()
- self.pump()
- assert self.c1.transport.channel_max == value, (self.c1.transport.channel_max, value)
-
- def test_channel_max_high(self, value=65535):
- self.c1.transport.channel_max = value
- self.c1.open()
- self.pump()
- assert self.c1.transport.channel_max == 32767, (self.c1.transport.channel_max, value)
-
- def test_channel_max_raise_and_lower(self):
- upper_limit = 32767
-
- # It's OK to lower the max below upper_limit.
- self.c1.transport.channel_max = 12345
- assert self.c1.transport.channel_max == 12345
-
- # But it won't let us raise the limit above PN_IMPL_CHANNEL_MAX.
- self.c1.transport.channel_max = 65535
- assert self.c1.transport.channel_max == upper_limit
-
- # send the OPEN frame
- self.c1.open()
- self.pump()
-
- # Now it's too late to make any change, because
- # we have already sent the OPEN frame.
- try:
- self.c1.transport.channel_max = 666
- assert False, "expected session exception"
- except:
- pass
-
- assert self.c1.transport.channel_max == upper_limit
-
-
- # TODO: Currently failing test - PROTON-1759 - skip
- def test_channel_max_limits_sessions(self):
- raise Skipped('Test fails - PROTON-1759')
- # This is an index -- so max number of channels should be 1.
- self.c1.transport.channel_max = 0
- self.c1.open()
- self.c2.open()
- ssn_0 = self.c2.session()
- assert ssn_0 != None
- ssn_0.open()
- self.pump()
- try:
- ssn_1 = self.c2.session()
- ssn_1.open()
- self.pump()
- assert False, "expected session exception"
- except SessionException:
- pass
-
- def test_cleanup(self):
- self.c1.open()
- self.c2.open()
- self.pump()
- assert self.c1.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
- assert self.c2.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
- t1 = self.c1.transport
- t2 = self.c2.transport
- c2 = self.c2
- self.c1.close()
- # release all references to C1, except that held by the transport
- self.cleanup()
- gc.collect()
- # transport should flush last state from C1:
- pump(t1, t2)
- assert c2.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED
-
- def test_user_config(self):
- self.c1.user = "vindaloo"
- self.c1.password = "secret"
- self.c1.open()
- self.pump()
-
- self.c2.user = "leela"
- self.c2.password = "trustno1"
- self.c2.open()
- self.pump()
-
- assert self.c1.user == "vindaloo", self.c1.user
- assert self.c1.password == None, self.c1.password
- assert self.c2.user == "leela", self.c2.user
- assert self.c2.password == None, self.c2.password
-
-class SessionTest(Test):
-
- def setUp(self):
- gc.enable()
- self.c1, self.c2 = self.connection()
- self.ssn = self.c1.session()
- self.c1.open()
- self.c2.open()
-
- def cleanup(self):
- # release resources created by this class
- super(SessionTest, self).cleanup()
- self.c1 = None
- self.c2 = None
- self.ssn = None
-
- def tearDown(self):
- self.cleanup()
- gc.collect()
- assert not gc.garbage
-
- def test_open_close(self):
- assert self.ssn.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
-
- self.ssn.open()
-
- assert self.ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT
-
- self.pump()
-
- assert self.ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT
-
- ssn = self.c2.session_head(Endpoint.REMOTE_ACTIVE | Endpoint.LOCAL_UNINIT)
-
- assert ssn != None
- assert ssn.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE
- assert self.ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT
-
- ssn.open()
-
- assert ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
- assert self.ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT
-
- self.pump()
-
- assert ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
- assert self.ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
-
- ssn.close()
-
- assert ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
- assert self.ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
-
- self.pump()
-
- assert ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
- assert self.ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED
-
- self.ssn.close()
-
- assert ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
- assert self.ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
-
- self.pump()
-
- assert ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
- assert self.ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
-
- def test_simultaneous_close(self):
- self.ssn.open()
- self.pump()
- ssn = self.c2.session_head(Endpoint.REMOTE_ACTIVE | Endpoint.LOCAL_UNINIT)
- assert ssn != None
- ssn.open()
- self.pump()
-
- assert self.ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
- assert ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
-
- self.ssn.close()
- ssn.close()
-
- assert self.ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
- assert ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
-
- self.pump()
-
- assert self.ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
- assert ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
-
- def test_closing_connection(self):
- self.ssn.open()
- self.pump()
- self.c1.close()
- self.pump()
- self.ssn.close()
- self.pump()
-
- def test_condition(self):
- self.ssn.open()
- self.pump()
- ssn = self.c2.session_head(Endpoint.REMOTE_ACTIVE | Endpoint.LOCAL_UNINIT)
- assert ssn != None
- ssn.open()
- self.pump()
-
- assert self.ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
- assert ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
-
- cond = Condition("blah:bleh", "this is a description", {symbol("foo"): "bar"})
- self.ssn.condition = cond
- self.ssn.close()
-
- self.pump()
-
- assert self.ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
- assert ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED
-
- rcond = ssn.remote_condition
- assert rcond == cond, (rcond, cond)
-
- def test_cleanup(self):
- snd, rcv = self.link("test-link")
- snd.open()
- rcv.open()
- self.pump()
- snd_ssn = snd.session
- rcv_ssn = rcv.session
- assert rcv_ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
- self.ssn = None
- snd_ssn.close()
- snd_ssn.free()
- del snd_ssn
- gc.collect()
- self.pump()
- assert rcv_ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED
-
- def test_reopen_on_same_session_without_free(self):
- """
- confirm that a link is correctly opened when attaching to a previously
- closed link *that has not been freed yet* on the same session
- """
- self.ssn.open()
- self.pump()
-
- ssn2 = self.c2.session_head(Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE)
- ssn2.open()
- self.pump()
- snd = self.ssn.sender("test-link")
- rcv = ssn2.receiver("test-link")
-
- assert snd.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
- assert rcv.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
-
- snd.open()
- rcv.open()
- self.pump()
-
- assert snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
- assert rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
-
- snd.close()
- rcv.close()
- self.pump()
-
- assert snd.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
- assert rcv.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
-
- snd = self.ssn.sender("test-link")
- rcv = ssn2.receiver("test-link")
- assert snd.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
- assert rcv.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
-
- snd.open()
- rcv.open()
- self.pump()
-
- assert snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
- assert rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
-
- def test_set_get_outgoing_window(self):
- assert self.ssn.outgoing_window == 2147483647
-
- self.ssn.outgoing_window = 1024
- assert self.ssn.outgoing_window == 1024
-
-
-class LinkTest(Test):
-
- def setUp(self):
- gc.enable()
- self.snd, self.rcv = self.link("test-link")
-
- def cleanup(self):
- # release resources created by this class
- super(LinkTest, self).cleanup()
- self.snd = None
- self.rcv = None
-
- def tearDown(self):
- self.cleanup()
- gc.collect()
- assert not gc.garbage, gc.garbage
-
- def test_open_close(self):
- assert self.snd.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
- assert self.rcv.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
-
- self.snd.open()
-
- assert self.snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT
- assert self.rcv.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
-
- self.pump()
-
- assert self.snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT
- assert self.rcv.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE
-
- self.rcv.open()
-
- assert self.snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT
- assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
-
- self.pump()
-
- assert self.snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
- assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
-
- self.snd.close()
-
- assert self.snd.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
- assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
-
- self.pump()
-
- assert self.snd.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
- assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED
-
- self.rcv.close()
-
- assert self.snd.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
- assert self.rcv.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
-
- self.pump()
-
- assert self.snd.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
- assert self.rcv.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
-
- def test_simultaneous_open_close(self):
- assert self.snd.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
- assert self.rcv.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
-
- self.snd.open()
- self.rcv.open()
-
- assert self.snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT
- assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT
-
- self.pump()
-
- assert self.snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
- assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
-
- self.snd.close()
- self.rcv.close()
-
- assert self.snd.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
- assert self.rcv.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
-
- self.pump()
-
- assert self.snd.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
- assert self.rcv.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
-
- def test_multiple(self):
- rcv = self.snd.session.receiver("second-rcv")
- assert rcv.name == "second-rcv"
- self.snd.open()
- rcv.open()
- self.pump()
- c2 = self.rcv.session.connection
- l = c2.link_head(Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE)
- while l:
- l.open()
- l = l.next(Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE)
- self.pump()
-
- assert self.snd
- assert rcv
- self.snd.close()
- rcv.close()
- ssn = rcv.session
- conn = ssn.connection
- ssn.close()
- conn.close()
- self.pump()
-
- def test_closing_session(self):
- self.snd.open()
- self.rcv.open()
- ssn1 = self.snd.session
- self.pump()
- ssn1.close()
- self.pump()
- self.snd.close()
- self.pump()
-
- def test_closing_connection(self):
- self.snd.open()
- self.rcv.open()
- ssn1 = self.snd.session
- c1 = ssn1.connection
- self.pump()
- c1.close()
- self.pump()
- self.snd.close()
- self.pump()
-
- def assertEqualTermini(self, t1, t2):
- assert t1.type == t2.type, (t1.type, t2.type)
- assert t1.address == t2.address, (t1.address, t2.address)
- assert t1.durability == t2.durability, (t1.durability, t2.durability)
- assert t1.expiry_policy == t2.expiry_policy, (t1.expiry_policy, t2.expiry_policy)
- assert t1.timeout == t2.timeout, (t1.timeout, t2.timeout)
- assert t1.dynamic == t2.dynamic, (t1.dynamic, t2.dynamic)
- for attr in ["properties", "capabilities", "outcomes", "filter"]:
- d1 = getattr(t1, attr)
- d2 = getattr(t2, attr)
- assert d1.format() == d2.format(), (attr, d1.format(), d2.format())
-
- def _test_source_target(self, config_source, config_target):
- if config_source is None:
- self.snd.source.type = Terminus.UNSPECIFIED
- else:
- config_source(self.snd.source)
- if config_target is None:
- self.snd.target.type = Terminus.UNSPECIFIED
- else:
- config_target(self.snd.target)
- self.snd.open()
- self.pump()
- self.assertEqualTermini(self.rcv.remote_source, self.snd.source)
- self.assertEqualTermini(self.rcv.remote_target, self.snd.target)
- self.rcv.target.copy(self.rcv.remote_target)
- self.rcv.source.copy(self.rcv.remote_source)
- self.rcv.open()
- self.pump()
- self.assertEqualTermini(self.snd.remote_target, self.snd.target)
- self.assertEqualTermini(self.snd.remote_source, self.snd.source)
-
- def test_source_target(self):
- self._test_source_target(TerminusConfig(address="source"),
- TerminusConfig(address="target"))
-
- def test_source(self):
- self._test_source_target(TerminusConfig(address="source"), None)
-
- def test_target(self):
- self._test_source_target(None, TerminusConfig(address="target"))
-
- def test_coordinator(self):
- self._test_source_target(None, TerminusConfig(type=Terminus.COORDINATOR))
-
- def test_source_target_full(self):
- self._test_source_target(TerminusConfig(address="source",
- timeout=3,
- dist_mode=Terminus.DIST_MODE_MOVE,
- filter=[("int", 1), ("symbol", "two"), ("string", "three")],
- capabilities=["one", "two", "three"]),
- TerminusConfig(address="source",
- timeout=7,
- capabilities=[]))
- def test_distribution_mode(self):
- self._test_source_target(TerminusConfig(address="source",
- dist_mode=Terminus.DIST_MODE_COPY),
- TerminusConfig(address="target"))
- assert self.rcv.remote_source.distribution_mode == Terminus.DIST_MODE_COPY
- assert self.rcv.remote_target.distribution_mode == Terminus.DIST_MODE_UNSPECIFIED
-
- def test_dynamic_link(self):
- self._test_source_target(TerminusConfig(address=None, dynamic=True), None)
- assert self.rcv.remote_source.dynamic
- assert self.rcv.remote_source.address is None
-
- def test_condition(self):
- self.snd.open()
- self.rcv.open()
- self.pump()
-
- assert self.snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
- assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
-
- cond = Condition("blah:bleh", "this is a description", {symbol("foo"): "bar"})
- self.snd.condition = cond
- self.snd.close()
-
- self.pump()
-
- assert self.snd.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
- assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED
-
- rcond = self.rcv.remote_condition
- assert rcond == cond, (rcond, cond)
-
- def test_settle_mode(self):
- self.snd.snd_settle_mode = Link.SND_UNSETTLED
- assert self.snd.snd_settle_mode == Link.SND_UNSETTLED
- self.rcv.rcv_settle_mode = Link.RCV_SECOND
- assert self.rcv.rcv_settle_mode == Link.RCV_SECOND
-
- assert self.snd.remote_rcv_settle_mode != Link.RCV_SECOND
- assert self.rcv.remote_snd_settle_mode != Link.SND_UNSETTLED
-
- self.snd.open()
- self.rcv.open()
- self.pump()
-
- assert self.snd.remote_rcv_settle_mode == Link.RCV_SECOND
- assert self.rcv.remote_snd_settle_mode == Link.SND_UNSETTLED
-
- def test_max_message_size(self):
- assert self.snd.max_message_size == 0
- assert self.rcv.remote_max_message_size == 0
- self.snd.max_message_size = 13579
- self.snd.open()
- self.rcv.open()
- self.pump()
- assert self.rcv.remote_max_message_size == 13579
-
- def test_cleanup(self):
- snd, rcv = self.link("test-link")
- snd.open()
- rcv.open()
- self.pump()
- assert rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
- snd.close()
- snd.free()
- del snd
- gc.collect()
- self.pump()
- assert rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED
-
-class TerminusConfig:
-
- def __init__(self, type=None, address=None, timeout=None, durability=None,
- filter=None, capabilities=None, dynamic=False, dist_mode=None):
- self.address = address
- self.timeout = timeout
- self.durability = durability
- self.filter = filter
- self.capabilities = capabilities
- self.dynamic = dynamic
- self.dist_mode = dist_mode
- self.type = type
-
- def __call__(self, terminus):
- if self.type is not None:
- terminus.type = self.type
- if self.address is not None:
- terminus.address = self.address
- if self.timeout is not None:
- terminus.timeout = self.timeout
- if self.durability is not None:
- terminus.durability = self.durability
- if self.capabilities is not None:
- terminus.capabilities.put_array(False, Data.SYMBOL)
- terminus.capabilities.enter()
- for c in self.capabilities:
- terminus.capabilities.put_symbol(c)
- if self.filter is not None:
- terminus.filter.put_map()
- terminus.filter.enter()
- for (t, v) in self.filter:
- setter = getattr(terminus.filter, "put_%s" % t)
- setter(v)
- if self.dynamic:
- terminus.dynamic = True
- if self.dist_mode is not None:
- terminus.distribution_mode = self.dist_mode
-
-class TransferTest(Test):
-
- def setUp(self):
- gc.enable()
- self.snd, self.rcv = self.link("test-link")
- self.c1 = self.snd.session.connection
- self.c2 = self.rcv.session.connection
- self.snd.open()
- self.rcv.open()
- self.pump()
-
- def cleanup(self):
- # release resources created by this class
- super(TransferTest, self).cleanup()
- self.c1 = None
- self.c2 = None
- self.snd = None
- self.rcv = None
-
- def tearDown(self):
- self.cleanup()
- gc.collect()
- assert not gc.garbage
-
- def test_work_queue(self):
- assert self.c1.work_head is None
- self.snd.delivery("tag")
- assert self.c1.work_head is None
- self.rcv.flow(1)
- self.pump()
- d = self.c1.work_head
- assert d is not None
- tag = d.tag
- assert tag == "tag", tag
- assert d.writable
-
- n = self.snd.send(b"this is a test")
- assert self.snd.advance()
- assert self.c1.work_head is None
-
- self.pump()
-
- d = self.c2.work_head
- assert d.tag == "tag"
- assert d.readable
-
- def test_multiframe(self):
- self.rcv.flow(1)
- self.snd.delivery("tag")
- msg = b"this is a test"
- n = self.snd.send(msg)
- assert n == len(msg)
-
- self.pump()
-
- d = self.rcv.current
- assert d
- assert d.tag == "tag", repr(d.tag)
- assert d.readable
-
- binary = self.rcv.recv(1024)
- assert binary == msg, (binary, msg)
-
- binary = self.rcv.recv(1024)
- assert binary == b""
-
- msg = b"this is more"
- n = self.snd.send(msg)
- assert n == len(msg)
- assert self.snd.advance()
-
- self.pump()
-
- binary = self.rcv.recv(1024)
- assert binary == msg, (binary, msg)
-
- binary = self.rcv.recv(1024)
- assert binary is None
-
- def test_disposition(self):
- self.rcv.flow(1)
-
- self.pump()
-
- sd = self.snd.delivery("tag")
- msg = b"this is a test"
- n = self.snd.send(msg)
- assert n == len(msg)
- assert self.snd.advance()
-
- self.pump()
-
- rd = self.rcv.current
- assert rd is not None
- assert rd.tag == sd.tag
- rmsg = self.rcv.recv(1024)
- assert rmsg == msg
- rd.update(Delivery.ACCEPTED)
-
- self.pump()
-
- rdisp = sd.remote_state
- ldisp = rd.local_state
- assert rdisp == ldisp == Delivery.ACCEPTED, (rdisp, ldisp)
- assert sd.updated
-
- sd.update(Delivery.ACCEPTED)
-
- self.pump()
-
- assert sd.local_state == rd.remote_state == Delivery.ACCEPTED
- sd.settle()
-
- def test_delivery_id_ordering(self):
- self.rcv.flow(1024)
- self.pump(buffer_size=64*1024)
-
- #fill up delivery buffer on sender
- for m in range(1024):
- sd = self.snd.delivery("tag%s" % m)
- msg = ("message %s" % m).encode('ascii')
- n = self.snd.send(msg)
- assert n == len(msg)
- assert self.snd.advance()
-
- self.pump(buffer_size=64*1024)
-
- #receive a session-windows worth of messages and accept them
- for m in range(1024):
- rd = self.rcv.current
- assert rd is not None, m
- assert rd.tag == ("tag%s" % m), (rd.tag, m)
- msg = self.rcv.recv(1024)
- assert msg == ("message %s" % m).encode('ascii'), (msg, m)
- rd.update(Delivery.ACCEPTED)
- rd.settle()
-
- self.pump(buffer_size=64*1024)
-
- #add some new deliveries
- for m in range(1024, 1450):
- sd = self.snd.delivery("tag%s" % m)
- msg = ("message %s" % m).encode('ascii')
- n = self.snd.send(msg)
- assert n == len(msg)
- assert self.snd.advance()
-
- #handle all disposition changes to sent messages
- d = self.c1.work_head
- while d:
- next_d = d.work_next
- if d.updated:
- d.update(Delivery.ACCEPTED)
- d.settle()
- d = next_d
-
- #submit some more deliveries
- for m in range(1450, 1500):
- sd = self.snd.delivery("tag%s" % m)
- msg = ("message %s" % m).encode('ascii')
- n = self.snd.send(msg)
- assert n == len(msg)
- assert self.snd.advance()
-
- self.pump(buffer_size=64*1024)
- self.rcv.flow(1024)
- self.pump(buffer_size=64*1024)
-
- #verify remaining messages can be received and accepted
- for m in range(1024, 1500):
- rd = self.rcv.current
- assert rd is not None, m
- assert rd.tag == ("tag%s" % m), (rd.tag, m)
- msg = self.rcv.recv(1024)
- assert msg == ("message %s" % m).encode('ascii'), (msg, m)
- rd.update(Delivery.ACCEPTED)
- rd.settle()
-
- def test_cleanup(self):
- self.rcv.flow(10)
- self.pump()
-
- for x in range(10):
- self.snd.delivery("tag%d" % x)
- msg = b"this is a test"
- n = self.snd.send(msg)
- assert n == len(msg)
- assert self.snd.advance()
- self.snd.close()
- self.snd.free()
- self.snd = None
- gc.collect()
-
- self.pump()
-
- for x in range(10):
- rd = self.rcv.current
- assert rd is not None
- assert rd.tag == "tag%d" % x
- rmsg = self.rcv.recv(1024)
- assert self.rcv.advance()
- assert rmsg == msg
- # close of snd should've settled:
- assert rd.settled
- rd.settle()
-
-class MaxFrameTransferTest(Test):
-
- def setUp(self):
- pass
-
- def cleanup(self):
- # release resources created by this class
- super(MaxFrameTransferTest, self).cleanup()
- self.c1 = None
- self.c2 = None
- self.snd = None
- self.rcv = None
-
- def tearDown(self):
- self.cleanup()
-
- def message(self, size):
- parts = []
- for i in range(size):
- parts.append(str(i))
- return "/".join(parts)[:size].encode("utf-8")
-
- def testMinFrame(self):
- """
- Configure receiver to support minimum max-frame as defined by AMQP-1.0.
- Verify transfer of messages larger than 512.
- """
- self.snd, self.rcv = self.link("test-link", max_frame=[0,512])
- self.c1 = self.snd.session.connection
- self.c2 = self.rcv.session.connection
- self.snd.open()
- self.rcv.open()
- self.pump()
- assert self.rcv.session.connection.transport.max_frame_size == 512
- assert self.snd.session.connection.transport.remote_max_frame_size == 512
-
- self.rcv.flow(1)
- self.snd.delivery("tag")
- msg = self.message(513)
- n = self.snd.send(msg)
- assert n == len(msg)
- assert self.snd.advance()
-
- self.pump()
-
- binary = self.rcv.recv(513)
- assert binary == msg
-
- binary = self.rcv.recv(1024)
- assert binary == None
-
- def testOddFrame(self):
- """
- Test an odd sized max limit with data that will require multiple frames to
- be transfered.
- """
- self.snd, self.rcv = self.link("test-link", max_frame=[0,521])
- self.c1 = self.snd.session.connection
- self.c2 = self.rcv.session.connection
- self.snd.open()
- self.rcv.open()
- self.pump()
- assert self.rcv.session.connection.transport.max_frame_size == 521
- assert self.snd.session.connection.transport.remote_max_frame_size == 521
-
- self.rcv.flow(2)
- self.snd.delivery("tag")
- msg = ("X" * 1699).encode('utf-8')
- n = self.snd.send(msg)
- assert n == len(msg)
- assert self.snd.advance()
-
- self.pump()
-
- binary = self.rcv.recv(1699)
- assert binary == msg
-
- binary = self.rcv.recv(1024)
- assert binary == None
-
- self.rcv.advance()
-
- self.snd.delivery("gat")
- msg = self.message(1426)
- n = self.snd.send(msg)
- assert n == len(msg)
- assert self.snd.advance()
-
- self.pump()
-
- binary = self.rcv.recv(1426)
- assert binary == msg
-
- self.pump()
-
- binary = self.rcv.recv(1024)
- assert binary == None
-
- def testSendQueuedMultiFrameMessages(self, sendSingleFrameMsg = False):
- """
- Test that multiple queued messages on the same link
- with multi-frame content are sent correctly. Use an
- odd max frame size, send enough data to use many.
- """
- self.snd, self.rcv = self.link("test-link", max_frame=[0,517])
- self.c1 = self.snd.session.connection
- self.c2 = self.rcv.session.connection
- self.snd.open()
- self.rcv.open()
- self.pump()
- assert self.rcv.session.connection.transport.max_frame_size == 517
- assert self.snd.session.connection.transport.remote_max_frame_size == 517
-
- self.rcv.flow(5)
-
- self.pump()
-
- # Send a delivery with 5 frames, all bytes as X1234
- self.snd.delivery("tag")
- msg = ("X1234" * 425).encode('utf-8')
- assert 2125 == len(msg)
- n = self.snd.send(msg)
- assert n == len(msg)
- assert self.snd.advance()
-
- # Send a delivery with 5 frames, all bytes as Y5678
- self.snd.delivery("tag2")
- msg2 = ("Y5678" * 425).encode('utf-8')
- assert 2125 == len(msg2)
- n = self.snd.send(msg2)
- assert n == len(msg2)
- assert self.snd.advance()
-
- self.pump()
-
- if sendSingleFrameMsg:
- # Send a delivery with 1 frame
- self.snd.delivery("tag3")
- msg3 = ("Z").encode('utf-8')
- assert 1 == len(msg3)
- n = self.snd.send(msg3)
- assert n == len(msg3)
- assert self.snd.advance()
- self.pump()
-
- binary = self.rcv.recv(5000)
- self.assertEqual(binary, msg)
-
- self.rcv.advance()
-
- binary2 = self.rcv.recv(5000)
- self.assertEqual(binary2, msg2)
-
- self.rcv.advance()
-
- if sendSingleFrameMsg:
- binary3 = self.rcv.recv(5000)
- self.assertEqual(binary3, msg3)
- self.rcv.advance()
-
- self.pump()
-
- def testSendQueuedMultiFrameMessagesThenSingleFrameMessage(self):
- self.testSendQueuedMultiFrameMessages(sendSingleFrameMsg = True)
-
- def testBigMessage(self):
- """
- Test transferring a big message.
- """
- self.snd, self.rcv = self.link("test-link")
- self.c1 = self.snd.session.connection
- self.c2 = self.rcv.session.connection
- self.snd.open()
- self.rcv.open()
- self.pump()
-
- self.rcv.flow(2)
- self.snd.delivery("tag")
- msg = self.message(1024*256)
- n = self.snd.send(msg)
- assert n == len(msg)
- assert self.snd.advance()
-
- self.pump()
-
- binary = self.rcv.recv(1024*256)
- assert binary == msg
-
- binary = self.rcv.recv(1024)
- assert binary == None
-
-
-class IdleTimeoutTest(Test):
-
- def setUp(self):
- pass
-
- def cleanup(self):
- # release resources created by this class
- super(IdleTimeoutTest, self).cleanup()
- self.snd = None
- self.rcv = None
- self.c1 = None
- self.c2 = None
-
- def tearDown(self):
- self.cleanup()
-
- def message(self, size):
- parts = []
- for i in range(size):
- parts.append(str(i))
- return "/".join(parts)[:size]
-
- def testGetSet(self):
- """
- Verify the configuration and negotiation of the idle timeout.
- """
-
- self.snd, self.rcv = self.link("test-link", idle_timeout=[1.0,2.0])
- self.c1 = self.snd.session.connection
- self.c2 = self.rcv.session.connection
- self.snd.open()
- self.rcv.open()
- self.pump()
- # proton advertises 1/2 the configured timeout to the peer:
- assert self.rcv.session.connection.transport.idle_timeout == 2.0
- assert self.rcv.session.connection.transport.remote_idle_timeout == 0.5
- assert self.snd.session.connection.transport.idle_timeout == 1.0
- assert self.snd.session.connection.transport.remote_idle_timeout == 1.0
-
- def testTimeout(self):
- """
- Verify the AMQP Connection idle timeout.
- """
-
- # snd will timeout the Connection if no frame is received within 1000 ticks
- self.snd, self.rcv = self.link("test-link", idle_timeout=[1.0,0])
- self.c1 = self.snd.session.connection
- self.c2 = self.rcv.session.connection
- self.snd.open()
- self.rcv.open()
- self.pump()
-
- t_snd = self.snd.session.connection.transport
- t_rcv = self.rcv.session.connection.transport
- assert t_rcv.idle_timeout == 0.0
- # proton advertises 1/2 the timeout (see spec)
- assert t_rcv.remote_idle_timeout == 0.5
- assert t_snd.idle_timeout == 1.0
- assert t_snd.remote_idle_timeout == 0.0
-
- sndr_frames_in = t_snd.frames_input
- rcvr_frames_out = t_rcv.frames_output
-
- # at t+1msec, nothing should happen:
- clock = 0.001
- assert t_snd.tick(clock) == 1.001, "deadline for remote timeout"
- assert t_rcv.tick(clock) == 0.251, "deadline to send keepalive"
- self.pump()
- assert sndr_frames_in == t_snd.frames_input, "unexpected received frame"
-
- # at one tick from expected idle frame send, nothing should happen:
- clock = 0.250
- assert t_snd.tick(clock) == 1.001, "deadline for remote timeout"
- assert t_rcv.tick(clock) == 0.251, "deadline to send keepalive"
- self.pump()
- assert sndr_frames_in == t_snd.frames_input, "unexpected received frame"
-
- # this should cause rcvr to expire and send a keepalive
- clock = 0.251
- assert t_snd.tick(clock) == 1.001, "deadline for remote timeout"
- assert t_rcv.tick(clock) == 0.501, "deadline to send keepalive"
- self.pump()
- sndr_frames_in += 1
- rcvr_frames_out += 1
- assert sndr_frames_in == t_snd.frames_input, "unexpected received frame"
- assert rcvr_frames_out == t_rcv.frames_output, "unexpected frame"
-
- # since a keepalive was received, sndr will rebase its clock against this tick:
- # and the receiver should not change its deadline
- clock = 0.498
- assert t_snd.tick(clock) == 1.498, "deadline for remote timeout"
- assert t_rcv.tick(clock) == 0.501, "deadline to send keepalive"
- self.pump()
- assert sndr_frames_in == t_snd.frames_input, "unexpected received frame"
-
- # now expire sndr
- clock = 1.499
- t_snd.tick(clock)
- self.pump()
- assert self.c2.state & Endpoint.REMOTE_CLOSED
- assert self.c2.remote_condition.name == "amqp:resource-limit-exceeded"
-
-class CreditTest(Test):
-
- def setUp(self):
- self.snd, self.rcv = self.link("test-link", max_frame=(16*1024, 16*1024))
- self.c1 = self.snd.session.connection
- self.c2 = self.rcv.session.connection
- self.snd.open()
- self.rcv.open()
- self.pump()
-
- def cleanup(self):
- # release resources created by this class
- super(CreditTest, self).cleanup()
- self.c1 = None
- self.snd = None
- self.c2 = None
- self.rcv2 = None
- self.snd2 = None
-
- def tearDown(self):
- self.cleanup()
-
- def testCreditSender(self, count=1024):
- credit = self.snd.credit
- assert credit == 0, credit
- self.rcv.flow(10)
- self.pump()
- credit = self.snd.credit
- assert credit == 10, credit
-
- self.rcv.flow(count)
- self.pump()
- credit = self.snd.credit
- assert credit == 10 + count, credit
-
- def testCreditReceiver(self):
- self.rcv.flow(10)
- self.pump()
- assert self.rcv.credit == 10, self.rcv.credit
-
- d = self.snd.delivery("tag")
- assert d
- assert self.snd.advance()
- self.pump()
- assert self.rcv.credit == 10, self.rcv.credit
- assert self.rcv.queued == 1, self.rcv.queued
- c = self.rcv.current
- assert c.tag == "tag", c.tag
- assert self.rcv.advance()
- assert self.rcv.credit == 9, self.rcv.credit
- assert self.rcv.queued == 0, self.rcv.queued
-
- def _testBufferingOnClose(self, a, b):
- for i in range(10):
- d = self.snd.delivery("tag-%s" % i)
- assert d
- d.settle()
- self.pump()
- assert self.snd.queued == 10
-
- endpoints = {"connection": (self.c1, self.c2),
- "session": (self.snd.session, self.rcv.session),
- "link": (self.snd, self.rcv)}
-
- local_a, remote_a = endpoints[a]
- local_b, remote_b = endpoints[b]
-
- remote_b.close()
- self.pump()
- assert local_b.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED
- local_a.close()
- self.pump()
- assert remote_a.state & Endpoint.REMOTE_CLOSED
- assert self.snd.queued == 10
-
- def testBufferingOnCloseLinkLink(self):
- self._testBufferingOnClose("link", "link")
-
- def testBufferingOnCloseLinkSession(self):
- self._testBufferingOnClose("link", "session")
-
- def testBufferingOnCloseLinkConnection(self):
- self._testBufferingOnClose("link", "connection")
-
- def testBufferingOnCloseSessionLink(self):
- self._testBufferingOnClose("session", "link")
-
- def testBufferingOnCloseSessionSession(self):
- self._testBufferingOnClose("session", "session")
-
- def testBufferingOnCloseSessionConnection(self):
- self._testBufferingOnClose("session", "connection")
-
- def testBufferingOnCloseConnectionLink(self):
- self._testBufferingOnClose("connection", "link")
-
- def testBufferingOnCloseConnectionSession(self):
- self._testBufferingOnClose("connection", "session")
-
- def testBufferingOnCloseConnectionConnection(self):
- self._testBufferingOnClose("connection", "connection")
-
- def testFullDrain(self):
- assert self.rcv.credit == 0
- assert self.snd.credit == 0
- self.rcv.drain(10)
- assert self.rcv.draining()
- assert self.rcv.credit == 10
- assert self.snd.credit == 0
- self.pump()
- assert self.rcv.credit == 10
- assert self.snd.credit == 10
- assert self.rcv.draining()
- self.snd.drained()
- assert self.rcv.credit == 10
- assert self.snd.credit == 0
- assert self.rcv.draining()
- self.pump()
- assert self.rcv.credit == 0
- assert self.snd.credit == 0
- assert not self.rcv.draining()
- drained = self.rcv.drained()
- assert drained == 10, drained
-
- def testPartialDrain(self):
- self.rcv.drain(2)
- assert self.rcv.draining()
- self.pump()
-
- d = self.snd.delivery("tag")
- assert d
- assert self.snd.advance()
- self.snd.drained()
- assert self.rcv.draining()
- self.pump()
- assert not self.rcv.draining()
-
- c = self.rcv.current
- assert self.rcv.queued == 1, self.rcv.queued
- assert c.tag == d.tag, c.tag
- assert self.rcv.advance()
- assert not self.rcv.current
- assert self.rcv.credit == 0, self.rcv.credit
- assert not self.rcv.draining()
- drained = self.rcv.drained()
- assert drained == 1, drained
-
- def testDrainFlow(self):
- assert self.rcv.credit == 0
- assert self.snd.credit == 0
- self.rcv.drain(10)
- assert self.rcv.credit == 10
- assert self.snd.credit == 0
- self.pump()
- assert self.rcv.credit == 10
- assert self.snd.credit == 10
- self.snd.drained()
- assert self.rcv.credit == 10
- assert self.snd.credit == 0
- self.pump()
- assert self.rcv.credit == 0
- assert self.snd.credit == 0
- self.rcv.flow(10)
- assert self.rcv.credit == 10
- assert self.snd.credit == 0
- self.pump()
- assert self.rcv.credit == 10
- assert self.snd.credit == 10
- self.snd.drained()
- assert self.rcv.credit == 10
- assert self.snd.credit == 10
- self.pump()
- assert self.rcv.credit == 10
- assert self.snd.credit == 10
- drained = self.rcv.drained()
- assert drained == 10, drained
-
- def testNegative(self):
- assert self.snd.credit == 0
- d = self.snd.delivery("tag")
- assert d
- assert self.snd.advance()
- self.pump()
-
- assert self.rcv.credit == 0
- assert self.rcv.queued == 0
-
- self.rcv.flow(1)
- assert self.rcv.credit == 1
- assert self.rcv.queued == 0
- self.pump()
- assert self.rcv.credit == 1
- assert self.rcv.queued == 1, self.rcv.queued
-
- c = self.rcv.current
- assert c
- assert c.tag == "tag"
- assert self.rcv.advance()
- assert self.rcv.credit == 0
- assert self.rcv.queued == 0
-
- def testDrainZero(self):
- assert self.snd.credit == 0
- assert self.rcv.credit == 0
- assert self.rcv.queued == 0
- drained = self.rcv.drained()
- assert drained == 0
-
- self.rcv.flow(10)
- self.pump()
- assert self.snd.credit == 10
- assert self.rcv.credit == 10
- assert self.rcv.queued == 0
-
- self.snd.drained()
- self.pump()
- assert self.snd.credit == 10
- assert self.rcv.credit == 10
- assert self.rcv.queued == 0
- drained = self.rcv.drained()
- assert drained == 0
-
- self.rcv.drain(0)
- assert self.snd.credit == 10
- assert self.rcv.credit == 10
- assert self.rcv.queued == 0
-
- self.pump()
-
- assert self.snd.credit == 10
- assert self.rcv.credit == 10
- assert self.rcv.queued == 0
-
- self.snd.drained()
- assert self.snd.credit == 0
- assert self.rcv.credit == 10
- assert self.rcv.queued == 0
- drained = self.rcv.drained()
- assert drained == 0
- self.pump()
-
- assert self.snd.credit == 0
- assert self.rcv.credit == 0
- assert self.rcv.queued == 0
- drained = self.rcv.drained()
- assert drained == 10
-
-
- def testDrainOrder(self):
- """ Verify drain/drained works regardless of ordering. See PROTON-401
- """
- assert self.snd.credit == 0
- assert self.rcv.credit == 0
- assert self.rcv.queued == 0
-
- #self.rcv.session.connection.transport.trace(Transport.TRACE_FRM)
- #self.snd.session.connection.transport.trace(Transport.TRACE_FRM)
-
- ## verify that a sender that has reached the drain state will respond
- ## promptly to a drain issued by the peer.
- self.rcv.flow(10)
- self.pump()
- assert self.snd.credit == 10, self.snd.credit
- assert self.rcv.credit == 10, self.rcv.credit
-
- sd = self.snd.delivery("tagA")
- assert sd
- n = self.snd.send(b"A")
- assert n == 1
- self.pump()
- self.snd.advance()
-
- # done sending, so signal that we are drained:
- self.snd.drained()
- self.pump()
- assert self.snd.credit == 9, self.snd.credit
- assert self.rcv.credit == 10, self.rcv.credit
-
- self.rcv.drain(0)
- self.pump()
- assert self.snd.credit == 9, self.snd.credit
- assert self.rcv.credit == 10, self.rcv.credit
-
- data = self.rcv.recv(10)
- assert data == b"A", data
- self.rcv.advance()
- self.pump()
- assert self.snd.credit == 9, self.snd.credit
- assert self.rcv.credit == 9, self.rcv.credit
-
- self.snd.drained()
- self.pump()
- assert self.snd.credit == 0, self.snd.credit
- assert self.rcv.credit == 0, self.rcv.credit
-
- # verify that a drain requested by the peer is not "acknowledged" until
- # after the sender has completed sending its pending messages
-
- self.rcv.flow(10)
- self.pump()
- assert self.snd.credit == 10, self.snd.credit
- assert self.rcv.credit == 10, self.rcv.credit
-
- sd = self.snd.delivery("tagB")
- assert sd
- n = self.snd.send(b"B")
- assert n == 1
- self.snd.advance()
- self.pump()
- assert self.snd.credit == 9, self.snd.credit
- assert self.rcv.credit == 10, self.rcv.credit
-
- self.rcv.drain(0)
- self.pump()
- assert self.snd.credit == 9, self.snd.credit
- assert self.rcv.credit == 10, self.rcv.credit
-
- sd = self.snd.delivery("tagC")
- assert sd
- n = self.snd.send(b"C")
- assert n == 1
- self.snd.advance()
- self.pump()
- assert self.snd.credit == 8, self.snd.credit
- assert self.rcv.credit == 10, self.rcv.credit
-
- # now that the sender has finished sending everything, it can signal
- # drained
- self.snd.drained()
- self.pump()
- assert self.snd.credit == 0, self.snd.credit
- assert self.rcv.credit == 2, self.rcv.credit
-
- data = self.rcv.recv(10)
- assert data == b"B", data
- self.rcv.advance()
- data = self.rcv.recv(10)
- assert data == b"C", data
- self.rcv.advance()
- self.pump()
- assert self.snd.credit == 0, self.snd.credit
- assert self.rcv.credit == 0, self.rcv.credit
-
-
- def testPushback(self, count=10):
- assert self.snd.credit == 0
- assert self.rcv.credit == 0
-
- self.rcv.flow(count)
- self.pump()
-
- for i in range(count):
- d = self.snd.delivery("tag%s" % i)
- assert d
- self.snd.advance()
-
- assert self.snd.queued == count
- assert self.rcv.queued == 0
- self.pump()
- assert self.snd.queued == 0
- assert self.rcv.queued == count
-
- d = self.snd.delivery("extra")
- self.snd.advance()
-
- assert self.snd.queued == 1
- assert self.rcv.queued == count
- self.pump()
- assert self.snd.queued == 1
- assert self.rcv.queued == count
-
- def testHeadOfLineBlocking(self):
- self.snd2 = self.snd.session.sender("link-2")
- self.rcv2 = self.rcv.session.receiver("link-2")
- self.snd2.open()
- self.rcv2.open()
- self.pump()
- assert self.snd2.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
- assert self.rcv2.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
-
- self.rcv.flow(5)
- self.rcv2.flow(10)
- self.pump()
-
- assert self.snd.credit == 5
- assert self.snd2.credit == 10
-
- for i in range(10):
- tag = "test %d" % i
- self.snd.delivery( tag )
- self.snd.send( tag.encode("ascii") )
- assert self.snd.advance()
- self.snd2.delivery( tag )
- self.snd2.send( tag.encode("ascii") )
- assert self.snd2.advance()
-
- self.pump()
-
- for i in range(5):
- b = self.rcv.recv( 512 )
- assert self.rcv.advance()
- b = self.rcv2.recv( 512 )
- assert self.rcv2.advance()
-
- for i in range(5):
- b = self.rcv2.recv( 512 )
- assert self.rcv2.advance()
-
-
-
-class SessionCreditTest(Test):
-
- def tearDown(self):
- self.cleanup()
-
- def testBuffering(self, count=32, size=1024, capacity=16*1024, max_frame=1024):
- snd, rcv = self.link("test-link", max_frame=(max_frame, max_frame))
- rcv.session.incoming_capacity = capacity
- snd.open()
- rcv.open()
- rcv.flow(count)
- self.pump()
-
- assert count > 0
-
- total_bytes = count * size
-
- assert snd.session.outgoing_bytes == 0, snd.session.outgoing_bytes
- assert rcv.session.incoming_bytes == 0, rcv.session.incoming_bytes
- assert snd.queued == 0, snd.queued
- assert rcv.queued == 0, rcv.queued
-
- data = bytes(bytearray(size))
- idx = 0
- while snd.credit:
- d = snd.delivery("tag%s" % idx)
- assert d
- n = snd.send(data)
- assert n == size, (n, size)
- assert snd.advance()
- self.pump()
- idx += 1
-
- assert idx == count, (idx, count)
-
- assert snd.session.outgoing_bytes < total_bytes, (snd.session.outgoing_bytes, total_bytes)
- assert rcv.session.incoming_bytes < capacity, (rcv.session.incoming_bytes, capacity)
- assert snd.session.outgoing_bytes + rcv.session.incoming_bytes == total_bytes, \
- (snd.session.outgoing_bytes, rcv.session.incoming_bytes, total_bytes)
- if snd.session.outgoing_bytes > 0:
- available = rcv.session.incoming_capacity - rcv.session.incoming_bytes
- assert available < max_frame, (available, max_frame)
-
- for i in range(count):
- d = rcv.current
- assert d, i
- pending = d.pending
- before = rcv.session.incoming_bytes
- assert rcv.advance()
- after = rcv.session.incoming_bytes
- assert before - after == pending, (before, after, pending)
- snd_before = snd.session.incoming_bytes
- self.pump()
- snd_after = snd.session.incoming_bytes
-
- assert rcv.session.incoming_bytes < capacity
- if snd_before > 0:
- assert capacity - after <= max_frame
- assert snd_before > snd_after
- if snd_after > 0:
- available = rcv.session.incoming_capacity - rcv.session.incoming_bytes
- assert available < max_frame, available
-
- def testBufferingSize16(self):
- self.testBuffering(size=16)
-
- def testBufferingSize256(self):
- self.testBuffering(size=256)
-
- def testBufferingSize512(self):
- self.testBuffering(size=512)
-
- def testBufferingSize2048(self):
- self.testBuffering(size=2048)
-
- def testBufferingSize1025(self):
- self.testBuffering(size=1025)
-
- def testBufferingSize1023(self):
- self.testBuffering(size=1023)
-
- def testBufferingSize989(self):
- self.testBuffering(size=989)
-
- def testBufferingSize1059(self):
- self.testBuffering(size=1059)
-
- def testCreditWithBuffering(self):
- snd, rcv = self.link("test-link", max_frame=(1024, 1024))
- rcv.session.incoming_capacity = 64*1024
- snd.open()
- rcv.open()
- rcv.flow(128)
- self.pump()
-
- assert snd.credit == 128, snd.credit
- assert rcv.queued == 0, rcv.queued
-
- idx = 0
- while snd.credit:
- d = snd.delivery("tag%s" % idx)
- snd.send(("x"*1024).encode('ascii'))
- assert d
- assert snd.advance()
- self.pump()
- idx += 1
-
- assert idx == 128, idx
- assert rcv.queued < 128, rcv.queued
-
- rcv.flow(1)
- self.pump()
- assert snd.credit == 1, snd.credit
-
-class SettlementTest(Test):
-
- def setUp(self):
- self.snd, self.rcv = self.link("test-link")
- self.c1 = self.snd.session.connection
- self.c2 = self.rcv.session.connection
- self.snd.open()
- self.rcv.open()
- self.pump()
-
- def cleanup(self):
- # release resources created by this class
- super(SettlementTest, self).cleanup()
- self.c1 = None
- self.snd = None
- self.c2 = None
- self.rcv2 = None
- self.snd2 = None
-
- def tearDown(self):
- self.cleanup()
-
- def testSettleCurrent(self):
- self.rcv.flow(10)
- self.pump()
-
- assert self.snd.credit == 10, self.snd.credit
- d = self.snd.delivery("tag")
- e = self.snd.delivery("tag2")
- assert d
- assert e
- c = self.snd.current
- assert c.tag == "tag", c.tag
- c.settle()
- c = self.snd.current
- assert c.tag == "tag2", c.tag
- c.settle()
- c = self.snd.current
- assert not c
- self.pump()
-
- c = self.rcv.current
- assert c
- assert c.tag == "tag", c.tag
- assert c.settled
- c.settle()
- c = self.rcv.current
- assert c
- assert c.tag == "tag2", c.tag
- assert c.settled
- c.settle()
- c = self.rcv.current
- assert not c
-
- def testUnsettled(self):
- self.rcv.flow(10)
- self.pump()
-
- assert self.snd.unsettled == 0, self.snd.unsettled
- assert self.rcv.unsettled == 0, self.rcv.unsettled
-
- d = self.snd.delivery("tag")
- assert d
- assert self.snd.unsettled == 1, self.snd.unsettled
- assert self.rcv.unsettled == 0, self.rcv.unsettled
- assert self.snd.advance()
- self.pump()
-
- assert self.snd.unsettled == 1, self.snd.unsettled
- assert self.rcv.unsettled == 1, self.rcv.unsettled
-
- c = self.rcv.current
- assert c
- c.settle()
-
- assert self.snd.unsettled == 1, self.snd.unsettled
- assert self.rcv.unsettled == 0, self.rcv.unsettled
-
- def testMultipleUnsettled(self, count=1024, size=1024):
- self.rcv.flow(count)
- self.pump()
-
- assert self.snd.unsettled == 0, self.snd.unsettled
- assert self.rcv.unsettled == 0, self.rcv.unsettled
-
- unsettled = []
-
- for i in range(count):
- sd = self.snd.delivery("tag%s" % i)
- assert sd
- n = self.snd.send(("x"*size).encode('ascii'))
- assert n == size, n
- assert self.snd.advance()
- self.pump()
-
- rd = self.rcv.current
- assert rd, "did not receive delivery %s" % i
- n = rd.pending
- b = self.rcv.recv(n)
- assert len(b) == n, (b, n)
- rd.update(Delivery.ACCEPTED)
- assert self.rcv.advance()
- self.pump()
- unsettled.append(rd)
-
- assert self.rcv.unsettled == count
-
- for rd in unsettled:
- rd.settle()
-
- def testMultipleUnsettled2K1K(self):
- self.testMultipleUnsettled(2048, 1024)
-
- def testMultipleUnsettled4K1K(self):
- self.testMultipleUnsettled(4096, 1024)
-
- def testMultipleUnsettled1K2K(self):
- self.testMultipleUnsettled(1024, 2048)
-
- def testMultipleUnsettled2K2K(self):
- self.testMultipleUnsettled(2048, 2048)
-
- def testMultipleUnsettled4K2K(self):
- self.testMultipleUnsettled(4096, 2048)
-
-class PipelineTest(Test):
-
- def setUp(self):
- self.c1, self.c2 = self.connection()
-
- def cleanup(self):
- # release resources created by this class
- super(PipelineTest, self).cleanup()
- self.c1 = None
- self.c2 = None
-
- def tearDown(self):
- self.cleanup()
-
- def test(self):
- ssn = self.c1.session()
- snd = ssn.sender("sender")
- self.c1.open()
- ssn.open()
- snd.open()
-
- for i in range(10):
- t = "delivery-%s" % i
- d = snd.delivery(t)
- snd.send(t.encode('ascii'))
- d.settle()
-
- snd.close()
- ssn.close()
- self.c1.close()
-
- self.pump()
-
- state = self.c2.state
- assert state == (Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE), "%x" % state
- ssn2 = self.c2.session_head(Endpoint.LOCAL_UNINIT)
- assert ssn2
- state == ssn2.state
- assert state == (Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE), "%x" % state
- rcv = self.c2.link_head(Endpoint.LOCAL_UNINIT)
- assert rcv
- state = rcv.state
- assert state == (Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE), "%x" % state
-
- self.c2.open()
- ssn2.open()
- rcv.open()
- rcv.flow(10)
- assert rcv.queued == 0, rcv.queued
-
- self.pump()
-
- assert rcv.queued == 10, rcv.queued
- state = rcv.state
- assert state == (Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED), "%x" % state
- state = ssn2.state
- assert state == (Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED), "%x" % state
- state = self.c2.state
- assert state == (Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED), "%x" % state
-
- for i in range(rcv.queued):
- d = rcv.current
- assert d
- assert d.tag == "delivery-%s" % i
- d.settle()
-
- assert rcv.queued == 0, rcv.queued
-
-
-class ServerTest(Test):
-
- def testKeepalive(self):
- """ Verify that idle frames are sent to keep a Connection alive
- """
- idle_timeout = self.delay
- server = common.TestServer()
- server.start()
-
- class Program:
-
- def on_reactor_init(self, event):
- self.conn = event.reactor.connection()
- self.conn.hostname = "%s:%s" % (server.host, server.port)
- self.conn.open()
- self.old_count = None
- event.reactor.schedule(3 * idle_timeout, self)
-
- def on_connection_bound(self, event):
- event.transport.idle_timeout = idle_timeout
-
- def on_connection_remote_open(self, event):
- self.old_count = event.transport.frames_input
-
- def on_timer_task(self, event):
- assert self.conn.state == (Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE), "Connection terminated"
- assert self.conn.transport.frames_input > self.old_count, "No idle frames received"
- self.conn.close()
-
- Reactor(Program()).run()
- server.stop()
-
- def testIdleTimeout(self):
- """ Verify that a Connection is terminated properly when Idle frames do not
- arrive in a timely manner.
- """
- idle_timeout = self.delay
- server = common.TestServer(idle_timeout=idle_timeout)
- server.start()
-
- class Program:
-
- def on_reactor_init(self, event):
- self.conn = event.reactor.connection()
- self.conn.hostname = "%s:%s" % (server.host, server.port)
- self.conn.open()
- self.remote_condition = None
- self.old_count = None
- # verify the connection stays up even if we don't explicitly send stuff
- # wait up to 3x the idle timeout
- event.reactor.schedule(3 * idle_timeout, self)
-
- def on_connection_bound(self, event):
- self.transport = event.transport
-
- def on_connection_remote_open(self, event):
- self.old_count = event.transport.frames_output
-
- def on_connection_remote_close(self, event):
- assert self.conn.remote_condition
- assert self.conn.remote_condition.name == "amqp:resource-limit-exceeded"
- self.remote_condition = self.conn.remote_condition
-
- def on_timer_task(self, event):
- assert self.conn.state == (Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE), "Connection terminated"
- assert self.conn.transport.frames_output > self.old_count, "No idle frames sent"
-
- # now wait to explicitly cause the other side to expire:
- suspend_time = 3 * idle_timeout
- if os.name=="nt":
- # On windows, the full delay gets too close to the graceful/hard close tipping point
- suspend_time = 2.5 * idle_timeout
- sleep(suspend_time)
-
- p = Program()
- Reactor(p).run()
- assert p.remote_condition
- assert p.remote_condition.name == "amqp:resource-limit-exceeded"
- server.stop()
-
-class NoValue:
-
- def __init__(self):
- pass
-
- def apply(self, dlv):
- pass
-
- def check(self, dlv):
- assert dlv.data == None
- assert dlv.section_number == 0
- assert dlv.section_offset == 0
- assert dlv.condition == None
- assert dlv.failed == False
- assert dlv.undeliverable == False
- assert dlv.annotations == None
-
-class RejectValue:
- def __init__(self, condition):
- self.condition = condition
-
- def apply(self, dlv):
- dlv.condition = self.condition
-
- def check(self, dlv):
- assert dlv.data == None, dlv.data
- assert dlv.section_number == 0
- assert dlv.section_offset == 0
- assert dlv.condition == self.condition, (dlv.condition, self.condition)
- assert dlv.failed == False
- assert dlv.undeliverable == False
- assert dlv.annotations == None
-
-class ReceivedValue:
- def __init__(self, section_number, section_offset):
- self.section_number = section_number
- self.section_offset = section_offset
-
- def apply(self, dlv):
- dlv.section_number = self.section_number
- dlv.section_offset = self.section_offset
-
- def check(self, dlv):
- assert dlv.data == None, dlv.data
- assert dlv.section_number == self.section_number, (dlv.section_number, self.section_number)
- assert dlv.section_offset == self.section_offset
- assert dlv.condition == None
- assert dlv.failed == False
- assert dlv.undeliverable == False
- assert dlv.annotations == None
-
-class ModifiedValue:
- def __init__(self, failed, undeliverable, annotations):
- self.failed = failed
- self.undeliverable = undeliverable
- self.annotations = annotations
-
- def apply(self, dlv):
- dlv.failed = self.failed
- dlv.undeliverable = self.undeliverable
- dlv.annotations = self.annotations
-
- def check(self, dlv):
- assert dlv.data == None, dlv.data
- assert dlv.section_number == 0
- assert dlv.section_offset == 0
- assert dlv.condition == None
- assert dlv.failed == self.failed
- assert dlv.undeliverable == self.undeliverable
- assert dlv.annotations == self.annotations, (dlv.annotations, self.annotations)
-
-class CustomValue:
- def __init__(self, data):
- self.data = data
-
- def apply(self, dlv):
- dlv.data = self.data
-
- def check(self, dlv):
- assert dlv.data == self.data, (dlv.data, self.data)
- assert dlv.section_number == 0
- assert dlv.section_offset == 0
- assert dlv.condition == None
- assert dlv.failed == False
- assert dlv.undeliverable == False
- assert dlv.annotations == None
-
-class DeliveryTest(Test):
-
- def tearDown(self):
- self.cleanup()
-
- def testDisposition(self, count=1, tag="tag%i", type=Delivery.ACCEPTED, value=NoValue()):
- snd, rcv = self.link("test-link")
- snd.open()
- rcv.open()
-
- snd_deliveries = []
- for i in range(count):
- d = snd.delivery(tag % i)
- snd_deliveries.append(d)
- snd.advance()
-
- rcv.flow(count)
- self.pump()
-
- rcv_deliveries = []
- for i in range(count):
- d = rcv.current
- assert d.tag == (tag % i)
- rcv_deliveries.append(d)
- rcv.advance()
-
- for d in rcv_deliveries:
- value.apply(d.local)
- d.update(type)
-
- self.pump()
-
- for d in snd_deliveries:
- assert d.remote_state == type
- assert d.remote.type == type
- value.check(d.remote)
- value.apply(d.local)
- d.update(type)
-
- self.pump()
-
- for d in rcv_deliveries:
- assert d.remote_state == type
- assert d.remote.type == type
- value.check(d.remote)
-
- for d in snd_deliveries:
- d.settle()
-
- self.pump()
-
- for d in rcv_deliveries:
- assert d.settled, d.settled
- d.settle()
-
- def testReceived(self):
- self.testDisposition(type=Disposition.RECEIVED, value=ReceivedValue(1, 2))
-
- def testRejected(self):
- self.testDisposition(type=Disposition.REJECTED, value=RejectValue(Condition(symbol("foo"))))
-
- def testReleased(self):
- self.testDisposition(type=Disposition.RELEASED)
-
- def testModified(self):
- self.testDisposition(type=Disposition.MODIFIED,
- value=ModifiedValue(failed=True, undeliverable=True,
- annotations={"key": "value"}))
-
- def testCustom(self):
- self.testDisposition(type=0x12345, value=CustomValue([1, 2, 3]))
-
-class CollectorTest(Test):
-
- def setUp(self):
- self.collector = Collector()
-
- def drain(self):
- result = []
- while True:
- e = self.collector.peek()
- if e:
- result.append(e)
- self.collector.pop()
- else:
- break
- return result
-
- def expect(self, *types):
- return self.expect_oneof(types)
-
- def expect_oneof(self, *sequences):
- events = self.drain()
- types = tuple([e.type for e in events])
-
- for alternative in sequences:
- if types == alternative:
- if len(events) == 1:
- return events[0]
- elif len(events) > 1:
- return events
- else:
- return
-
- assert False, "actual events %s did not match any of the expected sequences: %s" % (events, sequences)
-
- def expect_until(self, *types):
- events = self.drain()
- etypes = tuple([e.type for e in events[-len(types):]])
- assert etypes == types, "actual events %s did not end in expect sequence: %s" % (events, types)
-
-class EventTest(CollectorTest):
-
- def tearDown(self):
- self.cleanup()
-
- def testEndpointEvents(self):
- c1, c2 = self.connection()
- c1.collect(self.collector)
- self.expect(Event.CONNECTION_INIT)
- self.pump()
- self.expect()
- c2.open()
- self.pump()
- self.expect(Event.CONNECTION_REMOTE_OPEN)
- self.pump()
- self.expect()
-
- ssn = c2.session()
- snd = ssn.sender("sender")
- ssn.open()
- snd.open()
-
- self.expect()
- self.pump()
- self.expect(Event.SESSION_INIT, Event.SESSION_REMOTE_OPEN,
- Event.LINK_INIT, Event.LINK_REMOTE_OPEN)
-
- c1.open()
- ssn2 = c1.session()
- ssn2.open()
- rcv = ssn2.receiver("receiver")
- rcv.open()
- self.pump()
- self.expect(Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT,
- Event.SESSION_INIT, Event.SESSION_LOCAL_OPEN,
- Event.TRANSPORT, Event.LINK_INIT, Event.LINK_LOCAL_OPEN,
- Event.TRANSPORT)
-
- rcv.close()
- self.expect(Event.LINK_LOCAL_CLOSE, Event.TRANSPORT)
- self.pump()
- rcv.free()
- del rcv
- self.expect(Event.LINK_FINAL)
- ssn2.free()
- del ssn2
- self.pump()
- c1.free()
- c1.transport.unbind()
- self.expect_oneof((Event.SESSION_FINAL, Event.LINK_FINAL, Event.SESSION_FINAL,
- Event.CONNECTION_UNBOUND, Event.CONNECTION_FINAL),
- (Event.CONNECTION_UNBOUND, Event.SESSION_FINAL, Event.LINK_FINAL,
- Event.SESSION_FINAL, Event.CONNECTION_FINAL))
-
- def testConnectionINIT_FINAL(self):
- c = Connection()
- c.collect(self.collector)
- self.expect(Event.CONNECTION_INIT)
- c.free()
- self.expect(Event.CONNECTION_FINAL)
-
- def testSessionINIT_FINAL(self):
- c = Connection()
- c.collect(self.collector)
- self.expect(Event.CONNECTION_INIT)
- s = c.session()
- self.expect(Event.SESSION_INIT)
- s.free()
- self.expect(Event.SESSION_FINAL)
- c.free()
- self.expect(Event.CONNECTION_FINAL)
-
- def testLinkINIT_FINAL(self):
- c = Connection()
- c.collect(self.collector)
- self.expect(Event.CONNECTION_INIT)
- s = c.session()
- self.expect(Event.SESSION_INIT)
- r = s.receiver("asdf")
- self.expect(Event.LINK_INIT)
- r.free()
- self.expect(Event.LINK_FINAL)
- c.free()
- self.expect(Event.SESSION_FINAL, Event.CONNECTION_FINAL)
-
- def testFlowEvents(self):
- snd, rcv = self.link("test-link")
- snd.session.connection.collect(self.collector)
- rcv.open()
- rcv.flow(10)
- self.pump()
- self.expect(Event.CONNECTION_INIT, Event.SESSION_INIT,
- Event.LINK_INIT, Event.LINK_REMOTE_OPEN, Event.LINK_FLOW)
- rcv.flow(10)
- self.pump()
- self.expect(Event.LINK_FLOW)
- return snd, rcv
-
- def testDeliveryEvents(self):
- snd, rcv = self.link("test-link")
- rcv.session.connection.collect(self.collector)
- rcv.open()
- rcv.flow(10)
- self.pump()
- self.expect(Event.CONNECTION_INIT, Event.SESSION_INIT,
- Event.LINK_INIT, Event.LINK_LOCAL_OPEN, Event.TRANSPORT)
- snd.delivery("delivery")
- snd.send(b"Hello World!")
- snd.advance()
- self.pump()
- self.expect()
- snd.open()
- self.pump()
- self.expect(Event.LINK_REMOTE_OPEN, Event.DELIVERY)
- rcv.session.connection.transport.unbind()
- rcv.session.connection.free()
- self.expect(Event.CONNECTION_UNBOUND, Event.TRANSPORT, Event.LINK_FINAL,
- Event.SESSION_FINAL, Event.CONNECTION_FINAL)
-
- def testDeliveryEventsDisp(self):
- snd, rcv = self.testFlowEvents()
- snd.open()
- dlv = snd.delivery("delivery")
- snd.send(b"Hello World!")
- assert snd.advance()
- self.expect(Event.LINK_LOCAL_OPEN, Event.TRANSPORT)
- self.pump()
- self.expect(Event.LINK_FLOW)
- rdlv = rcv.current
- assert rdlv != None
- assert rdlv.tag == "delivery"
- rdlv.update(Delivery.ACCEPTED)
- self.pump()
- event = self.expect(Event.DELIVERY)
- assert event.context == dlv, (dlv, event.context)
-
- def testConnectionBOUND_UNBOUND(self):
- c = Connection()
- c.collect(self.collector)
- self.expect(Event.CONNECTION_INIT)
- t = Transport()
- t.bind(c)
- self.expect(Event.CONNECTION_BOUND)
- t.unbind()
- self.expect(Event.CONNECTION_UNBOUND, Event.TRANSPORT)
-
- def testTransportERROR_CLOSE(self):
- c = Connection()
- c.collect(self.collector)
- self.expect(Event.CONNECTION_INIT)
- t = Transport()
- t.bind(c)
- self.expect(Event.CONNECTION_BOUND)
- assert t.condition is None
- t.push(b"asdf")
- self.expect(Event.TRANSPORT_ERROR, Event.TRANSPORT_TAIL_CLOSED)
- assert t.condition is not None
- assert t.condition.name == "amqp:connection:framing-error"
- assert "AMQP header mismatch" in t.condition.description
- p = t.pending()
- assert p > 0
- t.pop(p)
- self.expect(Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED)
-
- def testTransportCLOSED(self):
- c = Connection()
- c.collect(self.collector)
- self.expect(Event.CONNECTION_INIT)
- t = Transport()
- t.bind(c)
- c.open()
-
- self.expect(Event.CONNECTION_BOUND, Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT)
-
- c2 = Connection()
- t2 = Transport()
- t2.bind(c2)
- c2.open()
- c2.close()
-
- pump(t, t2)
-
- self.expect(Event.CONNECTION_REMOTE_OPEN, Event.CONNECTION_REMOTE_CLOSE,
- Event.TRANSPORT_TAIL_CLOSED)
-
- c.close()
-
- pump(t, t2)
-
- self.expect(Event.CONNECTION_LOCAL_CLOSE, Event.TRANSPORT,
- Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED)
-
- def testLinkDetach(self):
- c1 = Connection()
- c1.collect(self.collector)
- t1 = Transport()
- t1.bind(c1)
- c1.open()
- s1 = c1.session()
- s1.open()
- l1 = s1.sender("asdf")
- l1.open()
- l1.detach()
- self.expect_until(Event.LINK_LOCAL_DETACH, Event.TRANSPORT)
-
- c2 = Connection()
- c2.collect(self.collector)
- t2 = Transport()
- t2.bind(c2)
-
- pump(t1, t2)
-
- self.expect_until(Event.LINK_REMOTE_DETACH)
-
-class PeerTest(CollectorTest):
-
- def setUp(self):
- CollectorTest.setUp(self)
- self.connection = Connection()
- self.connection.collect(self.collector)
- self.transport = Transport()
- self.transport.bind(self.connection)
- self.peer = Connection()
- self.peer_transport = Transport()
- self.peer_transport.bind(self.peer)
- self.peer_transport.trace(Transport.TRACE_OFF)
-
- def pump(self):
- pump(self.transport, self.peer_transport)
-
-class TeardownLeakTest(PeerTest):
-
- def doLeak(self, local, remote):
- self.connection.open()
- self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND,
- Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT)
-
- ssn = self.connection.session()
- ssn.open()
- self.expect(Event.SESSION_INIT, Event.SESSION_LOCAL_OPEN, Event.TRANSPORT)
-
- snd = ssn.sender("sender")
- snd.open()
- self.expect(Event.LINK_INIT, Event.LINK_LOCAL_OPEN, Event.TRANSPORT)
-
-
- self.pump()
-
- self.peer.open()
- self.peer.session_head(0).open()
- self.peer.link_head(0).open()
-
- self.pump()
- self.expect_oneof((Event.CONNECTION_REMOTE_OPEN, Event.SESSION_REMOTE_OPEN,
- Event.LINK_REMOTE_OPEN, Event.LINK_FLOW),
- (Event.CONNECTION_REMOTE_OPEN, Event.SESSION_REMOTE_OPEN,
- Event.LINK_REMOTE_OPEN))
-
- if local:
- snd.close() # ha!!
- self.expect(Event.LINK_LOCAL_CLOSE, Event.TRANSPORT)
- ssn.close()
- self.expect(Event.SESSION_LOCAL_CLOSE, Event.TRANSPORT)
- self.connection.close()
- self.expect(Event.CONNECTION_LOCAL_CLOSE, Event.TRANSPORT)
-
- if remote:
- self.peer.link_head(0).close() # ha!!
- self.peer.session_head(0).close()
- self.peer.close()
-
- self.pump()
-
- if remote:
- self.expect(Event.TRANSPORT_HEAD_CLOSED, Event.LINK_REMOTE_CLOSE,
- Event.SESSION_REMOTE_CLOSE, Event.CONNECTION_REMOTE_CLOSE,
- Event.TRANSPORT_TAIL_CLOSED, Event.TRANSPORT_CLOSED)
- else:
- self.expect(Event.TRANSPORT_HEAD_CLOSED, Event.SESSION_REMOTE_CLOSE,
- Event.CONNECTION_REMOTE_CLOSE, Event.TRANSPORT_TAIL_CLOSED,
- Event.TRANSPORT_CLOSED)
-
- self.connection.free()
- self.expect(Event.LINK_FINAL, Event.SESSION_FINAL)
- self.transport.unbind()
-
- self.expect(Event.CONNECTION_UNBOUND, Event.CONNECTION_FINAL)
-
- def testLocalRemoteLeak(self):
- self.doLeak(True, True)
-
- def testLocalLeak(self):
- self.doLeak(True, False)
-
- def testRemoteLeak(self):
- self.doLeak(False, True)
-
- def testLeak(self):
- self.doLeak(False, False)
-
-class IdleTimeoutEventTest(PeerTest):
-
- def half_pump(self):
- p = self.transport.pending()
- if p>0:
- self.transport.pop(p)
-
- def testTimeoutWithZombieServer(self, expectOpenCloseFrames=True):
- self.transport.idle_timeout = self.delay
- self.connection.open()
- self.half_pump()
- t = time()
- self.transport.tick(t)
- self.transport.tick(t + self.delay*4)
- self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND,
- Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT,
- Event.TRANSPORT_ERROR, Event.TRANSPORT_TAIL_CLOSED)
- assert self.transport.capacity() < 0
- if expectOpenCloseFrames:
- assert self.transport.pending() > 0
- self.half_pump()
- self.expect(Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED)
- assert self.transport.pending() < 0
-
- def testTimeoutWithZombieServerAndSASL(self):
- sasl = self.transport.sasl()
- self.testTimeoutWithZombieServer(expectOpenCloseFrames=False)
-
-class DeliverySegFaultTest(Test):
-
- def testDeliveryAfterUnbind(self):
- conn = Connection()
- t = Transport()
- ssn = conn.session()
- snd = ssn.sender("sender")
- dlv = snd.delivery("tag")
- dlv.settle()
- del dlv
- t.bind(conn)
- t.unbind()
- dlv = snd.delivery("tag")
-
-class SaslEventTest(CollectorTest):
-
- def testAnonymousNoInitialResponse(self):
- conn = Connection()
- conn.collect(self.collector)
- transport = Transport(Transport.SERVER)
- transport.bind(conn)
- self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND)
-
- transport.push(b'AMQP\x03\x01\x00\x00\x00\x00\x00 \x02\x01\x00\x00\x00SA'
- b'\xd0\x00\x00\x00\x10\x00\x00\x00\x02\xa3\tANONYMOUS@'
- b'AMQP\x00\x01\x00\x00')
- self.expect(Event.TRANSPORT)
- for i in range(1024):
- p = transport.pending()
- self.drain()
- p = transport.pending()
- self.expect()
-
- def testPipelinedServerReadFirst(self):
- conn = Connection()
- conn.collect(self.collector)
- transport = Transport(Transport.CLIENT)
- s = transport.sasl()
- s.allowed_mechs("ANONYMOUS PLAIN")
- transport.bind(conn)
- self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND)
- transport.push(
- # SASL
- b'AMQP\x03\x01\x00\x00'
- # @sasl-mechanisms(64) [sasl-server-mechanisms=@PN_SYMBOL[:ANONYMOUS]]
- b'\x00\x00\x00\x1c\x02\x01\x00\x00\x00S@\xc0\x0f\x01\xe0\x0c\x01\xa3\tANONYMOUS'
- # @sasl-outcome(68) [code=0]
- b'\x00\x00\x00\x10\x02\x01\x00\x00\x00SD\xc0\x03\x01P\x00'
- # AMQP
- b'AMQP\x00\x01\x00\x00'
- )
- self.expect(Event.TRANSPORT)
- p = transport.pending()
- bytes = transport.peek(p)
- transport.pop(p)
-
- server = Transport(Transport.SERVER)
- server.push(bytes)
- assert s.outcome == SASL.OK
- assert server.sasl().outcome == SASL.OK
-
- def testPipelinedServerWriteFirst(self):
- conn = Connection()
- conn.collect(self.collector)
- transport = Transport(Transport.CLIENT)
- s = transport.sasl()
- s.allowed_mechs("ANONYMOUS")
- transport.bind(conn)
- p = transport.pending()
- bytes = transport.peek(p)
- transport.pop(p)
- self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND)
- transport.push(
- # SASL
- b'AMQP\x03\x01\x00\x00'
- # @sasl-mechanisms(64) [sasl-server-mechanisms=@PN_SYMBOL[:ANONYMOUS]]
- b'\x00\x00\x00\x1c\x02\x01\x00\x00\x00S@\xc0\x0f\x01\xe0\x0c\x01\xa3\tANONYMOUS'
- # @sasl-outcome(68) [code=0]
- b'\x00\x00\x00\x10\x02\x01\x00\x00\x00SD\xc0\x03\x01P\x00'
- # AMQP
- b'AMQP\x00\x01\x00\x00'
- )
- self.expect(Event.TRANSPORT)
- p = transport.pending()
- bytes = transport.peek(p)
- transport.pop(p)
- assert s.outcome == SASL.OK
- # XXX: the bytes above appear to be correct, but we don't get any
- # sort of event indicating that the transport is authenticated
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/handler.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/handler.py b/tests/python/proton_tests/handler.py
deleted file mode 100644
index c7210f4..0000000
--- a/tests/python/proton_tests/handler.py
+++ /dev/null
@@ -1,123 +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 __future__ import absolute_import
-
-import os, gc, traceback
-import sys
-from . import common
-from time import time, sleep
-from proton import *
-from .common import pump, Skipped
-from proton.reactor import Reactor
-
-
-CUSTOM = EventType("custom")
-
-class HandlerTest(common.Test):
- def test_reactorHandlerCycling(self, n=0):
-
- class CustomHandler(Handler):
- UNSET = 999999999
- def __init__(self):
- self.offset = len(traceback.extract_stack())
- def on_reactor_init(self, event):
- self.depth = len(traceback.extract_stack())
- def reset(self):
- self.depth = self.UNSET
- @property
- def init_depth(self):
- d = self.depth - self.offset
- return d
- custom = CustomHandler()
-
- reactor = Reactor()
- reactor.handler = custom
- for i in range(n):
- h = reactor.handler
- reactor.handler = h
- custom.reset()
- reactor.run()
- assert custom.init_depth < 50, "Unexpectedly long traceback for a simple handler"
-
- def test_reactorHandlerCycling10k(self):
- self.test_reactorHandlerCycling(10000)
-
- def test_reactorHandlerCycling100(self):
- self.test_reactorHandlerCycling(100)
-
- def do_customEvent(self, reactor_handler, event_root):
-
- class CustomHandler:
- did_custom = False
- did_init = False
- def __init__(self, *handlers):
- self.handlers = handlers
- def on_reactor_init(self, event):
- self.did_init = True
- def on_custom(self, event):
- self.did_custom = True
-
- class CustomInvoker(CustomHandler):
- def on_reactor_init(self, event):
- h = event_root(event)
- event.dispatch(h, CUSTOM)
- self.did_init = True
-
- child = CustomInvoker()
- root = CustomHandler(child)
-
- reactor = Reactor()
-
- reactor_handler(reactor, root)
- reactor.run()
- assert root.did_init
- assert child.did_init
- assert root.did_custom
- assert child.did_custom
-
- def set_root(self, reactor, root):
- reactor.handler = root
- def add_root(self, reactor, root):
- reactor.handler.add(root)
- def append_root(self, reactor, root):
- reactor.handler.handlers.append(root)
-
- def event_root(self, event):
- return event.root
-
- def event_reactor_handler(self, event):
- return event.reactor.handler
-
- def test_set_handler(self):
- self.do_customEvent(self.set_root, self.event_reactor_handler)
-
- def test_add_handler(self):
- self.do_customEvent(self.add_root, self.event_reactor_handler)
-
- def test_append_handler(self):
- self.do_customEvent(self.append_root, self.event_reactor_handler)
-
- def test_set_root(self):
- self.do_customEvent(self.set_root, self.event_root)
-
- def test_add_root(self):
- self.do_customEvent(self.add_root, self.event_root)
-
- def test_append_root(self):
- self.do_customEvent(self.append_root, self.event_root)
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[11/11] qpid-proton git commit: PROTON-1885: [python] move
tests/python to python/tests
Posted by ac...@apache.org.
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 <ac...@redhat.com>
Authored: Wed Jul 4 14:52:06 2018 -0400
Committer: Alan Conway <ac...@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-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[07/11] qpid-proton git commit: PROTON-1885: [python] move
tests/python to python/tests
Posted by ac...@apache.org.
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
[05/11] qpid-proton git commit: PROTON-1885: [python] move
tests/python to python/tests
Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/interop.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/interop.py b/tests/python/proton_tests/interop.py
deleted file mode 100644
index 2825fe4..0000000
--- a/tests/python/proton_tests/interop.py
+++ /dev/null
@@ -1,147 +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 proton import *
-import os
-from . import common
-
-
-def find_test_interop_dir():
- """Walk up the directory tree to find the tests directory."""
- f = os.path.dirname(os.path.abspath(__file__))
- while f and os.path.basename(f) != "tests": f = os.path.dirname(f)
- f = os.path.join(f, "interop")
- if not os.path.isdir(f):
- raise Exception("Cannot find test/interop directory from "+__file__)
- return f
-
-test_interop_dir=find_test_interop_dir()
-
-class InteropTest(common.Test):
-
- def setUp(self):
- self.data = Data()
- self.message = Message()
-
- def tearDown(self):
- self.data = None
-
- def get_data(self, name):
- filename = os.path.join(test_interop_dir, name+".amqp")
- f = open(filename,"rb")
- try: return f.read()
- finally: f.close()
-
- def decode_data(self, encoded):
- buffer = encoded
- while buffer:
- n = self.data.decode(buffer)
- buffer = buffer[n:]
- self.data.rewind()
-
- def decode_data_file(self, name):
- encoded = self.get_data(name)
- self.decode_data(encoded)
- encoded_size = self.data.encoded_size()
- # Re-encode and verify pre-computed and actual encoded size match.
- reencoded = self.data.encode()
- assert encoded_size == len(reencoded), "%d != %d" % (encoded_size, len(reencoded))
- # verify round trip bytes
- assert reencoded == encoded, "Value mismatch: %s != %s" % (reencoded, encoded)
-
- def decode_message_file(self, name):
- self.message.decode(self.get_data(name))
- body = self.message.body
- if str(type(body)) == "<type 'org.apache.qpid.proton.amqp.Binary'>":
- body = body.array.tostring()
- self.decode_data(body)
-
- def assert_next(self, type, value):
- next_type = self.data.next()
- assert next_type == type, "Type mismatch: %s != %s"%(
- Data.type_names[next_type], Data.type_names[type])
- next_value = self.data.get_object()
- assert next_value == value, "Value mismatch: %s != %s"%(next_value, value)
-
- def test_message(self):
- self.decode_message_file("message")
- self.assert_next(Data.STRING, "hello")
- assert self.data.next() is None
-
- def test_primitives(self):
- self.decode_data_file("primitives")
- self.assert_next(Data.BOOL, True)
- self.assert_next(Data.BOOL, False)
- self.assert_next(Data.UBYTE, 42)
- self.assert_next(Data.USHORT, 42)
- self.assert_next(Data.SHORT, -42)
- self.assert_next(Data.UINT, 12345)
- self.assert_next(Data.INT, -12345)
- self.assert_next(Data.ULONG, 12345)
- self.assert_next(Data.LONG, -12345)
- self.assert_next(Data.FLOAT, 0.125)
- self.assert_next(Data.DOUBLE, 0.125)
- assert self.data.next() is None
-
- def test_strings(self):
- self.decode_data_file("strings")
- self.assert_next(Data.BINARY, b"abc\0defg")
- self.assert_next(Data.STRING, "abcdefg")
- self.assert_next(Data.SYMBOL, "abcdefg")
- self.assert_next(Data.BINARY, b"")
- self.assert_next(Data.STRING, "")
- self.assert_next(Data.SYMBOL, "")
- assert self.data.next() is None
-
- def test_described(self):
- self.decode_data_file("described")
- self.assert_next(Data.DESCRIBED, Described("foo-descriptor", "foo-value"))
- self.data.exit()
-
- assert self.data.next() == Data.DESCRIBED
- self.data.enter()
- self.assert_next(Data.INT, 12)
- self.assert_next(Data.INT, 13)
- self.data.exit()
-
- assert self.data.next() is None
-
- def test_described_array(self):
- self.decode_data_file("described_array")
- self.assert_next(Data.ARRAY, Array("int-array", Data.INT, *range(0,10)))
-
- def test_arrays(self):
- self.decode_data_file("arrays")
- self.assert_next(Data.ARRAY, Array(UNDESCRIBED, Data.INT, *range(0,100)))
- self.assert_next(Data.ARRAY, Array(UNDESCRIBED, Data.STRING, *["a", "b", "c"]))
- self.assert_next(Data.ARRAY, Array(UNDESCRIBED, Data.INT))
- assert self.data.next() is None
-
- def test_lists(self):
- self.decode_data_file("lists")
- self.assert_next(Data.LIST, [32, "foo", True])
- self.assert_next(Data.LIST, [])
- assert self.data.next() is None
-
- def test_maps(self):
- self.decode_data_file("maps")
- self.assert_next(Data.MAP, {"one":1, "two":2, "three":3 })
- self.assert_next(Data.MAP, {1:"one", 2:"two", 3:"three"})
- self.assert_next(Data.MAP, {})
- assert self.data.next() is None
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/message.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/message.py b/tests/python/proton_tests/message.py
deleted file mode 100644
index 1a2709c..0000000
--- a/tests/python/proton_tests/message.py
+++ /dev/null
@@ -1,275 +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
-from . import common
-from proton import *
-from uuid import uuid4
-
-class Test(common.Test):
-
- def setUp(self):
- self.msg = Message()
-
- def tearDown(self):
- self.msg = None
-
-
-class AccessorsTest(Test):
-
- def _test(self, name, default, values):
- d = getattr(self.msg, name)
- assert d == default, (d, default)
- for v in values:
- setattr(self.msg, name, v)
- gotten = getattr(self.msg, name)
- assert gotten == v, gotten
-
- def _test_symbol(self, name):
- self._test(name, symbol(None), (symbol(u"abc.123.#$%"), symbol(u"hello.world")))
-
- def _test_str(self, name):
- self._test(name, None, (u"asdf", u"fdsa", u""))
-
- def _test_time(self, name):
- self._test(name, 0, (0, 123456789, 987654321))
-
- def testId(self):
- self._test("id", None, ("bytes", None, 123, u"string", uuid4()))
-
- def testCorrelationId(self):
- self._test("correlation_id", None, ("bytes", None, 123, u"string", uuid4()))
-
- def testDurable(self):
- self._test("durable", False, (True, False))
-
- def testPriority(self):
- self._test("priority", Message.DEFAULT_PRIORITY, range(0, 255))
-
- def testTtl(self):
- self._test("ttl", 0, range(12345, 54321))
-
- def testFirstAcquirer(self):
- self._test("first_acquirer", False, (True, False))
-
- def testDeliveryCount(self):
- self._test("delivery_count", 0, range(0, 1024))
-
- def testUserId(self):
- self._test("user_id", b"", (b"asdf", b"fdsa", b"asd\x00fdsa", b""))
-
- def testAddress(self):
- self._test_str("address")
-
- def testSubject(self):
- self._test_str("subject")
-
- def testReplyTo(self):
- self._test_str("reply_to")
-
- def testContentType(self):
- self._test_symbol("content_type")
-
- def testContentEncoding(self):
- self._test_symbol("content_encoding")
-
- def testExpiryTime(self):
- self._test_time("expiry_time")
-
- def testCreationTime(self):
- self._test_time("creation_time")
-
- def testGroupId(self):
- self._test_str("group_id")
-
- def testGroupSequence(self):
- self._test("group_sequence", 0, (0, -10, 10, 20, -20))
-
- def testReplyToGroupId(self):
- self._test_str("reply_to_group_id")
-
-class CodecTest(Test):
-
- def testProperties(self):
- self.msg.properties = {}
- self.msg.properties['key'] = 'value'
- data = self.msg.encode()
-
- msg2 = Message()
- msg2.decode(data)
-
- assert msg2.properties['key'] == 'value', msg2.properties['key']
-
- def testRoundTrip(self):
- self.msg.id = "asdf"
- self.msg.correlation_id = uuid4()
- self.msg.ttl = 3
- self.msg.priority = 100
- self.msg.address = "address"
- self.msg.subject = "subject"
- self.msg.body = 'Hello World!'
-
- data = self.msg.encode()
-
- msg2 = Message()
- msg2.decode(data)
-
- assert self.msg.id == msg2.id, (self.msg.id, msg2.id)
- assert self.msg.correlation_id == msg2.correlation_id, (self.msg.correlation_id, msg2.correlation_id)
- assert self.msg.ttl == msg2.ttl, (self.msg.ttl, msg2.ttl)
- assert self.msg.priority == msg2.priority, (self.msg.priority, msg2.priority)
- assert self.msg.address == msg2.address, (self.msg.address, msg2.address)
- assert self.msg.subject == msg2.subject, (self.msg.subject, msg2.subject)
- assert self.msg.body == msg2.body, (self.msg.body, msg2.body)
-
- def testExpiryEncodeAsNull(self):
- self.msg.group_id = "A" # Force creation and expiry fields to be present
- data = self.msg.encode()
-
- decoder = Data()
-
- # Skip past the headers
- consumed = decoder.decode(data)
- decoder.clear()
- data = data[consumed:]
-
- decoder.decode(data)
- dproperties = decoder.get_py_described()
- # Check we've got the correct described list
- assert dproperties.descriptor == 0x73, (dproperties.descriptor)
-
- properties = dproperties.value
- assert properties[8] == None, properties[8]
-
- def testCreationEncodeAsNull(self):
- self.msg.group_id = "A" # Force creation and expiry fields to be present
- data = self.msg.encode()
-
- decoder = Data()
-
- # Skip past the headers
- consumed = decoder.decode(data)
- decoder.clear()
- data = data[consumed:]
-
- decoder.decode(data)
- dproperties = decoder.get_py_described()
- # Check we've got the correct described list
- assert dproperties.descriptor == 0x73, (dproperties.descriptor)
-
- properties = dproperties.value
- assert properties[9] == None, properties[9]
-
- def testGroupSequenceEncodeAsNull(self):
- self.msg.reply_to_group_id = "R" # Force group_id and group_sequence fields to be present
- data = self.msg.encode()
-
- decoder = Data()
-
- # Skip past the headers
- consumed = decoder.decode(data)
- decoder.clear()
- data = data[consumed:]
-
- decoder.decode(data)
- dproperties = decoder.get_py_described()
- # Check we've got the correct described list
- assert dproperties.descriptor == 0x73, (dproperties.descriptor)
-
- properties = dproperties.value
- assert properties[10] == None, properties[10]
- assert properties[11] == None, properties[11]
-
- def testGroupSequenceEncodeAsNonNull(self):
- self.msg.group_id = "G"
- self.msg.reply_to_group_id = "R" # Force group_id and group_sequence fields to be present
- data = self.msg.encode()
-
- decoder = Data()
-
- # Skip past the headers
- consumed = decoder.decode(data)
- decoder.clear()
- data = data[consumed:]
-
- decoder.decode(data)
- dproperties = decoder.get_py_described()
- # Check we've got the correct described list
- assert dproperties.descriptor == 0x73, (dproperties.descriptor)
-
- properties = dproperties.value
- assert properties[10] == 'G', properties[10]
- assert properties[11] == 0, properties[11]
-
- def testDefaultCreationExpiryDecode(self):
- # This is a message with everything filled explicitly as null or zero in LIST32 HEADER and PROPERTIES lists
- data = b'\x00\x53\x70\xd0\x00\x00\x00\x0a\x00\x00\x00\x05\x42\x40\x40\x42\x52\x00\x00\x53\x73\xd0\x00\x00\x00\x12\x00\x00\x00\x0d\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x52\x00\x40'
- msg2 = Message()
- msg2.decode(data)
- assert msg2.expiry_time == 0, (msg2.expiry_time)
- assert msg2.creation_time == 0, (msg2.creation_time)
-
- # The same message with LIST8s instead
- data = b'\x00\x53\x70\xc0\x07\x05\x42\x40\x40\x42\x52\x00\x00\x53\x73\xc0\x0f\x0d\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x52\x00\x40'
- msg3 = Message()
- msg3.decode(data)
- assert msg2.expiry_time == 0, (msg2.expiry_time)
- assert msg2.creation_time == 0, (msg2.creation_time)
-
- # Minified message with zero length HEADER and PROPERTIES lists
- data = b'\x00\x53\x70\x45' b'\x00\x53\x73\x45'
- msg4 = Message()
- msg4.decode(data)
- assert msg2.expiry_time == 0, (msg2.expiry_time)
- assert msg2.creation_time == 0, (msg2.creation_time)
-
- def testDefaultPriorityEncode(self):
- assert self.msg.priority == 4, (self.msg.priority)
- self.msg.ttl = 0.003 # field after priority, so forces priority to be present
- data = self.msg.encode()
-
- decoder = Data()
- decoder.decode(data)
-
- dheaders = decoder.get_py_described()
- # Check we've got the correct described list
- assert dheaders.descriptor == 0x70, (dheaders.descriptor)
-
- # Check that the priority field (second field) is encoded as null
- headers = dheaders.value
- assert headers[1] == None, (headers[1])
-
- def testDefaultPriorityDecode(self):
- # This is a message with everything filled explicitly as null or zero in LIST32 HEADER and PROPERTIES lists
- data = b'\x00\x53\x70\xd0\x00\x00\x00\x0a\x00\x00\x00\x05\x42\x40\x40\x42\x52\x00\x00\x53\x73\xd0\x00\x00\x00\x22\x00\x00\x00\x0d\x40\x40\x40\x40\x40\x40\x40\x40\x83\x00\x00\x00\x00\x00\x00\x00\x00\x83\x00\x00\x00\x00\x00\x00\x00\x00\x40\x52\x00\x40'
- msg2 = Message()
- msg2.decode(data)
- assert msg2.priority == 4, (msg2.priority)
-
- # The same message with LIST8s instead
- data = b'\x00\x53\x70\xc0\x07\x05\x42\x40\x40\x42\x52\x00\x00\x53\x73\xc0\x1f\x0d\x40\x40\x40\x40\x40\x40\x40\x40\x83\x00\x00\x00\x00\x00\x00\x00\x00\x83\x00\x00\x00\x00\x00\x00\x00\x00\x40\x52\x00\x40'
- msg3 = Message()
- msg3.decode(data)
- assert msg3.priority == 4, (msg3.priority)
-
- # Minified message with zero length HEADER and PROPERTIES lists
- data = b'\x00\x53\x70\x45' b'\x00\x53\x73\x45'
- msg4 = Message()
- msg4.decode(data)
- assert msg4.priority == 4, (msg4.priority)
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/reactor.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/reactor.py b/tests/python/proton_tests/reactor.py
deleted file mode 100644
index 1b1e2fc..0000000
--- a/tests/python/proton_tests/reactor.py
+++ /dev/null
@@ -1,485 +0,0 @@
-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.
-#
-
-import time
-import sys
-from .common import Test, SkipTest, TestServer, free_tcp_port, ensureCanTestExtendedSASL
-from proton.reactor import Container, Reactor, ApplicationEvent, EventInjector
-from proton.handlers import Handshaker, MessagingHandler
-from proton import Handler, Url
-
-class Barf(Exception):
- pass
-
-class BarfOnInit:
-
- def on_reactor_init(self, event):
- raise Barf()
-
- def on_connection_init(self, event):
- raise Barf()
-
- def on_session_init(self, event):
- raise Barf()
-
- def on_link_init(self, event):
- raise Barf()
-
-class BarfOnTask:
-
- def on_timer_task(self, event):
- raise Barf()
-
-class BarfOnFinal:
- init = False
-
- def on_reactor_init(self, event):
- self.init = True
-
- def on_reactor_final(self, event):
- raise Barf()
-
-class BarfOnFinalDerived(Handshaker):
- init = False
-
- def on_reactor_init(self, event):
- self.init = True
-
- def on_reactor_final(self, event):
- raise Barf()
-
-class ExceptionTest(Test):
-
- def setUp(self):
- self.reactor = Reactor()
-
- def test_reactor_final(self):
- self.reactor.global_handler = BarfOnFinal()
- try:
- self.reactor.run()
- assert False, "expected to barf"
- except Barf:
- pass
-
- def test_global_set(self):
- self.reactor.global_handler = BarfOnInit()
- try:
- self.reactor.run()
- assert False, "expected to barf"
- except Barf:
- pass
-
- def test_global_add(self):
- self.reactor.global_handler.add(BarfOnInit())
- try:
- self.reactor.run()
- assert False, "expected to barf"
- except Barf:
- pass
-
- def test_reactor_set(self):
- self.reactor.handler = BarfOnInit()
- try:
- self.reactor.run()
- assert False, "expected to barf"
- except Barf:
- pass
-
- def test_reactor_add(self):
- self.reactor.handler.add(BarfOnInit())
- try:
- self.reactor.run()
- assert False, "expected to barf"
- except Barf:
- pass
-
- def test_connection(self):
- self.reactor.connection(BarfOnInit())
- try:
- self.reactor.run()
- assert False, "expected to barf"
- except Barf:
- pass
-
- def test_connection_set(self):
- c = self.reactor.connection()
- c.handler = BarfOnInit()
- try:
- self.reactor.run()
- assert False, "expected to barf"
- except Barf:
- pass
-
- def test_connection_add(self):
- c = self.reactor.connection()
- c.handler = object()
- c.handler.add(BarfOnInit())
- try:
- self.reactor.run()
- assert False, "expected to barf"
- except Barf:
- pass
-
- def test_session_set(self):
- c = self.reactor.connection()
- s = c.session()
- s.handler = BarfOnInit()
- try:
- self.reactor.run()
- assert False, "expected to barf"
- except Barf:
- pass
-
- def test_session_add(self):
- c = self.reactor.connection()
- s = c.session()
- s.handler = object()
- s.handler.add(BarfOnInit())
- try:
- self.reactor.run()
- assert False, "expected to barf"
- except Barf:
- pass
-
- def test_link_set(self):
- c = self.reactor.connection()
- s = c.session()
- l = s.sender("xxx")
- l.handler = BarfOnInit()
- try:
- self.reactor.run()
- assert False, "expected to barf"
- except Barf:
- pass
-
- def test_link_add(self):
- c = self.reactor.connection()
- s = c.session()
- l = s.sender("xxx")
- l.handler = object()
- l.handler.add(BarfOnInit())
- try:
- self.reactor.run()
- assert False, "expected to barf"
- except Barf:
- pass
-
- def test_schedule(self):
- self.reactor.schedule(0, BarfOnTask())
- try:
- self.reactor.run()
- assert False, "expected to barf"
- except Barf:
- pass
-
- def test_schedule_many_nothings(self):
- class Nothing:
- results = []
- def on_timer_task(self, event):
- self.results.append(None)
- num = 12345
- for a in range(num):
- self.reactor.schedule(0, Nothing())
- self.reactor.run()
- assert len(Nothing.results) == num
-
- def test_schedule_many_nothing_refs(self):
- class Nothing:
- results = []
- def on_timer_task(self, event):
- self.results.append(None)
- num = 12345
- tasks = []
- for a in range(num):
- tasks.append(self.reactor.schedule(0, Nothing()))
- self.reactor.run()
- assert len(Nothing.results) == num
-
- def test_schedule_many_nothing_refs_cancel_before_run(self):
- class Nothing:
- results = []
- def on_timer_task(self, event):
- self.results.append(None)
- num = 12345
- tasks = []
- for a in range(num):
- tasks.append(self.reactor.schedule(0, Nothing()))
- for task in tasks:
- task.cancel()
- self.reactor.run()
- assert len(Nothing.results) == 0
-
- def test_schedule_cancel(self):
- barf = self.reactor.schedule(10, BarfOnTask())
- class CancelBarf:
- def __init__(self, barf):
- self.barf = barf
- def on_timer_task(self, event):
- self.barf.cancel()
- pass
- self.reactor.schedule(0, CancelBarf(barf))
- now = self.reactor.mark()
- try:
- self.reactor.run()
- elapsed = self.reactor.mark() - now
- assert elapsed < 10, "expected cancelled task to not delay the reactor by %s" % elapsed
- except Barf:
- assert False, "expected barf to be cancelled"
-
- def test_schedule_cancel_many(self):
- num = 12345
- barfs = set()
- for a in range(num):
- barf = self.reactor.schedule(10*(a+1), BarfOnTask())
- class CancelBarf:
- def __init__(self, barf):
- self.barf = barf
- def on_timer_task(self, event):
- self.barf.cancel()
- barfs.discard(self.barf)
- pass
- self.reactor.schedule(0, CancelBarf(barf))
- barfs.add(barf)
- now = self.reactor.mark()
- try:
- self.reactor.run()
- elapsed = self.reactor.mark() - now
- assert elapsed < num, "expected cancelled task to not delay the reactor by %s" % elapsed
- assert not barfs, "expected all barfs to be discarded"
- except Barf:
- assert False, "expected barf to be cancelled"
-
-
-class ApplicationEventTest(Test):
- """Test application defined events and handlers."""
-
- class MyTestServer(TestServer):
- def __init__(self):
- super(ApplicationEventTest.MyTestServer, self).__init__()
-
- class MyHandler(Handler):
- def __init__(self, test):
- super(ApplicationEventTest.MyHandler, self).__init__()
- self._test = test
-
- def on_hello(self, event):
- # verify PROTON-1056
- self._test.hello_rcvd = str(event)
-
- def on_goodbye(self, event):
- self._test.goodbye_rcvd = str(event)
-
- def setUp(self):
- import os
- if not hasattr(os, 'pipe'):
- # KAG: seems like Jython doesn't have an os.pipe() method
- raise SkipTest()
- if os.name=="nt":
- # Correct implementation on Windows is complicated
- raise SkipTest("PROTON-1071")
- self.server = ApplicationEventTest.MyTestServer()
- self.server.reactor.handler.add(ApplicationEventTest.MyHandler(self))
- self.event_injector = EventInjector()
- self.hello_event = ApplicationEvent("hello")
- self.goodbye_event = ApplicationEvent("goodbye")
- self.server.reactor.selectable(self.event_injector)
- self.hello_rcvd = None
- self.goodbye_rcvd = None
- self.server.start()
-
- def tearDown(self):
- self.server.stop()
-
- def _wait_for(self, predicate, timeout=10.0):
- deadline = time.time() + timeout
- while time.time() < deadline:
- if predicate():
- break
- time.sleep(0.1)
- assert predicate()
-
- def test_application_events(self):
- self.event_injector.trigger(self.hello_event)
- self._wait_for(lambda: self.hello_rcvd is not None)
- self.event_injector.trigger(self.goodbye_event)
- self._wait_for(lambda: self.goodbye_rcvd is not None)
-
-
-class AuthenticationTestHandler(MessagingHandler):
- def __init__(self):
- super(AuthenticationTestHandler, self).__init__()
- port = free_tcp_port()
- self.url = "localhost:%i" % port
- self.verified = False
-
- def on_start(self, event):
- self.listener = event.container.listen(self.url)
-
- def on_connection_opened(self, event):
- event.connection.close()
-
- def on_connection_opening(self, event):
- assert event.connection.transport.user == "user@proton"
- self.verified = True
-
- def on_connection_closed(self, event):
- event.connection.close()
- self.listener.close()
-
- def on_connection_error(self, event):
- event.connection.close()
- self.listener.close()
-
-class ContainerTest(Test):
- """Test container subclass of reactor."""
-
- def test_event_has_container_attribute(self):
- ensureCanTestExtendedSASL()
- class TestHandler(MessagingHandler):
- def __init__(self):
- super(TestHandler, self).__init__()
- port = free_tcp_port()
- self.url = "localhost:%i" % port
-
- def on_start(self, event):
- self.listener = event.container.listen(self.url)
-
- def on_connection_closing(self, event):
- event.connection.close()
- self.listener.close()
- test_handler = TestHandler()
- container = Container(test_handler)
- class ConnectionHandler(MessagingHandler):
- def __init__(self):
- super(ConnectionHandler, self).__init__()
-
- def on_connection_opened(self, event):
- event.connection.close()
- assert event.container == event.reactor
- assert event.container == container
- container.connect(test_handler.url, handler=ConnectionHandler())
- container.run()
-
- def test_authentication_via_url(self):
- ensureCanTestExtendedSASL()
- test_handler = AuthenticationTestHandler()
- container = Container(test_handler)
- container.connect("%s:password@%s" % ("user%40proton", test_handler.url), reconnect=False)
- container.run()
- assert test_handler.verified
-
- def test_authentication_via_container_attributes(self):
- ensureCanTestExtendedSASL()
- test_handler = AuthenticationTestHandler()
- container = Container(test_handler)
- container.user = "user@proton"
- container.password = "password"
- container.connect(test_handler.url, reconnect=False)
- container.run()
- assert test_handler.verified
-
- def test_authentication_via_kwargs(self):
- ensureCanTestExtendedSASL()
- test_handler = AuthenticationTestHandler()
- container = Container(test_handler)
- container.connect(test_handler.url, user="user@proton", password="password", reconnect=False)
- container.run()
- assert test_handler.verified
-
- class _ServerHandler(MessagingHandler):
- def __init__(self, host):
- super(ContainerTest._ServerHandler, self).__init__()
- self.host = host
- port = free_tcp_port()
- self.port = free_tcp_port()
- self.client_addr = None
- self.peer_hostname = None
-
- def on_start(self, event):
- self.listener = event.container.listen("%s:%s" % (self.host, self.port))
-
- def on_connection_opened(self, event):
- self.client_addr = event.reactor.get_connection_address(event.connection)
- self.peer_hostname = event.connection.remote_hostname
-
- def on_connection_closing(self, event):
- event.connection.close()
- self.listener.close()
-
- class _ClientHandler(MessagingHandler):
- def __init__(self):
- super(ContainerTest._ClientHandler, self).__init__()
- self.server_addr = None
-
- def on_connection_opened(self, event):
- self.server_addr = event.reactor.get_connection_address(event.connection)
- event.connection.close()
-
- def test_numeric_hostname(self):
- ensureCanTestExtendedSASL()
- server_handler = ContainerTest._ServerHandler("127.0.0.1")
- client_handler = ContainerTest._ClientHandler()
- container = Container(server_handler)
- container.connect(url=Url(host="127.0.0.1",
- port=server_handler.port),
- handler=client_handler)
- container.run()
- assert server_handler.client_addr
- assert client_handler.server_addr
- assert server_handler.peer_hostname == "127.0.0.1", server_handler.peer_hostname
- assert client_handler.server_addr.rsplit(':', 1)[1] == str(server_handler.port)
-
- def test_non_numeric_hostname(self):
- ensureCanTestExtendedSASL()
- server_handler = ContainerTest._ServerHandler("localhost")
- client_handler = ContainerTest._ClientHandler()
- container = Container(server_handler)
- container.connect(url=Url(host="localhost",
- port=server_handler.port),
- handler=client_handler)
- container.run()
- assert server_handler.client_addr
- assert client_handler.server_addr
- assert server_handler.peer_hostname == "localhost", server_handler.peer_hostname
- assert client_handler.server_addr.rsplit(':', 1)[1] == str(server_handler.port)
-
- def test_virtual_host(self):
- ensureCanTestExtendedSASL()
- server_handler = ContainerTest._ServerHandler("localhost")
- container = Container(server_handler)
- conn = container.connect(url=Url(host="localhost",
- port=server_handler.port),
- handler=ContainerTest._ClientHandler(),
- virtual_host="a.b.c.org")
- container.run()
- assert server_handler.peer_hostname == "a.b.c.org", server_handler.peer_hostname
-
- def test_no_virtual_host(self):
- # explicitly setting an empty virtual host should prevent the hostname
- # field from being sent in the Open performative when using the
- # Python Container.
- server_handler = ContainerTest._ServerHandler("localhost")
- container = Container(server_handler)
- conn = container.connect(url=Url(host="localhost",
- port=server_handler.port),
- handler=ContainerTest._ClientHandler(),
- virtual_host="")
- container.run()
- assert server_handler.peer_hostname is None, server_handler.peer_hostname
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/sasl.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/sasl.py b/tests/python/proton_tests/sasl.py
deleted file mode 100644
index 68ae200..0000000
--- a/tests/python/proton_tests/sasl.py
+++ /dev/null
@@ -1,587 +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 __future__ import absolute_import
-
-import sys, os
-from . import common
-from . import engine
-
-from proton import *
-from .common import pump, Skipped
-
-def _sslCertpath(file):
- """ Return the full path to the certificate, keyfile, etc.
- """
- if os.name=="nt":
- if file.find("private-key")!=-1:
- # The private key is not in a separate store
- return None
- # Substitute pkcs#12 equivalent for the CA/key store
- if file.endswith(".pem"):
- file = file[:-4] + ".p12"
- return os.path.join(os.path.dirname(__file__),
- "ssl_db/%s" % file)
-
-def _testSaslMech(self, mech, clientUser='user@proton', authUser='user@proton', encrypted=False, authenticated=True):
- self.s1.allowed_mechs(mech)
- self.c1.open()
- self.c2.open()
-
- pump(self.t1, self.t2, 1024)
-
- if encrypted is not None:
- assert self.t2.encrypted == encrypted, encrypted
- assert self.t1.encrypted == encrypted, encrypted
-
- assert self.t2.authenticated == authenticated, authenticated
- assert self.t1.authenticated == authenticated, authenticated
- if authenticated:
- # Server
- assert self.t2.user == authUser
- assert self.s2.user == authUser
- assert self.s2.mech == mech.strip()
- assert self.s2.outcome == SASL.OK, self.s2.outcome
- assert self.c2.state & Endpoint.LOCAL_ACTIVE and self.c2.state & Endpoint.REMOTE_ACTIVE,\
- "local_active=%s, remote_active=%s" % (self.c1.state & Endpoint.LOCAL_ACTIVE, self.c1.state & Endpoint.REMOTE_ACTIVE)
- # Client
- assert self.t1.user == clientUser
- assert self.s1.user == clientUser
- assert self.s1.mech == mech.strip()
- assert self.s1.outcome == SASL.OK, self.s1.outcome
- assert self.c1.state & Endpoint.LOCAL_ACTIVE and self.c1.state & Endpoint.REMOTE_ACTIVE,\
- "local_active=%s, remote_active=%s" % (self.c1.state & Endpoint.LOCAL_ACTIVE, self.c1.state & Endpoint.REMOTE_ACTIVE)
- else:
- # Server
- assert self.t2.user == None
- assert self.s2.user == None
- assert self.s2.outcome != SASL.OK, self.s2.outcome
- # Client
- assert self.t1.user == clientUser
- assert self.s1.user == clientUser
- assert self.s1.outcome != SASL.OK, self.s1.outcome
-
-class Test(common.Test):
- pass
-
-def consumeAllOuput(t):
- stops = 0
- while stops<1:
- out = t.peek(1024)
- l = len(out) if out else 0
- t.pop(l)
- if l <= 0:
- stops += 1
-
-class SaslTest(Test):
-
- def setUp(self):
- self.t1 = Transport()
- self.s1 = SASL(self.t1)
- self.t2 = Transport(Transport.SERVER)
- self.t2.max_frame_size = 65536
- self.s2 = SASL(self.t2)
-
- def pump(self):
- pump(self.t1, self.t2, 1024)
-
- # We have to generate the client frames manually because proton does not
- # generate pipelined SASL and AMQP frames together
- def testIllegalProtocolLayering(self):
- # Server
- self.s2.allowed_mechs('ANONYMOUS')
-
- c2 = Connection()
- self.t2.bind(c2)
-
- assert self.s2.outcome is None
-
- # Push client bytes into server
- self.t2.push(
- # SASL
- b'AMQP\x03\x01\x00\x00'
- # @sasl-init(65) [mechanism=:ANONYMOUS, initial-response=b"anonymous@fuschia"]
- b'\x00\x00\x002\x02\x01\x00\x00\x00SA\xd0\x00\x00\x00"\x00\x00\x00\x02\xa3\x09ANONYMOUS\xa0\x11anonymous@fuschia'
- # SASL (again illegally)
- b'AMQP\x03\x01\x00\x00'
- # @sasl-init(65) [mechanism=:ANONYMOUS, initial-response=b"anonymous@fuschia"]
- b'\x00\x00\x002\x02\x01\x00\x00\x00SA\xd0\x00\x00\x00"\x00\x00\x00\x02\xa3\x09ANONYMOUS\xa0\x11anonymous@fuschia'
- # AMQP
- b'AMQP\x00\x01\x00\x00'
- # @open(16) [container-id="", channel-max=1234]
- b'\x00\x00\x00!\x02\x00\x00\x00\x00S\x10\xd0\x00\x00\x00\x11\x00\x00\x00\x0a\xa1\x00@@`\x04\xd2@@@@@@'
- )
-
- consumeAllOuput(self.t2)
-
- assert self.t2.condition
- assert self.t2.closed
- assert not c2.state & Endpoint.REMOTE_ACTIVE
-
- def testPipelinedClient(self):
- # Server
- self.s2.allowed_mechs('ANONYMOUS')
-
- c2 = Connection()
- self.t2.bind(c2)
-
- assert self.s2.outcome is None
-
- # Push client bytes into server
- self.t2.push(
- # SASL
- b'AMQP\x03\x01\x00\x00'
- # @sasl-init(65) [mechanism=:ANONYMOUS, initial-response=b"anonymous@fuschia"]
- b'\x00\x00\x002\x02\x01\x00\x00\x00SA\xd0\x00\x00\x00"\x00\x00\x00\x02\xa3\x09ANONYMOUS\xa0\x11anonymous@fuschia'
- # AMQP
- b'AMQP\x00\x01\x00\x00'
- # @open(16) [container-id="", channel-max=1234]
- b'\x00\x00\x00!\x02\x00\x00\x00\x00S\x10\xd0\x00\x00\x00\x11\x00\x00\x00\x0a\xa1\x00@@`\x04\xd2@@@@@@'
- )
-
- consumeAllOuput(self.t2)
-
- assert not self.t2.condition
- assert self.s2.outcome == SASL.OK
- assert c2.state & Endpoint.REMOTE_ACTIVE
-
- def testPipelinedServer(self):
- # Client
- self.s1.allowed_mechs('ANONYMOUS')
-
- c1 = Connection()
- self.t1.bind(c1)
-
- assert self.s1.outcome is None
-
- # Push server bytes into client
- # Commented out lines in this test are where the client input processing doesn't
- # run after output processing even though there is input waiting
- self.t1.push(
- # SASL
- b'AMQP\x03\x01\x00\x00'
- # @sasl-mechanisms(64) [sasl-server-mechanisms=@PN_SYMBOL[:ANONYMOUS]]
- b'\x00\x00\x00\x1c\x02\x01\x00\x00\x00S@\xc0\x0f\x01\xe0\x0c\x01\xa3\tANONYMOUS'
- # @sasl-outcome(68) [code=0]
- b'\x00\x00\x00\x10\x02\x01\x00\x00\x00SD\xc0\x03\x01P\x00'
- # AMQP
- b'AMQP\x00\x01\x00\x00'
- # @open(16) [container-id="", channel-max=1234]
- b'\x00\x00\x00!\x02\x00\x00\x00\x00S\x10\xd0\x00\x00\x00\x11\x00\x00\x00\x0a\xa1\x00@@`\x04\xd2@@@@@@'
- )
-
- consumeAllOuput(self.t1)
-
- assert self.s1.outcome == SASL.OK
- assert c1.state & Endpoint.REMOTE_ACTIVE
-
- def testPipelined2(self):
- out1 = self.t1.peek(1024)
- self.t1.pop(len(out1))
- self.t2.push(out1)
-
- self.s2.allowed_mechs('ANONYMOUS')
- c2 = Connection()
- c2.open()
- self.t2.bind(c2)
-
- out2 = self.t2.peek(1024)
- self.t2.pop(len(out2))
- self.t1.push(out2)
-
- out1 = self.t1.peek(1024)
- assert len(out1) > 0
-
- def testFracturedSASL(self):
- """ PROTON-235
- """
- assert self.s1.outcome is None
-
- # self.t1.trace(Transport.TRACE_FRM)
-
- out = self.t1.peek(1024)
- self.t1.pop(len(out))
- self.t1.push(b"AMQP\x03\x01\x00\x00")
- out = self.t1.peek(1024)
- self.t1.pop(len(out))
- self.t1.push(b"\x00\x00\x00")
- out = self.t1.peek(1024)
- self.t1.pop(len(out))
-
- self.t1.push(b"6\x02\x01\x00\x00\x00S@\xc0\x29\x01\xe0\x26\x04\xa3\x05PLAIN\x0aDIGEST-MD5\x09ANONYMOUS\x08CRAM-MD5")
- out = self.t1.peek(1024)
- self.t1.pop(len(out))
- self.t1.push(b"\x00\x00\x00\x10\x02\x01\x00\x00\x00SD\xc0\x03\x01P\x00")
- out = self.t1.peek(1024)
- self.t1.pop(len(out))
- while out:
- out = self.t1.peek(1024)
- self.t1.pop(len(out))
-
- assert self.s1.outcome == SASL.OK, self.s1.outcome
-
- def test_singleton(self):
- """Verify that only a single instance of SASL can exist per Transport"""
- transport = Transport()
- attr = object()
- sasl1 = SASL(transport)
- sasl1.my_attribute = attr
- sasl2 = transport.sasl()
- sasl3 = SASL(transport)
- assert sasl1 == sasl2
- assert sasl1 == sasl3
- assert sasl1.my_attribute == attr
- assert sasl2.my_attribute == attr
- assert sasl3.my_attribute == attr
- transport = Transport()
- sasl1 = transport.sasl()
- sasl1.my_attribute = attr
- sasl2 = SASL(transport)
- assert sasl1 == sasl2
- assert sasl1.my_attribute == attr
- assert sasl2.my_attribute == attr
-
- def testSaslSkipped(self):
- """Verify that the server (with SASL) correctly handles a client without SASL"""
- self.t1 = Transport()
- self.t2.require_auth(False)
- self.pump()
- assert self.s2.outcome == None
- assert self.t2.condition == None
- assert self.t2.authenticated == False
- assert self.s1.outcome == None
- assert self.t1.condition == None
- assert self.t1.authenticated == False
-
- def testSaslSkippedFail(self):
- """Verify that the server (with SASL) correctly handles a client without SASL"""
- self.t1 = Transport()
- self.t2.require_auth(True)
- self.pump()
- assert self.s2.outcome == None
- assert self.t2.condition != None
- assert self.s1.outcome == None
- assert self.t1.condition != None
-
- def testMechNotFound(self):
- self.c1 = Connection()
- self.c1.open()
- self.t1.bind(self.c1)
- self.s1.allowed_mechs('IMPOSSIBLE')
-
- self.pump()
-
- assert self.t2.authenticated == False
- assert self.t1.authenticated == False
- assert self.s1.outcome != SASL.OK
- assert self.s2.outcome != SASL.OK
-
-class SASLMechTest(Test):
- def setUp(self):
- self.t1 = Transport()
- self.s1 = SASL(self.t1)
- self.t2 = Transport(Transport.SERVER)
- self.s2 = SASL(self.t2)
-
- self.c1 = Connection()
- self.c1.user = 'user@proton'
- self.c1.password = 'password'
- self.c1.hostname = 'localhost'
-
- self.c2 = Connection()
-
- def testANON(self):
- self.t1.bind(self.c1)
- self.t2.bind(self.c2)
- _testSaslMech(self, 'ANONYMOUS', authUser='anonymous')
-
- def testCRAMMD5(self):
- common.ensureCanTestExtendedSASL()
-
- self.t1.bind(self.c1)
- self.t2.bind(self.c2)
- _testSaslMech(self, 'CRAM-MD5')
-
- def testDIGESTMD5(self):
- common.ensureCanTestExtendedSASL()
-
- self.t1.bind(self.c1)
- self.t2.bind(self.c2)
- _testSaslMech(self, 'DIGEST-MD5')
-
- # PLAIN shouldn't work without encryption without special setting
- def testPLAINfail(self):
- common.ensureCanTestExtendedSASL()
-
- self.t1.bind(self.c1)
- self.t2.bind(self.c2)
- _testSaslMech(self, 'PLAIN', authenticated=False)
-
- # Client won't accept PLAIN even if offered by server without special setting
- def testPLAINClientFail(self):
- common.ensureCanTestExtendedSASL()
-
- self.s2.allow_insecure_mechs = True
- self.t1.bind(self.c1)
- self.t2.bind(self.c2)
- _testSaslMech(self, 'PLAIN', authenticated=False)
-
- # PLAIN will only work if both ends are specially set up
- def testPLAIN(self):
- common.ensureCanTestExtendedSASL()
-
- self.s1.allow_insecure_mechs = True
- self.s2.allow_insecure_mechs = True
- self.t1.bind(self.c1)
- self.t2.bind(self.c2)
- _testSaslMech(self, 'PLAIN')
-
-# SCRAM not supported before Cyrus SASL 2.1.26
-# so not universal and hence need a test for support
-# to keep it in tests.
-# def testSCRAMSHA1(self):
-# common.ensureCanTestExtendedSASL()
-#
-# self.t1.bind(self.c1)
-# self.t2.bind(self.c2)
-# _testSaslMech(self, 'SCRAM-SHA-1')
-
-def _sslConnection(domain, transport, connection):
- transport.bind(connection)
- ssl = SSL(transport, domain, None )
- return connection
-
-class SSLSASLTest(Test):
- def setUp(self):
- if not common.isSSLPresent():
- raise Skipped("No SSL libraries found.")
-
- self.server_domain = SSLDomain(SSLDomain.MODE_SERVER)
- self.client_domain = SSLDomain(SSLDomain.MODE_CLIENT)
-
- self.t1 = Transport()
- self.s1 = SASL(self.t1)
- self.t2 = Transport(Transport.SERVER)
- self.s2 = SASL(self.t2)
-
- self.c1 = Connection()
- self.c2 = Connection()
-
- def testSSLPlainSimple(self):
- if not SASL.extended():
- raise Skipped("Simple SASL server does not support PLAIN")
- common.ensureCanTestExtendedSASL()
-
- clientUser = 'user@proton'
- mech = 'PLAIN'
-
- self.c1.user = clientUser
- self.c1.password = 'password'
- self.c1.hostname = 'localhost'
-
- ssl1 = _sslConnection(self.client_domain, self.t1, self.c1)
- ssl2 = _sslConnection(self.server_domain, self.t2, self.c2)
-
- _testSaslMech(self, mech, encrypted=True)
-
- def testSSLPlainSimpleFail(self):
- if not SASL.extended():
- raise Skipped("Simple SASL server does not support PLAIN")
- common.ensureCanTestExtendedSASL()
-
- clientUser = 'usr@proton'
- mech = 'PLAIN'
-
- self.c1.user = clientUser
- self.c1.password = 'password'
- self.c1.hostname = 'localhost'
-
- ssl1 = _sslConnection(self.client_domain, self.t1, self.c1)
- ssl2 = _sslConnection(self.server_domain, self.t2, self.c2)
-
- _testSaslMech(self, mech, clientUser='usr@proton', encrypted=True, authenticated=False)
-
- def testSSLExternalSimple(self):
- if os.name=="nt":
- extUser = 'O=Client, CN=127.0.0.1'
- else:
- extUser = 'O=Client,CN=127.0.0.1'
- mech = 'EXTERNAL'
-
- self.server_domain.set_credentials(_sslCertpath("server-certificate.pem"),
- _sslCertpath("server-private-key.pem"),
- "server-password")
- self.server_domain.set_trusted_ca_db(_sslCertpath("ca-certificate.pem"))
- self.server_domain.set_peer_authentication(SSLDomain.VERIFY_PEER,
- _sslCertpath("ca-certificate.pem") )
- self.client_domain.set_credentials(_sslCertpath("client-certificate.pem"),
- _sslCertpath("client-private-key.pem"),
- "client-password")
- self.client_domain.set_trusted_ca_db(_sslCertpath("ca-certificate.pem"))
- self.client_domain.set_peer_authentication(SSLDomain.VERIFY_PEER)
-
- ssl1 = _sslConnection(self.client_domain, self.t1, self.c1)
- ssl2 = _sslConnection(self.server_domain, self.t2, self.c2)
-
- _testSaslMech(self, mech, clientUser=None, authUser=extUser, encrypted=True)
-
- def testSSLExternalSimpleFail(self):
- mech = 'EXTERNAL'
-
- self.server_domain.set_credentials(_sslCertpath("server-certificate.pem"),
- _sslCertpath("server-private-key.pem"),
- "server-password")
- self.server_domain.set_trusted_ca_db(_sslCertpath("ca-certificate.pem"))
- self.server_domain.set_peer_authentication(SSLDomain.VERIFY_PEER,
- _sslCertpath("ca-certificate.pem") )
- self.client_domain.set_trusted_ca_db(_sslCertpath("ca-certificate.pem"))
- self.client_domain.set_peer_authentication(SSLDomain.VERIFY_PEER)
-
- ssl1 = _sslConnection(self.client_domain, self.t1, self.c1)
- ssl2 = _sslConnection(self.server_domain, self.t2, self.c2)
-
- _testSaslMech(self, mech, clientUser=None, authUser=None, encrypted=None, authenticated=False)
-
-class SASLEventTest(engine.CollectorTest):
- def setUp(self):
- engine.CollectorTest.setUp(self)
- self.t1 = Transport()
- self.s1 = SASL(self.t1)
- self.t2 = Transport(Transport.SERVER)
- self.s2 = SASL(self.t2)
-
- self.c1 = Connection()
- self.c1.user = 'user@proton'
- self.c1.password = 'password'
- self.c1.hostname = 'localhost'
-
- self.c2 = Connection()
-
- self.collector = Collector()
-
- def testNormalAuthenticationClient(self):
- common.ensureCanTestExtendedSASL()
- self.c1.collect(self.collector)
- self.t1.bind(self.c1)
- self.t2.bind(self.c2)
- _testSaslMech(self, 'DIGEST-MD5')
- self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND,
- Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT,
- Event.CONNECTION_REMOTE_OPEN)
-
- def testNormalAuthenticationServer(self):
- common.ensureCanTestExtendedSASL()
- self.c2.collect(self.collector)
- self.t1.bind(self.c1)
- self.t2.bind(self.c2)
- _testSaslMech(self, 'DIGEST-MD5')
- self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND,
- Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT,
- Event.CONNECTION_REMOTE_OPEN)
-
- def testFailedAuthenticationClient(self):
- common.ensureCanTestExtendedSASL()
- clientUser = "usr@proton"
- self.c1.user = clientUser
- self.c1.collect(self.collector)
- self.t1.bind(self.c1)
- self.t2.bind(self.c2)
- _testSaslMech(self, 'DIGEST-MD5', clientUser=clientUser, authenticated=False)
- self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND,
- Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT,
- Event.TRANSPORT_ERROR,
- Event.TRANSPORT_TAIL_CLOSED,
- Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED)
-
- def testFailedAuthenticationServer(self):
- common.ensureCanTestExtendedSASL()
- clientUser = "usr@proton"
- self.c1.user = clientUser
- self.c2.collect(self.collector)
- self.t1.bind(self.c1)
- self.t2.bind(self.c2)
- _testSaslMech(self, 'DIGEST-MD5', clientUser=clientUser, authenticated=False)
- self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND,
- Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT,
- Event.TRANSPORT_ERROR,
- Event.TRANSPORT_TAIL_CLOSED,
- Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED)
-
- def testNoMechClient(self):
- common.ensureCanTestExtendedSASL()
- self.c1.collect(self.collector)
- self.s2.allowed_mechs('IMPOSSIBLE')
- self.t1.bind(self.c1)
- self.t2.bind(self.c2)
- _testSaslMech(self, 'DIGEST-MD5', authenticated=False)
- self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND,
- Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT,
- Event.TRANSPORT_ERROR,
- Event.TRANSPORT_TAIL_CLOSED, Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED)
-
- def testNoMechServer(self):
- common.ensureCanTestExtendedSASL()
- self.c2.collect(self.collector)
- self.s2.allowed_mechs('IMPOSSIBLE')
- self.t1.bind(self.c1)
- self.t2.bind(self.c2)
- _testSaslMech(self, 'DIGEST-MD5', authenticated=False)
- self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND,
- Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT,
- Event.TRANSPORT_TAIL_CLOSED,
- Event.TRANSPORT_ERROR, Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED)
-
- def testDisallowedMechClient(self):
- self.c1.collect(self.collector)
- self.t1.bind(self.c1)
- self.t2.bind(self.c2)
- _testSaslMech(self, 'IMPOSSIBLE', authenticated=False)
- self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND,
- Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT,
- Event.TRANSPORT_ERROR,
- Event.TRANSPORT_TAIL_CLOSED, Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED)
-
- def testDisallowedMechServer(self):
- self.c2.collect(self.collector)
- self.t1.bind(self.c1)
- self.t2.bind(self.c2)
- _testSaslMech(self, 'IMPOSSIBLE', authenticated=False)
- self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND,
- Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT,
- Event.TRANSPORT_TAIL_CLOSED,
- Event.TRANSPORT_ERROR, Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED)
-
- def testDisallowedPlainClient(self):
- self.c1.collect(self.collector)
- self.t1.bind(self.c1)
- self.t2.bind(self.c2)
- _testSaslMech(self, 'PLAIN', authenticated=False)
- self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND,
- Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT,
- Event.TRANSPORT_ERROR,
- Event.TRANSPORT_TAIL_CLOSED, Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED)
-
- def testDisallowedPlainServer(self):
- self.c2.collect(self.collector)
- self.t1.bind(self.c1)
- self.t2.bind(self.c2)
- _testSaslMech(self, 'PLAIN', authenticated=False)
- self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND,
- Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT,
- Event.TRANSPORT_TAIL_CLOSED,
- Event.TRANSPORT_ERROR, Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED)
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/soak.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/soak.py b/tests/python/proton_tests/soak.py
deleted file mode 100644
index b7b521c..0000000
--- a/tests/python/proton_tests/soak.py
+++ /dev/null
@@ -1,334 +0,0 @@
-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.
-#
-import os
-import sys
-from .common import Test, Skipped, free_tcp_ports, \
- MessengerReceiverC, MessengerSenderC, \
- MessengerReceiverValgrind, MessengerSenderValgrind, \
- ReactorReceiverC, ReactorSenderC, \
- ReactorReceiverValgrind, ReactorSenderValgrind, \
- isSSLPresent
-from proton import *
-
-#
-# Tests that run the apps
-#
-
-class AppTests(Test):
-
- def __init__(self, *args):
- Test.__init__(self, *args)
- self.is_valgrind = False
-
- def default(self, name, value, **kwargs):
- if self.is_valgrind:
- default = kwargs.get("valgrind", value)
- else:
- default = value
- return Test.default(self, name, default, **kwargs)
-
- @property
- def iterations(self):
- return int(self.default("iterations", 2, fast=1, valgrind=2))
-
- @property
- def send_count(self):
- return int(self.default("send_count", 17, fast=1, valgrind=2))
-
- @property
- def target_count(self):
- return int(self.default("target_count", 5, fast=1, valgrind=2))
-
- @property
- def send_batch(self):
- return int(self.default("send_batch", 7, fast=1, valgrind=2))
-
- @property
- def forward_count(self):
- return int(self.default("forward_count", 5, fast=1, valgrind=2))
-
- @property
- def port_count(self):
- return int(self.default("port_count", 3, fast=1, valgrind=2))
-
- @property
- def sender_count(self):
- return int(self.default("sender_count", 3, fast=1, valgrind=2))
-
- def valgrind_test(self):
- self.is_valgrind = True
-
- def setUp(self):
- self.senders = []
- self.receivers = []
-
- def tearDown(self):
- pass
-
- def _do_test(self, iterations=1):
- verbose = self.verbose
-
- for R in self.receivers:
- R.start( verbose )
-
- for j in range(iterations):
- for S in self.senders:
- S.start( verbose )
-
- for S in self.senders:
- S.wait()
- #print("SENDER OUTPUT:")
- #print( S.stdout() )
- assert S.status() == 0, ("Command '%s' failed status=%d: '%s' '%s'"
- % (str(S.cmdline()),
- S.status(),
- S.stdout(),
- S.stderr()))
-
- for R in self.receivers:
- R.wait()
- #print("RECEIVER OUTPUT")
- #print( R.stdout() )
- assert R.status() == 0, ("Command '%s' failed status=%d: '%s' '%s'"
- % (str(R.cmdline()),
- R.status(),
- R.stdout(),
- R.stderr()))
-
-#
-# Traffic passing tests based on the Messenger apps
-#
-
-class MessengerTests(AppTests):
-
- _timeout = 60
-
- def _ssl_check(self):
- if not isSSLPresent():
- raise Skipped("No SSL libraries found.")
- if os.name=="nt":
- raise Skipped("Windows SChannel lacks anonymous cipher support.")
-
- def __init__(self, *args):
- AppTests.__init__(self, *args)
-
- def _do_oneway_test(self, receiver, sender, domain="amqp"):
- """ Send N messages to a receiver.
- Parameters:
- iterations - repeat the senders this many times
- target_count = # of targets to send to.
- send_count = # messages sent to each target
- """
- iterations = self.iterations
- send_count = self.send_count
- target_count = self.target_count
-
- send_total = send_count * target_count
- receive_total = send_total * iterations
-
- port = free_tcp_ports()[0]
-
- receiver.subscriptions = ["%s://~0.0.0.0:%s" % (domain, port)]
- receiver.receive_count = receive_total
- receiver.timeout = MessengerTests._timeout
- self.receivers.append( receiver )
-
- sender.targets = ["%s://0.0.0.0:%s/X%d" % (domain, port, j) for j in range(target_count)]
- sender.send_count = send_total
- sender.timeout = MessengerTests._timeout
- self.senders.append( sender )
-
- self._do_test(iterations)
-
- def _do_echo_test(self, receiver, sender, domain="amqp"):
- """ Send N messages to a receiver, which responds to each.
- Parameters:
- iterations - repeat the senders this many times
- target_count - # targets to send to
- send_count = # messages sent to each target
- send_batch - wait for replies after this many messages sent
- """
- iterations = self.iterations
- send_count = self.send_count
- target_count = self.target_count
- send_batch = self.send_batch
-
- send_total = send_count * target_count
- receive_total = send_total * iterations
-
- port = free_tcp_ports()[0]
-
- receiver.subscriptions = ["%s://~0.0.0.0:%s" % (domain, port)]
- receiver.receive_count = receive_total
- receiver.send_reply = True
- receiver.timeout = MessengerTests._timeout
- self.receivers.append( receiver )
-
- sender.targets = ["%s://0.0.0.0:%s/%dY" % (domain, port, j) for j in range(target_count)]
- sender.send_count = send_total
- sender.get_reply = True
- sender.send_batch = send_batch
- sender.timeout = MessengerTests._timeout
- self.senders.append( sender )
-
- self._do_test(iterations)
-
- def _do_relay_test(self, receiver, relay, sender, domain="amqp"):
- """ Send N messages to a receiver, which replies to each and forwards
- each of them to different receiver.
- Parameters:
- iterations - repeat the senders this many times
- target_count - # targets to send to
- send_count = # messages sent to each target
- send_batch - wait for replies after this many messages sent
- forward_count - forward to this many targets
- """
- iterations = self.iterations
- send_count = self.send_count
- target_count = self.target_count
- send_batch = self.send_batch
- forward_count = self.forward_count
-
- send_total = send_count * target_count
- receive_total = send_total * iterations
-
- port = free_tcp_ports()[0]
-
- receiver.subscriptions = ["%s://~0.0.0.0:%s" % (domain, port)]
- receiver.receive_count = receive_total
- receiver.send_reply = True
- # forward to 'relay' - uses two links
- # ## THIS FAILS:
- # receiver.forwards = ["amqp://Relay/%d" % j for j in range(forward_count)]
- receiver.forwards = ["%s://Relay" % domain]
- receiver.timeout = MessengerTests._timeout
- self.receivers.append( receiver )
-
- relay.subscriptions = ["%s://0.0.0.0:%s" % (domain, port)]
- relay.name = "Relay"
- relay.receive_count = receive_total
- relay.timeout = MessengerTests._timeout
- self.receivers.append( relay )
-
- # send to 'receiver'
- sender.targets = ["%s://0.0.0.0:%s/X%dY" % (domain, port, j) for j in range(target_count)]
- sender.send_count = send_total
- sender.get_reply = True
- sender.timeout = MessengerTests._timeout
- self.senders.append( sender )
-
- self._do_test(iterations)
-
-
- def _do_star_topology_test(self, r_factory, s_factory, domain="amqp"):
- """
- A star-like topology, with a central receiver at the hub, and senders at
- the spokes. Each sender will connect to each of the ports the receiver is
- listening on. Each sender will then create N links per each connection.
- Each sender will send X messages per link, waiting for a response.
- Parameters:
- iterations - repeat the senders this many times
- port_count - # of ports the receiver will listen on. Each sender connects
- to all ports.
- sender_count - # of senders
- target_count - # of targets per connection
- send_count - # of messages sent to each target
- send_batch - # of messages to send before waiting for response
- """
- iterations = self.iterations
- port_count = self.port_count
- sender_count = self.sender_count
- target_count = self.target_count
- send_count = self.send_count
- send_batch = self.send_batch
-
- send_total = port_count * target_count * send_count
- receive_total = send_total * sender_count * iterations
-
- ports = free_tcp_ports(port_count)
-
- receiver = r_factory()
- receiver.subscriptions = ["%s://~0.0.0.0:%s" % (domain, port) for port in ports]
- receiver.receive_count = receive_total
- receiver.send_reply = True
- receiver.timeout = MessengerTests._timeout
- self.receivers.append( receiver )
-
- for i in range(sender_count):
- sender = s_factory()
- sender.targets = ["%s://0.0.0.0:%s/%d" % (domain, port, j) for port in ports for j in range(target_count)]
- sender.send_count = send_total
- sender.send_batch = send_batch
- sender.get_reply = True
- sender.timeout = MessengerTests._timeout
- self.senders.append( sender )
-
- self._do_test(iterations)
-
- def test_oneway_C(self):
- self._do_oneway_test(MessengerReceiverC(), MessengerSenderC())
-
- def test_oneway_C_SSL(self):
- self._ssl_check()
- self._do_oneway_test(MessengerReceiverC(), MessengerSenderC(), "amqps")
-
- def test_oneway_valgrind(self):
- self.valgrind_test()
- self._do_oneway_test(MessengerReceiverValgrind(), MessengerSenderValgrind())
-
- def test_echo_C(self):
- self._do_echo_test(MessengerReceiverC(), MessengerSenderC())
-
- def test_echo_C_SSL(self):
- self._ssl_check()
- self._do_echo_test(MessengerReceiverC(), MessengerSenderC(), "amqps")
-
- def test_echo_valgrind(self):
- self.valgrind_test()
- self._do_echo_test(MessengerReceiverValgrind(), MessengerSenderValgrind())
-
- def test_relay_C(self):
- self._do_relay_test(MessengerReceiverC(), MessengerReceiverC(), MessengerSenderC())
-
- def test_relay_C_SSL(self):
- self._ssl_check()
- self._do_relay_test(MessengerReceiverC(), MessengerReceiverC(), MessengerSenderC(), "amqps")
-
- def test_relay_valgrind(self):
- self.valgrind_test()
- self._do_relay_test(MessengerReceiverValgrind(), MessengerReceiverValgrind(), MessengerSenderValgrind())
-
- def test_star_topology_C(self):
- self._do_star_topology_test( MessengerReceiverC, MessengerSenderC )
-
- def test_star_topology_C_SSL(self):
- self._ssl_check()
- self._do_star_topology_test( MessengerReceiverC, MessengerSenderC, "amqps" )
-
- def test_star_topology_valgrind(self):
- self.valgrind_test()
- self._do_star_topology_test( MessengerReceiverValgrind, MessengerSenderValgrind )
-
- def test_oneway_reactor(self):
- self._do_oneway_test(ReactorReceiverC(), ReactorSenderC())
-
- def test_oneway_reactor_valgrind(self):
- self.valgrind_test()
- self._do_oneway_test(ReactorReceiverValgrind(), ReactorSenderValgrind())
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[03/11] qpid-proton git commit: PROTON-1885: [python] move
tests/python to python/tests
Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/transport.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/transport.py b/tests/python/proton_tests/transport.py
deleted file mode 100644
index 5390d07..0000000
--- a/tests/python/proton_tests/transport.py
+++ /dev/null
@@ -1,393 +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
-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/tests/python/proton_tests/url.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/url.py b/tests/python/proton_tests/url.py
deleted file mode 100644
index b44699a..0000000
--- a/tests/python/proton_tests/url.py
+++ /dev/null
@@ -1,147 +0,0 @@
-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/tests/python/proton_tests/utils.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/utils.py b/tests/python/proton_tests/utils.py
deleted file mode 100644
index 1f20bba..0000000
--- a/tests/python/proton_tests/utils.py
+++ /dev/null
@@ -1,163 +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, 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/tests/python/tox-blacklist
----------------------------------------------------------------------
diff --git a/tests/python/tox-blacklist b/tests/python/tox-blacklist
deleted file mode 100644
index 3c10c71..0000000
--- a/tests/python/tox-blacklist
+++ /dev/null
@@ -1,13 +0,0 @@
-# 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
-
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[08/11] qpid-proton git commit: PROTON-1885: [python] move
tests/python to python/tests
Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl.py
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl.py b/python/tests/proton_tests/ssl.py
new file mode 100644
index 0000000..da237f9
--- /dev/null
+++ b/python/tests/proton_tests/ssl.py
@@ -0,0 +1,936 @@
+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.
+#
+
+import os
+from . import common
+import random
+import string
+import subprocess
+import sys
+from proton import *
+from .common import Skipped, pump
+
+
+def _testpath(file):
+ """ Set the full path to the certificate,keyfile, etc. for the test.
+ """
+ if os.name=="nt":
+ if file.find("private-key")!=-1:
+ # The private key is not in a separate store
+ return None
+ # Substitute pkcs#12 equivalent for the CA/key store
+ if file.endswith(".pem"):
+ file = file[:-4] + ".p12"
+ return os.path.join(os.path.dirname(__file__),
+ "ssl_db/%s" % file)
+
+class SslTest(common.Test):
+
+ def __init__(self, *args):
+ common.Test.__init__(self, *args)
+ self._testpath = _testpath
+
+ def setUp(self):
+ if not common.isSSLPresent():
+ raise Skipped("No SSL libraries found.")
+ self.server_domain = SSLDomain(SSLDomain.MODE_SERVER)
+ self.client_domain = SSLDomain(SSLDomain.MODE_CLIENT)
+
+ def tearDown(self):
+ self.server_domain = None
+ self.client_domain = None
+
+ class SslTestConnection(object):
+ """ Represents a single SSL connection.
+ """
+ def __init__(self, domain=None, mode=Transport.CLIENT,
+ session_details=None, conn_hostname=None,
+ ssl_peername=None):
+ if not common.isSSLPresent():
+ raise Skipped("No SSL libraries found.")
+
+ self.ssl = None
+ self.domain = domain
+ self.transport = Transport(mode)
+ self.connection = Connection()
+ if conn_hostname:
+ self.connection.hostname = conn_hostname
+ if domain:
+ self.ssl = SSL( self.transport, self.domain, session_details )
+ if ssl_peername:
+ self.ssl.peer_hostname = ssl_peername
+ # bind last, after all configuration complete:
+ self.transport.bind(self.connection)
+
+ def _pump(self, ssl_client, ssl_server, buffer_size=1024):
+ pump(ssl_client.transport, ssl_server.transport, buffer_size)
+
+ def _do_handshake(self, client, server):
+ """ Attempt to connect client to server. Will throw a TransportException if the SSL
+ handshake fails.
+ """
+ client.connection.open()
+ server.connection.open()
+ self._pump(client, server)
+ if client.transport.closed:
+ return
+ assert client.ssl.protocol_name() is not None
+ client.connection.close()
+ server.connection.close()
+ self._pump(client, server)
+
+ def test_defaults(self):
+ if os.name=="nt":
+ raise Skipped("Windows SChannel lacks anonymous cipher support.")
+ """ By default, both the server and the client support anonymous
+ ciphers - they should connect without need for a certificate.
+ """
+ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
+ client = SslTest.SslTestConnection( self.client_domain )
+
+ # check that no SSL connection exists
+ assert not server.ssl.cipher_name()
+ assert not client.ssl.protocol_name()
+
+ #client.transport.trace(Transport.TRACE_DRV)
+ #server.transport.trace(Transport.TRACE_DRV)
+
+ client.connection.open()
+ server.connection.open()
+ self._pump( client, server )
+
+ # now SSL should be active
+ assert server.ssl.cipher_name() is not None
+ assert client.ssl.protocol_name() is not None
+
+ client.connection.close()
+ server.connection.close()
+ self._pump( client, server )
+
+ def test_ssl_with_small_buffer(self):
+ self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
+ self._testpath("server-private-key.pem"),
+ "server-password")
+ self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER )
+
+ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
+ client = SslTest.SslTestConnection( self.client_domain )
+
+ client.connection.open()
+ server.connection.open()
+
+ small_buffer_size = 1
+ self._pump( client, server, small_buffer_size )
+
+ assert client.ssl.protocol_name() is not None
+ client.connection.close()
+ server.connection.close()
+ self._pump( client, server )
+
+
+ def test_server_certificate(self):
+ """ Test that anonymous clients can still connect to a server that has
+ a certificate configured.
+ """
+ self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
+ self._testpath("server-private-key.pem"),
+ "server-password")
+ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
+ client = SslTest.SslTestConnection( self.client_domain )
+
+ client.connection.open()
+ server.connection.open()
+ self._pump( client, server )
+ assert client.ssl.protocol_name() is not None
+ client.connection.close()
+ server.connection.close()
+ self._pump( client, server )
+
+ def test_server_authentication(self):
+ """ Simple SSL connection with authentication of the server
+ """
+ self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
+ self._testpath("server-private-key.pem"),
+ "server-password")
+
+ self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER )
+
+ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
+ client = SslTest.SslTestConnection( self.client_domain )
+
+ client.connection.open()
+ server.connection.open()
+ self._pump( client, server )
+ assert client.ssl.protocol_name() is not None
+ client.connection.close()
+ server.connection.close()
+ self._pump( client, server )
+
+ def test_certificate_fingerprint_and_subfields(self):
+ if os.name=="nt":
+ raise Skipped("Windows support for certificate fingerprint and subfield not implemented yet")
+
+ self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
+ self._testpath("server-private-key.pem"),
+ "server-password")
+ self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER,
+ self._testpath("ca-certificate.pem") )
+ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
+
+ # give the client a certificate, but let's not require server authentication
+ self.client_domain.set_credentials(self._testpath("client-certificate1.pem"),
+ self._testpath("client-private-key1.pem"),
+ "client-password")
+ self.client_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER )
+ client = SslTest.SslTestConnection( self.client_domain )
+
+ client.connection.open()
+ server.connection.open()
+ self._pump( client, server )
+
+ # Test the subject subfields
+ self.assertEqual("Client", server.ssl.get_cert_organization())
+ self.assertEqual("Dev", server.ssl.get_cert_organization_unit())
+ self.assertEqual("ST", server.ssl.get_cert_state_or_province())
+ self.assertEqual("US", server.ssl.get_cert_country())
+ self.assertEqual("City", server.ssl.get_cert_locality_or_city())
+ self.assertEqual("O=Server,CN=A1.Good.Server.domain.com", client.ssl.get_cert_subject())
+ self.assertEqual("O=Client,CN=127.0.0.1,C=US,ST=ST,L=City,OU=Dev", server.ssl.get_cert_subject())
+
+ self.assertEqual("f78f03ec31317c213dcf607c095242adbf067824", server.ssl.get_cert_fingerprint_sha1())
+ self.assertEqual("3836fd0d7bbc155158997ff336de29545cc1ce4137f8419062ceb8b50fd7a6f9", server.ssl.get_cert_fingerprint_sha256())
+ self.assertEqual("a8390634eb10c7a12ba3ce0837001bc6ae78c7690984f4788cf4430acdb496d5d9e02c8ec39219f5c4dcd908c34861d09481c2faf53b4ccc95dac60e623165c4",
+ server.ssl.get_cert_fingerprint_sha512())
+ self.assertEqual("32b7bc119f61c71d368caaf9a6bf58b2", server.ssl.get_cert_fingerprint_md5())
+
+ # Test the various fingerprint algorithms
+ self.assertEqual("0aab5922c8657a7fb78402b79379506d3d7806ce", client.ssl.get_cert_fingerprint_sha1())
+ self.assertEqual("de5e0c4097f841815a769ce1a30dbe912b83711438a5aaf50001da23cee5a8a8", client.ssl.get_cert_fingerprint_sha256())
+ self.assertEqual("d0aceeb68ab9de57c9e1c21a43a4511c54ec94011e770a523a6352b1374f59c8b58adc93d5cad6f25aa125b5934309a61a25e74a5d5e0cb40b07c7468615944c",
+ client.ssl.get_cert_fingerprint_sha512())
+ self.assertEqual("ae0ebcebc1f970fb696ef9f56e3235da", client.ssl.get_cert_fingerprint_md5())
+
+ self.assertEqual(None, client.ssl.get_cert_fingerprint(21, SSL.SHA1)) # Should be at least 41
+ self.assertEqual(None, client.ssl.get_cert_fingerprint(50, SSL.SHA256)) # Should be at least 65
+ self.assertEqual(None, client.ssl.get_cert_fingerprint(128, SSL.SHA512)) # Should be at least 129
+ self.assertEqual(None, client.ssl.get_cert_fingerprint(10, SSL.MD5)) # Should be at least 33
+ self.assertEqual(None, client.ssl._get_cert_subject_unknown_subfield())
+
+ self.assertNotEqual(None, client.ssl.get_cert_fingerprint(50, SSL.SHA1)) # Should be at least 41
+ self.assertNotEqual(None, client.ssl.get_cert_fingerprint(70, SSL.SHA256)) # Should be at least 65
+ self.assertNotEqual(None, client.ssl.get_cert_fingerprint(130, SSL.SHA512)) # Should be at least 129
+ self.assertNotEqual(None, client.ssl.get_cert_fingerprint(35, SSL.MD5)) # Should be at least 33
+ self.assertEqual(None, client.ssl._get_cert_fingerprint_unknown_hash_alg())
+
+ def test_client_authentication(self):
+ """ Force the client to authenticate.
+ """
+ # note: when requesting client auth, the server _must_ send its
+ # certificate, so make sure we configure one!
+ self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
+ self._testpath("server-private-key.pem"),
+ "server-password")
+ self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER,
+ self._testpath("ca-certificate.pem") )
+ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
+
+ # give the client a certificate, but let's not require server authentication
+ self.client_domain.set_credentials(self._testpath("client-certificate.pem"),
+ self._testpath("client-private-key.pem"),
+ "client-password")
+ self.client_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER )
+ client = SslTest.SslTestConnection( self.client_domain )
+
+ client.connection.open()
+ server.connection.open()
+ self._pump( client, server )
+
+ assert client.ssl.protocol_name() is not None
+ client.connection.close()
+ server.connection.close()
+ self._pump( client, server )
+
+ def test_client_authentication_fail_bad_cert(self):
+ """ Ensure that the server can detect a bad client certificate.
+ """
+ # note: when requesting client auth, the server _must_ send its
+ # certificate, so make sure we configure one!
+ self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
+ self._testpath("server-private-key.pem"),
+ "server-password")
+ self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER,
+ self._testpath("ca-certificate.pem") )
+ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
+
+ self.client_domain.set_credentials(self._testpath("bad-server-certificate.pem"),
+ self._testpath("bad-server-private-key.pem"),
+ "server-password")
+ self.client_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER )
+ client = SslTest.SslTestConnection( self.client_domain )
+
+ client.connection.open()
+ server.connection.open()
+ self._pump( client, server )
+ assert client.transport.closed
+ assert server.transport.closed
+ assert client.connection.state & Endpoint.REMOTE_UNINIT
+ assert server.connection.state & Endpoint.REMOTE_UNINIT
+
+ def test_client_authentication_fail_no_cert(self):
+ """ Ensure that the server will fail a client that does not provide a
+ certificate.
+ """
+ # note: when requesting client auth, the server _must_ send its
+ # certificate, so make sure we configure one!
+ self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
+ self._testpath("server-private-key.pem"),
+ "server-password")
+ self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER,
+ self._testpath("ca-certificate.pem") )
+ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
+
+ self.client_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER )
+ client = SslTest.SslTestConnection( self.client_domain )
+
+ client.connection.open()
+ server.connection.open()
+ self._pump( client, server )
+ assert client.transport.closed
+ assert server.transport.closed
+ assert client.connection.state & Endpoint.REMOTE_UNINIT
+ assert server.connection.state & Endpoint.REMOTE_UNINIT
+
+ def test_client_server_authentication(self):
+ """ Require both client and server to mutually identify themselves.
+ """
+ self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
+ self._testpath("server-private-key.pem"),
+ "server-password")
+ self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER,
+ self._testpath("ca-certificate.pem") )
+
+ self.client_domain.set_credentials(self._testpath("client-certificate.pem"),
+ self._testpath("client-private-key.pem"),
+ "client-password")
+ self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER )
+
+ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
+ client = SslTest.SslTestConnection( self.client_domain )
+
+ client.connection.open()
+ server.connection.open()
+ self._pump( client, server )
+ assert client.ssl.protocol_name() is not None
+ client.connection.close()
+ server.connection.close()
+ self._pump( client, server )
+
+ def test_server_only_authentication(self):
+ """ Client verifies server, but server does not verify client.
+ """
+ self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
+ self._testpath("server-private-key.pem"),
+ "server-password")
+ self.server_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER )
+
+ self.client_domain.set_credentials(self._testpath("client-certificate.pem"),
+ self._testpath("client-private-key.pem"),
+ "client-password")
+ self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER )
+
+ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
+ client = SslTest.SslTestConnection( self.client_domain )
+
+ client.connection.open()
+ server.connection.open()
+ self._pump( client, server )
+ assert client.ssl.protocol_name() is not None
+ client.connection.close()
+ server.connection.close()
+ self._pump( client, server )
+
+ def test_bad_server_certificate(self):
+ """ A server with a self-signed certificate that is not trusted by the
+ client. The client should reject the server.
+ """
+ self.server_domain.set_credentials(self._testpath("bad-server-certificate.pem"),
+ self._testpath("bad-server-private-key.pem"),
+ "server-password")
+ self.server_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER )
+
+ self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER )
+
+ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
+ client = SslTest.SslTestConnection( self.client_domain )
+
+ client.connection.open()
+ server.connection.open()
+ self._pump( client, server )
+ assert client.transport.closed
+ assert server.transport.closed
+ assert client.connection.state & Endpoint.REMOTE_UNINIT
+ assert server.connection.state & Endpoint.REMOTE_UNINIT
+
+ del server
+ del client
+
+ # now re-try with a client that does not require peer verification
+ self.client_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER )
+
+ client = SslTest.SslTestConnection( self.client_domain )
+ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
+
+ client.connection.open()
+ server.connection.open()
+ self._pump( client, server )
+ assert client.ssl.protocol_name() is not None
+ client.connection.close()
+ server.connection.close()
+ self._pump( client, server )
+
+ def test_allow_unsecured_client_which_connects_unsecured(self):
+ """ Server allows an unsecured client to connect if configured.
+ """
+ self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
+ self._testpath("server-private-key.pem"),
+ "server-password")
+ self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER,
+ self._testpath("ca-certificate.pem") )
+ # allow unsecured clients on this connection
+ self.server_domain.allow_unsecured_client()
+ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
+
+ # non-ssl connection
+ client = SslTest.SslTestConnection()
+
+ client.connection.open()
+ server.connection.open()
+ self._pump( client, server )
+ assert server.ssl.protocol_name() is None
+ client.connection.close()
+ server.connection.close()
+ self._pump( client, server )
+
+ def test_allow_unsecured_client_which_connects_secured(self):
+ """ As per test_allow_unsecured_client_which_connects_unsecured
+ but client actually uses SSL
+ """
+ self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
+ self._testpath("server-private-key.pem"),
+ "server-password")
+ self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER,
+ self._testpath("ca-certificate.pem") )
+
+ self.client_domain.set_credentials(self._testpath("client-certificate.pem"),
+ self._testpath("client-private-key.pem"),
+ "client-password")
+ self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER )
+
+ # allow unsecured clients on this connection
+ #self.server_domain.allow_unsecured_client()
+
+ # client uses ssl. Server should detect this.
+ client = SslTest.SslTestConnection( self.client_domain )
+ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
+
+ client.connection.open()
+ server.connection.open()
+ self._pump( client, server )
+ assert server.ssl.protocol_name() is not None
+ client.connection.close()
+ server.connection.close()
+ self._pump( client, server )
+
+
+ def test_disallow_unsecured_client(self):
+ """ Non-SSL Client is disallowed from connecting to server.
+ """
+ self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
+ self._testpath("server-private-key.pem"),
+ "server-password")
+ self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.server_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER )
+ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
+
+ # non-ssl connection
+ client = SslTest.SslTestConnection()
+
+ client.connection.open()
+ server.connection.open()
+ self._pump( client, server )
+ assert client.transport.closed
+ assert server.transport.closed
+ assert client.connection.state & Endpoint.REMOTE_UNINIT
+ assert server.connection.state & Endpoint.REMOTE_UNINIT
+
+ def test_session_resume(self):
+ """ Test resume of client session.
+ """
+ if os.name=="nt":
+ raise Skipped("Windows SChannel session resume not yet implemented.")
+
+ self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
+ self._testpath("server-private-key.pem"),
+ "server-password")
+ self.server_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER )
+
+ self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER )
+
+ # details will be used in initial and subsequent connections to allow session to be resumed
+ initial_session_details = SSLSessionDetails("my-session-id")
+
+ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
+ client = SslTest.SslTestConnection( self.client_domain, session_details=initial_session_details )
+
+ # bring up the connection and store its state
+ client.connection.open()
+ server.connection.open()
+ self._pump( client, server )
+ assert client.ssl.protocol_name() is not None
+
+ # cleanly shutdown the connection
+ client.connection.close()
+ server.connection.close()
+ self._pump( client, server )
+
+ # destroy the existing clients
+ del client
+ del server
+
+ # now create a new set of connections, use last session id
+ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
+ # provide the details of the last session, allowing it to be resumed
+ client = SslTest.SslTestConnection( self.client_domain, session_details=initial_session_details )
+
+ #client.transport.trace(Transport.TRACE_DRV)
+ #server.transport.trace(Transport.TRACE_DRV)
+
+ client.connection.open()
+ server.connection.open()
+ self._pump( client, server )
+ assert server.ssl.protocol_name() is not None
+ if(API_LANGUAGE=="C"):
+ assert client.ssl.resume_status() == SSL.RESUME_REUSED
+ else:
+ # Java gives no way to check whether a previous session has been resumed
+ pass
+
+ client.connection.close()
+ server.connection.close()
+ self._pump( client, server )
+
+ # now try to resume using an unknown session-id, expect resume to fail
+ # and a new session is negotiated
+
+ del client
+ del server
+
+ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
+ client = SslTest.SslTestConnection( self.client_domain, session_details=SSLSessionDetails("some-other-session-id") )
+
+ client.connection.open()
+ server.connection.open()
+ self._pump( client, server )
+ assert server.ssl.protocol_name() is not None
+ if(API_LANGUAGE=="C"):
+ assert client.ssl.resume_status() == SSL.RESUME_NEW
+
+ client.connection.close()
+ server.connection.close()
+ self._pump( client, server )
+
+ def test_multiple_sessions(self):
+ """ Test multiple simultaneous active SSL sessions with bi-directional
+ certificate verification, shared across two domains.
+ """
+ self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
+ self._testpath("server-private-key.pem"),
+ "server-password")
+ self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER,
+ self._testpath("ca-certificate.pem") )
+
+ self.client_domain.set_credentials(self._testpath("client-certificate.pem"),
+ self._testpath("client-private-key.pem"),
+ "client-password")
+ self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER )
+
+ max_count = 100
+ sessions = [(SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ),
+ SslTest.SslTestConnection( self.client_domain )) for x in
+ range(max_count)]
+ for s in sessions:
+ s[0].connection.open()
+ self._pump( s[0], s[1] )
+
+ for s in sessions:
+ s[1].connection.open()
+ self._pump( s[1], s[0] )
+ assert s[0].ssl.cipher_name() is not None
+ assert s[1].ssl.cipher_name() == s[0].ssl.cipher_name()
+
+ for s in sessions:
+ s[1].connection.close()
+ self._pump( s[0], s[1] )
+
+ for s in sessions:
+ s[0].connection.close()
+ self._pump( s[1], s[0] )
+
+ def test_server_hostname_authentication(self):
+ """ Test authentication of the names held in the server's certificate
+ against various configured hostnames.
+ """
+ if os.name=="nt":
+ raise Skipped("PROTON-1057: disable temporarily on Windows.")
+
+ # Check the CommonName matches (case insensitive).
+ # Assumes certificate contains "CN=A1.Good.Server.domain.com"
+ self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
+ self._testpath("server-private-key.pem"),
+ "server-password")
+ self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME )
+
+ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
+ client = SslTest.SslTestConnection( self.client_domain )
+
+ client.ssl.peer_hostname = "a1.good.server.domain.com"
+ assert client.ssl.peer_hostname == "a1.good.server.domain.com"
+ self._do_handshake( client, server )
+ del server
+ del client
+ self.tearDown()
+
+ # Should fail on CN name mismatch:
+ self.setUp()
+ self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
+ self._testpath("server-private-key.pem"),
+ "server-password")
+ self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME )
+
+ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
+ client = SslTest.SslTestConnection( self.client_domain )
+
+ client.ssl.peer_hostname = "A1.Good.Server.domain.comX"
+ self._do_handshake( client, server )
+ assert client.transport.closed
+ assert server.transport.closed
+ assert client.connection.state & Endpoint.REMOTE_UNINIT
+ assert server.connection.state & Endpoint.REMOTE_UNINIT
+ del server
+ del client
+ self.tearDown()
+
+ # Wildcarded Certificate
+ # Assumes:
+ # 1) certificate contains Server Alternate Names:
+ # "alternate.name.one.com" and "another.name.com"
+ # 2) certificate has wildcarded CommonName "*.prefix*.domain.com"
+ #
+
+ # Pass: match an alternate
+ self.setUp()
+ self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"),
+ self._testpath("server-wc-private-key.pem"),
+ "server-password")
+ self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME )
+
+ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
+ client = SslTest.SslTestConnection( self.client_domain )
+
+ client.ssl.peer_hostname = "alternate.Name.one.com"
+ self._do_handshake( client, server )
+ del client
+ del server
+ self.tearDown()
+
+ # Pass: match an alternate
+ self.setUp()
+ self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"),
+ self._testpath("server-wc-private-key.pem"),
+ "server-password")
+ self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME )
+
+ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
+ client = SslTest.SslTestConnection( self.client_domain )
+
+ client.ssl.peer_hostname = "ANOTHER.NAME.COM"
+ self._do_handshake(client, server)
+ del client
+ del server
+ self.tearDown()
+
+ # Pass: match the pattern
+ self.setUp()
+ self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"),
+ self._testpath("server-wc-private-key.pem"),
+ "server-password")
+ self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME )
+
+ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
+ client = SslTest.SslTestConnection( self.client_domain )
+
+ client.ssl.peer_hostname = "SOME.PREfix.domain.COM"
+ self._do_handshake( client, server )
+ del client
+ del server
+ self.tearDown()
+
+ # Pass: match the pattern
+ self.setUp()
+ self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"),
+ self._testpath("server-wc-private-key.pem"),
+ "server-password")
+ self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME )
+
+ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
+ client = SslTest.SslTestConnection( self.client_domain )
+
+ client.ssl.peer_hostname = "FOO.PREfixZZZ.domain.com"
+ self._do_handshake( client, server )
+ del client
+ del server
+ self.tearDown()
+
+ # Fail: must match prefix on wildcard
+ self.setUp()
+ self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"),
+ self._testpath("server-wc-private-key.pem"),
+ "server-password")
+ self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME )
+
+ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
+ client = SslTest.SslTestConnection( self.client_domain )
+
+ client.ssl.peer_hostname = "FOO.PREfi.domain.com"
+ self._do_handshake( client, server )
+ assert client.transport.closed
+ assert server.transport.closed
+ assert client.connection.state & Endpoint.REMOTE_UNINIT
+ assert server.connection.state & Endpoint.REMOTE_UNINIT
+ del server
+ del client
+ self.tearDown()
+
+ # Fail: leading wildcards are not optional
+ self.setUp()
+ self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"),
+ self._testpath("server-wc-private-key.pem"),
+ "server-password")
+ self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME )
+
+ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
+ client = SslTest.SslTestConnection( self.client_domain )
+
+ client.ssl.peer_hostname = "PREfix.domain.COM"
+ self._do_handshake( client, server )
+ assert client.transport.closed
+ assert server.transport.closed
+ assert client.connection.state & Endpoint.REMOTE_UNINIT
+ assert server.connection.state & Endpoint.REMOTE_UNINIT
+ self.tearDown()
+
+ # Pass: ensure that the user can give an alternate name that overrides
+ # the connection's configured hostname
+ self.setUp()
+ self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"),
+ self._testpath("server-wc-private-key.pem"),
+ "server-password")
+ self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME )
+
+ server = SslTest.SslTestConnection(self.server_domain, mode=Transport.SERVER)
+ client = SslTest.SslTestConnection(self.client_domain,
+ conn_hostname="This.Name.Does.not.Match",
+ ssl_peername="alternate.name.one.com")
+ self._do_handshake(client, server)
+ del client
+ del server
+ self.tearDown()
+
+ # Pass: ensure that the hostname supplied by the connection is used if
+ # none has been specified for the SSL instance
+ self.setUp()
+ self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
+ self._testpath("server-private-key.pem"),
+ "server-password")
+ self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME )
+
+ server = SslTest.SslTestConnection(self.server_domain, mode=Transport.SERVER)
+ client = SslTest.SslTestConnection(self.client_domain,
+ conn_hostname="a1.good.server.domain.com")
+ self._do_handshake(client, server)
+ del client
+ del server
+ self.tearDown()
+
+ def test_server_hostname_authentication_2(self):
+ """Initially separated from test_server_hostname_authentication
+ above to force Windows checking and sidestep PROTON-1057 exclusion.
+ """
+
+ # Fail for a null peer name.
+ self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"),
+ self._testpath("server-wc-private-key.pem"),
+ "server-password")
+ self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME )
+
+ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
+ client = SslTest.SslTestConnection( self.client_domain )
+
+ # Next line results in an eventual pn_ssl_set_peer_hostname(client.ssl._ssl, None)
+ client.ssl.peer_hostname = None
+ self._do_handshake( client, server )
+ assert client.transport.closed
+ assert server.transport.closed
+ assert client.connection.state & Endpoint.REMOTE_UNINIT
+ assert server.connection.state & Endpoint.REMOTE_UNINIT
+ self.tearDown()
+
+ def test_defaults_messenger_app(self):
+ """ Test an SSL connection using the Messenger apps (no certificates)
+ """
+ if os.name=="nt":
+ raise Skipped("Windows SChannel lacks anonymous cipher support.")
+ port = common.free_tcp_ports()[0]
+
+ receiver = common.MessengerReceiverC()
+ receiver.subscriptions = ["amqps://~0.0.0.0:%s" % port]
+ receiver.receive_count = 1
+ receiver.timeout = self.timeout
+ receiver.start()
+
+ sender = common.MessengerSenderC()
+ sender.targets = ["amqps://0.0.0.0:%s/X" % port]
+ sender.send_count = 1
+ sender.timeout = self.timeout
+ sender.start()
+ sender.wait()
+ assert sender.status() == 0, "Command '%s' failed" % str(sender.cmdline())
+
+ receiver.wait()
+ assert receiver.status() == 0, "Command '%s' failed" % str(receiver.cmdline())
+
+ def test_server_authentication_messenger_app(self):
+ """ Test an SSL authentication using the Messenger apps.
+ """
+ port = common.free_tcp_ports()[0]
+
+ receiver = common.MessengerReceiverC()
+ receiver.subscriptions = ["amqps://~0.0.0.0:%s" % port]
+ receiver.receive_count = 1
+ receiver.timeout = self.timeout
+ # Note hack - by default we use the client-certificate for the
+ # _server_ because the client-certificate's common name field
+ # is "127.0.0.1", which will match the target address used by
+ # the sender.
+ receiver.certificate = self._testpath("client-certificate.pem")
+ receiver.privatekey = self._testpath("client-private-key.pem")
+ receiver.password = "client-password"
+ receiver.start()
+
+ sender = common.MessengerSenderC()
+ sender.targets = ["amqps://127.0.0.1:%s/X" % port]
+ sender.send_count = 1
+ sender.timeout = self.timeout
+ sender.ca_db = self._testpath("ca-certificate.pem")
+ sender.start()
+ sender.wait()
+ assert sender.status() == 0, "Command '%s' failed" % str(sender.cmdline())
+
+ receiver.wait()
+ assert receiver.status() == 0, "Command '%s' failed" % str(receiver.cmdline())
+
+ def DISABLED_test_defaults_valgrind(self):
+ """ Run valgrind over a simple SSL connection (no certificates)
+ """
+ # the openssl libraries produce far too many valgrind errors to be
+ # useful. AFAIK, there is no way to wriate a valgrind suppression
+ # expression that will ignore all errors from a given library.
+ # Until we can, skip this test.
+ port = common.free_tcp_ports()[0]
+
+ receiver = common.MessengerReceiverValgrind()
+ receiver.subscriptions = ["amqps://~127.0.0.1:%s" % port]
+ receiver.receive_count = 1
+ receiver.timeout = self.timeout
+ receiver.start()
+
+ sender = common.MessengerSenderValgrind()
+ sender.targets = ["amqps://127.0.0.1:%s/X" % port]
+ sender.send_count = 1
+ sender.timeout = self.timeout
+ sender.start()
+ sender.wait()
+ assert sender.status() == 0, "Command '%s' failed" % str(sender.cmdline())
+
+ receiver.wait()
+ assert receiver.status() == 0, "Command '%s' failed" % str(receiver.cmdline())
+
+ # self.server_domain.set_credentials(self._testpath("client-certificate.pem"),
+ # self._testpath("client-private-key.pem"),
+ # "client-password")
+
+ # self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ # self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER )
+
+ def test_singleton(self):
+ """Verify that only a single instance of SSL can exist per Transport"""
+ transport = Transport()
+ ssl1 = SSL(transport, self.client_domain)
+ ssl2 = transport.ssl(self.client_domain)
+ ssl3 = transport.ssl(self.client_domain)
+ assert ssl1 is ssl2
+ assert ssl1 is ssl3
+ transport = Transport()
+ ssl1 = transport.ssl(self.client_domain)
+ ssl2 = SSL(transport, self.client_domain)
+ assert ssl1 is ssl2
+ # catch attempt to re-configure existing SSL
+ try:
+ ssl3 = SSL(transport, self.server_domain)
+ assert False, "Expected error did not occur!"
+ except SSLException:
+ pass
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/README.txt
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/README.txt b/python/tests/proton_tests/ssl_db/README.txt
new file mode 100644
index 0000000..20c92b2
--- /dev/null
+++ b/python/tests/proton_tests/ssl_db/README.txt
@@ -0,0 +1,79 @@
+The following certificate files are used by the SSL unit tests (ssl.py):
+
+ca-certificate.pem - contains the public certificate identifying a "trusted" Certificate
+Authority. This certificate is used to sign the certificates that identify the SSL
+servers and clients run by the tests.
+
+client-certificate.pem - the public certificate used to identify the client. Signed by
+the CA.
+
+client-private-key.pem - encrypted key used to create client-certificate.pem. Password is
+"client-password"
+
+server-certificate.pem - the public certificate used to identify the server. Signed by
+the CA. The CommonName is "A1.Good.Server.domain.com", and is checked by some unit tests.
+
+server-private-key.pem - encrypted key used to create server-certificate.pem. Password is
+"server-password"
+
+bad-server-certificate.pem, bad-server-private-key.pem - a certificate/key that is not trusted by the client, for negative test.
+
+server-wc-certificate.pem and server-wc-private-key.pem - similar to
+server-certificate.pem and server-private-key.pem, but contains Subject Alternate Name
+entries, and a wildcard CommonName. Used for certificate name checking tests.
+
+These certificates have been created using the OpenSSL tool.
+
+The following bash script can be used to create these certificates (requires keytool from Java 1.7, and openssl):
+
+--8<--
+#!/bin/bash
+#set -x
+
+rm -f *.pem *.pkcs12
+
+# Create a self-signed certificate for the CA, and a private key to sign certificate requests:
+keytool -storetype pkcs12 -keystore ca.pkcs12 -storepass ca-password -alias ca -keypass ca-password -genkey -dname "O=Trust Me Inc.,CN=Trusted.CA.com" -validity 99999 -ext bc:c=ca:true,pathlen:0 -ext ku:c=digitalSignature,keyCertSign -ext ExtendedkeyUsage=serverAuth,clientAuth
+openssl pkcs12 -nokeys -passin pass:ca-password -in ca.pkcs12 -passout pass:ca-password -out ca-certificate.pem
+
+# Create a certificate request for the server certificate. Use the CA's certificate to sign it:
+keytool -storetype pkcs12 -keystore server.pkcs12 -storepass server-password -alias server-certificate -keypass server-password -genkey -dname "O=Server,CN=A1.Good.Server.domain.com" -validity 99999
+keytool -storetype pkcs12 -keystore server.pkcs12 -storepass server-password -alias server-certificate -keypass server-password -certreq -file server-request.pem
+keytool -storetype pkcs12 -keystore ca.pkcs12 -storepass ca-password -alias ca -keypass ca-password -gencert -rfc -validity 99999 -infile server-request.pem -outfile server-certificate.pem
+openssl pkcs12 -nocerts -passin pass:server-password -in server.pkcs12 -passout pass:server-password -out server-private-key.pem
+
+# Create a certificate request for the client certificate. Use the CA's certificate to sign it:
+keytool -storetype pkcs12 -keystore client.pkcs12 -storepass client-password -alias client-certificate -keypass client-password -genkey -dname "O=Client,CN=127.0.0.1" -validity 99999
+keytool -storetype pkcs12 -keystore client.pkcs12 -storepass client-password -alias client-certificate -keypass client-password -certreq -file client-request.pem
+keytool -storetype pkcs12 -keystore ca.pkcs12 -storepass ca-password -alias ca -keypass ca-password -gencert -rfc -validity 99999 -infile client-request.pem -outfile client-certificate.pem
+openssl pkcs12 -nocerts -passin pass:client-password -in client.pkcs12 -passout pass:client-password -out client-private-key.pem
+
+# Create another client certificate with a different subject line
+keytool -storetype pkcs12 -keystore client1.pkcs12 -storepass client-password -alias client-certificate1 -keypass client-password -genkey -dname "O=Client,CN=127.0.0.1,C=US,ST=ST,L=City,OU=Dev" -validity 99999
+keytool -storetype pkcs12 -keystore client1.pkcs12 -storepass client-password -alias client-certificate1 -keypass client-password -certreq -file client-request1.pem
+keytool -storetype pkcs12 -keystore ca.pkcs12 -storepass ca-password -alias ca -keypass ca-password -gencert -rfc -validity 99999 -infile client-request1.pem -outfile client-certificate1.pem
+openssl pkcs12 -nocerts -passin pass:client-password -in client1.pkcs12 -passout pass:client-password -out client-private-key1.pem
+
+# Create a "bad" certificate - not signed by a trusted authority
+keytool -storetype pkcs12 -keystore bad-server.pkcs12 -storepass server-password -alias bad-server -keypass server-password -genkey -dname "O=Not Trusted Inc,CN=127.0.0.1" -validity 99999
+openssl pkcs12 -nocerts -passin pass:server-password -in bad-server.pkcs12 -passout pass:server-password -out bad-server-private-key.pem
+openssl pkcs12 -nokeys -passin pass:server-password -in bad-server.pkcs12 -passout pass:server-password -out bad-server-certificate.pem
+
+# Create a server certificate with several alternate names, including a wildcarded common name:
+keytool -ext san=dns:alternate.name.one.com,dns:another.name.com -storetype pkcs12 -keystore server-wc.pkcs12 -storepass server-password -alias server-wc-certificate -keypass server-password -genkeypair -dname "O=Server,CN=*.prefix*.domain.com" -validity 99999
+keytool -ext san=dns:alternate.name.one.com,dns:another.name.com -storetype pkcs12 -keystore server-wc.pkcs12 -storepass server-password -alias server-wc-certificate -keypass server-password -certreq -file server-wc-request.pem
+keytool -ext san=dns:alternate.name.one.com,dns:another.name.com -storetype pkcs12 -keystore ca.pkcs12 -storepass ca-password -alias ca -keypass ca-password -gencert -rfc -validity 99999 -infile server-wc-request.pem -outfile server-wc-certificate.pem
+openssl pkcs12 -nocerts -passin pass:server-password -in server-wc.pkcs12 -passout pass:server-password -out server-wc-private-key.pem
+
+# Create pkcs12 versions of the above certificates (for Windows SChannel)
+# The CA certificate store/DB is created without public keys.
+# Give the "p12" files the same base name so the tests can just change the extension to switch between platforms.
+# These certificates might work for OpenSSL <-> SChannel interop tests, but note that the DH cypher suite
+# overlap is poor between platforms especially for older Windows versions. RSA certificates are better for
+# interop (or PFS-friendly certificates on newer platforms).
+openssl pkcs12 -export -out ca-certificate.p12 -in ca-certificate.pem -name ca-certificate -nokeys -passout pass:
+openssl pkcs12 -export -out server-certificate.p12 -passin pass:server-password -passout pass:server-password -inkey server-private-key.pem -in server-certificate.pem -name server-certificate
+openssl pkcs12 -export -out client-certificate.p12 -passin pass:client-password -passout pass:client-password -inkey client-private-key.pem -in client-certificate.pem -name client-certificate
+openssl pkcs12 -export -out client-certificate1.p12 -passin pass:client-password -passout pass:client-password -inkey client-private-key1.pem -in client-certificate1.pem -name client-certificate1
+openssl pkcs12 -export -out bad-server-certificate.p12 -passin pass:server-password -passout pass:server-password -inkey bad-server-private-key.pem -in bad-server-certificate.pem -name bad-server
+openssl pkcs12 -export -out server-wc-certificate.p12 -passin pass:server-password -passout pass:server-password -inkey server-wc-private-key.pem -in server-wc-certificate.pem -name server-wc-certificate
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/bad-server-certificate.p12
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/bad-server-certificate.p12 b/python/tests/proton_tests/ssl_db/bad-server-certificate.p12
new file mode 100644
index 0000000..7906831
Binary files /dev/null and b/python/tests/proton_tests/ssl_db/bad-server-certificate.p12 differ
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/bad-server-certificate.pem
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/bad-server-certificate.pem b/python/tests/proton_tests/ssl_db/bad-server-certificate.pem
new file mode 100644
index 0000000..1dc288b
--- /dev/null
+++ b/python/tests/proton_tests/ssl_db/bad-server-certificate.pem
@@ -0,0 +1,22 @@
+Bag Attributes
+ friendlyName: bad-server
+ localKeyID: 54 69 6D 65 20 31 35 30 31 37 31 30 38 31 38 32 39 36
+subject=/CN=127.0.0.1/O=Not Trusted Inc
+issuer=/CN=127.0.0.1/O=Not Trusted Inc
+-----BEGIN CERTIFICATE-----
+MIICuzCCAnmgAwIBAgIELMpW4jALBgcqhkjOOAQDBQAwLjESMBAGA1UEAxMJMTI3
+LjAuMC4xMRgwFgYDVQQKEw9Ob3QgVHJ1c3RlZCBJbmMwIBcNMTcwODAyMjE1MzM4
+WhgPMjI5MTA1MTcyMTUzMzhaMC4xEjAQBgNVBAMTCTEyNy4wLjAuMTEYMBYGA1UE
+ChMPTm90IFRydXN0ZWQgSW5jMIIBuDCCASwGByqGSM44BAEwggEfAoGBAP1/U4Ed
+dRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs
+14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208Ue
+wwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BY
+HPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+Zx
+BxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx
++2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYUAAoGBAK3E
+5j/UaiVHJYAf3DAIl5hjTZcChTp57GjODdfDteHeDh85HFyW0kxmXyhpUdODzAgG
+THhpxy/+Kkd8jmUBVFnU1EXByvGORBfnJkMTkuhmk9veytxlskQ0tQV8gmRNb0Xe
+hie7T9UT8TQJy9mPS74pSuviFSx0Hz0dKGi0eVUYoyEwHzAdBgNVHQ4EFgQUg2PE
+qycdV1oxVaA33ULDrVdSjhkwCwYHKoZIzjgEAwUAAy8AMCwCFGybqSwG3TauRJVw
+XA/xeSxpYbcBAhQ6ylf9XZAvM7tMyQQTcDAkmt+YWQ==
+-----END CERTIFICATE-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/bad-server-private-key.pem
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/bad-server-private-key.pem b/python/tests/proton_tests/ssl_db/bad-server-private-key.pem
new file mode 100644
index 0000000..331ade0
--- /dev/null
+++ b/python/tests/proton_tests/ssl_db/bad-server-private-key.pem
@@ -0,0 +1,15 @@
+Bag Attributes
+ friendlyName: bad-server
+ localKeyID: 54 69 6D 65 20 31 35 30 31 37 31 30 38 31 38 32 39 36
+Key Attributes: <No Attributes>
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIBljBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIqgLLe7iT+1wCAggA
+MBQGCCqGSIb3DQMHBAhg98ZJQMtngwSCAVCdhdOMr+VVTNaIPSy4nSwdRTlXIuRa
+4wPi+07mToJmEtGfpJ4MPjDF9yRptVQI4RoN/RrLl0WX/HNZ5U4JluL0j68+JB1d
+MoeSRiRc+Yd2vxey8reBrvx1m1mB3LXvm38oZVDFrQ9FNGK09EtTLN1rqckr1fxQ
+Imcvb63nu5UZB8WMCVfKqe9Zm9dQlsSlp3M5OCRm296Xsr0eWwe2W1/rJiKMZN7x
+eJMf4pWVrBHoi6VJHAEA7ZvhRfcHkSbyze5ouDpKbMZS9gq38Hs4d+wkxe9x3emx
+6OvppcpBolZhntF1vJXUXMc6D5Pw3mGEsRGwcMJqWCc8XJTkyP0ylNFNyaHaz0oC
+jSWmUu0s5628K+m8nGY4X7msfOddTA16W6mODjE2ddlTqwTFu2CYBk3WbprBRXo0
+ionZQTPTqcM0UR3KyF9CHRZbnQ/d7bk57/w=
+-----END ENCRYPTED PRIVATE KEY-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/bad-server.pkcs12
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/bad-server.pkcs12 b/python/tests/proton_tests/ssl_db/bad-server.pkcs12
new file mode 100644
index 0000000..dea2143
Binary files /dev/null and b/python/tests/proton_tests/ssl_db/bad-server.pkcs12 differ
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/ca-certificate.p12
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/ca-certificate.p12 b/python/tests/proton_tests/ssl_db/ca-certificate.p12
new file mode 100644
index 0000000..767b24d
Binary files /dev/null and b/python/tests/proton_tests/ssl_db/ca-certificate.p12 differ
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/ca-certificate.pem
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/ca-certificate.pem b/python/tests/proton_tests/ssl_db/ca-certificate.pem
new file mode 100644
index 0000000..6d27395
--- /dev/null
+++ b/python/tests/proton_tests/ssl_db/ca-certificate.pem
@@ -0,0 +1,24 @@
+Bag Attributes
+ friendlyName: ca
+ localKeyID: 54 69 6D 65 20 31 35 30 31 37 31 30 38 31 36 34 37 32
+subject=/CN=Trusted.CA.com/O=Trust Me Inc.
+issuer=/CN=Trusted.CA.com/O=Trust Me Inc.
+-----BEGIN CERTIFICATE-----
+MIIDBDCCAsKgAwIBAgIEBGGY1zALBgcqhkjOOAQDBQAwMTEXMBUGA1UEAxMOVHJ1
+c3RlZC5DQS5jb20xFjAUBgNVBAoTDVRydXN0IE1lIEluYy4wIBcNMTcwODAyMjE1
+MzM2WhgPMjI5MTA1MTcyMTUzMzZaMDExFzAVBgNVBAMTDlRydXN0ZWQuQ0EuY29t
+MRYwFAYDVQQKEw1UcnVzdCBNZSBJbmMuMIIBuDCCASwGByqGSM44BAEwggEfAoGB
+AP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6
+MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E
++4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmC
+ouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeO
+utRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/
+C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYUA
+AoGBALsRT+tH1c+TC78EYtPh+KQ0DosKKtxeSRos4eQ49erdI+tYhzeqN3Ebmeky
+TWfGjjU64PGRFDNGjpf9l7Yo22jk9U5zIFkFp5gP9DVBHrOrh8mdT+/oBhhVHxI5
+rWLqSjI/zXhRzRwueR81p0D3XJlV3g/xlOlWALoRnUWpDAo3o2QwYjASBgNVHRMB
+Af8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAOBgNV
+HQ8BAf8EBAMCAoQwHQYDVR0OBBYEFLI2ezwilYHGS5MRPMWlifHH+Y5qMAsGByqG
+SM44BAMFAAMvADAsAhRxomjEvDfhe1p+D6KLc0IGjDNgtgIUIZXb0/Fpzy6dpCwe
+Ay+soxvpfMU=
+-----END CERTIFICATE-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/ca.pkcs12
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/ca.pkcs12 b/python/tests/proton_tests/ssl_db/ca.pkcs12
new file mode 100644
index 0000000..d9ca00c
Binary files /dev/null and b/python/tests/proton_tests/ssl_db/ca.pkcs12 differ
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/client-certificate.p12
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/client-certificate.p12 b/python/tests/proton_tests/ssl_db/client-certificate.p12
new file mode 100644
index 0000000..82271f9
Binary files /dev/null and b/python/tests/proton_tests/ssl_db/client-certificate.p12 differ
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/client-certificate.pem
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/client-certificate.pem b/python/tests/proton_tests/ssl_db/client-certificate.pem
new file mode 100644
index 0000000..4c0d4d4
--- /dev/null
+++ b/python/tests/proton_tests/ssl_db/client-certificate.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC1jCCApOgAwIBAgIEeg2f8DALBgcqhkjOOAQDBQAwMTEXMBUGA1UEAxMOVHJ1
+c3RlZC5DQS5jb20xFjAUBgNVBAoTDVRydXN0IE1lIEluYy4wIBcNMTcwODAyMjE1
+MzM3WhgPMjI5MTA1MTcyMTUzMzdaMCUxEjAQBgNVBAMTCTEyNy4wLjAuMTEPMA0G
+A1UEChMGQ2xpZW50MIIBtzCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9K
+nC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00
+b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNa
+FpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA
+9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJ
+FnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7
+zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQAAoGAJ3g1ohpHgoxH
+3Yj0SIfiPcUaM5FIszemFwQ2FZoG/J7MiVIw442JheTR/iEB3LYheHBp7ToqhaMY
+NYidcxxUzgZJs3worXqAuUgDdbDcW6AjQ4olyGVt7sX9OL2amMq9BFCIt7SlyDKW
+8Accx46H+8BffMdCu56yw5WQtZ3cPD2jQjBAMB8GA1UdIwQYMBaAFLI2ezwilYHG
+S5MRPMWlifHH+Y5qMB0GA1UdDgQWBBQg7FbClmtrSAHA9lR8E7uexl5p1jALBgcq
+hkjOOAQDBQADMAAwLQIVAIpUbUYyA3DisZyENQwcN0rDQ+FyAhRPcfg9Slb6MfO4
+SBFqOiesk+cpqw==
+-----END CERTIFICATE-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/client-certificate1.p12
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/client-certificate1.p12 b/python/tests/proton_tests/ssl_db/client-certificate1.p12
new file mode 100644
index 0000000..d35f88f
Binary files /dev/null and b/python/tests/proton_tests/ssl_db/client-certificate1.p12 differ
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/client-certificate1.pem
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/client-certificate1.pem b/python/tests/proton_tests/ssl_db/client-certificate1.pem
new file mode 100644
index 0000000..c63b4f1
--- /dev/null
+++ b/python/tests/proton_tests/ssl_db/client-certificate1.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDDDCCAsqgAwIBAgIEBmzTzzALBgcqhkjOOAQDBQAwMTEXMBUGA1UEAxMOVHJ1
+c3RlZC5DQS5jb20xFjAUBgNVBAoTDVRydXN0IE1lIEluYy4wIBcNMTcwODAyMjE1
+MzM4WhgPMjI5MTA1MTcyMTUzMzhaMFwxDDAKBgNVBAsTA0RldjENMAsGA1UEBxME
+Q2l0eTELMAkGA1UECBMCU1QxCzAJBgNVBAYTAlVTMRIwEAYDVQQDEwkxMjcuMC4w
+LjExDzANBgNVBAoTBkNsaWVudDCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQD9f1OB
+HXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEmaUVdQCJR+1k9jVj6v8X1ujD2y5tV
+bNeBO4AdNG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb+DtX58aophUPBPuD9tPF
+HsMCNVQTWhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdgUI8VIwvMspK5gqLrhAvw
+WBz1AoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlXTAs9B4JnUVlXjrrUWU/m
+cQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCjrh4rs6Z1kW6jfwv6ITVi
+8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQBTDv+z0kqA4GEAAKBgHVu
+urVq1FFws/JN+I3yfA2RVmFwlYJID8yyO9lkHBPBDE0dqfFBF6F3nwsCiZF0n/v4
+od6MuuRSplV4kZH0jOOVw7e9cF2RNd/KahsIpm/Oq5aosm6W7KDK/xIwNyW+3DFt
+TGDTOZ6ejVMgGR2rAD+FEp2yycJACQBP1GtTSFXTo0IwQDAfBgNVHSMEGDAWgBSy
+Nns8IpWBxkuTETzFpYnxx/mOajAdBgNVHQ4EFgQUz4cx+zNqsCmWpBU2dw8GHO33
++eEwCwYHKoZIzjgEAwUAAy8AMCwCFCsfHJPB4Tq6qX5U+DZBc3jmLBiXAhRF17Dz
+fq+AxqyQ9PvTtH3UbFh1hQ==
+-----END CERTIFICATE-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/client-private-key.pem
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/client-private-key.pem b/python/tests/proton_tests/ssl_db/client-private-key.pem
new file mode 100644
index 0000000..bca85eb
--- /dev/null
+++ b/python/tests/proton_tests/ssl_db/client-private-key.pem
@@ -0,0 +1,15 @@
+Bag Attributes
+ friendlyName: client-certificate
+ localKeyID: 54 69 6D 65 20 31 35 30 31 37 31 30 38 31 37 32 33 39
+Key Attributes: <No Attributes>
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIBljBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIHmVKa1dEtm4CAggA
+MBQGCCqGSIb3DQMHBAgpc0Ay33xL9ASCAVBJ8D5DVRd0d6t3gSvTFBAflpUROv2/
+pQlMLGbGlJIoEPyMIc9/GcgS7U19nMdoJjI1TuT/hGwObualnRRjY6KL5cbK2oUQ
+371yUs6jGIQxtCeb1WgKpA/FKw9jRO7Tg5ztObItPiSQvkOcssfdRJYI1+W+ovj+
+j1BKMkJu197twIChYaz+3ppJzrh3qlqFgdRdE9H04ffWpNaZ6aOIIJHPMuZ8FScu
+bQyvD9JjI+JWJUaCyp/3dxxxVrZ3vu8i6LmrL6Nm9IkJtFMZOfgPkoRLML2DWKqB
+1qLk/Z45/THXDAxrPggFfqMvuctwJmtAGvo3MIbfCi+aewJE6/DjlSHDv6wGvOGB
+T5golvZ5siahHqwmufSQG8ZTsGcpu/jCA5ipIvcTVgWIxscNc2Yx9FDNWVNzUcTy
+ctRX6DS+s7rAy9ISjch4BbAtI7yALFt63eU=
+-----END ENCRYPTED PRIVATE KEY-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/client-private-key1.pem
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/client-private-key1.pem b/python/tests/proton_tests/ssl_db/client-private-key1.pem
new file mode 100644
index 0000000..bedf540
--- /dev/null
+++ b/python/tests/proton_tests/ssl_db/client-private-key1.pem
@@ -0,0 +1,15 @@
+Bag Attributes
+ friendlyName: client-certificate1
+ localKeyID: 54 69 6D 65 20 31 35 30 31 37 31 30 38 31 37 37 37 32
+Key Attributes: <No Attributes>
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIBljBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIg1n9vdGttqoCAggA
+MBQGCCqGSIb3DQMHBAgRjlrRQfGcLQSCAVChui/M+36/e0WzeM79aJV7YZds/OJY
+gprtJ2g5Cxb1L9hymwgxJtOAaRUqLUcfLHcKSxA+MaB+Ij+/8TH+miq0zZ9q0jZV
+BAm56FNgUjW0nPLueTNhWzVVfQU6H9Tj33OuKm1PQo84Af3OPMtE03pvGDPEAPbH
+a72HUgZyI7WTux4wpxfvUEVkT5OXgBHrFlqXiHHCI+9kqBXMCV3oHgZBcO+dqPKS
+rlaTY7xoQWLenB6EQeYopMA2GNUVtzB3y6/nX2z0Yp5oHqKPBNOyFlVmwCrENN1/
+qnrFfzVbnksWLKhg9O+TPsId1UIZVvBh67y5N5IZRrpuE03qd2BScKM/Tn6vkWNB
+Eus74Vba5vw9prauRC45FVgDe2YYYoULYPfhXWSiiWHDNKOBlz3l3hGlZsC8wKe5
+QlV5bVcOTfGIaBkD7SQyfRjMr8SWj4WMw1M=
+-----END ENCRYPTED PRIVATE KEY-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/client-request.pem
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/client-request.pem b/python/tests/proton_tests/ssl_db/client-request.pem
new file mode 100644
index 0000000..b247aab
--- /dev/null
+++ b/python/tests/proton_tests/ssl_db/client-request.pem
@@ -0,0 +1,15 @@
+-----BEGIN NEW CERTIFICATE REQUEST-----
+MIICWTCCAhcCAQAwJTESMBAGA1UEAxMJMTI3LjAuMC4xMQ8wDQYDVQQKEwZDbGll
+bnQwggG3MIIBLAYHKoZIzjgEATCCAR8CgYEA/X9TgR11EilS30qcLuzk5/YRt1I8
+70QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZUKWk
+n5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOuK2HX
+Ku/yIgMZndFIAccCFQCXYFCPFSMLzLKSuYKi64QL8Fgc9QKBgQD34aCF1ps93su8
+q1w2uFe5eZSvu/o66oL5V0wLPQeCZ1FZV4661FlP5nEHEIGAtEkWcSPoTCgWE7fP
+CTKMyKbhPBZ6i1R8jSjgo64eK7OmdZFuo38L+iE1YvH7YnoBJDvMpPG+qFGQiaiD
+3+Fa5Z8GkotmXoB7VSVkAUw7/s9JKgOBhAACgYAneDWiGkeCjEfdiPRIh+I9xRoz
+kUizN6YXBDYVmgb8nsyJUjDjjYmF5NH+IQHctiF4cGntOiqFoxg1iJ1zHFTOBkmz
+fCiteoC5SAN1sNxboCNDiiXIZW3uxf04vZqYyr0EUIi3tKXIMpbwBxzHjof7wF98
+x0K7nrLDlZC1ndw8PaAwMC4GCSqGSIb3DQEJDjEhMB8wHQYDVR0OBBYEFCDsVsKW
+a2tIAcD2VHwTu57GXmnWMAsGByqGSM44BAMFAAMvADAsAhQY5Zy4fQcy/SZOJ2Ix
+cl3/QfimvQIUVvSdet7NKWzMQoBDhlJTdTzJvE8=
+-----END NEW CERTIFICATE REQUEST-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/client-request1.pem
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/client-request1.pem b/python/tests/proton_tests/ssl_db/client-request1.pem
new file mode 100644
index 0000000..b46eb0a
--- /dev/null
+++ b/python/tests/proton_tests/ssl_db/client-request1.pem
@@ -0,0 +1,16 @@
+-----BEGIN NEW CERTIFICATE REQUEST-----
+MIICkTCCAk4CAQAwXDEMMAoGA1UECxMDRGV2MQ0wCwYDVQQHEwRDaXR5MQswCQYD
+VQQIEwJTVDELMAkGA1UEBhMCVVMxEjAQBgNVBAMTCTEyNy4wLjAuMTEPMA0GA1UE
+ChMGQ2xpZW50MIIBtzCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s
+5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/Jm
+YLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy
+9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+Gg
+hdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj
+6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTx
+vqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQAAoGAdW66tWrUUXCz8k34
+jfJ8DZFWYXCVgkgPzLI72WQcE8EMTR2p8UEXoXefCwKJkXSf+/ih3oy65FKmVXiR
+kfSM45XDt71wXZE138pqGwimb86rlqiybpbsoMr/EjA3Jb7cMW1MYNM5np6NUyAZ
+HasAP4USnbLJwkAJAE/Ua1NIVdOgMDAuBgkqhkiG9w0BCQ4xITAfMB0GA1UdDgQW
+BBTPhzH7M2qwKZakFTZ3DwYc7ff54TALBgcqhkjOOAQDBQADMAAwLQIUFs17HaTm
+vest72/4Caoo1sH39n0CFQCR680PPwr3lZ5jjEOp+n4htQNUvw==
+-----END NEW CERTIFICATE REQUEST-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/client.pkcs12
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/client.pkcs12 b/python/tests/proton_tests/ssl_db/client.pkcs12
new file mode 100644
index 0000000..575a551
Binary files /dev/null and b/python/tests/proton_tests/ssl_db/client.pkcs12 differ
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/client1.pkcs12
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/client1.pkcs12 b/python/tests/proton_tests/ssl_db/client1.pkcs12
new file mode 100644
index 0000000..0e7c888
Binary files /dev/null and b/python/tests/proton_tests/ssl_db/client1.pkcs12 differ
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/server-certificate.p12
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/server-certificate.p12 b/python/tests/proton_tests/ssl_db/server-certificate.p12
new file mode 100644
index 0000000..cacfa89
Binary files /dev/null and b/python/tests/proton_tests/ssl_db/server-certificate.p12 differ
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/server-certificate.pem
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/server-certificate.pem b/python/tests/proton_tests/ssl_db/server-certificate.pem
new file mode 100644
index 0000000..462f3a5
--- /dev/null
+++ b/python/tests/proton_tests/ssl_db/server-certificate.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC5jCCAqSgAwIBAgIEX8z6MDALBgcqhkjOOAQDBQAwMTEXMBUGA1UEAxMOVHJ1
+c3RlZC5DQS5jb20xFjAUBgNVBAoTDVRydXN0IE1lIEluYy4wIBcNMTcwODAyMjE1
+MzM3WhgPMjI5MTA1MTcyMTUzMzdaMDUxIjAgBgNVBAMTGUExLkdvb2QuU2VydmVy
+LmRvbWFpbi5jb20xDzANBgNVBAoTBlNlcnZlcjCCAbgwggEsBgcqhkjOOAQBMIIB
+HwKBgQD9f1OBHXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEmaUVdQCJR+1k9jVj6
+v8X1ujD2y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb+DtX58ao
+phUPBPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdgUI8VIwvM
+spK5gqLrhAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlXTAs9B4Jn
+UVlXjrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCjrh4rs6Z1
+kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQBTDv+z0kq
+A4GFAAKBgQCERpy6RrkNHpgXT/uL9gN/IgwY7kp3Iwzr1lrqo+HqmydE+Cz9uqPH
+VyxjX7nHVrdwl7xgsoki3QyoKcrZfTL1oS79kodWG7t6CyOtj2L3KGMUdIlqWepZ
+wzCKTWrb07VjpqhMh0Qh8+IqEmvfC/4UVOec9alX0NO/ckDbIBhITqNCMEAwHwYD
+VR0jBBgwFoAUsjZ7PCKVgcZLkxE8xaWJ8cf5jmowHQYDVR0OBBYEFBhEDdcBRqn5
+wFEbAad559yrQPE7MAsGByqGSM44BAMFAAMvADAsAhRuMRxWMKxy3USjfSFn47H4
+Z5VIHgIUB2i6+RQi7dHOEQYKKmxdQvAPA9M=
+-----END CERTIFICATE-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/server-private-key.pem
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/server-private-key.pem b/python/tests/proton_tests/ssl_db/server-private-key.pem
new file mode 100644
index 0000000..3ae25f8
--- /dev/null
+++ b/python/tests/proton_tests/ssl_db/server-private-key.pem
@@ -0,0 +1,15 @@
+Bag Attributes
+ friendlyName: server-certificate
+ localKeyID: 54 69 6D 65 20 31 35 30 31 37 31 30 38 31 36 36 35 36
+Key Attributes: <No Attributes>
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIBljBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI6jwDH/9bZYMCAggA
+MBQGCCqGSIb3DQMHBAgbIQ8UrRfmAgSCAVDejPh9sT2PMvDjjzXG6xpSmBPNZRiz
+f2k2a9EaI8L4xadveiZTzOpk2C/nltMCNY2Vwf/LMtbvcLiadBRWM/4Uf5fvL/94
+zlKE77wPSWK1R+btZm0KIaA+EPAvnIGcjHlcSU58eQexwVlMXJ9pdeHm9KWbV1D+
+PjrlJ+SDq7OSGprTCz9r+gQ7Fy2Oe9OKc92tE29QD2AZXtSodvY9CosXCx4cqXr3
+ey+HXmVXJohsL89NycL80TvkxppqZ1hT3DZMkrFg2jFPz505rzE48y62FMoKNCjQ
+6HXvsniWYXf7ipr+A4/diSSMBr/zmA+H+ZHKlNO8FJqZ8eI1eqRO+PjO1VV9bbG0
+lYoeoFu0Y1xw6V2jLYnFF1mTCC6kegl6kruvnwO7Oy+6kPEvDrejuI6uozW2etej
+cBq1lUK5QNKSoaB7Qw+2qlyFg/KFwXXDBqk=
+-----END ENCRYPTED PRIVATE KEY-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/server-request.pem
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/server-request.pem b/python/tests/proton_tests/ssl_db/server-request.pem
new file mode 100644
index 0000000..bd53fab
--- /dev/null
+++ b/python/tests/proton_tests/ssl_db/server-request.pem
@@ -0,0 +1,15 @@
+-----BEGIN NEW CERTIFICATE REQUEST-----
+MIICazCCAigCAQAwNTEiMCAGA1UEAxMZQTEuR29vZC5TZXJ2ZXIuZG9tYWluLmNv
+bTEPMA0GA1UEChMGU2VydmVyMIIBuDCCASwGByqGSM44BAEwggEfAoGBAP1/U4Ed
+dRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs
+14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208Ue
+wwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BY
+HPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+Zx
+BxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx
++2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYUAAoGBAIRG
+nLpGuQ0emBdP+4v2A38iDBjuSncjDOvWWuqj4eqbJ0T4LP26o8dXLGNfucdWt3CX
+vGCyiSLdDKgpytl9MvWhLv2Sh1Ybu3oLI62PYvcoYxR0iWpZ6lnDMIpNatvTtWOm
+qEyHRCHz4ioSa98L/hRU55z1qVfQ079yQNsgGEhOoDAwLgYJKoZIhvcNAQkOMSEw
+HzAdBgNVHQ4EFgQUGEQN1wFGqfnAURsBp3nn3KtA8TswCwYHKoZIzjgEAwUAAzAA
+MC0CFFIXSYKFVq90wR3lH+KCwvL+j0A4AhUAlxeczUtqTQFeGXFsDwIGO+5/uA4=
+-----END NEW CERTIFICATE REQUEST-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/server-wc-certificate.p12
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/server-wc-certificate.p12 b/python/tests/proton_tests/ssl_db/server-wc-certificate.p12
new file mode 100644
index 0000000..3f8a53d
Binary files /dev/null and b/python/tests/proton_tests/ssl_db/server-wc-certificate.p12 differ
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/server-wc-certificate.pem
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/server-wc-certificate.pem b/python/tests/proton_tests/ssl_db/server-wc-certificate.pem
new file mode 100644
index 0000000..4d32b40
--- /dev/null
+++ b/python/tests/proton_tests/ssl_db/server-wc-certificate.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDFTCCAtOgAwIBAgIEVTK/cTALBgcqhkjOOAQDBQAwMTEXMBUGA1UEAxMOVHJ1
+c3RlZC5DQS5jb20xFjAUBgNVBAoTDVRydXN0IE1lIEluYy4wIBcNMTcwODAyMjE1
+MzM4WhgPMjI5MTA1MTcyMTUzMzhaMDAxHTAbBgNVBAMMFCoucHJlZml4Ki5kb21h
+aW4uY29tMQ8wDQYDVQQKEwZTZXJ2ZXIwggG3MIIBLAYHKoZIzjgEATCCAR8CgYEA
+/X9TgR11EilS30qcLuzk5/YRt1I870QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow
+9subVWzXgTuAHTRv8mZgt2uZUKWkn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7
+g/bTxR7DAjVUE1oWkTL2dfOuK2HXKu/yIgMZndFIAccCFQCXYFCPFSMLzLKSuYKi
+64QL8Fgc9QKBgQD34aCF1ps93su8q1w2uFe5eZSvu/o66oL5V0wLPQeCZ1FZV466
+1FlP5nEHEIGAtEkWcSPoTCgWE7fPCTKMyKbhPBZ6i1R8jSjgo64eK7OmdZFuo38L
++iE1YvH7YnoBJDvMpPG+qFGQiaiD3+Fa5Z8GkotmXoB7VSVkAUw7/s9JKgOBhAAC
+gYATsU4dSb5vvYkuhnLJPYpiHOEOagLSwwggm8CD4JqA8CC/lzIJBI3LkR7Ve1Mw
+xYiDbQQPaxGsdCxaDuE+rOHmJcCNxum4gIYxeOOGHLa9eezTXLu2s0kBgsWx3I0U
+98lI4E+gRHiU27NXlNiEKvVq3GhzWvKdUqClbtLZ+67gzqN3MHUwHwYDVR0jBBgw
+FoAUsjZ7PCKVgcZLkxE8xaWJ8cf5jmowMwYDVR0RBCwwKoIWYWx0ZXJuYXRlLm5h
+bWUub25lLmNvbYIQYW5vdGhlci5uYW1lLmNvbTAdBgNVHQ4EFgQUas7dEjv/R3ig
+GcCdPRLL5P3HPU8wCwYHKoZIzjgEAwUAAy8AMCwCFFuvuEosI+5a+lSmpEahvhyE
+31WUAhR6+NkSdChlT0v6HmjyhBL1hLZYNA==
+-----END CERTIFICATE-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/server-wc-private-key.pem
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/server-wc-private-key.pem b/python/tests/proton_tests/ssl_db/server-wc-private-key.pem
new file mode 100644
index 0000000..7bae296
--- /dev/null
+++ b/python/tests/proton_tests/ssl_db/server-wc-private-key.pem
@@ -0,0 +1,15 @@
+Bag Attributes
+ friendlyName: server-wc-certificate
+ localKeyID: 54 69 6D 65 20 31 35 30 31 37 31 30 38 31 38 34 39 33
+Key Attributes: <No Attributes>
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIBljBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIFt9KwMYb/OQCAggA
+MBQGCCqGSIb3DQMHBAjQ+Hr462sAigSCAVAmqByfn+Ujb9TfpEI0d6mlW7Nyko00
+chzSFz61RVA/twfbLImhYvEo7P+UglcqGc1H3DaysDuMjbiNqgP25lDHO6ndhN7r
+XaeNshI8U3RQfUrhTwcA2pGpHQ6t+TGNKifRuJMbcHxWDNr+Tdod8uUADZt8Ywb+
+WQOqIrByNJryx5i2yZT7FphYrz6N0L5cNKVIirNv9/FOlKiyuzzg5c4NmABkpajE
+ZyT2H1p/qFipz8XeQ7BvFVDWSGn6Jb8vRvcc/swoCNSs8Wukr7tbryie2IbgktES
+gw7mVOw/Wdw6u26Q8Dz1c+eyy1WPuCiubFKUK12Ul0X9KKYCufVvQPoQBsMGikRM
+JcvrMd1cZ60pANJhnrogE6VEYE3NQrPC6SNao0NB+g4CW3tOH6m80H5+yHrMdvjo
+MQNXdlwdNWrCEH6hXJxzuE1qM5Ajc82bfwo=
+-----END ENCRYPTED PRIVATE KEY-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/server-wc-request.pem
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/server-wc-request.pem b/python/tests/proton_tests/ssl_db/server-wc-request.pem
new file mode 100644
index 0000000..f6f13bd
--- /dev/null
+++ b/python/tests/proton_tests/ssl_db/server-wc-request.pem
@@ -0,0 +1,16 @@
+-----BEGIN NEW CERTIFICATE REQUEST-----
+MIICmTCCAlcCAQAwMDEdMBsGA1UEAwwUKi5wcmVmaXgqLmRvbWFpbi5jb20xDzAN
+BgNVBAoTBlNlcnZlcjCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQD9f1OBHXUSKVLf
+Spwu7OTn9hG3UjzvRADDHj+AtlEmaUVdQCJR+1k9jVj6v8X1ujD2y5tVbNeBO4Ad
+NG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb+DtX58aophUPBPuD9tPFHsMCNVQT
+WhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdgUI8VIwvMspK5gqLrhAvwWBz1AoGB
+APfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlXTAs9B4JnUVlXjrrUWU/mcQcQgYC0
+SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCjrh4rs6Z1kW6jfwv6ITVi8ftiegEk
+O8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQBTDv+z0kqA4GEAAKBgBOxTh1Jvm+9
+iS6Gcsk9imIc4Q5qAtLDCCCbwIPgmoDwIL+XMgkEjcuRHtV7UzDFiINtBA9rEax0
+LFoO4T6s4eYlwI3G6biAhjF444Yctr157NNcu7azSQGCxbHcjRT3yUjgT6BEeJTb
+s1eU2IQq9WrcaHNa8p1SoKVu0tn7ruDOoGUwYwYJKoZIhvcNAQkOMVYwVDAzBgNV
+HREELDAqghZhbHRlcm5hdGUubmFtZS5vbmUuY29tghBhbm90aGVyLm5hbWUuY29t
+MB0GA1UdDgQWBBRqzt0SO/9HeKAZwJ09Esvk/cc9TzALBgcqhkjOOAQDBQADLwAw
+LAIUNn3ravBNvEsgZRjQd4EPPvQ1k9wCFEuakAyAzmt2ZfIKX3ZmTIgNKsvy
+-----END NEW CERTIFICATE REQUEST-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/server-wc.pkcs12
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/server-wc.pkcs12 b/python/tests/proton_tests/ssl_db/server-wc.pkcs12
new file mode 100644
index 0000000..0ceccbc
Binary files /dev/null and b/python/tests/proton_tests/ssl_db/server-wc.pkcs12 differ
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/ssl_db/server.pkcs12
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl_db/server.pkcs12 b/python/tests/proton_tests/ssl_db/server.pkcs12
new file mode 100644
index 0000000..f3c19e2
Binary files /dev/null and b/python/tests/proton_tests/ssl_db/server.pkcs12 differ
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[04/11] qpid-proton git commit: PROTON-1885: [python] move
tests/python to python/tests
Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl.py b/tests/python/proton_tests/ssl.py
deleted file mode 100644
index d2e2f44..0000000
--- a/tests/python/proton_tests/ssl.py
+++ /dev/null
@@ -1,936 +0,0 @@
-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.
-#
-
-import os
-from . import common
-import random
-import string
-import subprocess
-import sys
-from proton import *
-from .common import Skipped, pump
-
-
-def _testpath(file):
- """ Set the full path to the certificate,keyfile, etc. for the test.
- """
- if os.name=="nt":
- if file.find("private-key")!=-1:
- # The private key is not in a separate store
- return None
- # Substitute pkcs#12 equivalent for the CA/key store
- if file.endswith(".pem"):
- file = file[:-4] + ".p12"
- return os.path.join(os.path.dirname(__file__),
- "ssl_db/%s" % file)
-
-class SslTest(common.Test):
-
- def __init__(self, *args):
- common.Test.__init__(self, *args)
- self._testpath = _testpath
-
- def setUp(self):
- if not common.isSSLPresent():
- raise Skipped("No SSL libraries found.")
- self.server_domain = SSLDomain(SSLDomain.MODE_SERVER)
- self.client_domain = SSLDomain(SSLDomain.MODE_CLIENT)
-
- def tearDown(self):
- self.server_domain = None
- self.client_domain = None
-
- class SslTestConnection(object):
- """ Represents a single SSL connection.
- """
- def __init__(self, domain=None, mode=Transport.CLIENT,
- session_details=None, conn_hostname=None,
- ssl_peername=None):
- if not common.isSSLPresent():
- raise Skipped("No SSL libraries found.")
-
- self.ssl = None
- self.domain = domain
- self.transport = Transport(mode)
- self.connection = Connection()
- if conn_hostname:
- self.connection.hostname = conn_hostname
- if domain:
- self.ssl = SSL( self.transport, self.domain, session_details )
- if ssl_peername:
- self.ssl.peer_hostname = ssl_peername
- # bind last, after all configuration complete:
- self.transport.bind(self.connection)
-
- def _pump(self, ssl_client, ssl_server, buffer_size=1024):
- pump(ssl_client.transport, ssl_server.transport, buffer_size)
-
- def _do_handshake(self, client, server):
- """ Attempt to connect client to server. Will throw a TransportException if the SSL
- handshake fails.
- """
- client.connection.open()
- server.connection.open()
- self._pump(client, server)
- if client.transport.closed:
- return
- assert client.ssl.protocol_name() is not None
- client.connection.close()
- server.connection.close()
- self._pump(client, server)
-
- def test_defaults(self):
- if os.name=="nt":
- raise Skipped("Windows SChannel lacks anonymous cipher support.")
- """ By default, both the server and the client support anonymous
- ciphers - they should connect without need for a certificate.
- """
- server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
- client = SslTest.SslTestConnection( self.client_domain )
-
- # check that no SSL connection exists
- assert not server.ssl.cipher_name()
- assert not client.ssl.protocol_name()
-
- #client.transport.trace(Transport.TRACE_DRV)
- #server.transport.trace(Transport.TRACE_DRV)
-
- client.connection.open()
- server.connection.open()
- self._pump( client, server )
-
- # now SSL should be active
- assert server.ssl.cipher_name() is not None
- assert client.ssl.protocol_name() is not None
-
- client.connection.close()
- server.connection.close()
- self._pump( client, server )
-
- def test_ssl_with_small_buffer(self):
- self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
- self._testpath("server-private-key.pem"),
- "server-password")
- self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER )
-
- server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
- client = SslTest.SslTestConnection( self.client_domain )
-
- client.connection.open()
- server.connection.open()
-
- small_buffer_size = 1
- self._pump( client, server, small_buffer_size )
-
- assert client.ssl.protocol_name() is not None
- client.connection.close()
- server.connection.close()
- self._pump( client, server )
-
-
- def test_server_certificate(self):
- """ Test that anonymous clients can still connect to a server that has
- a certificate configured.
- """
- self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
- self._testpath("server-private-key.pem"),
- "server-password")
- server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
- client = SslTest.SslTestConnection( self.client_domain )
-
- client.connection.open()
- server.connection.open()
- self._pump( client, server )
- assert client.ssl.protocol_name() is not None
- client.connection.close()
- server.connection.close()
- self._pump( client, server )
-
- def test_server_authentication(self):
- """ Simple SSL connection with authentication of the server
- """
- self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
- self._testpath("server-private-key.pem"),
- "server-password")
-
- self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER )
-
- server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
- client = SslTest.SslTestConnection( self.client_domain )
-
- client.connection.open()
- server.connection.open()
- self._pump( client, server )
- assert client.ssl.protocol_name() is not None
- client.connection.close()
- server.connection.close()
- self._pump( client, server )
-
- def test_certificate_fingerprint_and_subfields(self):
- if os.name=="nt":
- raise Skipped("Windows support for certificate fingerprint and subfield not implemented yet")
-
- self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
- self._testpath("server-private-key.pem"),
- "server-password")
- self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER,
- self._testpath("ca-certificate.pem") )
- server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
-
- # give the client a certificate, but let's not require server authentication
- self.client_domain.set_credentials(self._testpath("client-certificate1.pem"),
- self._testpath("client-private-key1.pem"),
- "client-password")
- self.client_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER )
- client = SslTest.SslTestConnection( self.client_domain )
-
- client.connection.open()
- server.connection.open()
- self._pump( client, server )
-
- # Test the subject subfields
- self.assertEqual("Client", server.ssl.get_cert_organization())
- self.assertEqual("Dev", server.ssl.get_cert_organization_unit())
- self.assertEqual("ST", server.ssl.get_cert_state_or_province())
- self.assertEqual("US", server.ssl.get_cert_country())
- self.assertEqual("City", server.ssl.get_cert_locality_or_city())
- self.assertEqual("O=Server,CN=A1.Good.Server.domain.com", client.ssl.get_cert_subject())
- self.assertEqual("O=Client,CN=127.0.0.1,C=US,ST=ST,L=City,OU=Dev", server.ssl.get_cert_subject())
-
- self.assertEqual("f78f03ec31317c213dcf607c095242adbf067824", server.ssl.get_cert_fingerprint_sha1())
- self.assertEqual("3836fd0d7bbc155158997ff336de29545cc1ce4137f8419062ceb8b50fd7a6f9", server.ssl.get_cert_fingerprint_sha256())
- self.assertEqual("a8390634eb10c7a12ba3ce0837001bc6ae78c7690984f4788cf4430acdb496d5d9e02c8ec39219f5c4dcd908c34861d09481c2faf53b4ccc95dac60e623165c4",
- server.ssl.get_cert_fingerprint_sha512())
- self.assertEqual("32b7bc119f61c71d368caaf9a6bf58b2", server.ssl.get_cert_fingerprint_md5())
-
- # Test the various fingerprint algorithms
- self.assertEqual("0aab5922c8657a7fb78402b79379506d3d7806ce", client.ssl.get_cert_fingerprint_sha1())
- self.assertEqual("de5e0c4097f841815a769ce1a30dbe912b83711438a5aaf50001da23cee5a8a8", client.ssl.get_cert_fingerprint_sha256())
- self.assertEqual("d0aceeb68ab9de57c9e1c21a43a4511c54ec94011e770a523a6352b1374f59c8b58adc93d5cad6f25aa125b5934309a61a25e74a5d5e0cb40b07c7468615944c",
- client.ssl.get_cert_fingerprint_sha512())
- self.assertEqual("ae0ebcebc1f970fb696ef9f56e3235da", client.ssl.get_cert_fingerprint_md5())
-
- self.assertEqual(None, client.ssl.get_cert_fingerprint(21, SSL.SHA1)) # Should be at least 41
- self.assertEqual(None, client.ssl.get_cert_fingerprint(50, SSL.SHA256)) # Should be at least 65
- self.assertEqual(None, client.ssl.get_cert_fingerprint(128, SSL.SHA512)) # Should be at least 129
- self.assertEqual(None, client.ssl.get_cert_fingerprint(10, SSL.MD5)) # Should be at least 33
- self.assertEqual(None, client.ssl._get_cert_subject_unknown_subfield())
-
- self.assertNotEqual(None, client.ssl.get_cert_fingerprint(50, SSL.SHA1)) # Should be at least 41
- self.assertNotEqual(None, client.ssl.get_cert_fingerprint(70, SSL.SHA256)) # Should be at least 65
- self.assertNotEqual(None, client.ssl.get_cert_fingerprint(130, SSL.SHA512)) # Should be at least 129
- self.assertNotEqual(None, client.ssl.get_cert_fingerprint(35, SSL.MD5)) # Should be at least 33
- self.assertEqual(None, client.ssl._get_cert_fingerprint_unknown_hash_alg())
-
- def test_client_authentication(self):
- """ Force the client to authenticate.
- """
- # note: when requesting client auth, the server _must_ send its
- # certificate, so make sure we configure one!
- self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
- self._testpath("server-private-key.pem"),
- "server-password")
- self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER,
- self._testpath("ca-certificate.pem") )
- server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
-
- # give the client a certificate, but let's not require server authentication
- self.client_domain.set_credentials(self._testpath("client-certificate.pem"),
- self._testpath("client-private-key.pem"),
- "client-password")
- self.client_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER )
- client = SslTest.SslTestConnection( self.client_domain )
-
- client.connection.open()
- server.connection.open()
- self._pump( client, server )
-
- assert client.ssl.protocol_name() is not None
- client.connection.close()
- server.connection.close()
- self._pump( client, server )
-
- def test_client_authentication_fail_bad_cert(self):
- """ Ensure that the server can detect a bad client certificate.
- """
- # note: when requesting client auth, the server _must_ send its
- # certificate, so make sure we configure one!
- self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
- self._testpath("server-private-key.pem"),
- "server-password")
- self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER,
- self._testpath("ca-certificate.pem") )
- server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
-
- self.client_domain.set_credentials(self._testpath("bad-server-certificate.pem"),
- self._testpath("bad-server-private-key.pem"),
- "server-password")
- self.client_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER )
- client = SslTest.SslTestConnection( self.client_domain )
-
- client.connection.open()
- server.connection.open()
- self._pump( client, server )
- assert client.transport.closed
- assert server.transport.closed
- assert client.connection.state & Endpoint.REMOTE_UNINIT
- assert server.connection.state & Endpoint.REMOTE_UNINIT
-
- def test_client_authentication_fail_no_cert(self):
- """ Ensure that the server will fail a client that does not provide a
- certificate.
- """
- # note: when requesting client auth, the server _must_ send its
- # certificate, so make sure we configure one!
- self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
- self._testpath("server-private-key.pem"),
- "server-password")
- self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER,
- self._testpath("ca-certificate.pem") )
- server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
-
- self.client_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER )
- client = SslTest.SslTestConnection( self.client_domain )
-
- client.connection.open()
- server.connection.open()
- self._pump( client, server )
- assert client.transport.closed
- assert server.transport.closed
- assert client.connection.state & Endpoint.REMOTE_UNINIT
- assert server.connection.state & Endpoint.REMOTE_UNINIT
-
- def test_client_server_authentication(self):
- """ Require both client and server to mutually identify themselves.
- """
- self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
- self._testpath("server-private-key.pem"),
- "server-password")
- self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER,
- self._testpath("ca-certificate.pem") )
-
- self.client_domain.set_credentials(self._testpath("client-certificate.pem"),
- self._testpath("client-private-key.pem"),
- "client-password")
- self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER )
-
- server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
- client = SslTest.SslTestConnection( self.client_domain )
-
- client.connection.open()
- server.connection.open()
- self._pump( client, server )
- assert client.ssl.protocol_name() is not None
- client.connection.close()
- server.connection.close()
- self._pump( client, server )
-
- def test_server_only_authentication(self):
- """ Client verifies server, but server does not verify client.
- """
- self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
- self._testpath("server-private-key.pem"),
- "server-password")
- self.server_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER )
-
- self.client_domain.set_credentials(self._testpath("client-certificate.pem"),
- self._testpath("client-private-key.pem"),
- "client-password")
- self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER )
-
- server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
- client = SslTest.SslTestConnection( self.client_domain )
-
- client.connection.open()
- server.connection.open()
- self._pump( client, server )
- assert client.ssl.protocol_name() is not None
- client.connection.close()
- server.connection.close()
- self._pump( client, server )
-
- def test_bad_server_certificate(self):
- """ A server with a self-signed certificate that is not trusted by the
- client. The client should reject the server.
- """
- self.server_domain.set_credentials(self._testpath("bad-server-certificate.pem"),
- self._testpath("bad-server-private-key.pem"),
- "server-password")
- self.server_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER )
-
- self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER )
-
- server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
- client = SslTest.SslTestConnection( self.client_domain )
-
- client.connection.open()
- server.connection.open()
- self._pump( client, server )
- assert client.transport.closed
- assert server.transport.closed
- assert client.connection.state & Endpoint.REMOTE_UNINIT
- assert server.connection.state & Endpoint.REMOTE_UNINIT
-
- del server
- del client
-
- # now re-try with a client that does not require peer verification
- self.client_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER )
-
- client = SslTest.SslTestConnection( self.client_domain )
- server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
-
- client.connection.open()
- server.connection.open()
- self._pump( client, server )
- assert client.ssl.protocol_name() is not None
- client.connection.close()
- server.connection.close()
- self._pump( client, server )
-
- def test_allow_unsecured_client_which_connects_unsecured(self):
- """ Server allows an unsecured client to connect if configured.
- """
- self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
- self._testpath("server-private-key.pem"),
- "server-password")
- self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER,
- self._testpath("ca-certificate.pem") )
- # allow unsecured clients on this connection
- self.server_domain.allow_unsecured_client()
- server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
-
- # non-ssl connection
- client = SslTest.SslTestConnection()
-
- client.connection.open()
- server.connection.open()
- self._pump( client, server )
- assert server.ssl.protocol_name() is None
- client.connection.close()
- server.connection.close()
- self._pump( client, server )
-
- def test_allow_unsecured_client_which_connects_secured(self):
- """ As per test_allow_unsecured_client_which_connects_unsecured
- but client actually uses SSL
- """
- self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
- self._testpath("server-private-key.pem"),
- "server-password")
- self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER,
- self._testpath("ca-certificate.pem") )
-
- self.client_domain.set_credentials(self._testpath("client-certificate.pem"),
- self._testpath("client-private-key.pem"),
- "client-password")
- self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER )
-
- # allow unsecured clients on this connection
- #self.server_domain.allow_unsecured_client()
-
- # client uses ssl. Server should detect this.
- client = SslTest.SslTestConnection( self.client_domain )
- server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
-
- client.connection.open()
- server.connection.open()
- self._pump( client, server )
- assert server.ssl.protocol_name() is not None
- client.connection.close()
- server.connection.close()
- self._pump( client, server )
-
-
- def test_disallow_unsecured_client(self):
- """ Non-SSL Client is disallowed from connecting to server.
- """
- self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
- self._testpath("server-private-key.pem"),
- "server-password")
- self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.server_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER )
- server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
-
- # non-ssl connection
- client = SslTest.SslTestConnection()
-
- client.connection.open()
- server.connection.open()
- self._pump( client, server )
- assert client.transport.closed
- assert server.transport.closed
- assert client.connection.state & Endpoint.REMOTE_UNINIT
- assert server.connection.state & Endpoint.REMOTE_UNINIT
-
- def test_session_resume(self):
- """ Test resume of client session.
- """
- if os.name=="nt":
- raise Skipped("Windows SChannel session resume not yet implemented.")
-
- self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
- self._testpath("server-private-key.pem"),
- "server-password")
- self.server_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER )
-
- self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER )
-
- # details will be used in initial and subsequent connections to allow session to be resumed
- initial_session_details = SSLSessionDetails("my-session-id")
-
- server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
- client = SslTest.SslTestConnection( self.client_domain, session_details=initial_session_details )
-
- # bring up the connection and store its state
- client.connection.open()
- server.connection.open()
- self._pump( client, server )
- assert client.ssl.protocol_name() is not None
-
- # cleanly shutdown the connection
- client.connection.close()
- server.connection.close()
- self._pump( client, server )
-
- # destroy the existing clients
- del client
- del server
-
- # now create a new set of connections, use last session id
- server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
- # provide the details of the last session, allowing it to be resumed
- client = SslTest.SslTestConnection( self.client_domain, session_details=initial_session_details )
-
- #client.transport.trace(Transport.TRACE_DRV)
- #server.transport.trace(Transport.TRACE_DRV)
-
- client.connection.open()
- server.connection.open()
- self._pump( client, server )
- assert server.ssl.protocol_name() is not None
- if(API_LANGUAGE=="C"):
- assert client.ssl.resume_status() == SSL.RESUME_REUSED
- else:
- # Java gives no way to check whether a previous session has been resumed
- pass
-
- client.connection.close()
- server.connection.close()
- self._pump( client, server )
-
- # now try to resume using an unknown session-id, expect resume to fail
- # and a new session is negotiated
-
- del client
- del server
-
- server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
- client = SslTest.SslTestConnection( self.client_domain, session_details=SSLSessionDetails("some-other-session-id") )
-
- client.connection.open()
- server.connection.open()
- self._pump( client, server )
- assert server.ssl.protocol_name() is not None
- if(API_LANGUAGE=="C"):
- assert client.ssl.resume_status() == SSL.RESUME_NEW
-
- client.connection.close()
- server.connection.close()
- self._pump( client, server )
-
- def test_multiple_sessions(self):
- """ Test multiple simultaneous active SSL sessions with bi-directional
- certificate verification, shared across two domains.
- """
- self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
- self._testpath("server-private-key.pem"),
- "server-password")
- self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER,
- self._testpath("ca-certificate.pem") )
-
- self.client_domain.set_credentials(self._testpath("client-certificate.pem"),
- self._testpath("client-private-key.pem"),
- "client-password")
- self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER )
-
- max_count = 100
- sessions = [(SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ),
- SslTest.SslTestConnection( self.client_domain )) for x in
- range(max_count)]
- for s in sessions:
- s[0].connection.open()
- self._pump( s[0], s[1] )
-
- for s in sessions:
- s[1].connection.open()
- self._pump( s[1], s[0] )
- assert s[0].ssl.cipher_name() is not None
- assert s[1].ssl.cipher_name() == s[0].ssl.cipher_name()
-
- for s in sessions:
- s[1].connection.close()
- self._pump( s[0], s[1] )
-
- for s in sessions:
- s[0].connection.close()
- self._pump( s[1], s[0] )
-
- def test_server_hostname_authentication(self):
- """ Test authentication of the names held in the server's certificate
- against various configured hostnames.
- """
- if os.name=="nt":
- raise Skipped("PROTON-1057: disable temporarily on Windows.")
-
- # Check the CommonName matches (case insensitive).
- # Assumes certificate contains "CN=A1.Good.Server.domain.com"
- self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
- self._testpath("server-private-key.pem"),
- "server-password")
- self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME )
-
- server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
- client = SslTest.SslTestConnection( self.client_domain )
-
- client.ssl.peer_hostname = "a1.good.server.domain.com"
- assert client.ssl.peer_hostname == "a1.good.server.domain.com"
- self._do_handshake( client, server )
- del server
- del client
- self.tearDown()
-
- # Should fail on CN name mismatch:
- self.setUp()
- self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
- self._testpath("server-private-key.pem"),
- "server-password")
- self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME )
-
- server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
- client = SslTest.SslTestConnection( self.client_domain )
-
- client.ssl.peer_hostname = "A1.Good.Server.domain.comX"
- self._do_handshake( client, server )
- assert client.transport.closed
- assert server.transport.closed
- assert client.connection.state & Endpoint.REMOTE_UNINIT
- assert server.connection.state & Endpoint.REMOTE_UNINIT
- del server
- del client
- self.tearDown()
-
- # Wildcarded Certificate
- # Assumes:
- # 1) certificate contains Server Alternate Names:
- # "alternate.name.one.com" and "another.name.com"
- # 2) certificate has wildcarded CommonName "*.prefix*.domain.com"
- #
-
- # Pass: match an alternate
- self.setUp()
- self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"),
- self._testpath("server-wc-private-key.pem"),
- "server-password")
- self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME )
-
- server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
- client = SslTest.SslTestConnection( self.client_domain )
-
- client.ssl.peer_hostname = "alternate.Name.one.com"
- self._do_handshake( client, server )
- del client
- del server
- self.tearDown()
-
- # Pass: match an alternate
- self.setUp()
- self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"),
- self._testpath("server-wc-private-key.pem"),
- "server-password")
- self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME )
-
- server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
- client = SslTest.SslTestConnection( self.client_domain )
-
- client.ssl.peer_hostname = "ANOTHER.NAME.COM"
- self._do_handshake(client, server)
- del client
- del server
- self.tearDown()
-
- # Pass: match the pattern
- self.setUp()
- self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"),
- self._testpath("server-wc-private-key.pem"),
- "server-password")
- self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME )
-
- server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
- client = SslTest.SslTestConnection( self.client_domain )
-
- client.ssl.peer_hostname = "SOME.PREfix.domain.COM"
- self._do_handshake( client, server )
- del client
- del server
- self.tearDown()
-
- # Pass: match the pattern
- self.setUp()
- self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"),
- self._testpath("server-wc-private-key.pem"),
- "server-password")
- self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME )
-
- server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
- client = SslTest.SslTestConnection( self.client_domain )
-
- client.ssl.peer_hostname = "FOO.PREfixZZZ.domain.com"
- self._do_handshake( client, server )
- del client
- del server
- self.tearDown()
-
- # Fail: must match prefix on wildcard
- self.setUp()
- self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"),
- self._testpath("server-wc-private-key.pem"),
- "server-password")
- self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME )
-
- server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
- client = SslTest.SslTestConnection( self.client_domain )
-
- client.ssl.peer_hostname = "FOO.PREfi.domain.com"
- self._do_handshake( client, server )
- assert client.transport.closed
- assert server.transport.closed
- assert client.connection.state & Endpoint.REMOTE_UNINIT
- assert server.connection.state & Endpoint.REMOTE_UNINIT
- del server
- del client
- self.tearDown()
-
- # Fail: leading wildcards are not optional
- self.setUp()
- self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"),
- self._testpath("server-wc-private-key.pem"),
- "server-password")
- self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME )
-
- server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
- client = SslTest.SslTestConnection( self.client_domain )
-
- client.ssl.peer_hostname = "PREfix.domain.COM"
- self._do_handshake( client, server )
- assert client.transport.closed
- assert server.transport.closed
- assert client.connection.state & Endpoint.REMOTE_UNINIT
- assert server.connection.state & Endpoint.REMOTE_UNINIT
- self.tearDown()
-
- # Pass: ensure that the user can give an alternate name that overrides
- # the connection's configured hostname
- self.setUp()
- self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"),
- self._testpath("server-wc-private-key.pem"),
- "server-password")
- self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME )
-
- server = SslTest.SslTestConnection(self.server_domain, mode=Transport.SERVER)
- client = SslTest.SslTestConnection(self.client_domain,
- conn_hostname="This.Name.Does.not.Match",
- ssl_peername="alternate.name.one.com")
- self._do_handshake(client, server)
- del client
- del server
- self.tearDown()
-
- # Pass: ensure that the hostname supplied by the connection is used if
- # none has been specified for the SSL instance
- self.setUp()
- self.server_domain.set_credentials(self._testpath("server-certificate.pem"),
- self._testpath("server-private-key.pem"),
- "server-password")
- self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME )
-
- server = SslTest.SslTestConnection(self.server_domain, mode=Transport.SERVER)
- client = SslTest.SslTestConnection(self.client_domain,
- conn_hostname="a1.good.server.domain.com")
- self._do_handshake(client, server)
- del client
- del server
- self.tearDown()
-
- def test_server_hostname_authentication_2(self):
- """Initially separated from test_server_hostname_authentication
- above to force Windows checking and sidestep PROTON-1057 exclusion.
- """
-
- # Fail for a null peer name.
- self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"),
- self._testpath("server-wc-private-key.pem"),
- "server-password")
- self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME )
-
- server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER )
- client = SslTest.SslTestConnection( self.client_domain )
-
- # Next line results in an eventual pn_ssl_set_peer_hostname(client.ssl._ssl, None)
- client.ssl.peer_hostname = None
- self._do_handshake( client, server )
- assert client.transport.closed
- assert server.transport.closed
- assert client.connection.state & Endpoint.REMOTE_UNINIT
- assert server.connection.state & Endpoint.REMOTE_UNINIT
- self.tearDown()
-
- def test_defaults_messenger_app(self):
- """ Test an SSL connection using the Messenger apps (no certificates)
- """
- if os.name=="nt":
- raise Skipped("Windows SChannel lacks anonymous cipher support.")
- port = common.free_tcp_ports()[0]
-
- receiver = common.MessengerReceiverC()
- receiver.subscriptions = ["amqps://~0.0.0.0:%s" % port]
- receiver.receive_count = 1
- receiver.timeout = self.timeout
- receiver.start()
-
- sender = common.MessengerSenderC()
- sender.targets = ["amqps://0.0.0.0:%s/X" % port]
- sender.send_count = 1
- sender.timeout = self.timeout
- sender.start()
- sender.wait()
- assert sender.status() == 0, "Command '%s' failed" % str(sender.cmdline())
-
- receiver.wait()
- assert receiver.status() == 0, "Command '%s' failed" % str(receiver.cmdline())
-
- def test_server_authentication_messenger_app(self):
- """ Test an SSL authentication using the Messenger apps.
- """
- port = common.free_tcp_ports()[0]
-
- receiver = common.MessengerReceiverC()
- receiver.subscriptions = ["amqps://~0.0.0.0:%s" % port]
- receiver.receive_count = 1
- receiver.timeout = self.timeout
- # Note hack - by default we use the client-certificate for the
- # _server_ because the client-certificate's common name field
- # is "127.0.0.1", which will match the target address used by
- # the sender.
- receiver.certificate = self._testpath("client-certificate.pem")
- receiver.privatekey = self._testpath("client-private-key.pem")
- receiver.password = "client-password"
- receiver.start()
-
- sender = common.MessengerSenderC()
- sender.targets = ["amqps://127.0.0.1:%s/X" % port]
- sender.send_count = 1
- sender.timeout = self.timeout
- sender.ca_db = self._testpath("ca-certificate.pem")
- sender.start()
- sender.wait()
- assert sender.status() == 0, "Command '%s' failed" % str(sender.cmdline())
-
- receiver.wait()
- assert receiver.status() == 0, "Command '%s' failed" % str(receiver.cmdline())
-
- def DISABLED_test_defaults_valgrind(self):
- """ Run valgrind over a simple SSL connection (no certificates)
- """
- # the openssl libraries produce far too many valgrind errors to be
- # useful. AFAIK, there is no way to wriate a valgrind suppression
- # expression that will ignore all errors from a given library.
- # Until we can, skip this test.
- port = common.free_tcp_ports()[0]
-
- receiver = common.MessengerReceiverValgrind()
- receiver.subscriptions = ["amqps://~127.0.0.1:%s" % port]
- receiver.receive_count = 1
- receiver.timeout = self.timeout
- receiver.start()
-
- sender = common.MessengerSenderValgrind()
- sender.targets = ["amqps://127.0.0.1:%s/X" % port]
- sender.send_count = 1
- sender.timeout = self.timeout
- sender.start()
- sender.wait()
- assert sender.status() == 0, "Command '%s' failed" % str(sender.cmdline())
-
- receiver.wait()
- assert receiver.status() == 0, "Command '%s' failed" % str(receiver.cmdline())
-
- # self.server_domain.set_credentials(self._testpath("client-certificate.pem"),
- # self._testpath("client-private-key.pem"),
- # "client-password")
-
- # self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
- # self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER )
-
- def test_singleton(self):
- """Verify that only a single instance of SSL can exist per Transport"""
- transport = Transport()
- ssl1 = SSL(transport, self.client_domain)
- ssl2 = transport.ssl(self.client_domain)
- ssl3 = transport.ssl(self.client_domain)
- assert ssl1 is ssl2
- assert ssl1 is ssl3
- transport = Transport()
- ssl1 = transport.ssl(self.client_domain)
- ssl2 = SSL(transport, self.client_domain)
- assert ssl1 is ssl2
- # catch attempt to re-configure existing SSL
- try:
- ssl3 = SSL(transport, self.server_domain)
- assert False, "Expected error did not occur!"
- except SSLException:
- pass
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/README.txt
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/README.txt b/tests/python/proton_tests/ssl_db/README.txt
deleted file mode 100644
index 20c92b2..0000000
--- a/tests/python/proton_tests/ssl_db/README.txt
+++ /dev/null
@@ -1,79 +0,0 @@
-The following certificate files are used by the SSL unit tests (ssl.py):
-
-ca-certificate.pem - contains the public certificate identifying a "trusted" Certificate
-Authority. This certificate is used to sign the certificates that identify the SSL
-servers and clients run by the tests.
-
-client-certificate.pem - the public certificate used to identify the client. Signed by
-the CA.
-
-client-private-key.pem - encrypted key used to create client-certificate.pem. Password is
-"client-password"
-
-server-certificate.pem - the public certificate used to identify the server. Signed by
-the CA. The CommonName is "A1.Good.Server.domain.com", and is checked by some unit tests.
-
-server-private-key.pem - encrypted key used to create server-certificate.pem. Password is
-"server-password"
-
-bad-server-certificate.pem, bad-server-private-key.pem - a certificate/key that is not trusted by the client, for negative test.
-
-server-wc-certificate.pem and server-wc-private-key.pem - similar to
-server-certificate.pem and server-private-key.pem, but contains Subject Alternate Name
-entries, and a wildcard CommonName. Used for certificate name checking tests.
-
-These certificates have been created using the OpenSSL tool.
-
-The following bash script can be used to create these certificates (requires keytool from Java 1.7, and openssl):
-
---8<--
-#!/bin/bash
-#set -x
-
-rm -f *.pem *.pkcs12
-
-# Create a self-signed certificate for the CA, and a private key to sign certificate requests:
-keytool -storetype pkcs12 -keystore ca.pkcs12 -storepass ca-password -alias ca -keypass ca-password -genkey -dname "O=Trust Me Inc.,CN=Trusted.CA.com" -validity 99999 -ext bc:c=ca:true,pathlen:0 -ext ku:c=digitalSignature,keyCertSign -ext ExtendedkeyUsage=serverAuth,clientAuth
-openssl pkcs12 -nokeys -passin pass:ca-password -in ca.pkcs12 -passout pass:ca-password -out ca-certificate.pem
-
-# Create a certificate request for the server certificate. Use the CA's certificate to sign it:
-keytool -storetype pkcs12 -keystore server.pkcs12 -storepass server-password -alias server-certificate -keypass server-password -genkey -dname "O=Server,CN=A1.Good.Server.domain.com" -validity 99999
-keytool -storetype pkcs12 -keystore server.pkcs12 -storepass server-password -alias server-certificate -keypass server-password -certreq -file server-request.pem
-keytool -storetype pkcs12 -keystore ca.pkcs12 -storepass ca-password -alias ca -keypass ca-password -gencert -rfc -validity 99999 -infile server-request.pem -outfile server-certificate.pem
-openssl pkcs12 -nocerts -passin pass:server-password -in server.pkcs12 -passout pass:server-password -out server-private-key.pem
-
-# Create a certificate request for the client certificate. Use the CA's certificate to sign it:
-keytool -storetype pkcs12 -keystore client.pkcs12 -storepass client-password -alias client-certificate -keypass client-password -genkey -dname "O=Client,CN=127.0.0.1" -validity 99999
-keytool -storetype pkcs12 -keystore client.pkcs12 -storepass client-password -alias client-certificate -keypass client-password -certreq -file client-request.pem
-keytool -storetype pkcs12 -keystore ca.pkcs12 -storepass ca-password -alias ca -keypass ca-password -gencert -rfc -validity 99999 -infile client-request.pem -outfile client-certificate.pem
-openssl pkcs12 -nocerts -passin pass:client-password -in client.pkcs12 -passout pass:client-password -out client-private-key.pem
-
-# Create another client certificate with a different subject line
-keytool -storetype pkcs12 -keystore client1.pkcs12 -storepass client-password -alias client-certificate1 -keypass client-password -genkey -dname "O=Client,CN=127.0.0.1,C=US,ST=ST,L=City,OU=Dev" -validity 99999
-keytool -storetype pkcs12 -keystore client1.pkcs12 -storepass client-password -alias client-certificate1 -keypass client-password -certreq -file client-request1.pem
-keytool -storetype pkcs12 -keystore ca.pkcs12 -storepass ca-password -alias ca -keypass ca-password -gencert -rfc -validity 99999 -infile client-request1.pem -outfile client-certificate1.pem
-openssl pkcs12 -nocerts -passin pass:client-password -in client1.pkcs12 -passout pass:client-password -out client-private-key1.pem
-
-# Create a "bad" certificate - not signed by a trusted authority
-keytool -storetype pkcs12 -keystore bad-server.pkcs12 -storepass server-password -alias bad-server -keypass server-password -genkey -dname "O=Not Trusted Inc,CN=127.0.0.1" -validity 99999
-openssl pkcs12 -nocerts -passin pass:server-password -in bad-server.pkcs12 -passout pass:server-password -out bad-server-private-key.pem
-openssl pkcs12 -nokeys -passin pass:server-password -in bad-server.pkcs12 -passout pass:server-password -out bad-server-certificate.pem
-
-# Create a server certificate with several alternate names, including a wildcarded common name:
-keytool -ext san=dns:alternate.name.one.com,dns:another.name.com -storetype pkcs12 -keystore server-wc.pkcs12 -storepass server-password -alias server-wc-certificate -keypass server-password -genkeypair -dname "O=Server,CN=*.prefix*.domain.com" -validity 99999
-keytool -ext san=dns:alternate.name.one.com,dns:another.name.com -storetype pkcs12 -keystore server-wc.pkcs12 -storepass server-password -alias server-wc-certificate -keypass server-password -certreq -file server-wc-request.pem
-keytool -ext san=dns:alternate.name.one.com,dns:another.name.com -storetype pkcs12 -keystore ca.pkcs12 -storepass ca-password -alias ca -keypass ca-password -gencert -rfc -validity 99999 -infile server-wc-request.pem -outfile server-wc-certificate.pem
-openssl pkcs12 -nocerts -passin pass:server-password -in server-wc.pkcs12 -passout pass:server-password -out server-wc-private-key.pem
-
-# Create pkcs12 versions of the above certificates (for Windows SChannel)
-# The CA certificate store/DB is created without public keys.
-# Give the "p12" files the same base name so the tests can just change the extension to switch between platforms.
-# These certificates might work for OpenSSL <-> SChannel interop tests, but note that the DH cypher suite
-# overlap is poor between platforms especially for older Windows versions. RSA certificates are better for
-# interop (or PFS-friendly certificates on newer platforms).
-openssl pkcs12 -export -out ca-certificate.p12 -in ca-certificate.pem -name ca-certificate -nokeys -passout pass:
-openssl pkcs12 -export -out server-certificate.p12 -passin pass:server-password -passout pass:server-password -inkey server-private-key.pem -in server-certificate.pem -name server-certificate
-openssl pkcs12 -export -out client-certificate.p12 -passin pass:client-password -passout pass:client-password -inkey client-private-key.pem -in client-certificate.pem -name client-certificate
-openssl pkcs12 -export -out client-certificate1.p12 -passin pass:client-password -passout pass:client-password -inkey client-private-key1.pem -in client-certificate1.pem -name client-certificate1
-openssl pkcs12 -export -out bad-server-certificate.p12 -passin pass:server-password -passout pass:server-password -inkey bad-server-private-key.pem -in bad-server-certificate.pem -name bad-server
-openssl pkcs12 -export -out server-wc-certificate.p12 -passin pass:server-password -passout pass:server-password -inkey server-wc-private-key.pem -in server-wc-certificate.pem -name server-wc-certificate
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/bad-server-certificate.p12
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/bad-server-certificate.p12 b/tests/python/proton_tests/ssl_db/bad-server-certificate.p12
deleted file mode 100644
index 7906831..0000000
Binary files a/tests/python/proton_tests/ssl_db/bad-server-certificate.p12 and /dev/null differ
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/bad-server-certificate.pem
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/bad-server-certificate.pem b/tests/python/proton_tests/ssl_db/bad-server-certificate.pem
deleted file mode 100644
index 0aacfa2..0000000
--- a/tests/python/proton_tests/ssl_db/bad-server-certificate.pem
+++ /dev/null
@@ -1,22 +0,0 @@
-Bag Attributes
- friendlyName: bad-server
- localKeyID: 54 69 6D 65 20 31 35 30 31 37 31 30 38 31 38 32 39 36
-subject=/CN=127.0.0.1/O=Not Trusted Inc
-issuer=/CN=127.0.0.1/O=Not Trusted Inc
------BEGIN CERTIFICATE-----
-MIICuzCCAnmgAwIBAgIELMpW4jALBgcqhkjOOAQDBQAwLjESMBAGA1UEAxMJMTI3
-LjAuMC4xMRgwFgYDVQQKEw9Ob3QgVHJ1c3RlZCBJbmMwIBcNMTcwODAyMjE1MzM4
-WhgPMjI5MTA1MTcyMTUzMzhaMC4xEjAQBgNVBAMTCTEyNy4wLjAuMTEYMBYGA1UE
-ChMPTm90IFRydXN0ZWQgSW5jMIIBuDCCASwGByqGSM44BAEwggEfAoGBAP1/U4Ed
-dRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs
-14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208Ue
-wwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BY
-HPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+Zx
-BxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx
-+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYUAAoGBAK3E
-5j/UaiVHJYAf3DAIl5hjTZcChTp57GjODdfDteHeDh85HFyW0kxmXyhpUdODzAgG
-THhpxy/+Kkd8jmUBVFnU1EXByvGORBfnJkMTkuhmk9veytxlskQ0tQV8gmRNb0Xe
-hie7T9UT8TQJy9mPS74pSuviFSx0Hz0dKGi0eVUYoyEwHzAdBgNVHQ4EFgQUg2PE
-qycdV1oxVaA33ULDrVdSjhkwCwYHKoZIzjgEAwUAAy8AMCwCFGybqSwG3TauRJVw
-XA/xeSxpYbcBAhQ6ylf9XZAvM7tMyQQTcDAkmt+YWQ==
------END CERTIFICATE-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/bad-server-private-key.pem
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/bad-server-private-key.pem b/tests/python/proton_tests/ssl_db/bad-server-private-key.pem
deleted file mode 100644
index 3a30d41..0000000
--- a/tests/python/proton_tests/ssl_db/bad-server-private-key.pem
+++ /dev/null
@@ -1,15 +0,0 @@
-Bag Attributes
- friendlyName: bad-server
- localKeyID: 54 69 6D 65 20 31 35 30 31 37 31 30 38 31 38 32 39 36
-Key Attributes: <No Attributes>
------BEGIN ENCRYPTED PRIVATE KEY-----
-MIIBljBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIqgLLe7iT+1wCAggA
-MBQGCCqGSIb3DQMHBAhg98ZJQMtngwSCAVCdhdOMr+VVTNaIPSy4nSwdRTlXIuRa
-4wPi+07mToJmEtGfpJ4MPjDF9yRptVQI4RoN/RrLl0WX/HNZ5U4JluL0j68+JB1d
-MoeSRiRc+Yd2vxey8reBrvx1m1mB3LXvm38oZVDFrQ9FNGK09EtTLN1rqckr1fxQ
-Imcvb63nu5UZB8WMCVfKqe9Zm9dQlsSlp3M5OCRm296Xsr0eWwe2W1/rJiKMZN7x
-eJMf4pWVrBHoi6VJHAEA7ZvhRfcHkSbyze5ouDpKbMZS9gq38Hs4d+wkxe9x3emx
-6OvppcpBolZhntF1vJXUXMc6D5Pw3mGEsRGwcMJqWCc8XJTkyP0ylNFNyaHaz0oC
-jSWmUu0s5628K+m8nGY4X7msfOddTA16W6mODjE2ddlTqwTFu2CYBk3WbprBRXo0
-ionZQTPTqcM0UR3KyF9CHRZbnQ/d7bk57/w=
------END ENCRYPTED PRIVATE KEY-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/bad-server.pkcs12
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/bad-server.pkcs12 b/tests/python/proton_tests/ssl_db/bad-server.pkcs12
deleted file mode 100644
index dea2143..0000000
Binary files a/tests/python/proton_tests/ssl_db/bad-server.pkcs12 and /dev/null differ
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/ca-certificate.p12
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/ca-certificate.p12 b/tests/python/proton_tests/ssl_db/ca-certificate.p12
deleted file mode 100644
index 767b24d..0000000
Binary files a/tests/python/proton_tests/ssl_db/ca-certificate.p12 and /dev/null differ
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/ca-certificate.pem
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/ca-certificate.pem b/tests/python/proton_tests/ssl_db/ca-certificate.pem
deleted file mode 100644
index 1461f25..0000000
--- a/tests/python/proton_tests/ssl_db/ca-certificate.pem
+++ /dev/null
@@ -1,24 +0,0 @@
-Bag Attributes
- friendlyName: ca
- localKeyID: 54 69 6D 65 20 31 35 30 31 37 31 30 38 31 36 34 37 32
-subject=/CN=Trusted.CA.com/O=Trust Me Inc.
-issuer=/CN=Trusted.CA.com/O=Trust Me Inc.
------BEGIN CERTIFICATE-----
-MIIDBDCCAsKgAwIBAgIEBGGY1zALBgcqhkjOOAQDBQAwMTEXMBUGA1UEAxMOVHJ1
-c3RlZC5DQS5jb20xFjAUBgNVBAoTDVRydXN0IE1lIEluYy4wIBcNMTcwODAyMjE1
-MzM2WhgPMjI5MTA1MTcyMTUzMzZaMDExFzAVBgNVBAMTDlRydXN0ZWQuQ0EuY29t
-MRYwFAYDVQQKEw1UcnVzdCBNZSBJbmMuMIIBuDCCASwGByqGSM44BAEwggEfAoGB
-AP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6
-MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E
-+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmC
-ouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeO
-utRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/
-C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYUA
-AoGBALsRT+tH1c+TC78EYtPh+KQ0DosKKtxeSRos4eQ49erdI+tYhzeqN3Ebmeky
-TWfGjjU64PGRFDNGjpf9l7Yo22jk9U5zIFkFp5gP9DVBHrOrh8mdT+/oBhhVHxI5
-rWLqSjI/zXhRzRwueR81p0D3XJlV3g/xlOlWALoRnUWpDAo3o2QwYjASBgNVHRMB
-Af8ECDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAOBgNV
-HQ8BAf8EBAMCAoQwHQYDVR0OBBYEFLI2ezwilYHGS5MRPMWlifHH+Y5qMAsGByqG
-SM44BAMFAAMvADAsAhRxomjEvDfhe1p+D6KLc0IGjDNgtgIUIZXb0/Fpzy6dpCwe
-Ay+soxvpfMU=
------END CERTIFICATE-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/ca.pkcs12
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/ca.pkcs12 b/tests/python/proton_tests/ssl_db/ca.pkcs12
deleted file mode 100644
index d9ca00c..0000000
Binary files a/tests/python/proton_tests/ssl_db/ca.pkcs12 and /dev/null differ
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/client-certificate.p12
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/client-certificate.p12 b/tests/python/proton_tests/ssl_db/client-certificate.p12
deleted file mode 100644
index 82271f9..0000000
Binary files a/tests/python/proton_tests/ssl_db/client-certificate.p12 and /dev/null differ
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/client-certificate.pem
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/client-certificate.pem b/tests/python/proton_tests/ssl_db/client-certificate.pem
deleted file mode 100644
index 5b4aa86..0000000
--- a/tests/python/proton_tests/ssl_db/client-certificate.pem
+++ /dev/null
@@ -1,18 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIC1jCCApOgAwIBAgIEeg2f8DALBgcqhkjOOAQDBQAwMTEXMBUGA1UEAxMOVHJ1
-c3RlZC5DQS5jb20xFjAUBgNVBAoTDVRydXN0IE1lIEluYy4wIBcNMTcwODAyMjE1
-MzM3WhgPMjI5MTA1MTcyMTUzMzdaMCUxEjAQBgNVBAMTCTEyNy4wLjAuMTEPMA0G
-A1UEChMGQ2xpZW50MIIBtzCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9K
-nC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00
-b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNa
-FpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA
-9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJ
-FnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7
-zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQAAoGAJ3g1ohpHgoxH
-3Yj0SIfiPcUaM5FIszemFwQ2FZoG/J7MiVIw442JheTR/iEB3LYheHBp7ToqhaMY
-NYidcxxUzgZJs3worXqAuUgDdbDcW6AjQ4olyGVt7sX9OL2amMq9BFCIt7SlyDKW
-8Accx46H+8BffMdCu56yw5WQtZ3cPD2jQjBAMB8GA1UdIwQYMBaAFLI2ezwilYHG
-S5MRPMWlifHH+Y5qMB0GA1UdDgQWBBQg7FbClmtrSAHA9lR8E7uexl5p1jALBgcq
-hkjOOAQDBQADMAAwLQIVAIpUbUYyA3DisZyENQwcN0rDQ+FyAhRPcfg9Slb6MfO4
-SBFqOiesk+cpqw==
------END CERTIFICATE-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/client-certificate1.p12
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/client-certificate1.p12 b/tests/python/proton_tests/ssl_db/client-certificate1.p12
deleted file mode 100644
index d35f88f..0000000
Binary files a/tests/python/proton_tests/ssl_db/client-certificate1.p12 and /dev/null differ
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/client-certificate1.pem
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/client-certificate1.pem b/tests/python/proton_tests/ssl_db/client-certificate1.pem
deleted file mode 100644
index f4549a4..0000000
--- a/tests/python/proton_tests/ssl_db/client-certificate1.pem
+++ /dev/null
@@ -1,19 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDDDCCAsqgAwIBAgIEBmzTzzALBgcqhkjOOAQDBQAwMTEXMBUGA1UEAxMOVHJ1
-c3RlZC5DQS5jb20xFjAUBgNVBAoTDVRydXN0IE1lIEluYy4wIBcNMTcwODAyMjE1
-MzM4WhgPMjI5MTA1MTcyMTUzMzhaMFwxDDAKBgNVBAsTA0RldjENMAsGA1UEBxME
-Q2l0eTELMAkGA1UECBMCU1QxCzAJBgNVBAYTAlVTMRIwEAYDVQQDEwkxMjcuMC4w
-LjExDzANBgNVBAoTBkNsaWVudDCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQD9f1OB
-HXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEmaUVdQCJR+1k9jVj6v8X1ujD2y5tV
-bNeBO4AdNG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb+DtX58aophUPBPuD9tPF
-HsMCNVQTWhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdgUI8VIwvMspK5gqLrhAvw
-WBz1AoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlXTAs9B4JnUVlXjrrUWU/m
-cQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCjrh4rs6Z1kW6jfwv6ITVi
-8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQBTDv+z0kqA4GEAAKBgHVu
-urVq1FFws/JN+I3yfA2RVmFwlYJID8yyO9lkHBPBDE0dqfFBF6F3nwsCiZF0n/v4
-od6MuuRSplV4kZH0jOOVw7e9cF2RNd/KahsIpm/Oq5aosm6W7KDK/xIwNyW+3DFt
-TGDTOZ6ejVMgGR2rAD+FEp2yycJACQBP1GtTSFXTo0IwQDAfBgNVHSMEGDAWgBSy
-Nns8IpWBxkuTETzFpYnxx/mOajAdBgNVHQ4EFgQUz4cx+zNqsCmWpBU2dw8GHO33
-+eEwCwYHKoZIzjgEAwUAAy8AMCwCFCsfHJPB4Tq6qX5U+DZBc3jmLBiXAhRF17Dz
-fq+AxqyQ9PvTtH3UbFh1hQ==
------END CERTIFICATE-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/client-private-key.pem
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/client-private-key.pem b/tests/python/proton_tests/ssl_db/client-private-key.pem
deleted file mode 100644
index b6256e7..0000000
--- a/tests/python/proton_tests/ssl_db/client-private-key.pem
+++ /dev/null
@@ -1,15 +0,0 @@
-Bag Attributes
- friendlyName: client-certificate
- localKeyID: 54 69 6D 65 20 31 35 30 31 37 31 30 38 31 37 32 33 39
-Key Attributes: <No Attributes>
------BEGIN ENCRYPTED PRIVATE KEY-----
-MIIBljBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIHmVKa1dEtm4CAggA
-MBQGCCqGSIb3DQMHBAgpc0Ay33xL9ASCAVBJ8D5DVRd0d6t3gSvTFBAflpUROv2/
-pQlMLGbGlJIoEPyMIc9/GcgS7U19nMdoJjI1TuT/hGwObualnRRjY6KL5cbK2oUQ
-371yUs6jGIQxtCeb1WgKpA/FKw9jRO7Tg5ztObItPiSQvkOcssfdRJYI1+W+ovj+
-j1BKMkJu197twIChYaz+3ppJzrh3qlqFgdRdE9H04ffWpNaZ6aOIIJHPMuZ8FScu
-bQyvD9JjI+JWJUaCyp/3dxxxVrZ3vu8i6LmrL6Nm9IkJtFMZOfgPkoRLML2DWKqB
-1qLk/Z45/THXDAxrPggFfqMvuctwJmtAGvo3MIbfCi+aewJE6/DjlSHDv6wGvOGB
-T5golvZ5siahHqwmufSQG8ZTsGcpu/jCA5ipIvcTVgWIxscNc2Yx9FDNWVNzUcTy
-ctRX6DS+s7rAy9ISjch4BbAtI7yALFt63eU=
------END ENCRYPTED PRIVATE KEY-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/client-private-key1.pem
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/client-private-key1.pem b/tests/python/proton_tests/ssl_db/client-private-key1.pem
deleted file mode 100644
index 544d2ae..0000000
--- a/tests/python/proton_tests/ssl_db/client-private-key1.pem
+++ /dev/null
@@ -1,15 +0,0 @@
-Bag Attributes
- friendlyName: client-certificate1
- localKeyID: 54 69 6D 65 20 31 35 30 31 37 31 30 38 31 37 37 37 32
-Key Attributes: <No Attributes>
------BEGIN ENCRYPTED PRIVATE KEY-----
-MIIBljBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIg1n9vdGttqoCAggA
-MBQGCCqGSIb3DQMHBAgRjlrRQfGcLQSCAVChui/M+36/e0WzeM79aJV7YZds/OJY
-gprtJ2g5Cxb1L9hymwgxJtOAaRUqLUcfLHcKSxA+MaB+Ij+/8TH+miq0zZ9q0jZV
-BAm56FNgUjW0nPLueTNhWzVVfQU6H9Tj33OuKm1PQo84Af3OPMtE03pvGDPEAPbH
-a72HUgZyI7WTux4wpxfvUEVkT5OXgBHrFlqXiHHCI+9kqBXMCV3oHgZBcO+dqPKS
-rlaTY7xoQWLenB6EQeYopMA2GNUVtzB3y6/nX2z0Yp5oHqKPBNOyFlVmwCrENN1/
-qnrFfzVbnksWLKhg9O+TPsId1UIZVvBh67y5N5IZRrpuE03qd2BScKM/Tn6vkWNB
-Eus74Vba5vw9prauRC45FVgDe2YYYoULYPfhXWSiiWHDNKOBlz3l3hGlZsC8wKe5
-QlV5bVcOTfGIaBkD7SQyfRjMr8SWj4WMw1M=
------END ENCRYPTED PRIVATE KEY-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/client-request.pem
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/client-request.pem b/tests/python/proton_tests/ssl_db/client-request.pem
deleted file mode 100644
index 1265153..0000000
--- a/tests/python/proton_tests/ssl_db/client-request.pem
+++ /dev/null
@@ -1,15 +0,0 @@
------BEGIN NEW CERTIFICATE REQUEST-----
-MIICWTCCAhcCAQAwJTESMBAGA1UEAxMJMTI3LjAuMC4xMQ8wDQYDVQQKEwZDbGll
-bnQwggG3MIIBLAYHKoZIzjgEATCCAR8CgYEA/X9TgR11EilS30qcLuzk5/YRt1I8
-70QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZUKWk
-n5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOuK2HX
-Ku/yIgMZndFIAccCFQCXYFCPFSMLzLKSuYKi64QL8Fgc9QKBgQD34aCF1ps93su8
-q1w2uFe5eZSvu/o66oL5V0wLPQeCZ1FZV4661FlP5nEHEIGAtEkWcSPoTCgWE7fP
-CTKMyKbhPBZ6i1R8jSjgo64eK7OmdZFuo38L+iE1YvH7YnoBJDvMpPG+qFGQiaiD
-3+Fa5Z8GkotmXoB7VSVkAUw7/s9JKgOBhAACgYAneDWiGkeCjEfdiPRIh+I9xRoz
-kUizN6YXBDYVmgb8nsyJUjDjjYmF5NH+IQHctiF4cGntOiqFoxg1iJ1zHFTOBkmz
-fCiteoC5SAN1sNxboCNDiiXIZW3uxf04vZqYyr0EUIi3tKXIMpbwBxzHjof7wF98
-x0K7nrLDlZC1ndw8PaAwMC4GCSqGSIb3DQEJDjEhMB8wHQYDVR0OBBYEFCDsVsKW
-a2tIAcD2VHwTu57GXmnWMAsGByqGSM44BAMFAAMvADAsAhQY5Zy4fQcy/SZOJ2Ix
-cl3/QfimvQIUVvSdet7NKWzMQoBDhlJTdTzJvE8=
------END NEW CERTIFICATE REQUEST-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/client-request1.pem
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/client-request1.pem b/tests/python/proton_tests/ssl_db/client-request1.pem
deleted file mode 100644
index c73275f..0000000
--- a/tests/python/proton_tests/ssl_db/client-request1.pem
+++ /dev/null
@@ -1,16 +0,0 @@
------BEGIN NEW CERTIFICATE REQUEST-----
-MIICkTCCAk4CAQAwXDEMMAoGA1UECxMDRGV2MQ0wCwYDVQQHEwRDaXR5MQswCQYD
-VQQIEwJTVDELMAkGA1UEBhMCVVMxEjAQBgNVBAMTCTEyNy4wLjAuMTEPMA0GA1UE
-ChMGQ2xpZW50MIIBtzCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s
-5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/Jm
-YLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy
-9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+Gg
-hdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj
-6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTx
-vqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQAAoGAdW66tWrUUXCz8k34
-jfJ8DZFWYXCVgkgPzLI72WQcE8EMTR2p8UEXoXefCwKJkXSf+/ih3oy65FKmVXiR
-kfSM45XDt71wXZE138pqGwimb86rlqiybpbsoMr/EjA3Jb7cMW1MYNM5np6NUyAZ
-HasAP4USnbLJwkAJAE/Ua1NIVdOgMDAuBgkqhkiG9w0BCQ4xITAfMB0GA1UdDgQW
-BBTPhzH7M2qwKZakFTZ3DwYc7ff54TALBgcqhkjOOAQDBQADMAAwLQIUFs17HaTm
-vest72/4Caoo1sH39n0CFQCR680PPwr3lZ5jjEOp+n4htQNUvw==
------END NEW CERTIFICATE REQUEST-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/client.pkcs12
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/client.pkcs12 b/tests/python/proton_tests/ssl_db/client.pkcs12
deleted file mode 100644
index 575a551..0000000
Binary files a/tests/python/proton_tests/ssl_db/client.pkcs12 and /dev/null differ
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/client1.pkcs12
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/client1.pkcs12 b/tests/python/proton_tests/ssl_db/client1.pkcs12
deleted file mode 100644
index 0e7c888..0000000
Binary files a/tests/python/proton_tests/ssl_db/client1.pkcs12 and /dev/null differ
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/server-certificate.p12
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/server-certificate.p12 b/tests/python/proton_tests/ssl_db/server-certificate.p12
deleted file mode 100644
index cacfa89..0000000
Binary files a/tests/python/proton_tests/ssl_db/server-certificate.p12 and /dev/null differ
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/server-certificate.pem
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/server-certificate.pem b/tests/python/proton_tests/ssl_db/server-certificate.pem
deleted file mode 100644
index e324df5..0000000
--- a/tests/python/proton_tests/ssl_db/server-certificate.pem
+++ /dev/null
@@ -1,18 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIC5jCCAqSgAwIBAgIEX8z6MDALBgcqhkjOOAQDBQAwMTEXMBUGA1UEAxMOVHJ1
-c3RlZC5DQS5jb20xFjAUBgNVBAoTDVRydXN0IE1lIEluYy4wIBcNMTcwODAyMjE1
-MzM3WhgPMjI5MTA1MTcyMTUzMzdaMDUxIjAgBgNVBAMTGUExLkdvb2QuU2VydmVy
-LmRvbWFpbi5jb20xDzANBgNVBAoTBlNlcnZlcjCCAbgwggEsBgcqhkjOOAQBMIIB
-HwKBgQD9f1OBHXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEmaUVdQCJR+1k9jVj6
-v8X1ujD2y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb+DtX58ao
-phUPBPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdgUI8VIwvM
-spK5gqLrhAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlXTAs9B4Jn
-UVlXjrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCjrh4rs6Z1
-kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQBTDv+z0kq
-A4GFAAKBgQCERpy6RrkNHpgXT/uL9gN/IgwY7kp3Iwzr1lrqo+HqmydE+Cz9uqPH
-VyxjX7nHVrdwl7xgsoki3QyoKcrZfTL1oS79kodWG7t6CyOtj2L3KGMUdIlqWepZ
-wzCKTWrb07VjpqhMh0Qh8+IqEmvfC/4UVOec9alX0NO/ckDbIBhITqNCMEAwHwYD
-VR0jBBgwFoAUsjZ7PCKVgcZLkxE8xaWJ8cf5jmowHQYDVR0OBBYEFBhEDdcBRqn5
-wFEbAad559yrQPE7MAsGByqGSM44BAMFAAMvADAsAhRuMRxWMKxy3USjfSFn47H4
-Z5VIHgIUB2i6+RQi7dHOEQYKKmxdQvAPA9M=
------END CERTIFICATE-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/server-private-key.pem
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/server-private-key.pem b/tests/python/proton_tests/ssl_db/server-private-key.pem
deleted file mode 100644
index e68a39d..0000000
--- a/tests/python/proton_tests/ssl_db/server-private-key.pem
+++ /dev/null
@@ -1,15 +0,0 @@
-Bag Attributes
- friendlyName: server-certificate
- localKeyID: 54 69 6D 65 20 31 35 30 31 37 31 30 38 31 36 36 35 36
-Key Attributes: <No Attributes>
------BEGIN ENCRYPTED PRIVATE KEY-----
-MIIBljBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI6jwDH/9bZYMCAggA
-MBQGCCqGSIb3DQMHBAgbIQ8UrRfmAgSCAVDejPh9sT2PMvDjjzXG6xpSmBPNZRiz
-f2k2a9EaI8L4xadveiZTzOpk2C/nltMCNY2Vwf/LMtbvcLiadBRWM/4Uf5fvL/94
-zlKE77wPSWK1R+btZm0KIaA+EPAvnIGcjHlcSU58eQexwVlMXJ9pdeHm9KWbV1D+
-PjrlJ+SDq7OSGprTCz9r+gQ7Fy2Oe9OKc92tE29QD2AZXtSodvY9CosXCx4cqXr3
-ey+HXmVXJohsL89NycL80TvkxppqZ1hT3DZMkrFg2jFPz505rzE48y62FMoKNCjQ
-6HXvsniWYXf7ipr+A4/diSSMBr/zmA+H+ZHKlNO8FJqZ8eI1eqRO+PjO1VV9bbG0
-lYoeoFu0Y1xw6V2jLYnFF1mTCC6kegl6kruvnwO7Oy+6kPEvDrejuI6uozW2etej
-cBq1lUK5QNKSoaB7Qw+2qlyFg/KFwXXDBqk=
------END ENCRYPTED PRIVATE KEY-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/server-request.pem
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/server-request.pem b/tests/python/proton_tests/ssl_db/server-request.pem
deleted file mode 100644
index da57b89..0000000
--- a/tests/python/proton_tests/ssl_db/server-request.pem
+++ /dev/null
@@ -1,15 +0,0 @@
------BEGIN NEW CERTIFICATE REQUEST-----
-MIICazCCAigCAQAwNTEiMCAGA1UEAxMZQTEuR29vZC5TZXJ2ZXIuZG9tYWluLmNv
-bTEPMA0GA1UEChMGU2VydmVyMIIBuDCCASwGByqGSM44BAEwggEfAoGBAP1/U4Ed
-dRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs
-14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208Ue
-wwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BY
-HPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+Zx
-BxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx
-+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYUAAoGBAIRG
-nLpGuQ0emBdP+4v2A38iDBjuSncjDOvWWuqj4eqbJ0T4LP26o8dXLGNfucdWt3CX
-vGCyiSLdDKgpytl9MvWhLv2Sh1Ybu3oLI62PYvcoYxR0iWpZ6lnDMIpNatvTtWOm
-qEyHRCHz4ioSa98L/hRU55z1qVfQ079yQNsgGEhOoDAwLgYJKoZIhvcNAQkOMSEw
-HzAdBgNVHQ4EFgQUGEQN1wFGqfnAURsBp3nn3KtA8TswCwYHKoZIzjgEAwUAAzAA
-MC0CFFIXSYKFVq90wR3lH+KCwvL+j0A4AhUAlxeczUtqTQFeGXFsDwIGO+5/uA4=
------END NEW CERTIFICATE REQUEST-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/server-wc-certificate.p12
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/server-wc-certificate.p12 b/tests/python/proton_tests/ssl_db/server-wc-certificate.p12
deleted file mode 100644
index 3f8a53d..0000000
Binary files a/tests/python/proton_tests/ssl_db/server-wc-certificate.p12 and /dev/null differ
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/server-wc-certificate.pem
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/server-wc-certificate.pem b/tests/python/proton_tests/ssl_db/server-wc-certificate.pem
deleted file mode 100644
index f48c6fe..0000000
--- a/tests/python/proton_tests/ssl_db/server-wc-certificate.pem
+++ /dev/null
@@ -1,19 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDFTCCAtOgAwIBAgIEVTK/cTALBgcqhkjOOAQDBQAwMTEXMBUGA1UEAxMOVHJ1
-c3RlZC5DQS5jb20xFjAUBgNVBAoTDVRydXN0IE1lIEluYy4wIBcNMTcwODAyMjE1
-MzM4WhgPMjI5MTA1MTcyMTUzMzhaMDAxHTAbBgNVBAMMFCoucHJlZml4Ki5kb21h
-aW4uY29tMQ8wDQYDVQQKEwZTZXJ2ZXIwggG3MIIBLAYHKoZIzjgEATCCAR8CgYEA
-/X9TgR11EilS30qcLuzk5/YRt1I870QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow
-9subVWzXgTuAHTRv8mZgt2uZUKWkn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7
-g/bTxR7DAjVUE1oWkTL2dfOuK2HXKu/yIgMZndFIAccCFQCXYFCPFSMLzLKSuYKi
-64QL8Fgc9QKBgQD34aCF1ps93su8q1w2uFe5eZSvu/o66oL5V0wLPQeCZ1FZV466
-1FlP5nEHEIGAtEkWcSPoTCgWE7fPCTKMyKbhPBZ6i1R8jSjgo64eK7OmdZFuo38L
-+iE1YvH7YnoBJDvMpPG+qFGQiaiD3+Fa5Z8GkotmXoB7VSVkAUw7/s9JKgOBhAAC
-gYATsU4dSb5vvYkuhnLJPYpiHOEOagLSwwggm8CD4JqA8CC/lzIJBI3LkR7Ve1Mw
-xYiDbQQPaxGsdCxaDuE+rOHmJcCNxum4gIYxeOOGHLa9eezTXLu2s0kBgsWx3I0U
-98lI4E+gRHiU27NXlNiEKvVq3GhzWvKdUqClbtLZ+67gzqN3MHUwHwYDVR0jBBgw
-FoAUsjZ7PCKVgcZLkxE8xaWJ8cf5jmowMwYDVR0RBCwwKoIWYWx0ZXJuYXRlLm5h
-bWUub25lLmNvbYIQYW5vdGhlci5uYW1lLmNvbTAdBgNVHQ4EFgQUas7dEjv/R3ig
-GcCdPRLL5P3HPU8wCwYHKoZIzjgEAwUAAy8AMCwCFFuvuEosI+5a+lSmpEahvhyE
-31WUAhR6+NkSdChlT0v6HmjyhBL1hLZYNA==
------END CERTIFICATE-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/server-wc-private-key.pem
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/server-wc-private-key.pem b/tests/python/proton_tests/ssl_db/server-wc-private-key.pem
deleted file mode 100644
index c4556fb..0000000
--- a/tests/python/proton_tests/ssl_db/server-wc-private-key.pem
+++ /dev/null
@@ -1,15 +0,0 @@
-Bag Attributes
- friendlyName: server-wc-certificate
- localKeyID: 54 69 6D 65 20 31 35 30 31 37 31 30 38 31 38 34 39 33
-Key Attributes: <No Attributes>
------BEGIN ENCRYPTED PRIVATE KEY-----
-MIIBljBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIFt9KwMYb/OQCAggA
-MBQGCCqGSIb3DQMHBAjQ+Hr462sAigSCAVAmqByfn+Ujb9TfpEI0d6mlW7Nyko00
-chzSFz61RVA/twfbLImhYvEo7P+UglcqGc1H3DaysDuMjbiNqgP25lDHO6ndhN7r
-XaeNshI8U3RQfUrhTwcA2pGpHQ6t+TGNKifRuJMbcHxWDNr+Tdod8uUADZt8Ywb+
-WQOqIrByNJryx5i2yZT7FphYrz6N0L5cNKVIirNv9/FOlKiyuzzg5c4NmABkpajE
-ZyT2H1p/qFipz8XeQ7BvFVDWSGn6Jb8vRvcc/swoCNSs8Wukr7tbryie2IbgktES
-gw7mVOw/Wdw6u26Q8Dz1c+eyy1WPuCiubFKUK12Ul0X9KKYCufVvQPoQBsMGikRM
-JcvrMd1cZ60pANJhnrogE6VEYE3NQrPC6SNao0NB+g4CW3tOH6m80H5+yHrMdvjo
-MQNXdlwdNWrCEH6hXJxzuE1qM5Ajc82bfwo=
------END ENCRYPTED PRIVATE KEY-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/server-wc-request.pem
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/server-wc-request.pem b/tests/python/proton_tests/ssl_db/server-wc-request.pem
deleted file mode 100644
index af867f2..0000000
--- a/tests/python/proton_tests/ssl_db/server-wc-request.pem
+++ /dev/null
@@ -1,16 +0,0 @@
------BEGIN NEW CERTIFICATE REQUEST-----
-MIICmTCCAlcCAQAwMDEdMBsGA1UEAwwUKi5wcmVmaXgqLmRvbWFpbi5jb20xDzAN
-BgNVBAoTBlNlcnZlcjCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQD9f1OBHXUSKVLf
-Spwu7OTn9hG3UjzvRADDHj+AtlEmaUVdQCJR+1k9jVj6v8X1ujD2y5tVbNeBO4Ad
-NG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb+DtX58aophUPBPuD9tPFHsMCNVQT
-WhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdgUI8VIwvMspK5gqLrhAvwWBz1AoGB
-APfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlXTAs9B4JnUVlXjrrUWU/mcQcQgYC0
-SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCjrh4rs6Z1kW6jfwv6ITVi8ftiegEk
-O8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQBTDv+z0kqA4GEAAKBgBOxTh1Jvm+9
-iS6Gcsk9imIc4Q5qAtLDCCCbwIPgmoDwIL+XMgkEjcuRHtV7UzDFiINtBA9rEax0
-LFoO4T6s4eYlwI3G6biAhjF444Yctr157NNcu7azSQGCxbHcjRT3yUjgT6BEeJTb
-s1eU2IQq9WrcaHNa8p1SoKVu0tn7ruDOoGUwYwYJKoZIhvcNAQkOMVYwVDAzBgNV
-HREELDAqghZhbHRlcm5hdGUubmFtZS5vbmUuY29tghBhbm90aGVyLm5hbWUuY29t
-MB0GA1UdDgQWBBRqzt0SO/9HeKAZwJ09Esvk/cc9TzALBgcqhkjOOAQDBQADLwAw
-LAIUNn3ravBNvEsgZRjQd4EPPvQ1k9wCFEuakAyAzmt2ZfIKX3ZmTIgNKsvy
------END NEW CERTIFICATE REQUEST-----
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/server-wc.pkcs12
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/server-wc.pkcs12 b/tests/python/proton_tests/ssl_db/server-wc.pkcs12
deleted file mode 100644
index 0ceccbc..0000000
Binary files a/tests/python/proton_tests/ssl_db/server-wc.pkcs12 and /dev/null differ
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/tests/python/proton_tests/ssl_db/server.pkcs12
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/ssl_db/server.pkcs12 b/tests/python/proton_tests/ssl_db/server.pkcs12
deleted file mode 100644
index f3c19e2..0000000
Binary files a/tests/python/proton_tests/ssl_db/server.pkcs12 and /dev/null differ
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[10/11] qpid-proton git commit: PROTON-1885: [python] move
tests/python to python/tests
Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/engine.py
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/engine.py b/python/tests/proton_tests/engine.py
new file mode 100644
index 0000000..d4f5a5d
--- /dev/null
+++ b/python/tests/proton_tests/engine.py
@@ -0,0 +1,2714 @@
+#
+# 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 __future__ import absolute_import
+
+import os, gc
+import sys
+from . import common
+from time import time, sleep
+from proton import *
+from .common import pump, Skipped
+from proton.reactor import Reactor
+
+
+# older versions of gc do not provide the garbage list
+if not hasattr(gc, "garbage"):
+ gc.garbage=[]
+
+# future test areas
+# + different permutations of setup
+# - creating deliveries and calling input/output before opening the session/link
+# + shrinking output_size down to something small? should the engine buffer?
+# + resuming
+# - locally and remotely created deliveries with the same tag
+
+# Jython 2.5 needs this:
+try:
+ bytes()
+except:
+ bytes = str
+
+# and this...
+try:
+ bytearray()
+except:
+ def bytearray(x):
+ return b'\x00' * x
+
+OUTPUT_SIZE = 10*1024
+
+class Test(common.Test):
+
+ def __init__(self, *args):
+ common.Test.__init__(self, *args)
+ self._wires = []
+
+ def connection(self):
+ c1 = Connection()
+ c2 = Connection()
+ t1 = Transport()
+ t1.bind(c1)
+ t2 = Transport()
+ t2.bind(c2)
+ self._wires.append((c1, t1, c2, t2))
+
+ mask1 = 0
+ mask2 = 0
+
+ for cat in ("TRACE_FRM", "TRACE_RAW"):
+ trc = os.environ.get("PN_%s" % cat)
+ if trc and trc.lower() in ("1", "2", "yes", "true"):
+ mask1 = mask1 | getattr(Transport, cat)
+ if trc == "2":
+ mask2 = mask2 | getattr(Transport, cat)
+ t1.trace(mask1)
+ t2.trace(mask2)
+
+ return c1, c2
+
+ def link(self, name, max_frame=None, idle_timeout=None):
+ c1, c2 = self.connection()
+ if max_frame:
+ c1.transport.max_frame_size = max_frame[0]
+ c2.transport.max_frame_size = max_frame[1]
+ if idle_timeout:
+ # idle_timeout in seconds expressed as float
+ c1.transport.idle_timeout = idle_timeout[0]
+ c2.transport.idle_timeout = idle_timeout[1]
+ c1.open()
+ c2.open()
+ ssn1 = c1.session()
+ ssn1.open()
+ self.pump()
+ ssn2 = c2.session_head(Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE)
+ ssn2.open()
+ self.pump()
+ snd = ssn1.sender(name)
+ rcv = ssn2.receiver(name)
+ return snd, rcv
+
+ def cleanup(self):
+ self._wires = []
+
+ def pump(self, buffer_size=OUTPUT_SIZE):
+ for c1, t1, c2, t2 in self._wires:
+ pump(t1, t2, buffer_size)
+
+class ConnectionTest(Test):
+
+ def setUp(self):
+ gc.enable()
+ self.c1, self.c2 = self.connection()
+
+ def cleanup(self):
+ # release resources created by this class
+ super(ConnectionTest, self).cleanup()
+ self.c1 = None
+ self.c2 = None
+
+ def tearDown(self):
+ self.cleanup()
+ gc.collect()
+ assert not gc.garbage
+
+ def test_open_close(self):
+ assert self.c1.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
+ assert self.c2.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
+
+ self.c1.open()
+ self.pump()
+
+ assert self.c1.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT
+ assert self.c2.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE
+
+ self.c2.open()
+ self.pump()
+
+ assert self.c1.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+ assert self.c2.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+
+ self.c1.close()
+ self.pump()
+
+ assert self.c1.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
+ assert self.c2.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED
+
+ self.c2.close()
+ self.pump()
+
+ assert self.c1.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
+ assert self.c2.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
+
+ def test_simultaneous_open_close(self):
+ assert self.c1.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
+ assert self.c2.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
+
+ self.c1.open()
+ self.c2.open()
+
+ self.pump()
+
+ assert self.c1.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+ assert self.c2.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+
+ self.c1.close()
+ self.c2.close()
+
+ self.pump()
+
+ assert self.c1.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
+ assert self.c2.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
+
+ def test_capabilities(self):
+ self.c1.offered_capabilities = Array(UNDESCRIBED, Data.SYMBOL,
+ symbol("O_one"),
+ symbol("O_two"),
+ symbol("O_three"))
+
+ self.c1.desired_capabilities = Array(UNDESCRIBED, Data.SYMBOL,
+ symbol("D_one"),
+ symbol("D_two"),
+ symbol("D_three"))
+ self.c1.open()
+
+ assert self.c2.remote_offered_capabilities is None
+ assert self.c2.remote_desired_capabilities is None
+
+ self.pump()
+
+ assert self.c2.remote_offered_capabilities == self.c1.offered_capabilities, \
+ (self.c2.remote_offered_capabilities, self.c1.offered_capabilities)
+ assert self.c2.remote_desired_capabilities == self.c1.desired_capabilities, \
+ (self.c2.remote_desired_capabilities, self.c1.desired_capabilities)
+
+ def test_condition(self):
+ self.c1.open()
+ self.c2.open()
+ self.pump()
+ assert self.c1.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+ assert self.c2.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+
+ cond = Condition("blah:bleh", "this is a description", {symbol("foo"): "bar"})
+ self.c1.condition = cond
+ self.c1.close()
+
+ self.pump()
+
+ assert self.c1.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
+ assert self.c2.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED
+
+ rcond = self.c2.remote_condition
+ assert rcond == cond, (rcond, cond)
+
+ def test_properties(self, p1={symbol("key"): symbol("value")}, p2=None):
+ self.c1.properties = p1
+ self.c2.properties = p2
+ self.c1.open()
+ self.c2.open()
+ self.pump()
+
+ assert self.c2.remote_properties == p1, (self.c2.remote_properties, p1)
+ assert self.c1.remote_properties == p2, (self.c2.remote_properties, p2)
+
+ # The proton implementation limits channel_max to 32767.
+ # If I set the application's limit lower than that, I should
+ # get my wish. If I set it higher -- not.
+ def test_channel_max_low(self, value=1234):
+ self.c1.transport.channel_max = value
+ self.c1.open()
+ self.pump()
+ assert self.c1.transport.channel_max == value, (self.c1.transport.channel_max, value)
+
+ def test_channel_max_high(self, value=65535):
+ self.c1.transport.channel_max = value
+ self.c1.open()
+ self.pump()
+ assert self.c1.transport.channel_max == 32767, (self.c1.transport.channel_max, value)
+
+ def test_channel_max_raise_and_lower(self):
+ upper_limit = 32767
+
+ # It's OK to lower the max below upper_limit.
+ self.c1.transport.channel_max = 12345
+ assert self.c1.transport.channel_max == 12345
+
+ # But it won't let us raise the limit above PN_IMPL_CHANNEL_MAX.
+ self.c1.transport.channel_max = 65535
+ assert self.c1.transport.channel_max == upper_limit
+
+ # send the OPEN frame
+ self.c1.open()
+ self.pump()
+
+ # Now it's too late to make any change, because
+ # we have already sent the OPEN frame.
+ try:
+ self.c1.transport.channel_max = 666
+ assert False, "expected session exception"
+ except:
+ pass
+
+ assert self.c1.transport.channel_max == upper_limit
+
+
+ # TODO: Currently failing test - PROTON-1759 - skip
+ def test_channel_max_limits_sessions(self):
+ raise Skipped('Test fails - PROTON-1759')
+ # This is an index -- so max number of channels should be 1.
+ self.c1.transport.channel_max = 0
+ self.c1.open()
+ self.c2.open()
+ ssn_0 = self.c2.session()
+ assert ssn_0 != None
+ ssn_0.open()
+ self.pump()
+ try:
+ ssn_1 = self.c2.session()
+ ssn_1.open()
+ self.pump()
+ assert False, "expected session exception"
+ except SessionException:
+ pass
+
+ def test_cleanup(self):
+ self.c1.open()
+ self.c2.open()
+ self.pump()
+ assert self.c1.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+ assert self.c2.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+ t1 = self.c1.transport
+ t2 = self.c2.transport
+ c2 = self.c2
+ self.c1.close()
+ # release all references to C1, except that held by the transport
+ self.cleanup()
+ gc.collect()
+ # transport should flush last state from C1:
+ pump(t1, t2)
+ assert c2.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED
+
+ def test_user_config(self):
+ self.c1.user = "vindaloo"
+ self.c1.password = "secret"
+ self.c1.open()
+ self.pump()
+
+ self.c2.user = "leela"
+ self.c2.password = "trustno1"
+ self.c2.open()
+ self.pump()
+
+ assert self.c1.user == "vindaloo", self.c1.user
+ assert self.c1.password == None, self.c1.password
+ assert self.c2.user == "leela", self.c2.user
+ assert self.c2.password == None, self.c2.password
+
+class SessionTest(Test):
+
+ def setUp(self):
+ gc.enable()
+ self.c1, self.c2 = self.connection()
+ self.ssn = self.c1.session()
+ self.c1.open()
+ self.c2.open()
+
+ def cleanup(self):
+ # release resources created by this class
+ super(SessionTest, self).cleanup()
+ self.c1 = None
+ self.c2 = None
+ self.ssn = None
+
+ def tearDown(self):
+ self.cleanup()
+ gc.collect()
+ assert not gc.garbage
+
+ def test_open_close(self):
+ assert self.ssn.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
+
+ self.ssn.open()
+
+ assert self.ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT
+
+ self.pump()
+
+ assert self.ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT
+
+ ssn = self.c2.session_head(Endpoint.REMOTE_ACTIVE | Endpoint.LOCAL_UNINIT)
+
+ assert ssn != None
+ assert ssn.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE
+ assert self.ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT
+
+ ssn.open()
+
+ assert ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+ assert self.ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT
+
+ self.pump()
+
+ assert ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+ assert self.ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+
+ ssn.close()
+
+ assert ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
+ assert self.ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+
+ self.pump()
+
+ assert ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
+ assert self.ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED
+
+ self.ssn.close()
+
+ assert ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
+ assert self.ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
+
+ self.pump()
+
+ assert ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
+ assert self.ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
+
+ def test_simultaneous_close(self):
+ self.ssn.open()
+ self.pump()
+ ssn = self.c2.session_head(Endpoint.REMOTE_ACTIVE | Endpoint.LOCAL_UNINIT)
+ assert ssn != None
+ ssn.open()
+ self.pump()
+
+ assert self.ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+ assert ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+
+ self.ssn.close()
+ ssn.close()
+
+ assert self.ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
+ assert ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
+
+ self.pump()
+
+ assert self.ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
+ assert ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
+
+ def test_closing_connection(self):
+ self.ssn.open()
+ self.pump()
+ self.c1.close()
+ self.pump()
+ self.ssn.close()
+ self.pump()
+
+ def test_condition(self):
+ self.ssn.open()
+ self.pump()
+ ssn = self.c2.session_head(Endpoint.REMOTE_ACTIVE | Endpoint.LOCAL_UNINIT)
+ assert ssn != None
+ ssn.open()
+ self.pump()
+
+ assert self.ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+ assert ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+
+ cond = Condition("blah:bleh", "this is a description", {symbol("foo"): "bar"})
+ self.ssn.condition = cond
+ self.ssn.close()
+
+ self.pump()
+
+ assert self.ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
+ assert ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED
+
+ rcond = ssn.remote_condition
+ assert rcond == cond, (rcond, cond)
+
+ def test_cleanup(self):
+ snd, rcv = self.link("test-link")
+ snd.open()
+ rcv.open()
+ self.pump()
+ snd_ssn = snd.session
+ rcv_ssn = rcv.session
+ assert rcv_ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+ self.ssn = None
+ snd_ssn.close()
+ snd_ssn.free()
+ del snd_ssn
+ gc.collect()
+ self.pump()
+ assert rcv_ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED
+
+ def test_reopen_on_same_session_without_free(self):
+ """
+ confirm that a link is correctly opened when attaching to a previously
+ closed link *that has not been freed yet* on the same session
+ """
+ self.ssn.open()
+ self.pump()
+
+ ssn2 = self.c2.session_head(Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE)
+ ssn2.open()
+ self.pump()
+ snd = self.ssn.sender("test-link")
+ rcv = ssn2.receiver("test-link")
+
+ assert snd.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
+ assert rcv.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
+
+ snd.open()
+ rcv.open()
+ self.pump()
+
+ assert snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+ assert rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+
+ snd.close()
+ rcv.close()
+ self.pump()
+
+ assert snd.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
+ assert rcv.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
+
+ snd = self.ssn.sender("test-link")
+ rcv = ssn2.receiver("test-link")
+ assert snd.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
+ assert rcv.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
+
+ snd.open()
+ rcv.open()
+ self.pump()
+
+ assert snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+ assert rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+
+ def test_set_get_outgoing_window(self):
+ assert self.ssn.outgoing_window == 2147483647
+
+ self.ssn.outgoing_window = 1024
+ assert self.ssn.outgoing_window == 1024
+
+
+class LinkTest(Test):
+
+ def setUp(self):
+ gc.enable()
+ self.snd, self.rcv = self.link("test-link")
+
+ def cleanup(self):
+ # release resources created by this class
+ super(LinkTest, self).cleanup()
+ self.snd = None
+ self.rcv = None
+
+ def tearDown(self):
+ self.cleanup()
+ gc.collect()
+ assert not gc.garbage, gc.garbage
+
+ def test_open_close(self):
+ assert self.snd.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
+ assert self.rcv.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
+
+ self.snd.open()
+
+ assert self.snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT
+ assert self.rcv.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
+
+ self.pump()
+
+ assert self.snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT
+ assert self.rcv.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE
+
+ self.rcv.open()
+
+ assert self.snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT
+ assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+
+ self.pump()
+
+ assert self.snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+ assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+
+ self.snd.close()
+
+ assert self.snd.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
+ assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+
+ self.pump()
+
+ assert self.snd.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
+ assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED
+
+ self.rcv.close()
+
+ assert self.snd.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
+ assert self.rcv.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
+
+ self.pump()
+
+ assert self.snd.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
+ assert self.rcv.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
+
+ def test_simultaneous_open_close(self):
+ assert self.snd.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
+ assert self.rcv.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT
+
+ self.snd.open()
+ self.rcv.open()
+
+ assert self.snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT
+ assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT
+
+ self.pump()
+
+ assert self.snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+ assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+
+ self.snd.close()
+ self.rcv.close()
+
+ assert self.snd.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
+ assert self.rcv.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
+
+ self.pump()
+
+ assert self.snd.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
+ assert self.rcv.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED
+
+ def test_multiple(self):
+ rcv = self.snd.session.receiver("second-rcv")
+ assert rcv.name == "second-rcv"
+ self.snd.open()
+ rcv.open()
+ self.pump()
+ c2 = self.rcv.session.connection
+ l = c2.link_head(Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE)
+ while l:
+ l.open()
+ l = l.next(Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE)
+ self.pump()
+
+ assert self.snd
+ assert rcv
+ self.snd.close()
+ rcv.close()
+ ssn = rcv.session
+ conn = ssn.connection
+ ssn.close()
+ conn.close()
+ self.pump()
+
+ def test_closing_session(self):
+ self.snd.open()
+ self.rcv.open()
+ ssn1 = self.snd.session
+ self.pump()
+ ssn1.close()
+ self.pump()
+ self.snd.close()
+ self.pump()
+
+ def test_closing_connection(self):
+ self.snd.open()
+ self.rcv.open()
+ ssn1 = self.snd.session
+ c1 = ssn1.connection
+ self.pump()
+ c1.close()
+ self.pump()
+ self.snd.close()
+ self.pump()
+
+ def assertEqualTermini(self, t1, t2):
+ assert t1.type == t2.type, (t1.type, t2.type)
+ assert t1.address == t2.address, (t1.address, t2.address)
+ assert t1.durability == t2.durability, (t1.durability, t2.durability)
+ assert t1.expiry_policy == t2.expiry_policy, (t1.expiry_policy, t2.expiry_policy)
+ assert t1.timeout == t2.timeout, (t1.timeout, t2.timeout)
+ assert t1.dynamic == t2.dynamic, (t1.dynamic, t2.dynamic)
+ for attr in ["properties", "capabilities", "outcomes", "filter"]:
+ d1 = getattr(t1, attr)
+ d2 = getattr(t2, attr)
+ assert d1.format() == d2.format(), (attr, d1.format(), d2.format())
+
+ def _test_source_target(self, config_source, config_target):
+ if config_source is None:
+ self.snd.source.type = Terminus.UNSPECIFIED
+ else:
+ config_source(self.snd.source)
+ if config_target is None:
+ self.snd.target.type = Terminus.UNSPECIFIED
+ else:
+ config_target(self.snd.target)
+ self.snd.open()
+ self.pump()
+ self.assertEqualTermini(self.rcv.remote_source, self.snd.source)
+ self.assertEqualTermini(self.rcv.remote_target, self.snd.target)
+ self.rcv.target.copy(self.rcv.remote_target)
+ self.rcv.source.copy(self.rcv.remote_source)
+ self.rcv.open()
+ self.pump()
+ self.assertEqualTermini(self.snd.remote_target, self.snd.target)
+ self.assertEqualTermini(self.snd.remote_source, self.snd.source)
+
+ def test_source_target(self):
+ self._test_source_target(TerminusConfig(address="source"),
+ TerminusConfig(address="target"))
+
+ def test_source(self):
+ self._test_source_target(TerminusConfig(address="source"), None)
+
+ def test_target(self):
+ self._test_source_target(None, TerminusConfig(address="target"))
+
+ def test_coordinator(self):
+ self._test_source_target(None, TerminusConfig(type=Terminus.COORDINATOR))
+
+ def test_source_target_full(self):
+ self._test_source_target(TerminusConfig(address="source",
+ timeout=3,
+ dist_mode=Terminus.DIST_MODE_MOVE,
+ filter=[("int", 1), ("symbol", "two"), ("string", "three")],
+ capabilities=["one", "two", "three"]),
+ TerminusConfig(address="source",
+ timeout=7,
+ capabilities=[]))
+ def test_distribution_mode(self):
+ self._test_source_target(TerminusConfig(address="source",
+ dist_mode=Terminus.DIST_MODE_COPY),
+ TerminusConfig(address="target"))
+ assert self.rcv.remote_source.distribution_mode == Terminus.DIST_MODE_COPY
+ assert self.rcv.remote_target.distribution_mode == Terminus.DIST_MODE_UNSPECIFIED
+
+ def test_dynamic_link(self):
+ self._test_source_target(TerminusConfig(address=None, dynamic=True), None)
+ assert self.rcv.remote_source.dynamic
+ assert self.rcv.remote_source.address is None
+
+ def test_condition(self):
+ self.snd.open()
+ self.rcv.open()
+ self.pump()
+
+ assert self.snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+ assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+
+ cond = Condition("blah:bleh", "this is a description", {symbol("foo"): "bar"})
+ self.snd.condition = cond
+ self.snd.close()
+
+ self.pump()
+
+ assert self.snd.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE
+ assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED
+
+ rcond = self.rcv.remote_condition
+ assert rcond == cond, (rcond, cond)
+
+ def test_settle_mode(self):
+ self.snd.snd_settle_mode = Link.SND_UNSETTLED
+ assert self.snd.snd_settle_mode == Link.SND_UNSETTLED
+ self.rcv.rcv_settle_mode = Link.RCV_SECOND
+ assert self.rcv.rcv_settle_mode == Link.RCV_SECOND
+
+ assert self.snd.remote_rcv_settle_mode != Link.RCV_SECOND
+ assert self.rcv.remote_snd_settle_mode != Link.SND_UNSETTLED
+
+ self.snd.open()
+ self.rcv.open()
+ self.pump()
+
+ assert self.snd.remote_rcv_settle_mode == Link.RCV_SECOND
+ assert self.rcv.remote_snd_settle_mode == Link.SND_UNSETTLED
+
+ def test_max_message_size(self):
+ assert self.snd.max_message_size == 0
+ assert self.rcv.remote_max_message_size == 0
+ self.snd.max_message_size = 13579
+ self.snd.open()
+ self.rcv.open()
+ self.pump()
+ assert self.rcv.remote_max_message_size == 13579
+
+ def test_cleanup(self):
+ snd, rcv = self.link("test-link")
+ snd.open()
+ rcv.open()
+ self.pump()
+ assert rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+ snd.close()
+ snd.free()
+ del snd
+ gc.collect()
+ self.pump()
+ assert rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED
+
+class TerminusConfig:
+
+ def __init__(self, type=None, address=None, timeout=None, durability=None,
+ filter=None, capabilities=None, dynamic=False, dist_mode=None):
+ self.address = address
+ self.timeout = timeout
+ self.durability = durability
+ self.filter = filter
+ self.capabilities = capabilities
+ self.dynamic = dynamic
+ self.dist_mode = dist_mode
+ self.type = type
+
+ def __call__(self, terminus):
+ if self.type is not None:
+ terminus.type = self.type
+ if self.address is not None:
+ terminus.address = self.address
+ if self.timeout is not None:
+ terminus.timeout = self.timeout
+ if self.durability is not None:
+ terminus.durability = self.durability
+ if self.capabilities is not None:
+ terminus.capabilities.put_array(False, Data.SYMBOL)
+ terminus.capabilities.enter()
+ for c in self.capabilities:
+ terminus.capabilities.put_symbol(c)
+ if self.filter is not None:
+ terminus.filter.put_map()
+ terminus.filter.enter()
+ for (t, v) in self.filter:
+ setter = getattr(terminus.filter, "put_%s" % t)
+ setter(v)
+ if self.dynamic:
+ terminus.dynamic = True
+ if self.dist_mode is not None:
+ terminus.distribution_mode = self.dist_mode
+
+class TransferTest(Test):
+
+ def setUp(self):
+ gc.enable()
+ self.snd, self.rcv = self.link("test-link")
+ self.c1 = self.snd.session.connection
+ self.c2 = self.rcv.session.connection
+ self.snd.open()
+ self.rcv.open()
+ self.pump()
+
+ def cleanup(self):
+ # release resources created by this class
+ super(TransferTest, self).cleanup()
+ self.c1 = None
+ self.c2 = None
+ self.snd = None
+ self.rcv = None
+
+ def tearDown(self):
+ self.cleanup()
+ gc.collect()
+ assert not gc.garbage
+
+ def test_work_queue(self):
+ assert self.c1.work_head is None
+ self.snd.delivery("tag")
+ assert self.c1.work_head is None
+ self.rcv.flow(1)
+ self.pump()
+ d = self.c1.work_head
+ assert d is not None
+ tag = d.tag
+ assert tag == "tag", tag
+ assert d.writable
+
+ n = self.snd.send(b"this is a test")
+ assert self.snd.advance()
+ assert self.c1.work_head is None
+
+ self.pump()
+
+ d = self.c2.work_head
+ assert d.tag == "tag"
+ assert d.readable
+
+ def test_multiframe(self):
+ self.rcv.flow(1)
+ self.snd.delivery("tag")
+ msg = b"this is a test"
+ n = self.snd.send(msg)
+ assert n == len(msg)
+
+ self.pump()
+
+ d = self.rcv.current
+ assert d
+ assert d.tag == "tag", repr(d.tag)
+ assert d.readable
+
+ binary = self.rcv.recv(1024)
+ assert binary == msg, (binary, msg)
+
+ binary = self.rcv.recv(1024)
+ assert binary == b""
+
+ msg = b"this is more"
+ n = self.snd.send(msg)
+ assert n == len(msg)
+ assert self.snd.advance()
+
+ self.pump()
+
+ binary = self.rcv.recv(1024)
+ assert binary == msg, (binary, msg)
+
+ binary = self.rcv.recv(1024)
+ assert binary is None
+
+ def test_disposition(self):
+ self.rcv.flow(1)
+
+ self.pump()
+
+ sd = self.snd.delivery("tag")
+ msg = b"this is a test"
+ n = self.snd.send(msg)
+ assert n == len(msg)
+ assert self.snd.advance()
+
+ self.pump()
+
+ rd = self.rcv.current
+ assert rd is not None
+ assert rd.tag == sd.tag
+ rmsg = self.rcv.recv(1024)
+ assert rmsg == msg
+ rd.update(Delivery.ACCEPTED)
+
+ self.pump()
+
+ rdisp = sd.remote_state
+ ldisp = rd.local_state
+ assert rdisp == ldisp == Delivery.ACCEPTED, (rdisp, ldisp)
+ assert sd.updated
+
+ sd.update(Delivery.ACCEPTED)
+
+ self.pump()
+
+ assert sd.local_state == rd.remote_state == Delivery.ACCEPTED
+ sd.settle()
+
+ def test_delivery_id_ordering(self):
+ self.rcv.flow(1024)
+ self.pump(buffer_size=64*1024)
+
+ #fill up delivery buffer on sender
+ for m in range(1024):
+ sd = self.snd.delivery("tag%s" % m)
+ msg = ("message %s" % m).encode('ascii')
+ n = self.snd.send(msg)
+ assert n == len(msg)
+ assert self.snd.advance()
+
+ self.pump(buffer_size=64*1024)
+
+ #receive a session-windows worth of messages and accept them
+ for m in range(1024):
+ rd = self.rcv.current
+ assert rd is not None, m
+ assert rd.tag == ("tag%s" % m), (rd.tag, m)
+ msg = self.rcv.recv(1024)
+ assert msg == ("message %s" % m).encode('ascii'), (msg, m)
+ rd.update(Delivery.ACCEPTED)
+ rd.settle()
+
+ self.pump(buffer_size=64*1024)
+
+ #add some new deliveries
+ for m in range(1024, 1450):
+ sd = self.snd.delivery("tag%s" % m)
+ msg = ("message %s" % m).encode('ascii')
+ n = self.snd.send(msg)
+ assert n == len(msg)
+ assert self.snd.advance()
+
+ #handle all disposition changes to sent messages
+ d = self.c1.work_head
+ while d:
+ next_d = d.work_next
+ if d.updated:
+ d.update(Delivery.ACCEPTED)
+ d.settle()
+ d = next_d
+
+ #submit some more deliveries
+ for m in range(1450, 1500):
+ sd = self.snd.delivery("tag%s" % m)
+ msg = ("message %s" % m).encode('ascii')
+ n = self.snd.send(msg)
+ assert n == len(msg)
+ assert self.snd.advance()
+
+ self.pump(buffer_size=64*1024)
+ self.rcv.flow(1024)
+ self.pump(buffer_size=64*1024)
+
+ #verify remaining messages can be received and accepted
+ for m in range(1024, 1500):
+ rd = self.rcv.current
+ assert rd is not None, m
+ assert rd.tag == ("tag%s" % m), (rd.tag, m)
+ msg = self.rcv.recv(1024)
+ assert msg == ("message %s" % m).encode('ascii'), (msg, m)
+ rd.update(Delivery.ACCEPTED)
+ rd.settle()
+
+ def test_cleanup(self):
+ self.rcv.flow(10)
+ self.pump()
+
+ for x in range(10):
+ self.snd.delivery("tag%d" % x)
+ msg = b"this is a test"
+ n = self.snd.send(msg)
+ assert n == len(msg)
+ assert self.snd.advance()
+ self.snd.close()
+ self.snd.free()
+ self.snd = None
+ gc.collect()
+
+ self.pump()
+
+ for x in range(10):
+ rd = self.rcv.current
+ assert rd is not None
+ assert rd.tag == "tag%d" % x
+ rmsg = self.rcv.recv(1024)
+ assert self.rcv.advance()
+ assert rmsg == msg
+ # close of snd should've settled:
+ assert rd.settled
+ rd.settle()
+
+class MaxFrameTransferTest(Test):
+
+ def setUp(self):
+ pass
+
+ def cleanup(self):
+ # release resources created by this class
+ super(MaxFrameTransferTest, self).cleanup()
+ self.c1 = None
+ self.c2 = None
+ self.snd = None
+ self.rcv = None
+
+ def tearDown(self):
+ self.cleanup()
+
+ def message(self, size):
+ parts = []
+ for i in range(size):
+ parts.append(str(i))
+ return "/".join(parts)[:size].encode("utf-8")
+
+ def testMinFrame(self):
+ """
+ Configure receiver to support minimum max-frame as defined by AMQP-1.0.
+ Verify transfer of messages larger than 512.
+ """
+ self.snd, self.rcv = self.link("test-link", max_frame=[0,512])
+ self.c1 = self.snd.session.connection
+ self.c2 = self.rcv.session.connection
+ self.snd.open()
+ self.rcv.open()
+ self.pump()
+ assert self.rcv.session.connection.transport.max_frame_size == 512
+ assert self.snd.session.connection.transport.remote_max_frame_size == 512
+
+ self.rcv.flow(1)
+ self.snd.delivery("tag")
+ msg = self.message(513)
+ n = self.snd.send(msg)
+ assert n == len(msg)
+ assert self.snd.advance()
+
+ self.pump()
+
+ binary = self.rcv.recv(513)
+ assert binary == msg
+
+ binary = self.rcv.recv(1024)
+ assert binary == None
+
+ def testOddFrame(self):
+ """
+ Test an odd sized max limit with data that will require multiple frames to
+ be transfered.
+ """
+ self.snd, self.rcv = self.link("test-link", max_frame=[0,521])
+ self.c1 = self.snd.session.connection
+ self.c2 = self.rcv.session.connection
+ self.snd.open()
+ self.rcv.open()
+ self.pump()
+ assert self.rcv.session.connection.transport.max_frame_size == 521
+ assert self.snd.session.connection.transport.remote_max_frame_size == 521
+
+ self.rcv.flow(2)
+ self.snd.delivery("tag")
+ msg = ("X" * 1699).encode('utf-8')
+ n = self.snd.send(msg)
+ assert n == len(msg)
+ assert self.snd.advance()
+
+ self.pump()
+
+ binary = self.rcv.recv(1699)
+ assert binary == msg
+
+ binary = self.rcv.recv(1024)
+ assert binary == None
+
+ self.rcv.advance()
+
+ self.snd.delivery("gat")
+ msg = self.message(1426)
+ n = self.snd.send(msg)
+ assert n == len(msg)
+ assert self.snd.advance()
+
+ self.pump()
+
+ binary = self.rcv.recv(1426)
+ assert binary == msg
+
+ self.pump()
+
+ binary = self.rcv.recv(1024)
+ assert binary == None
+
+ def testSendQueuedMultiFrameMessages(self, sendSingleFrameMsg = False):
+ """
+ Test that multiple queued messages on the same link
+ with multi-frame content are sent correctly. Use an
+ odd max frame size, send enough data to use many.
+ """
+ self.snd, self.rcv = self.link("test-link", max_frame=[0,517])
+ self.c1 = self.snd.session.connection
+ self.c2 = self.rcv.session.connection
+ self.snd.open()
+ self.rcv.open()
+ self.pump()
+ assert self.rcv.session.connection.transport.max_frame_size == 517
+ assert self.snd.session.connection.transport.remote_max_frame_size == 517
+
+ self.rcv.flow(5)
+
+ self.pump()
+
+ # Send a delivery with 5 frames, all bytes as X1234
+ self.snd.delivery("tag")
+ msg = ("X1234" * 425).encode('utf-8')
+ assert 2125 == len(msg)
+ n = self.snd.send(msg)
+ assert n == len(msg)
+ assert self.snd.advance()
+
+ # Send a delivery with 5 frames, all bytes as Y5678
+ self.snd.delivery("tag2")
+ msg2 = ("Y5678" * 425).encode('utf-8')
+ assert 2125 == len(msg2)
+ n = self.snd.send(msg2)
+ assert n == len(msg2)
+ assert self.snd.advance()
+
+ self.pump()
+
+ if sendSingleFrameMsg:
+ # Send a delivery with 1 frame
+ self.snd.delivery("tag3")
+ msg3 = ("Z").encode('utf-8')
+ assert 1 == len(msg3)
+ n = self.snd.send(msg3)
+ assert n == len(msg3)
+ assert self.snd.advance()
+ self.pump()
+
+ binary = self.rcv.recv(5000)
+ self.assertEqual(binary, msg)
+
+ self.rcv.advance()
+
+ binary2 = self.rcv.recv(5000)
+ self.assertEqual(binary2, msg2)
+
+ self.rcv.advance()
+
+ if sendSingleFrameMsg:
+ binary3 = self.rcv.recv(5000)
+ self.assertEqual(binary3, msg3)
+ self.rcv.advance()
+
+ self.pump()
+
+ def testSendQueuedMultiFrameMessagesThenSingleFrameMessage(self):
+ self.testSendQueuedMultiFrameMessages(sendSingleFrameMsg = True)
+
+ def testBigMessage(self):
+ """
+ Test transferring a big message.
+ """
+ self.snd, self.rcv = self.link("test-link")
+ self.c1 = self.snd.session.connection
+ self.c2 = self.rcv.session.connection
+ self.snd.open()
+ self.rcv.open()
+ self.pump()
+
+ self.rcv.flow(2)
+ self.snd.delivery("tag")
+ msg = self.message(1024*256)
+ n = self.snd.send(msg)
+ assert n == len(msg)
+ assert self.snd.advance()
+
+ self.pump()
+
+ binary = self.rcv.recv(1024*256)
+ assert binary == msg
+
+ binary = self.rcv.recv(1024)
+ assert binary == None
+
+
+class IdleTimeoutTest(Test):
+
+ def setUp(self):
+ pass
+
+ def cleanup(self):
+ # release resources created by this class
+ super(IdleTimeoutTest, self).cleanup()
+ self.snd = None
+ self.rcv = None
+ self.c1 = None
+ self.c2 = None
+
+ def tearDown(self):
+ self.cleanup()
+
+ def message(self, size):
+ parts = []
+ for i in range(size):
+ parts.append(str(i))
+ return "/".join(parts)[:size]
+
+ def testGetSet(self):
+ """
+ Verify the configuration and negotiation of the idle timeout.
+ """
+
+ self.snd, self.rcv = self.link("test-link", idle_timeout=[1.0,2.0])
+ self.c1 = self.snd.session.connection
+ self.c2 = self.rcv.session.connection
+ self.snd.open()
+ self.rcv.open()
+ self.pump()
+ # proton advertises 1/2 the configured timeout to the peer:
+ assert self.rcv.session.connection.transport.idle_timeout == 2.0
+ assert self.rcv.session.connection.transport.remote_idle_timeout == 0.5
+ assert self.snd.session.connection.transport.idle_timeout == 1.0
+ assert self.snd.session.connection.transport.remote_idle_timeout == 1.0
+
+ def testTimeout(self):
+ """
+ Verify the AMQP Connection idle timeout.
+ """
+
+ # snd will timeout the Connection if no frame is received within 1000 ticks
+ self.snd, self.rcv = self.link("test-link", idle_timeout=[1.0,0])
+ self.c1 = self.snd.session.connection
+ self.c2 = self.rcv.session.connection
+ self.snd.open()
+ self.rcv.open()
+ self.pump()
+
+ t_snd = self.snd.session.connection.transport
+ t_rcv = self.rcv.session.connection.transport
+ assert t_rcv.idle_timeout == 0.0
+ # proton advertises 1/2 the timeout (see spec)
+ assert t_rcv.remote_idle_timeout == 0.5
+ assert t_snd.idle_timeout == 1.0
+ assert t_snd.remote_idle_timeout == 0.0
+
+ sndr_frames_in = t_snd.frames_input
+ rcvr_frames_out = t_rcv.frames_output
+
+ # at t+1msec, nothing should happen:
+ clock = 0.001
+ assert t_snd.tick(clock) == 1.001, "deadline for remote timeout"
+ assert t_rcv.tick(clock) == 0.251, "deadline to send keepalive"
+ self.pump()
+ assert sndr_frames_in == t_snd.frames_input, "unexpected received frame"
+
+ # at one tick from expected idle frame send, nothing should happen:
+ clock = 0.250
+ assert t_snd.tick(clock) == 1.001, "deadline for remote timeout"
+ assert t_rcv.tick(clock) == 0.251, "deadline to send keepalive"
+ self.pump()
+ assert sndr_frames_in == t_snd.frames_input, "unexpected received frame"
+
+ # this should cause rcvr to expire and send a keepalive
+ clock = 0.251
+ assert t_snd.tick(clock) == 1.001, "deadline for remote timeout"
+ assert t_rcv.tick(clock) == 0.501, "deadline to send keepalive"
+ self.pump()
+ sndr_frames_in += 1
+ rcvr_frames_out += 1
+ assert sndr_frames_in == t_snd.frames_input, "unexpected received frame"
+ assert rcvr_frames_out == t_rcv.frames_output, "unexpected frame"
+
+ # since a keepalive was received, sndr will rebase its clock against this tick:
+ # and the receiver should not change its deadline
+ clock = 0.498
+ assert t_snd.tick(clock) == 1.498, "deadline for remote timeout"
+ assert t_rcv.tick(clock) == 0.501, "deadline to send keepalive"
+ self.pump()
+ assert sndr_frames_in == t_snd.frames_input, "unexpected received frame"
+
+ # now expire sndr
+ clock = 1.499
+ t_snd.tick(clock)
+ self.pump()
+ assert self.c2.state & Endpoint.REMOTE_CLOSED
+ assert self.c2.remote_condition.name == "amqp:resource-limit-exceeded"
+
+class CreditTest(Test):
+
+ def setUp(self):
+ self.snd, self.rcv = self.link("test-link", max_frame=(16*1024, 16*1024))
+ self.c1 = self.snd.session.connection
+ self.c2 = self.rcv.session.connection
+ self.snd.open()
+ self.rcv.open()
+ self.pump()
+
+ def cleanup(self):
+ # release resources created by this class
+ super(CreditTest, self).cleanup()
+ self.c1 = None
+ self.snd = None
+ self.c2 = None
+ self.rcv2 = None
+ self.snd2 = None
+
+ def tearDown(self):
+ self.cleanup()
+
+ def testCreditSender(self, count=1024):
+ credit = self.snd.credit
+ assert credit == 0, credit
+ self.rcv.flow(10)
+ self.pump()
+ credit = self.snd.credit
+ assert credit == 10, credit
+
+ self.rcv.flow(count)
+ self.pump()
+ credit = self.snd.credit
+ assert credit == 10 + count, credit
+
+ def testCreditReceiver(self):
+ self.rcv.flow(10)
+ self.pump()
+ assert self.rcv.credit == 10, self.rcv.credit
+
+ d = self.snd.delivery("tag")
+ assert d
+ assert self.snd.advance()
+ self.pump()
+ assert self.rcv.credit == 10, self.rcv.credit
+ assert self.rcv.queued == 1, self.rcv.queued
+ c = self.rcv.current
+ assert c.tag == "tag", c.tag
+ assert self.rcv.advance()
+ assert self.rcv.credit == 9, self.rcv.credit
+ assert self.rcv.queued == 0, self.rcv.queued
+
+ def _testBufferingOnClose(self, a, b):
+ for i in range(10):
+ d = self.snd.delivery("tag-%s" % i)
+ assert d
+ d.settle()
+ self.pump()
+ assert self.snd.queued == 10
+
+ endpoints = {"connection": (self.c1, self.c2),
+ "session": (self.snd.session, self.rcv.session),
+ "link": (self.snd, self.rcv)}
+
+ local_a, remote_a = endpoints[a]
+ local_b, remote_b = endpoints[b]
+
+ remote_b.close()
+ self.pump()
+ assert local_b.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED
+ local_a.close()
+ self.pump()
+ assert remote_a.state & Endpoint.REMOTE_CLOSED
+ assert self.snd.queued == 10
+
+ def testBufferingOnCloseLinkLink(self):
+ self._testBufferingOnClose("link", "link")
+
+ def testBufferingOnCloseLinkSession(self):
+ self._testBufferingOnClose("link", "session")
+
+ def testBufferingOnCloseLinkConnection(self):
+ self._testBufferingOnClose("link", "connection")
+
+ def testBufferingOnCloseSessionLink(self):
+ self._testBufferingOnClose("session", "link")
+
+ def testBufferingOnCloseSessionSession(self):
+ self._testBufferingOnClose("session", "session")
+
+ def testBufferingOnCloseSessionConnection(self):
+ self._testBufferingOnClose("session", "connection")
+
+ def testBufferingOnCloseConnectionLink(self):
+ self._testBufferingOnClose("connection", "link")
+
+ def testBufferingOnCloseConnectionSession(self):
+ self._testBufferingOnClose("connection", "session")
+
+ def testBufferingOnCloseConnectionConnection(self):
+ self._testBufferingOnClose("connection", "connection")
+
+ def testFullDrain(self):
+ assert self.rcv.credit == 0
+ assert self.snd.credit == 0
+ self.rcv.drain(10)
+ assert self.rcv.draining()
+ assert self.rcv.credit == 10
+ assert self.snd.credit == 0
+ self.pump()
+ assert self.rcv.credit == 10
+ assert self.snd.credit == 10
+ assert self.rcv.draining()
+ self.snd.drained()
+ assert self.rcv.credit == 10
+ assert self.snd.credit == 0
+ assert self.rcv.draining()
+ self.pump()
+ assert self.rcv.credit == 0
+ assert self.snd.credit == 0
+ assert not self.rcv.draining()
+ drained = self.rcv.drained()
+ assert drained == 10, drained
+
+ def testPartialDrain(self):
+ self.rcv.drain(2)
+ assert self.rcv.draining()
+ self.pump()
+
+ d = self.snd.delivery("tag")
+ assert d
+ assert self.snd.advance()
+ self.snd.drained()
+ assert self.rcv.draining()
+ self.pump()
+ assert not self.rcv.draining()
+
+ c = self.rcv.current
+ assert self.rcv.queued == 1, self.rcv.queued
+ assert c.tag == d.tag, c.tag
+ assert self.rcv.advance()
+ assert not self.rcv.current
+ assert self.rcv.credit == 0, self.rcv.credit
+ assert not self.rcv.draining()
+ drained = self.rcv.drained()
+ assert drained == 1, drained
+
+ def testDrainFlow(self):
+ assert self.rcv.credit == 0
+ assert self.snd.credit == 0
+ self.rcv.drain(10)
+ assert self.rcv.credit == 10
+ assert self.snd.credit == 0
+ self.pump()
+ assert self.rcv.credit == 10
+ assert self.snd.credit == 10
+ self.snd.drained()
+ assert self.rcv.credit == 10
+ assert self.snd.credit == 0
+ self.pump()
+ assert self.rcv.credit == 0
+ assert self.snd.credit == 0
+ self.rcv.flow(10)
+ assert self.rcv.credit == 10
+ assert self.snd.credit == 0
+ self.pump()
+ assert self.rcv.credit == 10
+ assert self.snd.credit == 10
+ self.snd.drained()
+ assert self.rcv.credit == 10
+ assert self.snd.credit == 10
+ self.pump()
+ assert self.rcv.credit == 10
+ assert self.snd.credit == 10
+ drained = self.rcv.drained()
+ assert drained == 10, drained
+
+ def testNegative(self):
+ assert self.snd.credit == 0
+ d = self.snd.delivery("tag")
+ assert d
+ assert self.snd.advance()
+ self.pump()
+
+ assert self.rcv.credit == 0
+ assert self.rcv.queued == 0
+
+ self.rcv.flow(1)
+ assert self.rcv.credit == 1
+ assert self.rcv.queued == 0
+ self.pump()
+ assert self.rcv.credit == 1
+ assert self.rcv.queued == 1, self.rcv.queued
+
+ c = self.rcv.current
+ assert c
+ assert c.tag == "tag"
+ assert self.rcv.advance()
+ assert self.rcv.credit == 0
+ assert self.rcv.queued == 0
+
+ def testDrainZero(self):
+ assert self.snd.credit == 0
+ assert self.rcv.credit == 0
+ assert self.rcv.queued == 0
+ drained = self.rcv.drained()
+ assert drained == 0
+
+ self.rcv.flow(10)
+ self.pump()
+ assert self.snd.credit == 10
+ assert self.rcv.credit == 10
+ assert self.rcv.queued == 0
+
+ self.snd.drained()
+ self.pump()
+ assert self.snd.credit == 10
+ assert self.rcv.credit == 10
+ assert self.rcv.queued == 0
+ drained = self.rcv.drained()
+ assert drained == 0
+
+ self.rcv.drain(0)
+ assert self.snd.credit == 10
+ assert self.rcv.credit == 10
+ assert self.rcv.queued == 0
+
+ self.pump()
+
+ assert self.snd.credit == 10
+ assert self.rcv.credit == 10
+ assert self.rcv.queued == 0
+
+ self.snd.drained()
+ assert self.snd.credit == 0
+ assert self.rcv.credit == 10
+ assert self.rcv.queued == 0
+ drained = self.rcv.drained()
+ assert drained == 0
+ self.pump()
+
+ assert self.snd.credit == 0
+ assert self.rcv.credit == 0
+ assert self.rcv.queued == 0
+ drained = self.rcv.drained()
+ assert drained == 10
+
+
+ def testDrainOrder(self):
+ """ Verify drain/drained works regardless of ordering. See PROTON-401
+ """
+ assert self.snd.credit == 0
+ assert self.rcv.credit == 0
+ assert self.rcv.queued == 0
+
+ #self.rcv.session.connection.transport.trace(Transport.TRACE_FRM)
+ #self.snd.session.connection.transport.trace(Transport.TRACE_FRM)
+
+ ## verify that a sender that has reached the drain state will respond
+ ## promptly to a drain issued by the peer.
+ self.rcv.flow(10)
+ self.pump()
+ assert self.snd.credit == 10, self.snd.credit
+ assert self.rcv.credit == 10, self.rcv.credit
+
+ sd = self.snd.delivery("tagA")
+ assert sd
+ n = self.snd.send(b"A")
+ assert n == 1
+ self.pump()
+ self.snd.advance()
+
+ # done sending, so signal that we are drained:
+ self.snd.drained()
+ self.pump()
+ assert self.snd.credit == 9, self.snd.credit
+ assert self.rcv.credit == 10, self.rcv.credit
+
+ self.rcv.drain(0)
+ self.pump()
+ assert self.snd.credit == 9, self.snd.credit
+ assert self.rcv.credit == 10, self.rcv.credit
+
+ data = self.rcv.recv(10)
+ assert data == b"A", data
+ self.rcv.advance()
+ self.pump()
+ assert self.snd.credit == 9, self.snd.credit
+ assert self.rcv.credit == 9, self.rcv.credit
+
+ self.snd.drained()
+ self.pump()
+ assert self.snd.credit == 0, self.snd.credit
+ assert self.rcv.credit == 0, self.rcv.credit
+
+ # verify that a drain requested by the peer is not "acknowledged" until
+ # after the sender has completed sending its pending messages
+
+ self.rcv.flow(10)
+ self.pump()
+ assert self.snd.credit == 10, self.snd.credit
+ assert self.rcv.credit == 10, self.rcv.credit
+
+ sd = self.snd.delivery("tagB")
+ assert sd
+ n = self.snd.send(b"B")
+ assert n == 1
+ self.snd.advance()
+ self.pump()
+ assert self.snd.credit == 9, self.snd.credit
+ assert self.rcv.credit == 10, self.rcv.credit
+
+ self.rcv.drain(0)
+ self.pump()
+ assert self.snd.credit == 9, self.snd.credit
+ assert self.rcv.credit == 10, self.rcv.credit
+
+ sd = self.snd.delivery("tagC")
+ assert sd
+ n = self.snd.send(b"C")
+ assert n == 1
+ self.snd.advance()
+ self.pump()
+ assert self.snd.credit == 8, self.snd.credit
+ assert self.rcv.credit == 10, self.rcv.credit
+
+ # now that the sender has finished sending everything, it can signal
+ # drained
+ self.snd.drained()
+ self.pump()
+ assert self.snd.credit == 0, self.snd.credit
+ assert self.rcv.credit == 2, self.rcv.credit
+
+ data = self.rcv.recv(10)
+ assert data == b"B", data
+ self.rcv.advance()
+ data = self.rcv.recv(10)
+ assert data == b"C", data
+ self.rcv.advance()
+ self.pump()
+ assert self.snd.credit == 0, self.snd.credit
+ assert self.rcv.credit == 0, self.rcv.credit
+
+
+ def testPushback(self, count=10):
+ assert self.snd.credit == 0
+ assert self.rcv.credit == 0
+
+ self.rcv.flow(count)
+ self.pump()
+
+ for i in range(count):
+ d = self.snd.delivery("tag%s" % i)
+ assert d
+ self.snd.advance()
+
+ assert self.snd.queued == count
+ assert self.rcv.queued == 0
+ self.pump()
+ assert self.snd.queued == 0
+ assert self.rcv.queued == count
+
+ d = self.snd.delivery("extra")
+ self.snd.advance()
+
+ assert self.snd.queued == 1
+ assert self.rcv.queued == count
+ self.pump()
+ assert self.snd.queued == 1
+ assert self.rcv.queued == count
+
+ def testHeadOfLineBlocking(self):
+ self.snd2 = self.snd.session.sender("link-2")
+ self.rcv2 = self.rcv.session.receiver("link-2")
+ self.snd2.open()
+ self.rcv2.open()
+ self.pump()
+ assert self.snd2.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+ assert self.rcv2.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE
+
+ self.rcv.flow(5)
+ self.rcv2.flow(10)
+ self.pump()
+
+ assert self.snd.credit == 5
+ assert self.snd2.credit == 10
+
+ for i in range(10):
+ tag = "test %d" % i
+ self.snd.delivery( tag )
+ self.snd.send( tag.encode("ascii") )
+ assert self.snd.advance()
+ self.snd2.delivery( tag )
+ self.snd2.send( tag.encode("ascii") )
+ assert self.snd2.advance()
+
+ self.pump()
+
+ for i in range(5):
+ b = self.rcv.recv( 512 )
+ assert self.rcv.advance()
+ b = self.rcv2.recv( 512 )
+ assert self.rcv2.advance()
+
+ for i in range(5):
+ b = self.rcv2.recv( 512 )
+ assert self.rcv2.advance()
+
+
+
+class SessionCreditTest(Test):
+
+ def tearDown(self):
+ self.cleanup()
+
+ def testBuffering(self, count=32, size=1024, capacity=16*1024, max_frame=1024):
+ snd, rcv = self.link("test-link", max_frame=(max_frame, max_frame))
+ rcv.session.incoming_capacity = capacity
+ snd.open()
+ rcv.open()
+ rcv.flow(count)
+ self.pump()
+
+ assert count > 0
+
+ total_bytes = count * size
+
+ assert snd.session.outgoing_bytes == 0, snd.session.outgoing_bytes
+ assert rcv.session.incoming_bytes == 0, rcv.session.incoming_bytes
+ assert snd.queued == 0, snd.queued
+ assert rcv.queued == 0, rcv.queued
+
+ data = bytes(bytearray(size))
+ idx = 0
+ while snd.credit:
+ d = snd.delivery("tag%s" % idx)
+ assert d
+ n = snd.send(data)
+ assert n == size, (n, size)
+ assert snd.advance()
+ self.pump()
+ idx += 1
+
+ assert idx == count, (idx, count)
+
+ assert snd.session.outgoing_bytes < total_bytes, (snd.session.outgoing_bytes, total_bytes)
+ assert rcv.session.incoming_bytes < capacity, (rcv.session.incoming_bytes, capacity)
+ assert snd.session.outgoing_bytes + rcv.session.incoming_bytes == total_bytes, \
+ (snd.session.outgoing_bytes, rcv.session.incoming_bytes, total_bytes)
+ if snd.session.outgoing_bytes > 0:
+ available = rcv.session.incoming_capacity - rcv.session.incoming_bytes
+ assert available < max_frame, (available, max_frame)
+
+ for i in range(count):
+ d = rcv.current
+ assert d, i
+ pending = d.pending
+ before = rcv.session.incoming_bytes
+ assert rcv.advance()
+ after = rcv.session.incoming_bytes
+ assert before - after == pending, (before, after, pending)
+ snd_before = snd.session.incoming_bytes
+ self.pump()
+ snd_after = snd.session.incoming_bytes
+
+ assert rcv.session.incoming_bytes < capacity
+ if snd_before > 0:
+ assert capacity - after <= max_frame
+ assert snd_before > snd_after
+ if snd_after > 0:
+ available = rcv.session.incoming_capacity - rcv.session.incoming_bytes
+ assert available < max_frame, available
+
+ def testBufferingSize16(self):
+ self.testBuffering(size=16)
+
+ def testBufferingSize256(self):
+ self.testBuffering(size=256)
+
+ def testBufferingSize512(self):
+ self.testBuffering(size=512)
+
+ def testBufferingSize2048(self):
+ self.testBuffering(size=2048)
+
+ def testBufferingSize1025(self):
+ self.testBuffering(size=1025)
+
+ def testBufferingSize1023(self):
+ self.testBuffering(size=1023)
+
+ def testBufferingSize989(self):
+ self.testBuffering(size=989)
+
+ def testBufferingSize1059(self):
+ self.testBuffering(size=1059)
+
+ def testCreditWithBuffering(self):
+ snd, rcv = self.link("test-link", max_frame=(1024, 1024))
+ rcv.session.incoming_capacity = 64*1024
+ snd.open()
+ rcv.open()
+ rcv.flow(128)
+ self.pump()
+
+ assert snd.credit == 128, snd.credit
+ assert rcv.queued == 0, rcv.queued
+
+ idx = 0
+ while snd.credit:
+ d = snd.delivery("tag%s" % idx)
+ snd.send(("x"*1024).encode('ascii'))
+ assert d
+ assert snd.advance()
+ self.pump()
+ idx += 1
+
+ assert idx == 128, idx
+ assert rcv.queued < 128, rcv.queued
+
+ rcv.flow(1)
+ self.pump()
+ assert snd.credit == 1, snd.credit
+
+class SettlementTest(Test):
+
+ def setUp(self):
+ self.snd, self.rcv = self.link("test-link")
+ self.c1 = self.snd.session.connection
+ self.c2 = self.rcv.session.connection
+ self.snd.open()
+ self.rcv.open()
+ self.pump()
+
+ def cleanup(self):
+ # release resources created by this class
+ super(SettlementTest, self).cleanup()
+ self.c1 = None
+ self.snd = None
+ self.c2 = None
+ self.rcv2 = None
+ self.snd2 = None
+
+ def tearDown(self):
+ self.cleanup()
+
+ def testSettleCurrent(self):
+ self.rcv.flow(10)
+ self.pump()
+
+ assert self.snd.credit == 10, self.snd.credit
+ d = self.snd.delivery("tag")
+ e = self.snd.delivery("tag2")
+ assert d
+ assert e
+ c = self.snd.current
+ assert c.tag == "tag", c.tag
+ c.settle()
+ c = self.snd.current
+ assert c.tag == "tag2", c.tag
+ c.settle()
+ c = self.snd.current
+ assert not c
+ self.pump()
+
+ c = self.rcv.current
+ assert c
+ assert c.tag == "tag", c.tag
+ assert c.settled
+ c.settle()
+ c = self.rcv.current
+ assert c
+ assert c.tag == "tag2", c.tag
+ assert c.settled
+ c.settle()
+ c = self.rcv.current
+ assert not c
+
+ def testUnsettled(self):
+ self.rcv.flow(10)
+ self.pump()
+
+ assert self.snd.unsettled == 0, self.snd.unsettled
+ assert self.rcv.unsettled == 0, self.rcv.unsettled
+
+ d = self.snd.delivery("tag")
+ assert d
+ assert self.snd.unsettled == 1, self.snd.unsettled
+ assert self.rcv.unsettled == 0, self.rcv.unsettled
+ assert self.snd.advance()
+ self.pump()
+
+ assert self.snd.unsettled == 1, self.snd.unsettled
+ assert self.rcv.unsettled == 1, self.rcv.unsettled
+
+ c = self.rcv.current
+ assert c
+ c.settle()
+
+ assert self.snd.unsettled == 1, self.snd.unsettled
+ assert self.rcv.unsettled == 0, self.rcv.unsettled
+
+ def testMultipleUnsettled(self, count=1024, size=1024):
+ self.rcv.flow(count)
+ self.pump()
+
+ assert self.snd.unsettled == 0, self.snd.unsettled
+ assert self.rcv.unsettled == 0, self.rcv.unsettled
+
+ unsettled = []
+
+ for i in range(count):
+ sd = self.snd.delivery("tag%s" % i)
+ assert sd
+ n = self.snd.send(("x"*size).encode('ascii'))
+ assert n == size, n
+ assert self.snd.advance()
+ self.pump()
+
+ rd = self.rcv.current
+ assert rd, "did not receive delivery %s" % i
+ n = rd.pending
+ b = self.rcv.recv(n)
+ assert len(b) == n, (b, n)
+ rd.update(Delivery.ACCEPTED)
+ assert self.rcv.advance()
+ self.pump()
+ unsettled.append(rd)
+
+ assert self.rcv.unsettled == count
+
+ for rd in unsettled:
+ rd.settle()
+
+ def testMultipleUnsettled2K1K(self):
+ self.testMultipleUnsettled(2048, 1024)
+
+ def testMultipleUnsettled4K1K(self):
+ self.testMultipleUnsettled(4096, 1024)
+
+ def testMultipleUnsettled1K2K(self):
+ self.testMultipleUnsettled(1024, 2048)
+
+ def testMultipleUnsettled2K2K(self):
+ self.testMultipleUnsettled(2048, 2048)
+
+ def testMultipleUnsettled4K2K(self):
+ self.testMultipleUnsettled(4096, 2048)
+
+class PipelineTest(Test):
+
+ def setUp(self):
+ self.c1, self.c2 = self.connection()
+
+ def cleanup(self):
+ # release resources created by this class
+ super(PipelineTest, self).cleanup()
+ self.c1 = None
+ self.c2 = None
+
+ def tearDown(self):
+ self.cleanup()
+
+ def test(self):
+ ssn = self.c1.session()
+ snd = ssn.sender("sender")
+ self.c1.open()
+ ssn.open()
+ snd.open()
+
+ for i in range(10):
+ t = "delivery-%s" % i
+ d = snd.delivery(t)
+ snd.send(t.encode('ascii'))
+ d.settle()
+
+ snd.close()
+ ssn.close()
+ self.c1.close()
+
+ self.pump()
+
+ state = self.c2.state
+ assert state == (Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE), "%x" % state
+ ssn2 = self.c2.session_head(Endpoint.LOCAL_UNINIT)
+ assert ssn2
+ state == ssn2.state
+ assert state == (Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE), "%x" % state
+ rcv = self.c2.link_head(Endpoint.LOCAL_UNINIT)
+ assert rcv
+ state = rcv.state
+ assert state == (Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE), "%x" % state
+
+ self.c2.open()
+ ssn2.open()
+ rcv.open()
+ rcv.flow(10)
+ assert rcv.queued == 0, rcv.queued
+
+ self.pump()
+
+ assert rcv.queued == 10, rcv.queued
+ state = rcv.state
+ assert state == (Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED), "%x" % state
+ state = ssn2.state
+ assert state == (Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED), "%x" % state
+ state = self.c2.state
+ assert state == (Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED), "%x" % state
+
+ for i in range(rcv.queued):
+ d = rcv.current
+ assert d
+ assert d.tag == "delivery-%s" % i
+ d.settle()
+
+ assert rcv.queued == 0, rcv.queued
+
+
+class ServerTest(Test):
+
+ def testKeepalive(self):
+ """ Verify that idle frames are sent to keep a Connection alive
+ """
+ idle_timeout = self.delay
+ server = common.TestServer()
+ server.start()
+
+ class Program:
+
+ def on_reactor_init(self, event):
+ self.conn = event.reactor.connection()
+ self.conn.hostname = "%s:%s" % (server.host, server.port)
+ self.conn.open()
+ self.old_count = None
+ event.reactor.schedule(3 * idle_timeout, self)
+
+ def on_connection_bound(self, event):
+ event.transport.idle_timeout = idle_timeout
+
+ def on_connection_remote_open(self, event):
+ self.old_count = event.transport.frames_input
+
+ def on_timer_task(self, event):
+ assert self.conn.state == (Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE), "Connection terminated"
+ assert self.conn.transport.frames_input > self.old_count, "No idle frames received"
+ self.conn.close()
+
+ Reactor(Program()).run()
+ server.stop()
+
+ def testIdleTimeout(self):
+ """ Verify that a Connection is terminated properly when Idle frames do not
+ arrive in a timely manner.
+ """
+ idle_timeout = self.delay
+ server = common.TestServer(idle_timeout=idle_timeout)
+ server.start()
+
+ class Program:
+
+ def on_reactor_init(self, event):
+ self.conn = event.reactor.connection()
+ self.conn.hostname = "%s:%s" % (server.host, server.port)
+ self.conn.open()
+ self.remote_condition = None
+ self.old_count = None
+ # verify the connection stays up even if we don't explicitly send stuff
+ # wait up to 3x the idle timeout
+ event.reactor.schedule(3 * idle_timeout, self)
+
+ def on_connection_bound(self, event):
+ self.transport = event.transport
+
+ def on_connection_remote_open(self, event):
+ self.old_count = event.transport.frames_output
+
+ def on_connection_remote_close(self, event):
+ assert self.conn.remote_condition
+ assert self.conn.remote_condition.name == "amqp:resource-limit-exceeded"
+ self.remote_condition = self.conn.remote_condition
+
+ def on_timer_task(self, event):
+ assert self.conn.state == (Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE), "Connection terminated"
+ assert self.conn.transport.frames_output > self.old_count, "No idle frames sent"
+
+ # now wait to explicitly cause the other side to expire:
+ suspend_time = 3 * idle_timeout
+ if os.name=="nt":
+ # On windows, the full delay gets too close to the graceful/hard close tipping point
+ suspend_time = 2.5 * idle_timeout
+ sleep(suspend_time)
+
+ p = Program()
+ Reactor(p).run()
+ assert p.remote_condition
+ assert p.remote_condition.name == "amqp:resource-limit-exceeded"
+ server.stop()
+
+class NoValue:
+
+ def __init__(self):
+ pass
+
+ def apply(self, dlv):
+ pass
+
+ def check(self, dlv):
+ assert dlv.data == None
+ assert dlv.section_number == 0
+ assert dlv.section_offset == 0
+ assert dlv.condition == None
+ assert dlv.failed == False
+ assert dlv.undeliverable == False
+ assert dlv.annotations == None
+
+class RejectValue:
+ def __init__(self, condition):
+ self.condition = condition
+
+ def apply(self, dlv):
+ dlv.condition = self.condition
+
+ def check(self, dlv):
+ assert dlv.data == None, dlv.data
+ assert dlv.section_number == 0
+ assert dlv.section_offset == 0
+ assert dlv.condition == self.condition, (dlv.condition, self.condition)
+ assert dlv.failed == False
+ assert dlv.undeliverable == False
+ assert dlv.annotations == None
+
+class ReceivedValue:
+ def __init__(self, section_number, section_offset):
+ self.section_number = section_number
+ self.section_offset = section_offset
+
+ def apply(self, dlv):
+ dlv.section_number = self.section_number
+ dlv.section_offset = self.section_offset
+
+ def check(self, dlv):
+ assert dlv.data == None, dlv.data
+ assert dlv.section_number == self.section_number, (dlv.section_number, self.section_number)
+ assert dlv.section_offset == self.section_offset
+ assert dlv.condition == None
+ assert dlv.failed == False
+ assert dlv.undeliverable == False
+ assert dlv.annotations == None
+
+class ModifiedValue:
+ def __init__(self, failed, undeliverable, annotations):
+ self.failed = failed
+ self.undeliverable = undeliverable
+ self.annotations = annotations
+
+ def apply(self, dlv):
+ dlv.failed = self.failed
+ dlv.undeliverable = self.undeliverable
+ dlv.annotations = self.annotations
+
+ def check(self, dlv):
+ assert dlv.data == None, dlv.data
+ assert dlv.section_number == 0
+ assert dlv.section_offset == 0
+ assert dlv.condition == None
+ assert dlv.failed == self.failed
+ assert dlv.undeliverable == self.undeliverable
+ assert dlv.annotations == self.annotations, (dlv.annotations, self.annotations)
+
+class CustomValue:
+ def __init__(self, data):
+ self.data = data
+
+ def apply(self, dlv):
+ dlv.data = self.data
+
+ def check(self, dlv):
+ assert dlv.data == self.data, (dlv.data, self.data)
+ assert dlv.section_number == 0
+ assert dlv.section_offset == 0
+ assert dlv.condition == None
+ assert dlv.failed == False
+ assert dlv.undeliverable == False
+ assert dlv.annotations == None
+
+class DeliveryTest(Test):
+
+ def tearDown(self):
+ self.cleanup()
+
+ def testDisposition(self, count=1, tag="tag%i", type=Delivery.ACCEPTED, value=NoValue()):
+ snd, rcv = self.link("test-link")
+ snd.open()
+ rcv.open()
+
+ snd_deliveries = []
+ for i in range(count):
+ d = snd.delivery(tag % i)
+ snd_deliveries.append(d)
+ snd.advance()
+
+ rcv.flow(count)
+ self.pump()
+
+ rcv_deliveries = []
+ for i in range(count):
+ d = rcv.current
+ assert d.tag == (tag % i)
+ rcv_deliveries.append(d)
+ rcv.advance()
+
+ for d in rcv_deliveries:
+ value.apply(d.local)
+ d.update(type)
+
+ self.pump()
+
+ for d in snd_deliveries:
+ assert d.remote_state == type
+ assert d.remote.type == type
+ value.check(d.remote)
+ value.apply(d.local)
+ d.update(type)
+
+ self.pump()
+
+ for d in rcv_deliveries:
+ assert d.remote_state == type
+ assert d.remote.type == type
+ value.check(d.remote)
+
+ for d in snd_deliveries:
+ d.settle()
+
+ self.pump()
+
+ for d in rcv_deliveries:
+ assert d.settled, d.settled
+ d.settle()
+
+ def testReceived(self):
+ self.testDisposition(type=Disposition.RECEIVED, value=ReceivedValue(1, 2))
+
+ def testRejected(self):
+ self.testDisposition(type=Disposition.REJECTED, value=RejectValue(Condition(symbol("foo"))))
+
+ def testReleased(self):
+ self.testDisposition(type=Disposition.RELEASED)
+
+ def testModified(self):
+ self.testDisposition(type=Disposition.MODIFIED,
+ value=ModifiedValue(failed=True, undeliverable=True,
+ annotations={"key": "value"}))
+
+ def testCustom(self):
+ self.testDisposition(type=0x12345, value=CustomValue([1, 2, 3]))
+
+class CollectorTest(Test):
+
+ def setUp(self):
+ self.collector = Collector()
+
+ def drain(self):
+ result = []
+ while True:
+ e = self.collector.peek()
+ if e:
+ result.append(e)
+ self.collector.pop()
+ else:
+ break
+ return result
+
+ def expect(self, *types):
+ return self.expect_oneof(types)
+
+ def expect_oneof(self, *sequences):
+ events = self.drain()
+ types = tuple([e.type for e in events])
+
+ for alternative in sequences:
+ if types == alternative:
+ if len(events) == 1:
+ return events[0]
+ elif len(events) > 1:
+ return events
+ else:
+ return
+
+ assert False, "actual events %s did not match any of the expected sequences: %s" % (events, sequences)
+
+ def expect_until(self, *types):
+ events = self.drain()
+ etypes = tuple([e.type for e in events[-len(types):]])
+ assert etypes == types, "actual events %s did not end in expect sequence: %s" % (events, types)
+
+class EventTest(CollectorTest):
+
+ def tearDown(self):
+ self.cleanup()
+
+ def testEndpointEvents(self):
+ c1, c2 = self.connection()
+ c1.collect(self.collector)
+ self.expect(Event.CONNECTION_INIT)
+ self.pump()
+ self.expect()
+ c2.open()
+ self.pump()
+ self.expect(Event.CONNECTION_REMOTE_OPEN)
+ self.pump()
+ self.expect()
+
+ ssn = c2.session()
+ snd = ssn.sender("sender")
+ ssn.open()
+ snd.open()
+
+ self.expect()
+ self.pump()
+ self.expect(Event.SESSION_INIT, Event.SESSION_REMOTE_OPEN,
+ Event.LINK_INIT, Event.LINK_REMOTE_OPEN)
+
+ c1.open()
+ ssn2 = c1.session()
+ ssn2.open()
+ rcv = ssn2.receiver("receiver")
+ rcv.open()
+ self.pump()
+ self.expect(Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT,
+ Event.SESSION_INIT, Event.SESSION_LOCAL_OPEN,
+ Event.TRANSPORT, Event.LINK_INIT, Event.LINK_LOCAL_OPEN,
+ Event.TRANSPORT)
+
+ rcv.close()
+ self.expect(Event.LINK_LOCAL_CLOSE, Event.TRANSPORT)
+ self.pump()
+ rcv.free()
+ del rcv
+ self.expect(Event.LINK_FINAL)
+ ssn2.free()
+ del ssn2
+ self.pump()
+ c1.free()
+ c1.transport.unbind()
+ self.expect_oneof((Event.SESSION_FINAL, Event.LINK_FINAL, Event.SESSION_FINAL,
+ Event.CONNECTION_UNBOUND, Event.CONNECTION_FINAL),
+ (Event.CONNECTION_UNBOUND, Event.SESSION_FINAL, Event.LINK_FINAL,
+ Event.SESSION_FINAL, Event.CONNECTION_FINAL))
+
+ def testConnectionINIT_FINAL(self):
+ c = Connection()
+ c.collect(self.collector)
+ self.expect(Event.CONNECTION_INIT)
+ c.free()
+ self.expect(Event.CONNECTION_FINAL)
+
+ def testSessionINIT_FINAL(self):
+ c = Connection()
+ c.collect(self.collector)
+ self.expect(Event.CONNECTION_INIT)
+ s = c.session()
+ self.expect(Event.SESSION_INIT)
+ s.free()
+ self.expect(Event.SESSION_FINAL)
+ c.free()
+ self.expect(Event.CONNECTION_FINAL)
+
+ def testLinkINIT_FINAL(self):
+ c = Connection()
+ c.collect(self.collector)
+ self.expect(Event.CONNECTION_INIT)
+ s = c.session()
+ self.expect(Event.SESSION_INIT)
+ r = s.receiver("asdf")
+ self.expect(Event.LINK_INIT)
+ r.free()
+ self.expect(Event.LINK_FINAL)
+ c.free()
+ self.expect(Event.SESSION_FINAL, Event.CONNECTION_FINAL)
+
+ def testFlowEvents(self):
+ snd, rcv = self.link("test-link")
+ snd.session.connection.collect(self.collector)
+ rcv.open()
+ rcv.flow(10)
+ self.pump()
+ self.expect(Event.CONNECTION_INIT, Event.SESSION_INIT,
+ Event.LINK_INIT, Event.LINK_REMOTE_OPEN, Event.LINK_FLOW)
+ rcv.flow(10)
+ self.pump()
+ self.expect(Event.LINK_FLOW)
+ return snd, rcv
+
+ def testDeliveryEvents(self):
+ snd, rcv = self.link("test-link")
+ rcv.session.connection.collect(self.collector)
+ rcv.open()
+ rcv.flow(10)
+ self.pump()
+ self.expect(Event.CONNECTION_INIT, Event.SESSION_INIT,
+ Event.LINK_INIT, Event.LINK_LOCAL_OPEN, Event.TRANSPORT)
+ snd.delivery("delivery")
+ snd.send(b"Hello World!")
+ snd.advance()
+ self.pump()
+ self.expect()
+ snd.open()
+ self.pump()
+ self.expect(Event.LINK_REMOTE_OPEN, Event.DELIVERY)
+ rcv.session.connection.transport.unbind()
+ rcv.session.connection.free()
+ self.expect(Event.CONNECTION_UNBOUND, Event.TRANSPORT, Event.LINK_FINAL,
+ Event.SESSION_FINAL, Event.CONNECTION_FINAL)
+
+ def testDeliveryEventsDisp(self):
+ snd, rcv = self.testFlowEvents()
+ snd.open()
+ dlv = snd.delivery("delivery")
+ snd.send(b"Hello World!")
+ assert snd.advance()
+ self.expect(Event.LINK_LOCAL_OPEN, Event.TRANSPORT)
+ self.pump()
+ self.expect(Event.LINK_FLOW)
+ rdlv = rcv.current
+ assert rdlv != None
+ assert rdlv.tag == "delivery"
+ rdlv.update(Delivery.ACCEPTED)
+ self.pump()
+ event = self.expect(Event.DELIVERY)
+ assert event.context == dlv, (dlv, event.context)
+
+ def testConnectionBOUND_UNBOUND(self):
+ c = Connection()
+ c.collect(self.collector)
+ self.expect(Event.CONNECTION_INIT)
+ t = Transport()
+ t.bind(c)
+ self.expect(Event.CONNECTION_BOUND)
+ t.unbind()
+ self.expect(Event.CONNECTION_UNBOUND, Event.TRANSPORT)
+
+ def testTransportERROR_CLOSE(self):
+ c = Connection()
+ c.collect(self.collector)
+ self.expect(Event.CONNECTION_INIT)
+ t = Transport()
+ t.bind(c)
+ self.expect(Event.CONNECTION_BOUND)
+ assert t.condition is None
+ t.push(b"asdf")
+ self.expect(Event.TRANSPORT_ERROR, Event.TRANSPORT_TAIL_CLOSED)
+ assert t.condition is not None
+ assert t.condition.name == "amqp:connection:framing-error"
+ assert "AMQP header mismatch" in t.condition.description
+ p = t.pending()
+ assert p > 0
+ t.pop(p)
+ self.expect(Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED)
+
+ def testTransportCLOSED(self):
+ c = Connection()
+ c.collect(self.collector)
+ self.expect(Event.CONNECTION_INIT)
+ t = Transport()
+ t.bind(c)
+ c.open()
+
+ self.expect(Event.CONNECTION_BOUND, Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT)
+
+ c2 = Connection()
+ t2 = Transport()
+ t2.bind(c2)
+ c2.open()
+ c2.close()
+
+ pump(t, t2)
+
+ self.expect(Event.CONNECTION_REMOTE_OPEN, Event.CONNECTION_REMOTE_CLOSE,
+ Event.TRANSPORT_TAIL_CLOSED)
+
+ c.close()
+
+ pump(t, t2)
+
+ self.expect(Event.CONNECTION_LOCAL_CLOSE, Event.TRANSPORT,
+ Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED)
+
+ def testLinkDetach(self):
+ c1 = Connection()
+ c1.collect(self.collector)
+ t1 = Transport()
+ t1.bind(c1)
+ c1.open()
+ s1 = c1.session()
+ s1.open()
+ l1 = s1.sender("asdf")
+ l1.open()
+ l1.detach()
+ self.expect_until(Event.LINK_LOCAL_DETACH, Event.TRANSPORT)
+
+ c2 = Connection()
+ c2.collect(self.collector)
+ t2 = Transport()
+ t2.bind(c2)
+
+ pump(t1, t2)
+
+ self.expect_until(Event.LINK_REMOTE_DETACH)
+
+class PeerTest(CollectorTest):
+
+ def setUp(self):
+ CollectorTest.setUp(self)
+ self.connection = Connection()
+ self.connection.collect(self.collector)
+ self.transport = Transport()
+ self.transport.bind(self.connection)
+ self.peer = Connection()
+ self.peer_transport = Transport()
+ self.peer_transport.bind(self.peer)
+ self.peer_transport.trace(Transport.TRACE_OFF)
+
+ def pump(self):
+ pump(self.transport, self.peer_transport)
+
+class TeardownLeakTest(PeerTest):
+
+ def doLeak(self, local, remote):
+ self.connection.open()
+ self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND,
+ Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT)
+
+ ssn = self.connection.session()
+ ssn.open()
+ self.expect(Event.SESSION_INIT, Event.SESSION_LOCAL_OPEN, Event.TRANSPORT)
+
+ snd = ssn.sender("sender")
+ snd.open()
+ self.expect(Event.LINK_INIT, Event.LINK_LOCAL_OPEN, Event.TRANSPORT)
+
+
+ self.pump()
+
+ self.peer.open()
+ self.peer.session_head(0).open()
+ self.peer.link_head(0).open()
+
+ self.pump()
+ self.expect_oneof((Event.CONNECTION_REMOTE_OPEN, Event.SESSION_REMOTE_OPEN,
+ Event.LINK_REMOTE_OPEN, Event.LINK_FLOW),
+ (Event.CONNECTION_REMOTE_OPEN, Event.SESSION_REMOTE_OPEN,
+ Event.LINK_REMOTE_OPEN))
+
+ if local:
+ snd.close() # ha!!
+ self.expect(Event.LINK_LOCAL_CLOSE, Event.TRANSPORT)
+ ssn.close()
+ self.expect(Event.SESSION_LOCAL_CLOSE, Event.TRANSPORT)
+ self.connection.close()
+ self.expect(Event.CONNECTION_LOCAL_CLOSE, Event.TRANSPORT)
+
+ if remote:
+ self.peer.link_head(0).close() # ha!!
+ self.peer.session_head(0).close()
+ self.peer.close()
+
+ self.pump()
+
+ if remote:
+ self.expect(Event.TRANSPORT_HEAD_CLOSED, Event.LINK_REMOTE_CLOSE,
+ Event.SESSION_REMOTE_CLOSE, Event.CONNECTION_REMOTE_CLOSE,
+ Event.TRANSPORT_TAIL_CLOSED, Event.TRANSPORT_CLOSED)
+ else:
+ self.expect(Event.TRANSPORT_HEAD_CLOSED, Event.SESSION_REMOTE_CLOSE,
+ Event.CONNECTION_REMOTE_CLOSE, Event.TRANSPORT_TAIL_CLOSED,
+ Event.TRANSPORT_CLOSED)
+
+ self.connection.free()
+ self.expect(Event.LINK_FINAL, Event.SESSION_FINAL)
+ self.transport.unbind()
+
+ self.expect(Event.CONNECTION_UNBOUND, Event.CONNECTION_FINAL)
+
+ def testLocalRemoteLeak(self):
+ self.doLeak(True, True)
+
+ def testLocalLeak(self):
+ self.doLeak(True, False)
+
+ def testRemoteLeak(self):
+ self.doLeak(False, True)
+
+ def testLeak(self):
+ self.doLeak(False, False)
+
+class IdleTimeoutEventTest(PeerTest):
+
+ def half_pump(self):
+ p = self.transport.pending()
+ if p>0:
+ self.transport.pop(p)
+
+ def testTimeoutWithZombieServer(self, expectOpenCloseFrames=True):
+ self.transport.idle_timeout = self.delay
+ self.connection.open()
+ self.half_pump()
+ t = time()
+ self.transport.tick(t)
+ self.transport.tick(t + self.delay*4)
+ self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND,
+ Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT,
+ Event.TRANSPORT_ERROR, Event.TRANSPORT_TAIL_CLOSED)
+ assert self.transport.capacity() < 0
+ if expectOpenCloseFrames:
+ assert self.transport.pending() > 0
+ self.half_pump()
+ self.expect(Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED)
+ assert self.transport.pending() < 0
+
+ def testTimeoutWithZombieServerAndSASL(self):
+ sasl = self.transport.sasl()
+ self.testTimeoutWithZombieServer(expectOpenCloseFrames=False)
+
+class DeliverySegFaultTest(Test):
+
+ def testDeliveryAfterUnbind(self):
+ conn = Connection()
+ t = Transport()
+ ssn = conn.session()
+ snd = ssn.sender("sender")
+ dlv = snd.delivery("tag")
+ dlv.settle()
+ del dlv
+ t.bind(conn)
+ t.unbind()
+ dlv = snd.delivery("tag")
+
+class SaslEventTest(CollectorTest):
+
+ def testAnonymousNoInitialResponse(self):
+ conn = Connection()
+ conn.collect(self.collector)
+ transport = Transport(Transport.SERVER)
+ transport.bind(conn)
+ self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND)
+
+ transport.push(b'AMQP\x03\x01\x00\x00\x00\x00\x00 \x02\x01\x00\x00\x00SA'
+ b'\xd0\x00\x00\x00\x10\x00\x00\x00\x02\xa3\tANONYMOUS@'
+ b'AMQP\x00\x01\x00\x00')
+ self.expect(Event.TRANSPORT)
+ for i in range(1024):
+ p = transport.pending()
+ self.drain()
+ p = transport.pending()
+ self.expect()
+
+ def testPipelinedServerReadFirst(self):
+ conn = Connection()
+ conn.collect(self.collector)
+ transport = Transport(Transport.CLIENT)
+ s = transport.sasl()
+ s.allowed_mechs("ANONYMOUS PLAIN")
+ transport.bind(conn)
+ self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND)
+ transport.push(
+ # SASL
+ b'AMQP\x03\x01\x00\x00'
+ # @sasl-mechanisms(64) [sasl-server-mechanisms=@PN_SYMBOL[:ANONYMOUS]]
+ b'\x00\x00\x00\x1c\x02\x01\x00\x00\x00S@\xc0\x0f\x01\xe0\x0c\x01\xa3\tANONYMOUS'
+ # @sasl-outcome(68) [code=0]
+ b'\x00\x00\x00\x10\x02\x01\x00\x00\x00SD\xc0\x03\x01P\x00'
+ # AMQP
+ b'AMQP\x00\x01\x00\x00'
+ )
+ self.expect(Event.TRANSPORT)
+ p = transport.pending()
+ bytes = transport.peek(p)
+ transport.pop(p)
+
+ server = Transport(Transport.SERVER)
+ server.push(bytes)
+ assert s.outcome == SASL.OK
+ assert server.sasl().outcome == SASL.OK
+
+ def testPipelinedServerWriteFirst(self):
+ conn = Connection()
+ conn.collect(self.collector)
+ transport = Transport(Transport.CLIENT)
+ s = transport.sasl()
+ s.allowed_mechs("ANONYMOUS")
+ transport.bind(conn)
+ p = transport.pending()
+ bytes = transport.peek(p)
+ transport.pop(p)
+ self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND)
+ transport.push(
+ # SASL
+ b'AMQP\x03\x01\x00\x00'
+ # @sasl-mechanisms(64) [sasl-server-mechanisms=@PN_SYMBOL[:ANONYMOUS]]
+ b'\x00\x00\x00\x1c\x02\x01\x00\x00\x00S@\xc0\x0f\x01\xe0\x0c\x01\xa3\tANONYMOUS'
+ # @sasl-outcome(68) [code=0]
+ b'\x00\x00\x00\x10\x02\x01\x00\x00\x00SD\xc0\x03\x01P\x00'
+ # AMQP
+ b'AMQP\x00\x01\x00\x00'
+ )
+ self.expect(Event.TRANSPORT)
+ p = transport.pending()
+ bytes = transport.peek(p)
+ transport.pop(p)
+ assert s.outcome == SASL.OK
+ # XXX: the bytes above appear to be correct, but we don't get any
+ # sort of event indicating that the transport is authenticated
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9778eda8/python/tests/proton_tests/handler.py
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/handler.py b/python/tests/proton_tests/handler.py
new file mode 100644
index 0000000..e239bb2
--- /dev/null
+++ b/python/tests/proton_tests/handler.py
@@ -0,0 +1,123 @@
+#
+# 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 __future__ import absolute_import
+
+import os, gc, traceback
+import sys
+from . import common
+from time import time, sleep
+from proton import *
+from .common import pump, Skipped
+from proton.reactor import Reactor
+
+
+CUSTOM = EventType("custom")
+
+class HandlerTest(common.Test):
+ def test_reactorHandlerCycling(self, n=0):
+
+ class CustomHandler(Handler):
+ UNSET = 999999999
+ def __init__(self):
+ self.offset = len(traceback.extract_stack())
+ def on_reactor_init(self, event):
+ self.depth = len(traceback.extract_stack())
+ def reset(self):
+ self.depth = self.UNSET
+ @property
+ def init_depth(self):
+ d = self.depth - self.offset
+ return d
+ custom = CustomHandler()
+
+ reactor = Reactor()
+ reactor.handler = custom
+ for i in range(n):
+ h = reactor.handler
+ reactor.handler = h
+ custom.reset()
+ reactor.run()
+ assert custom.init_depth < 50, "Unexpectedly long traceback for a simple handler"
+
+ def test_reactorHandlerCycling10k(self):
+ self.test_reactorHandlerCycling(10000)
+
+ def test_reactorHandlerCycling100(self):
+ self.test_reactorHandlerCycling(100)
+
+ def do_customEvent(self, reactor_handler, event_root):
+
+ class CustomHandler:
+ did_custom = False
+ did_init = False
+ def __init__(self, *handlers):
+ self.handlers = handlers
+ def on_reactor_init(self, event):
+ self.did_init = True
+ def on_custom(self, event):
+ self.did_custom = True
+
+ class CustomInvoker(CustomHandler):
+ def on_reactor_init(self, event):
+ h = event_root(event)
+ event.dispatch(h, CUSTOM)
+ self.did_init = True
+
+ child = CustomInvoker()
+ root = CustomHandler(child)
+
+ reactor = Reactor()
+
+ reactor_handler(reactor, root)
+ reactor.run()
+ assert root.did_init
+ assert child.did_init
+ assert root.did_custom
+ assert child.did_custom
+
+ def set_root(self, reactor, root):
+ reactor.handler = root
+ def add_root(self, reactor, root):
+ reactor.handler.add(root)
+ def append_root(self, reactor, root):
+ reactor.handler.handlers.append(root)
+
+ def event_root(self, event):
+ return event.root
+
+ def event_reactor_handler(self, event):
+ return event.reactor.handler
+
+ def test_set_handler(self):
+ self.do_customEvent(self.set_root, self.event_reactor_handler)
+
+ def test_add_handler(self):
+ self.do_customEvent(self.add_root, self.event_reactor_handler)
+
+ def test_append_handler(self):
+ self.do_customEvent(self.append_root, self.event_reactor_handler)
+
+ def test_set_root(self):
+ self.do_customEvent(self.set_root, self.event_root)
+
+ def test_add_root(self):
+ self.do_customEvent(self.add_root, self.event_root)
+
+ def test_append_root(self):
+ self.do_customEvent(self.append_root, self.event_root)
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org