def test_rpc_client_to_service_call(self): with TemporaryExchange(__name__) as tmp_exchange: tmp_exchange_address = tmp_exchange.address with BusListenerJanitor(RPCService(TEST_SERVICE_NAME, handler_type=MyServiceMessageHandler, handler_kwargs={'my_arg1': "foo", 'my_arg2': "bar"}, exchange=tmp_exchange.address, num_threads=1)) as service: service_queue_address = service.address self.assertTrue(service.is_listening()) self.assertTrue(service.is_running()) with RPCClient(service_name=TEST_SERVICE_NAME, exchange=tmp_exchange.address, timeout=1) as rpc_client: self.assertEqual("foo", rpc_client.execute("my_public_method1")) self.assertEqual(("bar", 42), rpc_client.execute("my_public_method2", 42)) with self.assertRaises(RPCException): rpc_client.execute("my_public_failing_method") with self.assertRaises(TimeoutError): rpc_client.execute("my_public_slow_method") with self.assertRaises(RPCTimeoutException): rpc_client.execute("my_public_slow_method") self.assertFalse(queue_exists(service_queue_address)) self.assertFalse(exchange_exists(tmp_exchange_address))
def test_empty_template_handler_raises(self): # define a MessageHandler with a template for callback on<something> methods class BaseTemplateHandler(AbstractMessageHandler): def handle_message(self, msg: LofarMessage): if 'foo' in msg.subject: self.on_foo() if 'bar' in msg.subject: self.on_bar(msg.content) def on_foo(self): pass def on_bar(self, some_arg): pass # try to start a BusListener using a BaseTemplateHandler. Should fail and raise a TypeError with TemporaryExchange(self.__class__.__name__) as tmp_exchange: tmp_exchange_name = tmp_exchange.address listener = BusListener(handler_type=BaseTemplateHandler, exchange=tmp_exchange_name) with self.assertRaises(RuntimeError): with BusListenerJanitor(listener): pass self.assertFalse(exchange_exists(tmp_exchange_name)) self.assertFalse(queue_exists(listener.designated_queue_name()))
def test_send_receive_over_temporary_exchange_and_queue(self): """ test the usage of the TemporaryExchange and TemporaryQueue in conjunction with normal ToBus and Frombus usage """ with TemporaryExchange("MyTestExchange") as tmp_exchange: tmp_exchange_address = tmp_exchange.address # create a normal ToBus on this tmp_exchange with tmp_exchange.create_tobus() as tobus_on_exchange: # create a TemporaryQueue, bound to the tmp_exchange with TemporaryQueue("MyTestQueue", exchange=tmp_exchange.address) as tmp_queue: tmp_queue_address = tmp_queue.address # create a normal FromBus on this tmp_queue with tmp_queue.create_frombus() as frombus: # and let's see if the tmp_queue can also create a tobus which then points to the bound_exchange with tmp_queue.create_tobus() as tobus_on_tmp_queue: self.assertEqual(tobus_on_exchange.exchange, tobus_on_tmp_queue.exchange) # test sending a message to both "types" of tobuses. for tobus in [tobus_on_exchange, tobus_on_tmp_queue]: # send a message... original_msg = EventMessage(content="foobar") tobus.send(original_msg) # ...receive the message... received_msg = frombus.receive() self.assertIsNotNone(received_msg) # and test if they are equal self.assertEqual(original_msg.id, received_msg.id) self.assertEqual(original_msg.content, received_msg.content) self.assertFalse(exchange_exists(tmp_exchange_address)) self.assertFalse(queue_exists(tmp_queue_address))
def test_send_receive_over_temporary_exchange_with_multiple_bound_queues_with_subject_filtering( self): """ test the usage of the TemporaryQueue in conjunction with normal ToBus and Frombus usage with additional filtering on subject """ with TemporaryExchange("MyTestExchange") as tmp_exchange: tmp_exchange_address = tmp_exchange.address with tmp_exchange.create_tobus() as tobus: SUBJECT1 = "FooBarSubject" SUBJECT2 = "FAKE_SUBJECT" with TemporaryQueue("MyTestQueue", exchange=tmp_exchange.address, routing_key=SUBJECT1) as tmp_queue1, \ TemporaryQueue("MyTestQueue", exchange=tmp_exchange.address, routing_key=SUBJECT2) as tmp_queue2: tmp_queue1_address = tmp_queue1.address tmp_queue2_address = tmp_queue2.address # create a normal To/FromBus on this tmp_queue NUM_MESSAGES_TO_SEND = 3 # create two FromBus'es, which listen for/receive only the messages with their routing_key with tmp_queue1.create_frombus() as frombus1, tmp_queue2.create_frombus() as frombus2: for i in range(NUM_MESSAGES_TO_SEND): # send a message... original_msg = EventMessage(subject=SUBJECT1, content="test message %d with subject='%s'" % ( i, SUBJECT1)) logger.info("Sending message: %s", original_msg) tobus.send(original_msg) # ...receive the message... received_msg1 = frombus1.receive(timeout=0.1) received_msg2 = frombus2.receive(timeout=0.1) self.assertIsNotNone(received_msg1) self.assertIsNone(received_msg2) logger.info("received message: %s", received_msg1) # and test if they are equal self.assertEqual(original_msg.id, received_msg1.id) self.assertEqual(original_msg.content, received_msg1.content) self.assertEqual(original_msg.subject, received_msg1.subject) # now send a message with a different subject... original_msg = EventMessage(subject=SUBJECT2, content="foobar") logger.info("Sending message: %s", original_msg) tobus.send(original_msg) # ... and try to receive it received_msg1 = frombus1.receive(timeout=0.1) received_msg2 = frombus2.receive(timeout=0.1) self.assertIsNone(received_msg1) self.assertIsNotNone(received_msg2) logger.info("received message: %s", received_msg2) # and test if they are equal self.assertEqual(original_msg.id, received_msg2.id) self.assertEqual(original_msg.content, received_msg2.content) self.assertEqual(original_msg.subject, received_msg2.subject) self.assertFalse(exchange_exists(tmp_exchange_address)) self.assertFalse(queue_exists(tmp_queue1_address)) self.assertFalse(queue_exists(tmp_queue2_address))
def tearDown(self): tmp_queue_address = self.tmp_queue.address self.tmp_queue.close() self.assertFalse(queue_exists(tmp_queue_address)) tmp_exchange_address = self.tmp_exchange.address self.tmp_exchange.close() self.assertFalse(exchange_exists(tmp_exchange_address))
def _play(self, num_threads_per_player): """simulate a ping/pong event driven loop until each player played a given amount of turns, or timeout""" # game parameters NUM_TURNS = 10 GAME_TIMEOUT = 10 # setup temporary exchange, on which the player can publish their messages (ping/pong balls) with TemporaryExchange("PingPongTable") as tmp_exchange: tmp_exchange_address = tmp_exchange.address # create two players, on "both sides of the table" # i.e.: they each play on the tmp_exchange, but have the auto-generated designated listen queues for incoming balls with BusListenerJanitor(PingPongPlayer("Player1", "Player2", tmp_exchange.address, num_threads_per_player)) as player1: player1_address = player1.address with BusListenerJanitor(PingPongPlayer("Player2", "Player1", tmp_exchange.address, num_threads_per_player)) as player2: player2_address = player2.address start_timestamp = datetime.utcnow() # first serve, referee throws a ping ball on the table in the direction of player1 with tmp_exchange.create_tobus() as referee: first_msg = EventMessage(content="ping", subject="Player1") logger.info("first message: sending %s to %s", first_msg.content, tmp_exchange.address) referee.send(first_msg) # play the game! # run the "event loop". Actually there are multiple loops: num_threads per player # this loop just tracks game progress. while True: player1_num_turns = player1.get_num_turns() player2_num_turns = player2.get_num_turns() time_remaining = GAME_TIMEOUT - (datetime.utcnow() - start_timestamp).total_seconds() logger.info("PingPongTester STATUS: player1_num_turns=%d/%d player2_num_turns=%d/%d time_remaining=%.1fsec", player1_num_turns, NUM_TURNS, player2_num_turns, NUM_TURNS, time_remaining) # assert on deadlocked game (should never happen!) self.assertGreater(time_remaining, 0) if player1_num_turns >= NUM_TURNS and player2_num_turns >= NUM_TURNS : break sleep(0.1) # assert on players who did not finish the game self.assertGreaterEqual(player1.get_num_turns(), NUM_TURNS) self.assertGreaterEqual(player2.get_num_turns(), NUM_TURNS) logger.info("SUCCESS! player1_num_turns=%d/%d player2_num_turns=%d/%d num_threads_per_player=%d #msg_per_sec=%.1f", player1_num_turns, NUM_TURNS, player2_num_turns, NUM_TURNS, num_threads_per_player, 2*NUM_TURNS/(datetime.utcnow() - start_timestamp).total_seconds()) self.assertFalse(exchange_exists(tmp_exchange_address)) self.assertFalse(queue_exists(player1_address)) self.assertFalse(queue_exists(player2_address))
def test_create_delete_exchange(self): name = "test-exchange-%s" % (uuid.uuid4()) self.assertFalse(exchange_exists(name)) # creating this new unique test exchange should succeed, and return True cause it's a new exchange self.assertTrue(create_exchange(name, durable=False)) self.assertTrue(exchange_exists(name)) # creating it again should return False self.assertFalse(create_exchange(name, durable=False)) # deleting it should succeed self.assertTrue(delete_exchange(name)) self.assertFalse(exchange_exists(name)) # deleting it again should return False as there is nothing to deleting self.assertFalse(delete_exchange(name))
def test_handler_init_raises(self): # define a MessageHandler that raises on init class RaisingHandler(AbstractMessageHandler): def __init__(self): raise Exception("intentional test exception") # try to start a BusListener using this handler. Should fail and raise a MessagingRuntimeError with TemporaryExchange(self.__class__.__name__) as tmp_exchange: tmp_exchange_name = tmp_exchange.address listener = BusListener(handler_type=RaisingHandler, exchange=tmp_exchange_name) with self.assertRaises(MessagingRuntimeError): with BusListenerJanitor(listener): pass self.assertFalse(exchange_exists(tmp_exchange_name)) self.assertFalse(queue_exists(listener.designated_queue_name()))
def test_temporary_exchange_is_really_temporary(self): """ test if the temporary exchange is really removed after usage """ tmp_exchange_address = None with TemporaryExchange("MyTestExchange") as tmp_exchange: tmp_exchange_address = tmp_exchange.address self.assertTrue("MyTestExchange" in tmp_exchange_address) self.assertFalse(exchange_exists(tmp_exchange_address)) # test if the temporary exchange has been deleted when leaving scope # We should not be able to connect to it anymore with self.assertRaisesRegex(MessageBusError, '.*NOT_FOUND.*'): with FromBus(tmp_exchange_address): pass
def test_send_receive_over_temporary_exchange_with_queue_with_subject_filtering(self): """ test the usage of the TemporaryQueue in conjunction with normal ToBus and Frombus usage with additional filtering on subject """ SUBJECT = "FooBarSubject" SUBJECT2 = "FAKE_SUBJECT" NUM_MESSAGES_TO_SEND = 3 with TemporaryExchange("MyTestExchange") as tmp_exchange: tmp_exchange_address = tmp_exchange.address with tmp_exchange.create_tobus() as tobus: # create a TemporaryQueue, which listens for/receives only the messages with the given SUBJECT with TemporaryQueue("MyTestQueue", exchange=tmp_exchange.address, routing_key=SUBJECT) as tmp_queue: tmp_queue_address = tmp_queue.address with tmp_queue.create_frombus() as frombus: for i in range(NUM_MESSAGES_TO_SEND): # send a message... original_msg = EventMessage(subject=SUBJECT, content="test message %d with subject='%s'" % ( i, SUBJECT)) logger.info("Sending message: %s", original_msg) tobus.send(original_msg) # ...receive the message... received_msg = frombus.receive(timeout=0.1) logger.info("received message: %s", received_msg) # and test if they are equal self.assertEqual(original_msg.id, received_msg.id) self.assertEqual(original_msg.content, received_msg.content) self.assertEqual(original_msg.subject, received_msg.subject) # now send a message with a different subject... original_msg = EventMessage(subject=SUBJECT2, content="foobar") logger.info("Sending message: %s", original_msg) tobus.send(original_msg) # ... and try to receive it (should yield None, because of the non-matching subject) received_msg = frombus.receive(timeout=0.1) logger.info("received message: %s", received_msg) self.assertEqual(None, received_msg) self.assertFalse(exchange_exists(tmp_exchange_address)) self.assertFalse(queue_exists(tmp_queue_address))
def test_reject_should_result_in_empty_queue(self): number_of_messages = 1000 with TemporaryExchange("Rejection") as tmp_exchange: tmp_exchange_address = tmp_exchange.address with BusListenerJanitor(Rejector(tmp_exchange.address)) as rejector: rejector_address = rejector.designated_queue_name() with tmp_exchange.create_tobus() as spammer: for _ in range(number_of_messages): msg = EventMessage(content="ping", subject="spam") spammer.send(msg) while rejector.handled_messages < number_of_messages: logger.info("Handled messages: {}".format(rejector.handled_messages)) sleep(1) with FromBus(rejector.address) as frombus: logger.info("Number of messages on queue: {}".format(frombus.nr_of_messages_in_queue())) self.assertEqual(0, frombus.nr_of_messages_in_queue()) self.assertFalse(exchange_exists(tmp_exchange_address)) self.assertFalse(queue_exists(rejector_address))
def test_priority(self): with TemporaryExchange(self.__class__.__name__) as tmp_exchange: tmp_exchange_address = tmp_exchange.address with tmp_exchange.create_temporary_queue() as tmp_queue: tmp_queue_address = tmp_queue.address msg1 = EventMessage(priority=4, subject="some.event", content=1) msg2 = EventMessage(priority=5, subject="some.event", content=2) with tmp_exchange.create_tobus() as tobus: tobus.send(msg1) tobus.send(msg2) with tmp_queue.create_frombus() as frombus: result_msg1 = frombus.receive() result_msg2 = frombus.receive() # message with highest priority should arrive first self.assertEqual(msg1.id, result_msg2.id) self.assertEqual(msg2.id, result_msg1.id) self.assertFalse(exchange_exists(tmp_exchange_address)) self.assertFalse(queue_exists(tmp_queue_address))