def test_send_exchange_with_reply(self): driver = amqp_driver.ProtonDriver(self.conf, self._broker_url) target1 = oslo_messaging.Target(topic="test-topic", exchange="e1") listener1 = _ListenerThread(driver.listen(target1), 1) target2 = oslo_messaging.Target(topic="test-topic", exchange="e2") listener2 = _ListenerThread(driver.listen(target2), 1) rc = driver.send(target1, {"context": "whatever"}, { "method": "echo", "id": "e1" }, wait_for_reply=True, timeout=30) self.assertIsNotNone(rc) self.assertEqual(rc.get('correlation-id'), 'e1') rc = driver.send(target2, {"context": "whatever"}, { "method": "echo", "id": "e2" }, wait_for_reply=True, timeout=30) self.assertIsNotNone(rc) self.assertEqual(rc.get('correlation-id'), 'e2') listener1.join(timeout=30) self.assertFalse(listener1.isAlive()) listener2.join(timeout=30) self.assertFalse(listener2.isAlive()) driver.cleanup()
def test_notification(self): driver = amqp_driver.ProtonDriver(self.conf, self._broker_url) notifications = [(oslo_messaging.Target(topic="topic-1"), 'info'), (oslo_messaging.Target(topic="topic-1"), 'error'), (oslo_messaging.Target(topic="topic-2"), 'debug')] nl = driver.listen_for_notifications(notifications) listener = _ListenerThread(nl, 3) targets = [ 'topic-1.info', 'topic-1.bad', # should be dropped 'bad-topic.debug', # should be dropped 'topic-1.error', 'topic-2.debug' ] for t in targets: driver.send_notification(oslo_messaging.Target(topic=t), "context", {'target': t}, 1.0) listener.join(timeout=30) self.assertFalse(listener.isAlive()) topics = [x.message.get('target') for x in listener.get_messages()] self.assertTrue('topic-1.info' in topics) self.assertTrue('topic-1.error' in topics) self.assertTrue('topic-2.debug' in topics) self.assertEqual(self._broker.dropped_count, 2) driver.cleanup()
def test_listener_cleanup(self): """Verify unused listener can cleanly shutdown.""" driver = amqp_driver.ProtonDriver(self.conf, self._broker_url) target = oslo_messaging.Target(topic="test-topic") listener = driver.listen(target) self.assertIsInstance(listener, amqp_driver.ProtonListener) driver.cleanup()
def test_notification(self): driver = amqp_driver.ProtonDriver(self.conf, self._broker_url) notifications = [(oslo_messaging.Target(topic="topic-1"), 'info'), (oslo_messaging.Target(topic="topic-1"), 'error'), (oslo_messaging.Target(topic="topic-2"), 'debug')] nl = driver.listen_for_notifications(notifications, None) # send one for each support version: msg_count = len(notifications) * 2 listener = _ListenerThread(nl, msg_count) targets = [ 'topic-1.info', 'topic-1.bad', # should be dropped 'bad-topic.debug', # should be dropped 'topic-1.error', 'topic-2.debug' ] for version in (1.0, 2.0): for t in targets: driver.send_notification(oslo_messaging.Target(topic=t), "context", {'target': t}, version) listener.join(timeout=30) self.assertFalse(listener.isAlive()) topics = [x.message.get('target') for x in listener.get_messages()] self.assertEqual(len(topics), msg_count) self.assertEqual(topics.count('topic-1.info'), 2) self.assertEqual(topics.count('topic-1.error'), 2) self.assertEqual(topics.count('topic-2.debug'), 2) self.assertEqual(self._broker.dropped_count, 4) driver.cleanup()
def test_send_no_reply(self): driver = amqp_driver.ProtonDriver(self.conf, self._broker_url) target = oslo_messaging.Target(topic="test-topic") listener = _ListenerThread(driver.listen(target), 1) rc = driver.send(target, {"context": True}, {"msg": "value"}, wait_for_reply=False) self.assertIsNone(rc) listener.join(timeout=30) self.assertFalse(listener.isAlive()) self.assertEqual(listener.messages.get().message, {"msg": "value"}) driver.cleanup()
def _failover(self, fail_brokers): self._brokers[0].start() # self.config(trace=True, group="oslo_messaging_amqp") driver = amqp_driver.ProtonDriver(self.conf, self._broker_url) target = oslo_messaging.Target(topic="my-topic") listener = _ListenerThread( driver.listen(target, None, None)._poll_style_listener, 2) # wait for listener links to come up # 4 == 3 links per listener + 1 for the global reply queue predicate = lambda: self._brokers[0].sender_link_count == 4 _wait_until(predicate, 30) self.assertTrue(predicate()) rc = driver.send(target, {"context": "whatever"}, {"method": "echo", "id": "echo-1"}, wait_for_reply=True, timeout=30) self.assertIsNotNone(rc) self.assertEqual(rc.get('correlation-id'), 'echo-1') # 1 request msg, 1 response: self.assertEqual(self._brokers[0].topic_count, 1) self.assertEqual(self._brokers[0].direct_count, 1) # invoke failover method fail_brokers(self._brokers[0], self._brokers[1]) # wait for listener links to re-establish on broker 1 # 4 = 3 links per listener + 1 for the global reply queue predicate = lambda: self._brokers[1].sender_link_count == 4 _wait_until(predicate, 30) self.assertTrue(predicate()) rc = driver.send(target, {"context": "whatever"}, {"method": "echo", "id": "echo-2"}, wait_for_reply=True, timeout=2) self.assertIsNotNone(rc) self.assertEqual(rc.get('correlation-id'), 'echo-2') # 1 request msg, 1 response: self.assertEqual(self._brokers[1].topic_count, 1) self.assertEqual(self._brokers[1].direct_count, 1) listener.join(timeout=30) self.assertFalse(listener.isAlive()) # note: stopping the broker first tests cleaning up driver without a # connection active self._brokers[1].stop() driver.cleanup()
def test_broker_failover(self): """Simulate failover of one broker to another.""" self._brokers[0].start() driver = amqp_driver.ProtonDriver(self.conf, self._broker_url) target = oslo_messaging.Target(topic="my-topic") listener = _ListenerThread(driver.listen(target), 2) rc = driver.send(target, {"context": "whatever"}, { "method": "echo", "id": "echo-1" }, wait_for_reply=True, timeout=30) self.assertIsNotNone(rc) self.assertEqual(rc.get('correlation-id'), 'echo-1') # 1 request msg, 1 response: self.assertEqual(self._brokers[0].topic_count, 1) self.assertEqual(self._brokers[0].direct_count, 1) # fail broker 0 and start broker 1: self._brokers[0].stop() self._brokers[1].start() deadline = time.time() + 30 responded = False sequence = 2 while deadline > time.time() and not responded: if not listener.isAlive(): # listener may have exited after replying to an old correlation # id: restart new listener listener = _ListenerThread(driver.listen(target), 1) try: rc = driver.send(target, {"context": "whatever"}, { "method": "echo", "id": "echo-%d" % sequence }, wait_for_reply=True, timeout=2) self.assertIsNotNone(rc) self.assertEqual(rc.get('correlation-id'), 'echo-%d' % sequence) responded = True except oslo_messaging.MessagingTimeout: sequence += 1 self.assertTrue(responded) listener.join(timeout=30) self.assertFalse(listener.isAlive()) # note: stopping the broker first tests cleaning up driver without a # connection active self._brokers[1].stop() driver.cleanup()
def test_listener_failover(self): """Verify that Listeners sharing the same topic are re-established after failover. """ self._brokers[0].start() # self.config(trace=True, group="oslo_messaging_amqp") driver = amqp_driver.ProtonDriver(self.conf, self._broker_url) target = oslo_messaging.Target(topic="my-topic") bcast = oslo_messaging.Target(topic="my-topic", fanout=True) listener1 = _ListenerThread( driver.listen(target, None, None)._poll_style_listener, 2) listener2 = _ListenerThread( driver.listen(target, None, None)._poll_style_listener, 2) # wait for 7 sending links to become active on the broker. # 7 = 3 links per Listener + 1 global reply link predicate = lambda: self._brokers[0].sender_link_count == 7 _wait_until(predicate, 30) self.assertTrue(predicate()) driver.send(bcast, {"context": "whatever"}, {"method": "ignore", "id": "echo-1"}) # 1 message per listener predicate = lambda: self._brokers[0].fanout_sent_count == 2 _wait_until(predicate, 30) self.assertTrue(predicate()) # start broker 1 then shutdown broker 0: self._brokers[1].start() self._brokers[0].stop(clean=True) # wait again for 7 sending links to re-establish on broker 1 predicate = lambda: self._brokers[1].sender_link_count == 7 _wait_until(predicate, 30) self.assertTrue(predicate()) driver.send(bcast, {"context": "whatever"}, {"method": "ignore", "id": "echo-2"}) # 1 message per listener predicate = lambda: self._brokers[1].fanout_sent_count == 2 _wait_until(predicate, 30) self.assertTrue(predicate()) listener1.join(timeout=30) listener2.join(timeout=30) self.assertFalse(listener1.isAlive() or listener2.isAlive()) driver.cleanup() self._brokers[1].stop()
def test_authentication_failure(self): """Verify that a bad password given in TransportHost is rejected by the broker. """ addr = "amqp://*****:*****@%s:%d" % (self._broker.host, self._broker.port) url = oslo_messaging.TransportURL.parse(self.conf, addr) driver = amqp_driver.ProtonDriver(self.conf, url) target = oslo_messaging.Target(topic="test-topic") _ListenerThread(driver.listen(target), 1) self.assertRaises(oslo_messaging.MessagingTimeout, driver.send, target, {"context": True}, {"method": "echo"}, wait_for_reply=True, timeout=2.0) driver.cleanup()
def test_authentication_ok(self): """Verify that username and password given in TransportHost are accepted by the broker. """ addr = "amqp://*****:*****@%s:%d" % (self._broker.host, self._broker.port) url = oslo_messaging.TransportURL.parse(self.conf, addr) driver = amqp_driver.ProtonDriver(self.conf, url) target = oslo_messaging.Target(topic="test-topic") listener = _ListenerThread(driver.listen(target), 1) rc = driver.send(target, {"context": True}, {"method": "echo"}, wait_for_reply=True) self.assertIsNotNone(rc) listener.join(timeout=30) self.assertFalse(listener.isAlive()) driver.cleanup()
def test_send_timeout(self): """Verify send timeout.""" driver = amqp_driver.ProtonDriver(self.conf, self._broker_url) target = oslo_messaging.Target(topic="test-topic") listener = _ListenerThread(driver.listen(target), 1) # the listener will drop this message: try: driver.send(target, {"context": "whatever"}, {"method": "drop"}, wait_for_reply=True, timeout=1.0) except Exception as ex: self.assertIsInstance(ex, oslo_messaging.MessagingTimeout, ex) else: self.assertTrue(False, "No Exception raised!") listener.join(timeout=30) self.assertFalse(listener.isAlive()) driver.cleanup()
def test_authentication_default_username(self): """Verify that a configured username/password is used if none appears in the URL. """ addr = "amqp://%s:%d" % (self._broker.host, self._broker.port) self.config(username="******", password="******", group="oslo_messaging_amqp") url = oslo_messaging.TransportURL.parse(self.conf, addr) driver = amqp_driver.ProtonDriver(self.conf, url) target = oslo_messaging.Target(topic="test-topic") listener = _ListenerThread(driver.listen(target), 1) rc = driver.send(target, {"context": True}, {"method": "echo"}, wait_for_reply=True) self.assertIsNotNone(rc) listener.join(timeout=30) self.assertFalse(listener.isAlive()) driver.cleanup()
def test_authentication_bad_mechs(self): """Verify that the connection fails if the client's SASL mechanisms do not match the broker's. """ self.config(sasl_mechanisms="EXTERNAL ANONYMOUS", group="oslo_messaging_amqp") addr = "amqp://*****:*****@%s:%d" % (self._broker.host, self._broker.port) url = oslo_messaging.TransportURL.parse(self.conf, addr) driver = amqp_driver.ProtonDriver(self.conf, url) target = oslo_messaging.Target(topic="test-topic") _ListenerThread(driver.listen(target), 1) self.assertRaises(oslo_messaging.MessagingTimeout, driver.send, target, {"context": True}, {"method": "echo"}, wait_for_reply=True, timeout=2.0) driver.cleanup()
def test_notification(self): driver = amqp_driver.ProtonDriver(self.conf, self._broker_url) notifications = [(messaging.Target(topic="topic-1"), 'info'), (messaging.Target(topic="topic-1"), 'error'), (messaging.Target(topic="topic-2"), 'debug')] nl = driver.listen_for_notifications(notifications, None) # send one for each support version: msg_count = len(notifications) * 2 listener = _ListenerThread(nl, msg_count) targets = [ 'topic-1.info', 'topic-1.bad', # will raise MessagingDeliveryFailure 'bad-topic.debug', # will raise MessagingDeliveryFailure 'topic-1.error', 'topic-2.debug' ] excepted_targets = [] exception_count = 0 for version in (1.0, 2.0): for t in targets: try: driver.send_notification(messaging.Target(topic=t), "context", {'target': t}, version) except messaging.MessageDeliveryFailure: exception_count += 1 excepted_targets.append(t) listener.join(timeout=30) self.assertFalse(listener.isAlive()) topics = [x.message.get('target') for x in listener.get_messages()] self.assertEqual(len(topics), msg_count) self.assertEqual(topics.count('topic-1.info'), 2) self.assertEqual(topics.count('topic-1.error'), 2) self.assertEqual(topics.count('topic-2.debug'), 2) self.assertEqual(self._broker.dropped_count, 4) self.assertEqual(exception_count, 4) self.assertEqual(excepted_targets.count('topic-1.bad'), 2) self.assertEqual(excepted_targets.count('bad-topic.debug'), 2) driver.cleanup()
def test_messaging_patterns(self): """Verify the direct, shared, and fanout message patterns work.""" driver = amqp_driver.ProtonDriver(self.conf, self._broker_url) target1 = oslo_messaging.Target(topic="test-topic", server="server1") listener1 = _ListenerThread(driver.listen(target1), 4) target2 = oslo_messaging.Target(topic="test-topic", server="server2") listener2 = _ListenerThread(driver.listen(target2), 3) shared_target = oslo_messaging.Target(topic="test-topic") fanout_target = oslo_messaging.Target(topic="test-topic", fanout=True) # this should go to only one server: driver.send(shared_target, {"context": "whatever"}, { "method": "echo", "id": "either-1" }, wait_for_reply=True) self.assertEqual(self._broker.topic_count, 1) self.assertEqual(self._broker.direct_count, 1) # reply # this should go to the other server: driver.send(shared_target, {"context": "whatever"}, { "method": "echo", "id": "either-2" }, wait_for_reply=True) self.assertEqual(self._broker.topic_count, 2) self.assertEqual(self._broker.direct_count, 2) # reply # these should only go to listener1: driver.send(target1, {"context": "whatever"}, { "method": "echo", "id": "server1-1" }, wait_for_reply=True) driver.send(target1, {"context": "whatever"}, { "method": "echo", "id": "server1-2" }, wait_for_reply=True) self.assertEqual(self._broker.direct_count, 6) # 2X(send+reply) # this should only go to listener2: driver.send(target2, {"context": "whatever"}, { "method": "echo", "id": "server2" }, wait_for_reply=True) self.assertEqual(self._broker.direct_count, 8) # both listeners should get a copy: driver.send(fanout_target, {"context": "whatever"}, { "method": "echo", "id": "fanout" }) listener1.join(timeout=30) self.assertFalse(listener1.isAlive()) listener2.join(timeout=30) self.assertFalse(listener2.isAlive()) self.assertEqual(self._broker.fanout_count, 1) listener1_ids = [x.message.get('id') for x in listener1.get_messages()] listener2_ids = [x.message.get('id') for x in listener2.get_messages()] self.assertTrue('fanout' in listener1_ids and 'fanout' in listener2_ids) self.assertTrue('server1-1' in listener1_ids and 'server1-1' not in listener2_ids) self.assertTrue('server1-2' in listener1_ids and 'server1-2' not in listener2_ids) self.assertTrue('server2' in listener2_ids and 'server2' not in listener1_ids) if 'either-1' in listener1_ids: self.assertTrue('either-2' in listener2_ids and 'either-2' not in listener1_ids and 'either-1' not in listener2_ids) else: self.assertTrue('either-2' in listener1_ids and 'either-2' not in listener2_ids and 'either-1' in listener2_ids) driver.cleanup()
def test_driver_unconnected_cleanup(self): """Verify the driver can cleanly shutdown even if never connected.""" driver = amqp_driver.ProtonDriver(self.conf, self._broker_url) driver.cleanup()