class testPLEXRegistration(unittest.TestCase): """ Tests the registration process of the Scaling Executive to the broker and the plugin manager, and the heartbeat process. """ def setUp(self): #a new Scaling Executive in another process for each test self.plex_proc = Process(target=ScalingExecutive) self.plex_proc.daemon = True if 'broker_man_host' in os.environ: self.man_host = os.environ['broker_man_host'] else: self.man_host = 'http://localhost:15672' if 'sm_broker_host' in os.environ: self.sm_host = os.environ['sm_broker_host'] else: self.sm_host = 'http://localhost:15672' url_user = "******".format(self.man_host) url_create = '{0}/api/vhosts/fsm-1234'.format(self.man_host) url_permission = '{0}/api/permissions/fsm-1234/specific-management'.format(self.man_host) self.headers = {'content-type': 'application/json'} data1 = '{"password":"******","tags":"son-sm"}' data2 = '{"configure":".*","write":".*","read":".*"}' res = requests.put(url=url_user, headers=self.headers, data=data1, auth=('guest', 'guest')) LOG.info(res.content) res1 = requests.put(url=url_create, headers=self.headers, auth=('guest', 'guest')) LOG.info(res1.content) res2= requests.put(url=url_permission, headers=self.headers, data=data2, auth=('guest', 'guest')) LOG.info(res2.content) #make a new connection with the broker before each test url = "{0}/fsm-1234".format(self.sm_host) self.manoconn = ManoBrokerRequestResponseConnection('son-plugin.SonPluginManager') self.sm_connection = ManoBrokerRequestResponseConnection('son-plugin.FSM', url=url) #Some threading events that can be used during the tests self.wait_for_event1 = threading.Event() self.wait_for_event1.clear() self.wait_for_event2 = threading.Event() self.wait_for_event2.clear() def tearDown(self): #Killing the scaling Executive if self.plex_proc is not None: self.plex_proc.terminate() del self.plex_proc #Killing the connection with the broker try: self.manoconn.stop_connection() self.sm_connection.stop_connection() except Exception as e: LOG.exception("Stop connection exception.") #Clearing the threading helpers del self.wait_for_event1 del self.wait_for_event2 url_user = "******".format(self.man_host) url_vhost = "{0}/api/vhosts/fsm-1234".format(self.man_host) requests.delete(url=url_user, headers=self.headers, auth=('guest', 'guest')) requests.delete(url=url_vhost, headers=self.headers, auth=('guest', 'guest')) #Method that terminates the timer that waits for an event def eventFinished1(self): self.wait_for_event1.set() def eventFinished2(self): self.wait_for_event2.set() #Method that starts a timer, waiting for an event def waitForEvent1(self, timeout=5, msg="Event timed out."): if not self.wait_for_event1.wait(timeout): self.assertEqual(True, False, msg=msg) def waitForEvent2(self, timeout=5, msg="Event timed out."): if not self.wait_for_event2.wait(timeout): self.assertEqual(True, False, msg=msg) def test_1_SCEX_Registration(self): """ TEST: This test verifies whether the Scaling Executive is sending out a message, and whether it contains all the needed info on the platform.management.plugin.register topic to register to the plugin manager. """ #STEP3a: When receiving the message, we need to check whether all fields present. def on_register_receive(ch, method, properties, message): msg = yaml.load(message) #CHECK: The message should be a dictionary. self.assertTrue(isinstance(msg, dict), msg='message is not a dictionary') #CHECK: The dictionary should have a key 'name'. self.assertIn('name', msg.keys(), msg='No name provided in message.') if isinstance(msg['name'], str): #CHECK: The value of 'name' should not be an empty string. self.assertTrue(len(msg['name']) > 0, msg='empty name provided.') else: #CHECK: The value of 'name' should be a string self.assertEqual(True, False, msg='name is not a string') #CHECK: The dictionary should have a key 'version'. self.assertIn('version', msg.keys(), msg='No version provided in message.') if isinstance(msg['version'], str): #CHECK: The value of 'version' should not be an empty string. self.assertTrue(len(msg['version']) > 0, msg='empty version provided.') else: #CHECK: The value of 'version' should be a string self.assertEqual(True, False, msg='version is not a string') #CHECK: The dictionary should have a key 'description' self.assertIn('description', msg.keys(), msg='No description provided in message.') if isinstance(msg['description'], str): #CHECK: The value of 'description' should not be an empty string. self.assertTrue(len(msg['description']) > 0, msg='empty description provided.') else: #CHECK: The value of 'description' should be a string self.assertEqual(True, False, msg='description is not a string') # stop waiting self.eventFinished1() #STEP1: Listen to the platform.management.plugin.register topic self.manoconn.subscribe(on_register_receive, 'platform.management.plugin.register') #STEP2: Start the Scaling Executive self.plex_proc.start() #STEP3b: When not receiving the message, the test failed self.waitForEvent1(timeout=5, msg="message not received.") def test_2_SCEX_request_response(self): def on_request_send(ch, method, properties, message): if properties.app_id == "son-plugin.ScalingExecutive": msg = yaml.load(message) self.assertTrue(isinstance(msg, dict), msg='message is not a dictionary') self.assertIn('uuid', msg.keys(), msg='No uuid provided in message.') if isinstance(msg['uuid'], str): self.assertTrue(msg['uuid'] == '1234', msg='empty uuid provided.') self.assertNotIn('scale', msg.keys(), msg='wrong message!') res_payload = yaml.dump({'uuid': '1234', 'scale': '2'}) self.eventFinished1() return res_payload def on_response_send(ch, method, properties, message): if properties.app_id == "son-plugin.ScalingExecutive": msg = yaml.load(message) self.assertTrue(isinstance(msg, dict), msg='message is not a dictionary') self.assertIn('uuid', msg.keys(), msg='No uuid provided in message.') if isinstance(msg['uuid'], str): self.assertTrue(msg['uuid'] == '1234', msg='empty uuid provided.') self.assertIn('scale', msg.keys(), msg='No scale provided in message.') if isinstance(msg['scale'], str): self.assertTrue(msg['scale'] == '2', msg='empty uuid provided.') self.eventFinished2() self.plex_proc.start() time.sleep(2) self.manoconn.subscribe(on_response_send, 'scaling.executive.request') self.sm_connection.register_async_endpoint(on_request_send, 'scaling.fsm.1234') req_payload = yaml.dump({'uuid': '1234'}) self.manoconn.publish("scaling.executive.request", message=req_payload) self.waitForEvent1(timeout=5, msg="response message not received.") self.waitForEvent2(timeout=5, msg="request message not received.")
class TestManoBrokerRequestResponseConnection(BaseTestCase): """ Test async. request/response and notification functionality. """ def setUp(self): super().setUp() self.m = ManoBrokerRequestResponseConnection( "test-request-response-broker-connection") #@unittest.skip("disabled") def test_broker_connection(self): """ Test broker connection. """ self.m.notify("test.topic2", "simplemessage") #@unittest.skip("disabled") def test_request_response(self): """ Test request/response messaging pattern. """ self.m.register_async_endpoint(self._simple_request_echo_cbf, "test.request") time.sleep(0.5) # give broker some time to register subscriptions self.m.call_async(self._simple_subscribe_cbf1, "test.request", "ping-pong") self.assertEqual(self.wait_for_messages()[0], "ping-pong") #@unittest.skip("disabled") def test_request_response_sync(self): """ Test request/response messaging pattern (synchronous). """ self.m.register_async_endpoint(self._simple_request_echo_cbf, "test.request.sync") time.sleep(0.5) # give broker some time to register subscriptions result = self.m.call_sync("test.request.sync", "ping-pong") self.assertTrue(len(result) == 4) self.assertEqual(str(result[3]), "ping-pong") #@unittest.skip("disabled") def test_notification(self): """ Test notification messaging pattern. """ self.m.register_notification_endpoint(self._simple_subscribe_cbf1, "test.notification") time.sleep(0.5) # give broker some time to register subscriptions self.m.notify("test.notification", "my-notification") self.assertTrue(self.wait_for_particular_messages("my-notification")) #@unittest.skip("disabled") def test_notification_pub_sub_mix(self): """ Test notification messaging pattern mixed with basic pub/sub calls. """ self.m.register_notification_endpoint(self._simple_subscribe_cbf1, "test.notification1") self.m.subscribe(self._simple_subscribe_cbf1, "test.notification2") time.sleep(0.5) # give broker some time to register subscriptions # send publish to notify endpoint self.m.publish("test.notification1", "my-notification1") self.assertEqual(self.wait_for_messages()[0], "my-notification1") # send notify to subscribe endpoint self.m.notify("test.notification2", "my-notification2") #res = self.wait_for_messages(n_messages=2) self.assertTrue(self.wait_for_particular_messages("my-notification1")) self.assertTrue(self.wait_for_particular_messages("my-notification2")) #@unittest.skip("disabled") def test_double_subscriptions(self): """ Ensure that messages are delivered to all subscriptions of a topic. (e.g. identifies queue setup problems) :return: """ self.m.subscribe(self._simple_subscribe_cbf1, "test.interleave") self.m.subscribe(self._simple_subscribe_cbf2, "test.interleave") time.sleep(0.5) # send publish to notify endpoint self.m.publish("test.interleave", "my-notification1") # enusre that it is received by each subscription self.assertTrue( self.wait_for_particular_messages("my-notification1", buffer=0)) self.assertTrue( self.wait_for_particular_messages("my-notification1", buffer=1)) #@unittest.skip("disabled") def test_interleaved_subscriptions(self): """ Ensure that interleaved subscriptions to the same topic do not lead to problems. :return: """ self.m.subscribe(self._simple_subscribe_cbf2, "test.interleave2") time.sleep(0.5) # do a async call on the same topic self.m.register_async_endpoint(self._simple_request_echo_cbf, "test.interleave2") time.sleep(0.5) # give broker some time to register subscriptions self.m.call_async(self._simple_subscribe_cbf1, "test.interleave2", "ping-pong") self.assertTrue(self.wait_for_particular_messages("ping-pong")) # send publish to notify endpoint self.m.publish("test.interleave2", "my-notification1") time.sleep(0.5) # ensure that the subcriber still gets the message (and also sees the one from async_call) self.assertTrue(self.wait_for_particular_messages("ping-pong")) self.assertTrue( self.wait_for_particular_messages("my-notification1", buffer=1))
class testPLEXRegistration(unittest.TestCase): """ Tests the registration process of the Scaling Executive to the broker and the plugin manager, and the heartbeat process. """ def setUp(self): #a new Scaling Executive in another process for each test self.plex_proc = Process(target=ScalingExecutive) self.plex_proc.daemon = True if 'broker_man_host' in os.environ: self.man_host = os.environ['broker_man_host'] else: self.man_host = 'http://localhost:15672' if 'sm_broker_host' in os.environ: self.sm_host = os.environ['sm_broker_host'] else: self.sm_host = 'http://localhost:15672' url_user = "******".format(self.man_host) url_create = '{0}/api/vhosts/fsm-1234'.format(self.man_host) url_permission = '{0}/api/permissions/fsm-1234/specific-management'.format( self.man_host) self.headers = {'content-type': 'application/json'} data1 = '{"password":"******","tags":"son-sm"}' data2 = '{"configure":".*","write":".*","read":".*"}' res = requests.put(url=url_user, headers=self.headers, data=data1, auth=('guest', 'guest')) LOG.info(res.content) res1 = requests.put(url=url_create, headers=self.headers, auth=('guest', 'guest')) LOG.info(res1.content) res2 = requests.put(url=url_permission, headers=self.headers, data=data2, auth=('guest', 'guest')) LOG.info(res2.content) #make a new connection with the broker before each test url = "{0}/fsm-1234".format(self.sm_host) self.manoconn = ManoBrokerRequestResponseConnection( 'son-plugin.SonPluginManager') self.sm_connection = ManoBrokerRequestResponseConnection( 'son-plugin.FSM', url=url) #Some threading events that can be used during the tests self.wait_for_event1 = threading.Event() self.wait_for_event1.clear() self.wait_for_event2 = threading.Event() self.wait_for_event2.clear() def tearDown(self): #Killing the scaling Executive if self.plex_proc is not None: self.plex_proc.terminate() del self.plex_proc #Killing the connection with the broker try: self.manoconn.stop_connection() self.sm_connection.stop_connection() except Exception as e: LOG.exception("Stop connection exception.") #Clearing the threading helpers del self.wait_for_event1 del self.wait_for_event2 url_user = "******".format(self.man_host) url_vhost = "{0}/api/vhosts/fsm-1234".format(self.man_host) requests.delete(url=url_user, headers=self.headers, auth=('guest', 'guest')) requests.delete(url=url_vhost, headers=self.headers, auth=('guest', 'guest')) #Method that terminates the timer that waits for an event def eventFinished1(self): self.wait_for_event1.set() def eventFinished2(self): self.wait_for_event2.set() #Method that starts a timer, waiting for an event def waitForEvent1(self, timeout=5, msg="Event timed out."): if not self.wait_for_event1.wait(timeout): self.assertEqual(True, False, msg=msg) def waitForEvent2(self, timeout=5, msg="Event timed out."): if not self.wait_for_event2.wait(timeout): self.assertEqual(True, False, msg=msg) def test_1_SCEX_Registration(self): """ TEST: This test verifies whether the Scaling Executive is sending out a message, and whether it contains all the needed info on the platform.management.plugin.register topic to register to the plugin manager. """ #STEP3a: When receiving the message, we need to check whether all fields present. def on_register_receive(ch, method, properties, message): msg = yaml.load(message) #CHECK: The message should be a dictionary. self.assertTrue(isinstance(msg, dict), msg='message is not a dictionary') #CHECK: The dictionary should have a key 'name'. self.assertIn('name', msg.keys(), msg='No name provided in message.') if isinstance(msg['name'], str): #CHECK: The value of 'name' should not be an empty string. self.assertTrue(len(msg['name']) > 0, msg='empty name provided.') else: #CHECK: The value of 'name' should be a string self.assertEqual(True, False, msg='name is not a string') #CHECK: The dictionary should have a key 'version'. self.assertIn('version', msg.keys(), msg='No version provided in message.') if isinstance(msg['version'], str): #CHECK: The value of 'version' should not be an empty string. self.assertTrue(len(msg['version']) > 0, msg='empty version provided.') else: #CHECK: The value of 'version' should be a string self.assertEqual(True, False, msg='version is not a string') #CHECK: The dictionary should have a key 'description' self.assertIn('description', msg.keys(), msg='No description provided in message.') if isinstance(msg['description'], str): #CHECK: The value of 'description' should not be an empty string. self.assertTrue(len(msg['description']) > 0, msg='empty description provided.') else: #CHECK: The value of 'description' should be a string self.assertEqual(True, False, msg='description is not a string') # stop waiting self.eventFinished1() #STEP1: Listen to the platform.management.plugin.register topic self.manoconn.subscribe(on_register_receive, 'platform.management.plugin.register') #STEP2: Start the Scaling Executive self.plex_proc.start() #STEP3b: When not receiving the message, the test failed self.waitForEvent1(timeout=5, msg="message not received.") def test_2_SCEX_request_response(self): def on_request_send(ch, method, properties, message): if properties.app_id == "son-plugin.ScalingExecutive": msg = yaml.load(message) self.assertTrue(isinstance(msg, dict), msg='message is not a dictionary') self.assertIn('uuid', msg.keys(), msg='No uuid provided in message.') if isinstance(msg['uuid'], str): self.assertTrue(msg['uuid'] == '1234', msg='empty uuid provided.') self.assertNotIn('scale', msg.keys(), msg='wrong message!') res_payload = yaml.dump({'uuid': '1234', 'scale': '2'}) self.eventFinished1() return res_payload def on_response_send(ch, method, properties, message): if properties.app_id == "son-plugin.ScalingExecutive": msg = yaml.load(message) self.assertTrue(isinstance(msg, dict), msg='message is not a dictionary') self.assertIn('uuid', msg.keys(), msg='No uuid provided in message.') if isinstance(msg['uuid'], str): self.assertTrue(msg['uuid'] == '1234', msg='empty uuid provided.') self.assertIn('scale', msg.keys(), msg='No scale provided in message.') if isinstance(msg['scale'], str): self.assertTrue(msg['scale'] == '2', msg='empty uuid provided.') self.eventFinished2() self.plex_proc.start() time.sleep(2) self.manoconn.subscribe(on_response_send, 'scaling.executive.request') self.sm_connection.register_async_endpoint(on_request_send, 'scaling.fsm.1234') req_payload = yaml.dump({'uuid': '1234'}) self.manoconn.publish("scaling.executive.request", message=req_payload) self.waitForEvent1(timeout=5, msg="response message not received.") self.waitForEvent2(timeout=5, msg="request message not received.")
class TestManoBrokerRequestResponseConnection(BaseTestCase): """ Test async. request/response and notification functionality. """ def setUp(self): super().setUp() self.m = ManoBrokerRequestResponseConnection("test-request-response-broker-connection") #@unittest.skip("disabled") def test_broker_connection(self): """ Test broker connection. """ self.m.notify("test.topic2", "simplemessage") #@unittest.skip("disabled") def test_request_response(self): """ Test request/response messaging pattern. """ self.m.register_async_endpoint(self._simple_request_echo_cbf, "test.request") time.sleep(0.5) # give broker some time to register subscriptions self.m.call_async(self._simple_subscribe_cbf1, "test.request", "ping-pong") self.assertEqual(self.wait_for_messages()[0], "ping-pong") #@unittest.skip("disabled") def test_request_response_sync(self): """ Test request/response messaging pattern (synchronous). """ self.m.register_async_endpoint(self._simple_request_echo_cbf, "test.request.sync") time.sleep(0.5) # give broker some time to register subscriptions result = self.m.call_sync("test.request.sync", "ping-pong") self.assertTrue(len(result) == 4) self.assertEqual(str(result[3]), "ping-pong") #@unittest.skip("disabled") def test_notification(self): """ Test notification messaging pattern. """ self.m.register_notification_endpoint(self._simple_subscribe_cbf1, "test.notification") time.sleep(0.5) # give broker some time to register subscriptions self.m.notify("test.notification", "my-notification") self.assertTrue(self.wait_for_particular_messages("my-notification")) #@unittest.skip("disabled") def test_notification_pub_sub_mix(self): """ Test notification messaging pattern mixed with basic pub/sub calls. """ self.m.register_notification_endpoint(self._simple_subscribe_cbf1, "test.notification1") self.m.subscribe(self._simple_subscribe_cbf1, "test.notification2") time.sleep(0.5) # give broker some time to register subscriptions # send publish to notify endpoint self.m.publish("test.notification1", "my-notification1") self.assertEqual(self.wait_for_messages()[0], "my-notification1") # send notify to subscribe endpoint self.m.notify("test.notification2", "my-notification2") #res = self.wait_for_messages(n_messages=2) self.assertTrue(self.wait_for_particular_messages("my-notification1")) self.assertTrue(self.wait_for_particular_messages("my-notification2")) #@unittest.skip("disabled") def test_double_subscriptions(self): """ Ensure that messages are delivered to all subscriptions of a topic. (e.g. identifies queue setup problems) :return: """ self.m.subscribe(self._simple_subscribe_cbf1, "test.interleave") self.m.subscribe(self._simple_subscribe_cbf2, "test.interleave") time.sleep(0.5) # send publish to notify endpoint self.m.publish("test.interleave", "my-notification1") # enusre that it is received by each subscription self.assertTrue(self.wait_for_particular_messages("my-notification1", buffer=0)) self.assertTrue(self.wait_for_particular_messages("my-notification1", buffer=1)) #@unittest.skip("disabled") def test_interleaved_subscriptions(self): """ Ensure that interleaved subscriptions to the same topic do not lead to problems. :return: """ self.m.subscribe(self._simple_subscribe_cbf2, "test.interleave2") time.sleep(0.5) # do a async call on the same topic self.m.register_async_endpoint(self._simple_request_echo_cbf, "test.interleave2") time.sleep(0.5) # give broker some time to register subscriptions self.m.call_async(self._simple_subscribe_cbf1, "test.interleave2", "ping-pong") self.assertTrue(self.wait_for_particular_messages("ping-pong")) # send publish to notify endpoint self.m.publish("test.interleave2", "my-notification1") time.sleep(0.5) # ensure that the subcriber still gets the message (and also sees the one from async_call) self.assertTrue(self.wait_for_particular_messages("ping-pong")) self.assertTrue(self.wait_for_particular_messages("my-notification1", buffer=1))
class TestManoBrokerRequestResponseConnection(unittest.TestCase): """ Test async. request/response and notification functionality. """ def setUp(self): self._last_message = None self.m = ManoBrokerRequestResponseConnection("test") def tearDown(self): del self.m def _simple_request_echo_cbf(self, ch, method, properties, message): """ Simple echo function. """ assert (properties.correlation_id is not None) assert (properties.reply_to is not None) assert (properties.content_type == "application/json") assert ("key" in properties.headers) return str(message, "utf-8") def _simple_message_cbf(self, ch, method, properties, message): assert (properties.content_type == "application/json") self._last_message = str(message, "utf-8") def wait_for_message(self, timeout=2): """ Helper to deal with async messaging system. Waits until a response is available in self._last_message or until a timeout is reached. :param timeout: seconds to wait :return: """ waiting = 0 while self._last_message is None and waiting < timeout: time.sleep(0.01) waiting += 0.01 if not waiting < timeout: raise Exception("Message lost. Subscription timeout reached.") m = self._last_message self._last_message = None return m def test_broker_connection(self): """ Test broker connection. """ self.m.notify("test.topic", "simplemessage") def test_request_response(self): """ Test request/response messaging pattern. """ self.m.register_async_endpoint(self._simple_request_echo_cbf, "test.request") time.sleep(0.5) # give broker some time to register subscriptions self.m.call_async(self._simple_message_cbf, "test.request", "ping-pong") self.assertEqual(self.wait_for_message(), "ping-pong") def test_request_response_sync(self): """ Test request/response messaging pattern (synchronous). """ self.m.register_async_endpoint(self._simple_request_echo_cbf, "test.request.sync") time.sleep(0.5) # give broker some time to register subscriptions result = self.m.call_sync("test.request.sync", "ping-pong") self.assertTrue(len(result) == 4) self.assertEqual(str(result[3], "utf-8"), "ping-pong") def test_notification(self): """ Test notification messaging pattern. """ self.m.register_notification_endpoint(self._simple_message_cbf, "test.notification") time.sleep(0.5) # give broker some time to register subscriptions self.m.notify("test.notification", "my-notification") self.assertEqual(self.wait_for_message(), "my-notification") def test_notification_pub_sub_mix(self): """ Test notification messaging pattern mixed with basic pub/sub calls. """ self.m.register_notification_endpoint(self._simple_message_cbf, "test.notification1") self.m.subscribe(self._simple_message_cbf, "test.notification2") time.sleep(0.5) # give broker some time to register subscriptions # send publish to notify endpoint self.m.publish("test.notification1", "my-notification1") self.assertEqual(self.wait_for_message(), "my-notification1") # send notify to subscribe endpoint self.m.notify("test.notification2", "my-notification2") self.assertEqual(self.wait_for_message(), "my-notification2")