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 2016/09/27 16:03:00 UTC
qpid-cpp git commit: QPID-7439: Proton-based library for QMF
management.
Repository: qpid-cpp
Updated Branches:
refs/heads/master 550b62723 -> a3bc7cd63
QPID-7439: Proton-based library for QMF management.
qmf.client is a port of qpidtoolibs to the proton AMQP 1.0 client library.
Project: http://git-wip-us.apache.org/repos/asf/qpid-cpp/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-cpp/commit/a3bc7cd6
Tree: http://git-wip-us.apache.org/repos/asf/qpid-cpp/tree/a3bc7cd6
Diff: http://git-wip-us.apache.org/repos/asf/qpid-cpp/diff/a3bc7cd6
Branch: refs/heads/master
Commit: a3bc7cd6389c24c001570b3501225336e9f7ba88
Parents: 550b627
Author: Alan Conway <ac...@redhat.com>
Authored: Mon Sep 26 17:14:10 2016 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Tue Sep 27 12:00:27 2016 -0400
----------------------------------------------------------------------
management/python/lib/qmf/client.py | 458 +++++++++++++++++++++++++++++++
src/tests/CMakeLists.txt | 1 +
src/tests/qmf_client_tests.py | 99 +++++++
src/tests/run_qmf_client_tests | 34 +++
4 files changed, 592 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-cpp/blob/a3bc7cd6/management/python/lib/qmf/client.py
----------------------------------------------------------------------
diff --git a/management/python/lib/qmf/client.py b/management/python/lib/qmf/client.py
new file mode 100644
index 0000000..bc8fe73
--- /dev/null
+++ b/management/python/lib/qmf/client.py
@@ -0,0 +1,458 @@
+#
+# 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
+#
+
+"""
+AMQP 1.0 QMF client for the Qpid C++ broker.
+
+This client is based on the Qpid-Proton library which only supports AMQP 1.0, it
+is intended for forward-looking projects that want to move to the newer client
+libraries. One important feature is that it does not start background threads,
+which makes it more suitable for environments that may fork.
+"""
+
+from proton import Message
+from proton.utils import BlockingConnection, IncomingMessageHandler
+import threading, struct
+
+class SyncRequestResponse(IncomingMessageHandler):
+ """
+ Implementation of the synchronous request-responce (aka RPC) pattern.
+ @ivar address: Address for all requests, may be None.
+ @ivar connection: Connection for requests and responses.
+ """
+
+ def __init__(self, connection, address=None):
+ """
+ Send requests and receive responses. A single instance can send many requests
+ to the same or different addresses.
+
+ @param connection: A L{BlockingConnection}
+ @param address: Address for all requests.
+ If not specified, each request must have the address property set.
+ Sucessive messages may have different addresses.
+ """
+ super(SyncRequestResponse, self).__init__()
+ self.connection = connection
+ self.address = address
+ self.sender = self.connection.create_sender(self.address)
+ # dynamic=true generates a unique address dynamically for this receiver.
+ # credit=1 because we want to receive 1 response message initially.
+ self.receiver = self.connection.create_receiver(None, dynamic=True, credit=1, handler=self)
+ self.response = None
+ self._cid = 0
+ self.lock = threading.Lock()
+
+ def _next(self):
+ """Get the next correlation ID"""
+ self.lock.acquire()
+ try:
+ self._cid += 1;
+ return struct.pack("L", self._cid)
+ finally:
+ self.lock.release()
+
+ def call(self, request):
+ """
+ Send a request message, wait for and return the response message.
+
+ @param request: A L{proton.Message}. If L{self.address} is not set the
+ L{self.address} must be set and will be used.
+ """
+ return self.wait(self.send(request))
+
+ def send(self, request):
+ """
+ Send a request and return the correlation_id immediately. Use wait() to get the response.
+ @param request: A L{proton.Message}. If L{self.address} is not set the
+ L{self.address} must be set and will be used.
+ """
+ if not self.address and not request.address:
+ raise ValueError("Request message has no address: %s" % request)
+ request.reply_to = self.reply_to
+ request.correlation_id = self._next()
+ self.sender.send(request)
+ return request.correlation_id
+
+ def wait(self, correlation_id):
+ """Wait for and return a single response to a request previously sent with send()"""
+ def wakeup():
+ return self.response and (self.response.correlation_id == correlation_id)
+ self.connection.wait(wakeup, msg="Waiting for response")
+ response = self.response
+ self.response = None # Ready for next response.
+ self.receiver.flow(1) # Set up credit for the next response.
+ return response
+
+ @property
+ def reply_to(self):
+ """Return the dynamic address of our receiver."""
+ return self.receiver.remote_source.address
+
+ def on_message(self, event):
+ """Called when we receive a message for our receiver."""
+ self.response = event.message
+ self.connection.container.yield_() # Wake up the wait() loop to handle the message.
+
+class BrokerAgent(object):
+ """Proxy for a manageable Qpid broker"""
+
+ @staticmethod
+ def connection(url=None, timeout=10, ssl_domain=None, sasl=None):
+ """Return a BlockingConnection suitable for use with a BrokerAgent."""
+ return BlockingConnection(url,
+ timeout=timeout,
+ ssl_domain=ssl_domain,
+ allowed_mechs=str(sasl.mechs) if sasl else None,
+ user=str(sasl.user) if sasl else None,
+ password=str(sasl.password) if sasl else None)
+
+ @staticmethod
+ def connect(url=None, timeout=10, ssl_domain=None, sasl=None):
+ """Return a BrokerAgent connected with the given parameters"""
+ return BrokerAgent(BrokerAgent.connection(url, timeout, ssl_domain, sasl))
+
+ def __init__(self, connection):
+ """
+ Create a management node proxy using the given connection.
+ @param locales: Default list of locales for management operations.
+ @param connection: a L{BlockingConnection} to the management agent.
+ """
+ path = connection.url.path or "qmf.default.direct"
+ self._client = SyncRequestResponse(connection, path)
+
+ def close(self):
+ """Shut down the node"""
+ if self._client:
+ self._client.connection.close()
+ self._client = None
+
+ def __repr__(self):
+ return "%s(%s)"%(self.__class__.__name__, self._client.connection.url)
+
+ def _request(self, opcode, content):
+ props = {'method' : 'request',
+ 'qmf.opcode' : opcode,
+ 'x-amqp-0-10.app-id' : 'qmf2'}
+ return self._client.call(Message(body=content, properties=props, subject="broker"))
+
+ def _method(self, method, arguments=None, addr="org.apache.qpid.broker:broker:amqp-broker"):
+ """
+ Make a L{proton.Message} containining a QMF method request.
+ """
+ content = {'_object_id' : {'_object_name' : addr},
+ '_method_name' : method,
+ '_arguments' : arguments or {}}
+ response = self._request('_method_request', content)
+ if response.properties['qmf.opcode'] == '_exception':
+ raise Exception("management error: %r" % response.body['_values'])
+ if response.properties['qmf.opcode'] != '_method_response':
+ raise Exception("bad response: %r" % response.properties)
+ return response.body['_arguments']
+
+ def _gather(self, response):
+ items = response.body
+ while 'partial' in response.properties:
+ response = self._client.wait()
+ items += self._client.wait(response.correlation_id).body
+ return items
+
+ def _classQuery(self, class_name):
+ query = {'_what' : 'OBJECT', '_schema_id' : {'_class_name' : class_name}}
+ response = self._request('_query_request', query)
+ if response.properties['qmf.opcode'] != '_query_response':
+ raise Exception("bad response")
+ return self._gather(response)
+
+ def _nameQuery(self, object_id):
+ query = {'_what' : 'OBJECT', '_object_id' : {'_object_name' : object_id}}
+ response = self._request('_query_request', query)
+ if response.properties['qmf.opcode'] != '_query_response':
+ raise Exception("bad response")
+ items = self._gather(response)
+ if len(items) == 1:
+ return items[0]
+ return None
+
+ def _getAll(self, cls):
+ return [cls(self, x) for x in self._classQuery(cls.__name__.lower())]
+
+ def _getSingle(self, cls):
+ l = self._getAll(cls)
+ return l and l[0]
+
+ def _get(self, cls, oid):
+ x = self._nameQuery(oid)
+ return x and cls(self, x)
+
+ def getBroker(self): return self._getSingle(Broker)
+ def getCluster(self): return self._getSingle(Cluster)
+ def getHaBroker(self): return self._getSingle(HaBroker)
+ def getAllConnections(self): return self._getAll(Connection)
+ def getConnection(self, oid): return self._get(Connection, "org.apache.qpid.broker:connection:%s" % oid)
+ def getAllSessions(self): return self._getAll(Session)
+ def getSession(self, oid): return self._get(Session, "org.apache.qpid.broker:session:%s" % oid)
+ def getAllSubscriptions(self): return self._getAll(Subscription)
+ def getSubscription(self, oid): return self._get(Subscription, "org.apache.qpid.broker:subscription:%s" % oid)
+ def getAllExchanges(self): return self._getAll(Exchange)
+ def getExchange(self, name): return self._get(Exchange, "org.apache.qpid.broker:exchange:%s" % name)
+ def getAllQueues(self): return self._getAll(Queue)
+ def getQueue(self, name): return self._get(Queue, "org.apache.qpid.broker:queue:%s" % name)
+ def getAllBindings(self): return self._getAll(Binding)
+ def getAllLinks(self): return self._getAll(Link)
+ def getAcl(self): return self._getSingle(Acl)
+ def getMemory(self): return self._getSingle(Memory)
+
+ def echo(self, sequence = 1, body = "Body"):
+ """Request a response to test the path to the management broker"""
+ return self._method('echo', {'sequence' : sequence, 'body' : body})
+
+ def queueMoveMessages(self, srcQueue, destQueue, qty):
+ """Move messages from one queue to another"""
+ self._method("queueMoveMessages", {'srcQueue':srcQueue,'destQueue':destQueue,'qty':qty})
+
+ def queueRedirect(self, sourceQueue, targetQueue):
+ """Enable/disable delivery redirect for indicated queues"""
+ self._method("queueRedirect", {'sourceQueue':sourceQueue,'targetQueue':targetQueue})
+
+ def setLogLevel(self, level):
+ """Set the log level"""
+ self._method("setLogLevel", {'level':level})
+
+ def getLogLevel(self):
+ """Get the log level"""
+ return self._method('getLogLevel')
+
+ def setTimestampConfig(self, receive):
+ """Set the message timestamping configuration"""
+ self._method("setTimestampConfig", {'receive':receive})
+
+ def getTimestampConfig(self):
+ """Get the message timestamping configuration"""
+ return self._method('getTimestampConfig')
+
+ def setLogHiresTimestamp(self, logHires):
+ """Set the high resolution timestamp in logs"""
+ self._method("setLogHiresTimestamp", {'logHires':logHires})
+
+ def getLogHiresTimestamp(self):
+ """Get the high resolution timestamp in logs"""
+ return self._method('getLogHiresTimestamp')
+
+ def addExchange(self, exchange_type, name, options={}, **kwargs):
+ properties = {}
+ properties['exchange-type'] = exchange_type
+ for k,v in options.items():
+ properties[k] = v
+ for k,v in kwargs.items():
+ properties[k] = v
+ args = {'type': 'exchange',
+ 'name': name,
+ 'properties': properties,
+ 'strict': True}
+ self._method('create', args)
+
+ def delExchange(self, name):
+ args = {'type': 'exchange', 'name': name}
+ self._method('delete', args)
+
+ def addQueue(self, name, options={}, **kwargs):
+ properties = options
+ for k,v in kwargs.items():
+ properties[k] = v
+ args = {'type': 'queue',
+ 'name': name,
+ 'properties': properties,
+ 'strict': True}
+ self._method('create', args)
+
+ def delQueue(self, name, if_empty=True, if_unused=True):
+ options = {'if_empty': if_empty,
+ 'if_unused': if_unused}
+ args = {'type': 'queue',
+ 'name': name,
+ 'options': options}
+ self._method('delete', args)
+
+ def bind(self, exchange, queue, key="", options={}, **kwargs):
+ properties = options
+ for k,v in kwargs.items():
+ properties[k] = v
+ args = {'type': 'binding',
+ 'name': "%s/%s/%s" % (exchange, queue, key),
+ 'properties': properties,
+ 'strict': True}
+ self._method('create', args)
+
+ def unbind(self, exchange, queue, key, **kwargs):
+ args = {'type': 'binding',
+ 'name': "%s/%s/%s" % (exchange, queue, key),
+ 'strict': True}
+ self._method('delete', args)
+
+ def reloadAclFile(self):
+ self._method('reloadACLFile', {}, "org.apache.qpid.acl:acl:org.apache.qpid.broker:broker:amqp-broker")
+
+ def acl_lookup(self, userName, action, aclObj, aclObjName, propMap):
+ args = {'userId': userName,
+ 'action': action,
+ 'object': aclObj,
+ 'objectName': aclObjName,
+ 'propertyMap': propMap}
+ return self._method('Lookup', args, "org.apache.qpid.acl:acl:org.apache.qpid.broker:broker:amqp-broker")
+
+ def acl_lookupPublish(self, userName, exchange, key):
+ args = {'userId': userName,
+ 'exchangeName': exchange,
+ 'routingKey': key}
+ return self._method('LookupPublish', args, "org.apache.qpid.acl:acl:org.apache.qpid.broker:broker:amqp-broker")
+
+ def Redirect(self, sourceQueue, targetQueue):
+ args = {'sourceQueue': sourceQueue,
+ 'targetQueue': targetQueue}
+ return self._method('queueRedirect', args, "org.apache.qpid.broker:broker:amqp-broker")
+
+ def create(self, _type, name, properties={}, strict=False):
+ """Create an object of the specified type"""
+ args = {'type': _type,
+ 'name': name,
+ 'properties': properties,
+ 'strict': strict}
+ return self._method('create', args)
+
+ def delete(self, _type, name, options):
+ """Delete an object of the specified type"""
+ args = {'type': _type,
+ 'name': name,
+ 'options': options}
+ return self._method('delete', args)
+
+ def list(self, _type):
+ """List objects of the specified type"""
+ return [i["_values"] for i in self._doClassQuery(_type.lower())]
+
+ def query(self, _type, oid):
+ """Query the current state of an object"""
+ return self._get(self, _type, oid)
+
+
+class BrokerObject(object):
+ def __init__(self, broker, content):
+ self.broker = broker
+ self.content = content
+
+ @property
+ def values(self):
+ return self.content['_values']
+
+ def __getattr__(self, key):
+ return self.values.get(key)
+
+ def getObjectId(self):
+ return self.content['_object_id']['_object_name']
+
+ def getAttributes(self):
+ return self.values
+
+ def getCreateTime(self):
+ return self.content['_create_ts']
+
+ def getDeleteTime(self):
+ return self.content['_delete_ts']
+
+ def getUpdateTime(self):
+ return self.content['_update_ts']
+
+ def update(self):
+ """
+ Reload the property values from the agent.
+ """
+ refreshed = self.broker._get(self.__class__, self.getObjectId())
+ if refreshed:
+ self.content = refreshed.content
+ self.values = self.content['_values']
+ else:
+ raise Exception("No longer exists on the broker")
+
+ def __repr__(self):
+ return "%s(%s)"%(self.__class__.__name__, self.content)
+
+ def __str__(self):
+ return self.getObjectId()
+
+
+class Broker(BrokerObject):
+ def __init__(self, broker, values):
+ BrokerObject.__init__(self, broker, values)
+
+class Cluster(BrokerObject):
+ def __init__(self, broker, values):
+ BrokerObject.__init__(self, broker, values)
+
+class HaBroker(BrokerObject):
+ def __init__(self, broker, values):
+ BrokerObject.__init__(self, broker, values)
+
+class Memory(BrokerObject):
+ def __init__(self, broker, values):
+ BrokerObject.__init__(self, broker, values)
+
+class Connection(BrokerObject):
+ def __init__(self, broker, values):
+ BrokerObject.__init__(self, broker, values)
+
+ def close(self):
+ self.broker._method("close", {}, "org.apache.qpid.broker:connection:%s" % self.address)
+
+class Session(BrokerObject):
+ def __init__(self, broker, values):
+ BrokerObject.__init__(self, broker, values)
+
+class Subscription(BrokerObject):
+ def __init__(self, broker, values):
+ BrokerObject.__init__(self, broker, values)
+
+class Exchange(BrokerObject):
+ def __init__(self, broker, values):
+ BrokerObject.__init__(self, broker, values)
+
+class Binding(BrokerObject):
+ def __init__(self, broker, values):
+ BrokerObject.__init__(self, broker, values)
+
+class Queue(BrokerObject):
+ def __init__(self, broker, values):
+ BrokerObject.__init__(self, broker, values)
+
+ def purge(self, request):
+ """Discard all or some messages on a queue"""
+ self.broker._method("purge", {'request':request}, "org.apache.qpid.broker:queue:%s" % self.name)
+
+ def reroute(self, request, useAltExchange, exchange, filter={}):
+ """Remove all or some messages on this queue and route them to an exchange"""
+ self.broker._method("reroute", {'request':request,'useAltExchange':useAltExchange,'exchange':exchange,'filter':filter},
+ "org.apache.qpid.broker:queue:%s" % self.name)
+
+class Link(BrokerObject):
+ def __init__(self, broker, values):
+ BrokerObject.__init__(self, broker, values)
+
+class Acl(BrokerObject):
+ def __init__(self, broker, values):
+ BrokerObject.__init__(self, broker, values)
+
http://git-wip-us.apache.org/repos/asf/qpid-cpp/blob/a3bc7cd6/src/tests/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index a1a3334..546374e 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -289,6 +289,7 @@ add_test(NAME performance_tests COMMAND ${PYTHON_EXECUTABLE} run_performance_tes
add_test(NAME python_tests COMMAND ${PYTHON_EXECUTABLE} run_python_tests)
add_test(NAME queue_redirect_tests COMMAND ${PYTHON_EXECUTABLE} run_queue_redirect_tests)
add_test(NAME qmf_tests COMMAND ${PYTHON_EXECUTABLE} run_qmf_tests)
+add_test(NAME qmf_client_tests COMMAND ${PYTHON_EXECUTABLE} run_qmf_client_tests)
add_test(NAME transaction_tests COMMAND ${PYTHON_EXECUTABLE} run_transaction_tests)
if (BUILD_AMQP)
http://git-wip-us.apache.org/repos/asf/qpid-cpp/blob/a3bc7cd6/src/tests/qmf_client_tests.py
----------------------------------------------------------------------
diff --git a/src/tests/qmf_client_tests.py b/src/tests/qmf_client_tests.py
new file mode 100755
index 0000000..3264d22
--- /dev/null
+++ b/src/tests/qmf_client_tests.py
@@ -0,0 +1,99 @@
+#!/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.
+#
+
+# Runs QMF tests using the qmf.client API.
+
+import unittest, qmf.client, os
+
+class QmfClientTest(unittest.TestCase):
+ """
+ Test QMFv2 support using the qmf.console library.
+ """
+
+ def configure(self, config):
+ """Called by the qpid-python-test framework with broker config"""
+ self.broker = config.broker
+
+ def setUp(self):
+ self.agent = qmf.client.BrokerAgent.connect(self.broker)
+
+ def test_broker(self):
+ self.assertEqual(self.agent.getBroker().name, "amqp-broker")
+
+ def test_connections(self):
+ connections = self.agent.getAllConnections()
+ self.assertTrue(len(connections) > 0)
+
+ def test_queues(self):
+ connections = self.agent.getAllConnections()
+ qnames = [ "qq%s"%i for i in xrange(10)]
+ for q in qnames:
+ self.agent.addQueue(q)
+ self.assertEqual(q, self.agent.getQueue(q).name)
+ queues = self.agent.getAllQueues()
+ self.assertLess(set(qnames), set([q.name for q in queues]))
+ self.agent.delQueue("qq0")
+ self.assertIs(None, self.agent.getQueue("qq0"))
+ try:
+ self.agent.delQueue("nosuch")
+ except:
+ pass
+
+ def test_exchanges(self):
+ connections = self.agent.getAllConnections()
+ enames = [ "ee%s"%i for i in xrange(10)]
+ for e in enames:
+ self.agent.addExchange('fanout', e)
+ self.assertEqual(e, self.agent.getExchange(e).name)
+ exchanges = self.agent.getAllExchanges()
+ self.assertLess(set(enames), set([e.name for e in exchanges]))
+ self.agent.delExchange("ee0")
+ self.assertIs(None, self.agent.getExchange("ee0"))
+ try:
+ self.agent.delExchange("nosuch")
+ except:
+ pass
+
+ def test_bind(self):
+ self.agent.addQueue('qq')
+ self.agent.addExchange('direct', 'ex')
+ self.agent.bind('ex', 'qq', 'kk')
+ self.assertTrue([b for b in self.agent.getAllBindings() if b.bindingKey == 'kk'])
+ self.agent.unbind('ex', 'qq', 'kk')
+ self.assertFalse([b for b in self.agent.getAllBindings() if b.bindingKey == 'kk'])
+
+ def test_fork(self):
+ """Ensure that the client is fork-safe."""
+ self.agent.addQueue('parent')
+ pid = os.fork()
+ if pid: # parent
+ self.assertEqual((pid,0), os.waitpid(pid, 0))
+ self.assertIs(None, self.agent.addQueue('parent'))
+ self.assertEqual('child', self.agent.getQueue('child').name)
+ else: # child
+ # Can't use the parent's connection.
+ agent = qmf.client.BrokerAgent.connect(self.broker)
+ agent.delQueue('parent')
+ agent.addQueue('child')
+ os._exit(0) # Force exit, test framework will catch SystemExit
+
+if __name__ == "__main__":
+ shutil.rmtree("brokertest.tmp", True)
+ os.execvp("qpid-python-test", ["qpid-python-test", "-m", "qmf_client_tests"])
http://git-wip-us.apache.org/repos/asf/qpid-cpp/blob/a3bc7cd6/src/tests/run_qmf_client_tests
----------------------------------------------------------------------
diff --git a/src/tests/run_qmf_client_tests b/src/tests/run_qmf_client_tests
new file mode 100755
index 0000000..07b7cfc
--- /dev/null
+++ b/src/tests/run_qmf_client_tests
@@ -0,0 +1,34 @@
+#!/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.
+#
+
+from common import *
+try:
+ import proton
+ if AMQP_LIB:
+ port = start_broker("qmf_client", "--load-module", AMQP_LIB, "--log-enable=info+")
+ run_broker_tests(port, "-m qmf_client_tests")
+ check_results()
+ else:
+ warn("Skipping tests: AMQP 1.0 library not found")
+except:
+ warn("Skipping tests: proton library not found")
+
+
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org