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 TestPluginManagerBase(unittest.TestCase): """ Commen functionalities used my many test cases """ pm_proc = None @classmethod def setUpClass(cls): # start the plugin manger in another process so that we can connect to it using its broker interface cls.pm_proc = Process(target=SonPluginManager) cls.pm_proc.daemon = True cls.pm_proc.start() time.sleep(1) # give the plugin manager some time to start @classmethod def tearDownClass(cls): if cls.pm_proc is not None: cls.pm_proc.terminate() del cls.pm_proc def setUp(self): # initialize messaging subsystem self.m = ManoBrokerRequestResponseConnection("pm-client" + self.id()) self.wait_for_reply = threading.Event() self.plugin_uuid = None def tearDown(self): self.m.stop_connection() self.m.stop_threads() del self.m def waitForMessage(self, timeout=5): self.wait_for_reply.clear() if not self.wait_for_reply.wait(timeout): raise Exception("Timeout in wait for reply message.") def messageReceived(self): self.wait_for_reply.set() def register(self): """ Helper: We need this in many tests. :return: """ def on_register_reply(ch, method, properties, message): msg = json.loads(str(message)) assert(msg.get("status") == "OK") assert(len(msg.get("uuid")) > 0) assert(msg.get("error") is None) # set internal state variables self.plugin_uuid = msg.get("uuid") # stop waiting self.messageReceived() # create register request message msg = dict(name="test-plugin", version="v0.01", description="description") # do the registration call self.m.call_async(on_register_reply, "platform.management.plugin.register", json.dumps(msg)) # make our test synchronous: wait self.waitForMessage() def deregister(self): """ Helper: We need this in many tests. :return: """ assert(self.plugin_uuid is not None) def on_deregister_reply(ch, method, properties, message): msg = json.loads(str(message)) assert(msg.get("status") == "OK") # stop waiting self.messageReceived() # create register request message msg = dict(uuid=self.plugin_uuid) # do the registration call self.m.call_async(on_deregister_reply, "platform.management.plugin.deregister", json.dumps(msg)) # make our test synchronous: wait self.waitForMessage()
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 testSlmFunctionality(unittest.TestCase): """ Tests the tasks that the SLM should perform in the service life cycle of the network services. """ slm_proc = None manoconn_pm = None uuid = '1' corr_id = '1ba347d6-6210-4de7-9ca3-a383e50d0330' ######################## #SETUP ######################## # @classmethod # def setUpClass(cls): # """ # Starts the SLM instance and takes care if its registration. # """ # def on_register_trigger(ch, method, properties, message): # return json.dumps({'status':'OK','uuid':cls.uuid}) # #Some threading events that can be used during the tests # cls.wait_for_first_event = threading.Event() # cls.wait_for_first_event.clear() # cls.wait_for_second_event = threading.Event() # cls.wait_for_second_event.clear() #Deploy SLM and a connection to the broker # cls.slm_proc = Process(target=ServiceLifecycleManager) # cls.slm_proc.daemon = True # cls.manoconn_pm = ManoBrokerRequestResponseConnection('Son-plugin.SonPluginManager') # cls.manoconn_pm.subscribe(on_register_trigger,'platform.management.plugin.register') # cls.slm_proc.start() #wait until registration process finishes # if not cls.wait_for_first_event.wait(timeout=5): # pass @classmethod def tearDownClass(cls): if cls.slm_proc is not None: cls.slm_proc.terminate() del cls.slm_proc # cls.manoconn_pm.stop_connection() def setUp(self): def on_register_trigger(ch, method, properties, message): return json.dumps({'status': 'OK', 'uuid': self.uuid}) #Generate a new corr_id for every test self.corr_id = str(uuid.uuid4()) #Some threading events that can be used during the tests self.wait_for_first_event = threading.Event() self.wait_for_first_event.clear() self.wait_for_second_event = threading.Event() self.wait_for_second_event.clear() #Deploy SLM and a connection to the broker self.slm_proc = Process(target=ServiceLifecycleManager) self.slm_proc.daemon = True self.manoconn_pm = ManoBrokerRequestResponseConnection( 'son-plugin.SonPluginManager') self.manoconn_pm.subscribe(on_register_trigger, 'platform.management.plugin.register') self.slm_proc.start() #wait until registration process finishes if not self.wait_for_first_event.wait(timeout=5): pass #We make a spy connection to listen to the different topics on the broker self.manoconn_spy = ManoBrokerRequestResponseConnection( 'son-plugin.SonSpy') #we need a connection to simulate messages from the gatekeeper self.manoconn_gk = ManoBrokerRequestResponseConnection( 'son-plugin.SonGateKeeper') #we need a connection to simulate messages from the infrastructure adaptor self.manoconn_ia = ManoBrokerRequestResponseConnection( 'son-plugin.SonInfrastructureAdapter') def tearDown(self): try: self.manoconn_spy.stop_connection() self.manoconn_gk.stop_connection() self.manoconn_ia.stop_connection() except Exception as e: LOG.exception("Stop connection exception.") ######################## #GENERAL ######################## def createGkNewServiceRequestMessage(self, correctlyFormatted=True): """ This method helps creating messages for the service request packets. If it needs to be wrongly formatted, the nsd part of the request is removed. """ path_descriptors = '/plugins/son-mano-service-lifecycle-management/test/test_descriptors/' nsd_descriptor = open(path_descriptors + 'sonata-demo.yml', 'r') vnfd1_descriptor = open(path_descriptors + 'firewall-vnfd.yml', 'r') vnfd2_descriptor = open(path_descriptors + 'iperf-vnfd.yml', 'r') vnfd3_descriptor = open(path_descriptors + 'tcpdump-vnfd.yml', 'r') #import the nsd and vnfds that form the service if correctlyFormatted: service_request = { 'NSD': yaml.load(nsd_descriptor), 'VNFD1': yaml.load(vnfd1_descriptor), 'VNFD2': yaml.load(vnfd2_descriptor), 'VNFD3': yaml.load(vnfd3_descriptor) } else: service_request = { 'VNFD1': yaml.load(vnfd1_descriptor), 'VNFD2': yaml.load(vnfd2_descriptor), 'VNFD3': yaml.load(vnfd3_descriptor) } return yaml.dump(service_request) #Method that terminates the timer that waits for an event def firstEventFinished(self): self.wait_for_first_event.set() def secondEventFinished(self): self.wait_for_second_event.set() #Method that starts a timer, waiting for an event def waitForFirstEvent(self, timeout=5, msg="Event timed out."): if not self.wait_for_first_event.wait(timeout): self.assertEqual(True, False, msg=msg) def waitForSecondEvent(self, timeout=5, msg="Event timed out."): if not self.wait_for_second_event.wait(timeout): self.assertEqual(True, False, msg=msg) def dummy(self, ch, method, properties, message): """ Sometimes, we need a cbf for a async_call, without actually needing it. """ return ############################################################# #TEST1: Test Reaction To Correctly Formatted Service Request. ############################################################# def on_slm_infra_adaptor_vim_list_test1(self, ch, method, properties, message): """ This method checks what the SLM sends towards the IA when it receives a valid request from the gk. """ msg = yaml.load(message) #The message should have an empty body and a correlation_id different from the original correlation_id self.assertEqual(msg, {}, msg='message is not empty.') self.assertNotEqual( properties.correlation_id, self.corr_id, msg='message does not contain a new correlation_id.') self.assertEqual(properties.reply_to, 'infrastructure.management.compute.list', msg='not the correct reply_to topic.') self.firstEventFinished() def on_gk_response_to_correct_service_request(self, ch, method, properties, message): """ This method checks whether the SLM responds to a correctly formatted new service request it receives from the GK. """ msg = yaml.load(message) self.assertTrue(isinstance(msg, dict), msg='response to service request is not a dictionary.') self.assertEqual(msg['status'], 'INSTANTIATING', msg='not correct response, should be INSTANTIATING.') self.assertEqual(msg['error'], None, msg='not correct response, should be None.') self.assertTrue(isinstance(msg['timestamp'], float), msg='timestamp is not a float') self.assertEqual( properties.correlation_id, self.corr_id, msg='response to async call doesnt have the same correlation_id') self.secondEventFinished() def testReactionToCorrectlyFormattedServiceRequest(self): """ If the gk sends a request on the service.instances.create topic that is correctly formatted, then the SLM should respond by doing 2 things: 1. Replying with the message {'status':'INSTANTIATING', 'error':NULL, 'timestamp':<timestamp>} with the same correlation_id as the one in the request. 2. Requesting the available vims from the IA on the infrastructure.management.compute.list topic with a new correlation id and an empty body. """ self.wait_for_first_event.clear() self.wait_for_second_event.clear() #STEP1: Spy the topic on which the SLM will contact the infrastructure adaptor self.manoconn_spy.subscribe(self.on_slm_infra_adaptor_vim_list_test1, 'infrastructure.management.compute.list') #STEP2: Send a correctly formatted service request message (from the gk) to the SLM self.manoconn_gk.call_async( self.on_gk_response_to_correct_service_request, 'service.instances.create', msg=self.createGkNewServiceRequestMessage(correctlyFormatted=True), content_type='application/yaml', correlation_id=self.corr_id) #STEP3: Start waiting for the messages that are triggered by this request self.waitForFirstEvent( timeout=10, msg= 'Wait for message from SLM to IA to request resources timed out.') self.waitForSecondEvent( timeout=10, msg='Wait for reply to request from GK timed out.') ########################################################### #TEST2: Test reaction to wrongly formatted service request. ########################################################### def on_gk_response_to_wrong_service_request(self, ch, method, properties, message): """ This method checks whether the SLM responds to a wrongly formatted new service request it receives from the GK. """ msg = yaml.load(message) self.assertTrue(isinstance(msg, dict), msg='response to service request is not a dictionary.') self.assertEqual(msg['status'], 'ERROR', msg='not correct response, should be ERROR') self.assertTrue(isinstance(msg['error'], str), msg='Error message is not a string.') self.assertTrue(isinstance(msg['timestamp'], float), msg='timestamp is not a float') self.assertEqual( properties.correlation_id, self.corr_id, msg='response to async call doesnt have the same correlation_id') self.firstEventFinished() def testReactionToWronglyFormattedServiceRequest(self): """ If the gk sends a request on the service.instances.create topic that is wrongly formatted, then the SLM should respond by replying with the message {'status':'ERROR', 'error':<error message>, 'timestamp':<timestamp>} with the same correlation_id as the one in the request. """ self.wait_for_first_event.clear() #STEP1: Send a wrongly formatted service request message (from the gk) to the SLM self.manoconn_gk.call_async( self.on_gk_response_to_wrong_service_request, 'service.instances.create', msg=self.createGkNewServiceRequestMessage( correctlyFormatted=False), content_type='application/yaml', correlation_id=self.corr_id) #STEP2: Start waiting for the messages that are triggered by this request self.waitForFirstEvent( timeout=10, msg='Wait for reply to request from GK timed out.') ############################################################### #TEST3: Test Reaction when SLM receives a valid list of VIMs. ############################################################### def on_slm_infra_adaptor_vim_list_test3(self, ch, method, properties, message): """ This method replies to a request of the SLM to the IA to get the VIM-list. """ if properties.app_id == 'son-plugin.ServiceLifecycleManager': VIM_list = [{ 'vim_uuid': uuid.uuid4().hex }, { 'vim_uuid': uuid.uuid4().hex }, { 'vim_uuid': uuid.uuid4().hex }] self.manoconn_ia.notify('infrastructure.management.compute.list', yaml.dump(VIM_list), correlation_id=properties.correlation_id) def on_slm_infra_adaptor_service_deploy_request_test3( self, ch, method, properties, message): """ This method checks whether the request from the SLM to the IA to deploy a service is correctly formatted. """ msg = yaml.load(message) self.assertTrue(isinstance(msg, dict), msg="message is not a dictionary.") self.assertIn('vim_uuid', msg.keys(), msg="vim_uuid is not a key in the dictionary.") self.assertIn('nsd', msg.keys(), msg="nsd is not a key in the dictionary.") self.assertIn('vnfds', msg.keys(), msg="vnfds is not a key in the dictionary.") self.assertIn('instance_uuid', msg['nsd'].keys(), msg="instance_uuid is not a key in the dictionary.") for vnfd in msg['vnfds']: self.assertIn('instance_uuid', vnfd.keys(), msg='intance_uuid is not a key in the dictionary.') self.firstEventFinished() def testReactionToCorrectlyFormattedVimList(self): """ This method tests the response of the SLM when it receives a valid VIM list. The SLM should choose a VIM out of the list, and request whether it has enough resources to host the service. """ self.wait_for_first_event.clear() self.wait_for_second_event.clear() #STEP1: Spy the topic on which the SLM will contact the infrastructure adaptor self.manoconn_spy.subscribe(self.on_slm_infra_adaptor_vim_list_test3, 'infrastructure.management.compute.list') #STEP2: Spy the topic on which the SLM will contact the infrastructure adaptor the first time, to request the resource availability. self.manoconn_spy.subscribe( self.on_slm_infra_adaptor_service_deploy_request_test3, 'infrastructure.service.deploy') #STEP3: Send a correctly formatted service request message (from the gk) to the SLM self.manoconn_gk.call_async( self.dummy, 'service.instances.create', msg=self.createGkNewServiceRequestMessage(correctlyFormatted=True), content_type='application/yaml', correlation_id=self.corr_id) #STEP4: Start waiting for the messages that are triggered by this request self.waitForFirstEvent( timeout=10, msg= 'Wait for message from SLM to IA to request resources timed out.') ############################################################### #TEST4: Test Reaction when SLM receives an empty list of VIMs. ############################################################### def on_slm_infra_adaptor_vim_list_test4(self, ch, method, properties, message): """ This method replies to a request of the SLM to the IA to get the VIM-list. """ if properties.app_id == 'son-plugin.ServiceLifecycleManager': VIM_list = [] self.manoconn_ia.notify('infrastructure.management.compute.list', yaml.dump(VIM_list), correlation_id=properties.correlation_id) def on_slm_response_to_gk_with_empty_vim_list(self, ch, method, properties, message): """ This method checks the content of the message send from SLM to the GK to indicate that there are no vims available. """ msg = yaml.load(message) #We don't want to trigger on the first response (the async_call), butonly on the second(the notify) and we don't want to trigger on our outgoing message. if properties.app_id == 'son-plugin.ServiceLifecycleManager': if msg['status'] != 'INSTANTIATING': self.assertTrue(isinstance(msg, dict), msg='message is not a dictionary.') self.assertEqual(msg['status'], 'ERROR', msg='status is not correct.') self.assertEqual(msg['error'], 'No VIM.', msg='error message is not correct.') self.assertTrue(isinstance(msg['timestamp'], float), msg='timestamp is not a float.') self.firstEventFinished() def testReactionToWronglyFormattedVimList(self): """ This method tests the response of the SLM when it receives an empty VIM list. The SLM should report back to the gk with an error. """ self.wait_for_first_event.clear() #STEP1: Spy the topic on which the SLM will contact the infrastructure adaptor self.manoconn_spy.subscribe(self.on_slm_infra_adaptor_vim_list_test4, 'infrastructure.management.compute.list') #STEP2: Spy the topic on which the SLM will contact the GK, to indicate that the deployment is stopped due to lack of resources. self.manoconn_spy.subscribe( self.on_slm_response_to_gk_with_empty_vim_list, 'service.instances.create') #STEP3: Send a correctly formatted service request message (from the gk) to the SLM self.manoconn_gk.call_async( self.on_slm_response_to_gk_with_empty_vim_list, 'service.instances.create', msg=self.createGkNewServiceRequestMessage(correctlyFormatted=True), content_type='application/yaml', correlation_id=self.corr_id) #STEP4: Start waiting for the messages that are triggered by this request self.waitForFirstEvent( timeout=10, msg= 'Wait for message from SLM to IA to request resources timed out.') ############################################################################### #TEST7: Test reaction to negative response on deployment message to/from IA ############################################################################### def on_slm_infra_adaptor_vim_list_test7(self, ch, method, properties, message): """ This method replies to a request of the SLM to the IA to get the VIM-list. """ if properties.app_id == 'son-plugin.ServiceLifecycleManager': VIM_list = [{'vim_uuid': uuid.uuid4().hex}] self.manoconn_ia.notify('infrastructure.management.compute.list', yaml.dump(VIM_list), correlation_id=properties.correlation_id) def on_slm_infra_adaptor_service_deploy_request_test7( self, ch, method, properties, message): """ This method fakes a message from the IA to the SLM that indicates that the deployment has failed. """ if properties.app_id == 'son-plugin.ServiceLifecycleManager': reply_message = {'request_status': 'failed'} self.manoconn_ia.notify('infrastructure.service.deploy', yaml.dump(reply_message), correlation_id=properties.correlation_id) def on_slm_gk_service_deploy_request_failed(self, ch, method, properties, message): """ This method checks whether the message from the SLM to the GK to indicate that the deployment failed is correctly formatted. """ msg = yaml.load(message) #We don't want to trigger on the first response (the async_call), but only on the second(the notify) and we don't want to trigger on our outgoing message. if properties.app_id == 'son-plugin.ServiceLifecycleManager': if msg['status'] != 'INSTANTIATING': self.assertTrue(isinstance(msg, dict), msg='message is not a dictionary.') self.assertEqual(msg['status'], "ERROR", msg='status is not correct.') self.assertEqual(msg['error'], 'Deployment result: failed', msg='error message is not correct.') self.assertTrue(isinstance(msg['timestamp'], float), msg='timestamp is not a float.') self.firstEventFinished() def testReactionToNegativeReplyOnDeploymentFromIA(self): """ When the SLM contacts the IA to request whether enough resources are available, it gets a response from the IA. If this response indicates that the resources are available, the SLM should requestthe deployment of the service to the IA. """ self.wait_for_first_event.clear() #STEP1: Spy the topic on which the SLM will contact the infrastructure adaptor self.manoconn_spy.subscribe(self.on_slm_infra_adaptor_vim_list_test7, 'infrastructure.management.compute.list') #STEP2: Spy the topic on which the SLM will contact the IA the second time, to request the deployment of the service self.manoconn_ia.subscribe( self.on_slm_infra_adaptor_service_deploy_request_test7, 'infrastructure.service.deploy') #STEP3: Spy the topic on which the SLM will contact the GK to respond that the deployment has failed. self.manoconn_gk.subscribe( self.on_slm_gk_service_deploy_request_failed, 'service.instances.create') #STEP4: Send a correctly formatted service request message (from the gk) to the SLM self.manoconn_gk.call_async( self.dummy, 'service.instances.create', msg=self.createGkNewServiceRequestMessage(correctlyFormatted=True), content_type='application/yaml', correlation_id=self.corr_id) #STEP5: Start waiting for the messages that are triggered by this request self.waitForFirstEvent( timeout=15, msg= 'Wait for message from SLM to IA to request deployment timed out.') ############################################################################### #TEST8: Test Monitoring message creation. ############################################################################### def testMonitoringMessageGeneration(self): """ SLM should generate a message for the monitoring module in order to start the monitoring process to the deployed network service. This message is generated from the information existing in NSD, VNFDs, NSRs and VNFs. The test checks that, given the sonata-demo network service, SLM correctly generates the expected message for the monitoring module. """ #STEP1: create NSD and VNFD by reading test descriptors. gk_request = yaml.load(self.createGkNewServiceRequestMessage()) #STEP2: add ids to NSD and VNFDs (those used in the expected message) gk_request['NSD']['uuid'] = '005606ed-be7d-4ce3-983c-847039e3a5a2' gk_request['VNFD1']['uuid'] = '6a15313f-cb0a-4540-baa2-77cc6b3f5b68' gk_request['VNFD2']['uuid'] = '645db4fa-a714-4cba-9617-4001477d1281' gk_request['VNFD3']['uuid'] = '8a0aa837-ec1c-44e5-9907-898f6401c3ae' #STEP3: load nsr_file, containing both NSR and the list of VNFRs message_from_ia = yaml.load( open( '/plugins/son-mano-service-lifecycle-management/test/test_records/ia-nsr.yml', 'r')) nsr_file = yaml.load( open( '/plugins/son-mano-service-lifecycle-management/test/test_records/sonata-demo-nsr.yml', 'r')) vnfrs_file = yaml.load( open( '/plugins/son-mano-service-lifecycle-management/test/test_records/sonata-demo-vnfrs.yml', 'r')) #STEP4: call real method message = tools.build_monitoring_message(gk_request, message_from_ia, nsr_file, vnfrs_file) #STEP5: read expected message from descriptor file expected_message = json.load( open( '/plugins/son-mano-service-lifecycle-management/test/test_descriptors/monitoring-message.json', 'r')) #STEP6: compare that generated message is equals to the expected one self.assertEqual(message, expected_message, "messages are not equals") ############################################################################### #TEST9: Test creation of the message addressed to the Monitoring Repository ############################################################################### def testNsrCreation(self): """ Once the Infrastructure Adapter has deployed the network service, it would build the entire NSR from the information provided by the Infrastructure Adapter. This test checks that, given the sonata-demo network service, the IA is able to build the correct NSR. """ #STEP1: create NSD and VNFD by reading test descriptors. gk_request = yaml.load(self.createGkNewServiceRequestMessage()) #STEP2: read IA response and the expected NSR ia_nsr = yaml.load( open( '/plugins/son-mano-service-lifecycle-management/test/test_records/ia-nsr.yml', 'r')) expected_nsr = yaml.load( open( '/plugins/son-mano-service-lifecycle-management/test/test_records/sonata-demo-nsr.yml', 'r')) #STEP3: call real method message = tools.build_nsr(gk_request, ia_nsr) #STEP4: comprare the generated message is equals to the expected one self.assertEqual(message, expected_nsr, "Built NSR is not equal to the expected one") ############################################################################### #TEST10: Test creation of the NSR ############################################################################### def testVnfrsCreation(self): #STEP1: create NSD and VNFD by reading test descriptors. gk_request = yaml.load(self.createGkNewServiceRequestMessage()) #STEP2: read IA response and the expected NSR ia_nsr = yaml.load( open( '/plugins/son-mano-service-lifecycle-management/test/test_records/ia-nsr.yml', 'r')) expected_vnfrs = yaml.load( open( '/plugins/son-mano-service-lifecycle-management/test/test_records/sonata-demo-vnfrs.yml', 'r')) message = tools.build_vnfrs(gk_request, ia_nsr['vnfrs']) self.assertEqual(message, expected_vnfrs, "Built VNFRs are not equals to the expected ones")
class TestPluginManagerBase(unittest.TestCase): """ Commen functionalities used my many test cases """ pm_proc = None @classmethod def setUpClass(cls): # start the plugin manger in another process so that we can connect to it using its broker interface cls.pm_proc = Process(target=SonPluginManager) cls.pm_proc.daemon = True cls.pm_proc.start() time.sleep(1) # give the plugin manager some time to start @classmethod def tearDownClass(cls): if cls.pm_proc is not None: cls.pm_proc.terminate() del cls.pm_proc def setUp(self): # initialize messaging subsystem self.m = ManoBrokerRequestResponseConnection("pm-client" + self.id()) self.wait_for_reply = threading.Event() self.plugin_uuid = None def tearDown(self): self.m.stop_connection() self.m.stop_threads() del self.m def waitForMessage(self, timeout=5): self.wait_for_reply.clear() if not self.wait_for_reply.wait(timeout): raise Exception("Timeout in wait for reply message.") def messageReceived(self): self.wait_for_reply.set() def register(self): """ Helper: We need this in many tests. :return: """ def on_register_reply(ch, method, properties, message): msg = json.loads(str(message)) assert(msg.get("status") == "OK") assert(len(msg.get("uuid")) > 0) assert(msg.get("error") is None) # set internal state variables self.plugin_uuid = msg.get("uuid") # stop waiting self.messageReceived() # create register request message msg = dict(name="test-plugin", version="v0.01", description="description") # do the registration call self.m.call_async(on_register_reply, "platform.management.plugin.register", json.dumps(msg)) # make our test synchronous: wait self.waitForMessage() def deregister(self): """ Helper: We need this in many tests. :return: """ assert(self.plugin_uuid is not None) def on_deregister_reply(ch, method, properties, message): msg = json.loads(str(message)) assert(msg.get("status") == "OK") # stop waiting self.messageReceived() # create register request message msg = dict(uuid=self.plugin_uuid) # do the registration call self.m.call_async(on_deregister_reply, "platform.management.plugin.deregister", json.dumps(msg)) # make our test synchronous: wait self.waitForMessage()
class testSlmFunctionality(unittest.TestCase): """ Tests the tasks that the SLM should perform in the service life cycle of the network services. """ slm_proc = None manoconn_pm = None uuid = '1' corr_id = '1ba347d6-6210-4de7-9ca3-a383e50d0330' ######################## #SETUP ######################## # @classmethod # def setUpClass(cls): # """ # Starts the SLM instance and takes care if its registration. # """ # def on_register_trigger(ch, method, properties, message): # return json.dumps({'status':'OK','uuid':cls.uuid}) # #Some threading events that can be used during the tests # cls.wait_for_first_event = threading.Event() # cls.wait_for_first_event.clear() # cls.wait_for_second_event = threading.Event() # cls.wait_for_second_event.clear() #Deploy SLM and a connection to the broker # cls.slm_proc = Process(target=ServiceLifecycleManager) # cls.slm_proc.daemon = True # cls.manoconn_pm = ManoBrokerRequestResponseConnection('Son-plugin.SonPluginManager') # cls.manoconn_pm.subscribe(on_register_trigger,'platform.management.plugin.register') # cls.slm_proc.start() #wait until registration process finishes # if not cls.wait_for_first_event.wait(timeout=5): # pass @classmethod def tearDownClass(cls): if cls.slm_proc is not None: cls.slm_proc.terminate() del cls.slm_proc # cls.manoconn_pm.stop_connection() def setUp(self): def on_register_trigger(ch, method, properties, message): return json.dumps({'status': 'OK', 'uuid': self.uuid}) #Generate a new corr_id for every test self.corr_id = str(uuid.uuid4()) #Some threading events that can be used during the tests self.wait_for_first_event = threading.Event() self.wait_for_first_event.clear() self.wait_for_second_event = threading.Event() self.wait_for_second_event.clear() #Deploy SLM and a connection to the broker self.slm_proc = Process(target=ServiceLifecycleManager) self.slm_proc.daemon = True self.manoconn_pm = ManoBrokerRequestResponseConnection('son-plugin.SonPluginManager') self.manoconn_pm.subscribe(on_register_trigger, 'platform.management.plugin.register') self.slm_proc.start() #wait until registration process finishes if not self.wait_for_first_event.wait(timeout=5): pass #We make a spy connection to listen to the different topics on the broker self.manoconn_spy = ManoBrokerRequestResponseConnection('son-plugin.SonSpy') #we need a connection to simulate messages from the gatekeeper self.manoconn_gk = ManoBrokerRequestResponseConnection('son-plugin.SonGateKeeper') #we need a connection to simulate messages from the infrastructure adaptor self.manoconn_ia = ManoBrokerRequestResponseConnection('son-plugin.SonInfrastructureAdapter') def tearDown(self): try: self.manoconn_spy.stop_connection() self.manoconn_gk.stop_connection() self.manoconn_ia.stop_connection() except Exception as e: LOG.exception("Stop connection exception.") ######################## #GENERAL ######################## def createGkNewServiceRequestMessage(self, correctlyFormatted=True): """ This method helps creating messages for the service request packets. If it needs to be wrongly formatted, the nsd part of the request is removed. """ path_descriptors = '/plugins/son-mano-service-lifecycle-management/test/test_descriptors/' nsd_descriptor = open(path_descriptors + 'sonata-demo.yml', 'r') vnfd1_descriptor = open(path_descriptors + 'firewall-vnfd.yml', 'r') vnfd2_descriptor = open(path_descriptors + 'iperf-vnfd.yml', 'r') vnfd3_descriptor = open(path_descriptors + 'tcpdump-vnfd.yml', 'r') #import the nsd and vnfds that form the service if correctlyFormatted: service_request = {'NSD': yaml.load(nsd_descriptor), 'VNFD1': yaml.load(vnfd1_descriptor), 'VNFD2': yaml.load(vnfd2_descriptor), 'VNFD3': yaml.load(vnfd3_descriptor)} else: service_request = {'VNFD1': yaml.load(vnfd1_descriptor), 'VNFD2': yaml.load(vnfd2_descriptor), 'VNFD3': yaml.load(vnfd3_descriptor)} return yaml.dump(service_request) #Method that terminates the timer that waits for an event def firstEventFinished(self): self.wait_for_first_event.set() def secondEventFinished(self): self.wait_for_second_event.set() #Method that starts a timer, waiting for an event def waitForFirstEvent(self, timeout=5, msg="Event timed out."): if not self.wait_for_first_event.wait(timeout): self.assertEqual(True, False, msg=msg) def waitForSecondEvent(self, timeout=5, msg="Event timed out."): if not self.wait_for_second_event.wait(timeout): self.assertEqual(True, False, msg=msg) def dummy(self, ch, method, properties, message): """ Sometimes, we need a cbf for a async_call, without actually needing it. """ return ############################################################# #TEST1: Test Reaction To Correctly Formatted Service Request. ############################################################# def on_slm_infra_adaptor_vim_list_test1(self, ch, method, properties, message): """ This method checks what the SLM sends towards the IA when it receives a valid request from the gk. """ msg = yaml.load(message) #The message should have an empty body and a correlation_id different from the original correlation_id self.assertEqual(msg, {}, msg='message is not empty.') self.assertNotEqual(properties.correlation_id, self.corr_id, msg='message does not contain a new correlation_id.') self.assertEqual(properties.reply_to, 'infrastructure.management.compute.list', msg='not the correct reply_to topic.') self.firstEventFinished() def on_gk_response_to_correct_service_request(self, ch, method, properties, message): """ This method checks whether the SLM responds to a correctly formatted new service request it receives from the GK. """ msg = yaml.load(message) self.assertTrue(isinstance(msg, dict), msg='response to service request is not a dictionary.') self.assertEqual(msg['status'], 'INSTANTIATING', msg='not correct response, should be INSTANTIATING.') self.assertEqual(msg['error'], None, msg='not correct response, should be None.') self.assertTrue(isinstance(msg['timestamp'], float), msg='timestamp is not a float') self.assertEqual(properties.correlation_id, self.corr_id, msg='response to async call doesnt have the same correlation_id') self.secondEventFinished() def testReactionToCorrectlyFormattedServiceRequest(self): """ If the gk sends a request on the service.instances.create topic that is correctly formatted, then the SLM should respond by doing 2 things: 1. Replying with the message {'status':'INSTANTIATING', 'error':NULL, 'timestamp':<timestamp>} with the same correlation_id as the one in the request. 2. Requesting the available vims from the IA on the infrastructure.management.compute.list topic with a new correlation id and an empty body. """ self.wait_for_first_event.clear() self.wait_for_second_event.clear() #STEP1: Spy the topic on which the SLM will contact the infrastructure adaptor self.manoconn_spy.subscribe(self.on_slm_infra_adaptor_vim_list_test1, 'infrastructure.management.compute.list') #STEP2: Send a correctly formatted service request message (from the gk) to the SLM self.manoconn_gk.call_async(self.on_gk_response_to_correct_service_request, 'service.instances.create', msg=self.createGkNewServiceRequestMessage(correctlyFormatted=True), content_type='application/yaml', correlation_id=self.corr_id) #STEP3: Start waiting for the messages that are triggered by this request self.waitForFirstEvent(timeout=10, msg='Wait for message from SLM to IA to request resources timed out.') self.waitForSecondEvent(timeout=10, msg='Wait for reply to request from GK timed out.') ########################################################### #TEST2: Test reaction to wrongly formatted service request. ########################################################### def on_gk_response_to_wrong_service_request(self, ch, method, properties, message): """ This method checks whether the SLM responds to a wrongly formatted new service request it receives from the GK. """ msg = yaml.load(message) self.assertTrue(isinstance(msg, dict), msg='response to service request is not a dictionary.') self.assertEqual(msg['status'], 'ERROR', msg='not correct response, should be ERROR') self.assertTrue(isinstance(msg['error'], str), msg='Error message is not a string.') self.assertTrue(isinstance(msg['timestamp'], float), msg='timestamp is not a float') self.assertEqual(properties.correlation_id, self.corr_id, msg='response to async call doesnt have the same correlation_id') self.firstEventFinished() def testReactionToWronglyFormattedServiceRequest(self): """ If the gk sends a request on the service.instances.create topic that is wrongly formatted, then the SLM should respond by replying with the message {'status':'ERROR', 'error':<error message>, 'timestamp':<timestamp>} with the same correlation_id as the one in the request. """ self.wait_for_first_event.clear() #STEP1: Send a wrongly formatted service request message (from the gk) to the SLM self.manoconn_gk.call_async(self.on_gk_response_to_wrong_service_request, 'service.instances.create', msg=self.createGkNewServiceRequestMessage(correctlyFormatted=False), content_type='application/yaml', correlation_id=self.corr_id) #STEP2: Start waiting for the messages that are triggered by this request self.waitForFirstEvent(timeout=10, msg='Wait for reply to request from GK timed out.') ############################################################### #TEST3: Test Reaction when SLM receives a valid list of VIMs. ############################################################### def on_slm_infra_adaptor_vim_list_test3(self, ch, method, properties, message): """ This method replies to a request of the SLM to the IA to get the VIM-list. """ if properties.app_id == 'son-plugin.ServiceLifecycleManager': VIM_list = [{'vim_uuid': uuid.uuid4().hex}, {'vim_uuid': uuid.uuid4().hex}, {'vim_uuid': uuid.uuid4().hex}] self.manoconn_ia.notify('infrastructure.management.compute.list', yaml.dump(VIM_list), correlation_id=properties.correlation_id) def on_slm_infra_adaptor_service_deploy_request_test3(self, ch, method, properties, message): """ This method checks whether the request from the SLM to the IA to deploy a service is correctly formatted. """ msg = yaml.load(message) self.assertTrue(isinstance(msg, dict), msg="message is not a dictionary.") self.assertIn('vim_uuid', msg.keys(), msg="vim_uuid is not a key in the dictionary.") self.assertIn('nsd', msg.keys(), msg="nsd is not a key in the dictionary.") self.assertIn('vnfds', msg.keys(), msg="vnfds is not a key in the dictionary.") self.assertIn('instance_uuid', msg['nsd'].keys(), msg="instance_uuid is not a key in the dictionary.") for vnfd in msg['vnfds']: self.assertIn('instance_uuid', vnfd.keys(), msg='intance_uuid is not a key in the dictionary.') self.firstEventFinished() def testReactionToCorrectlyFormattedVimList(self): """ This method tests the response of the SLM when it receives a valid VIM list. The SLM should choose a VIM out of the list, and request whether it has enough resources to host the service. """ self.wait_for_first_event.clear() self.wait_for_second_event.clear() #STEP1: Spy the topic on which the SLM will contact the infrastructure adaptor self.manoconn_spy.subscribe(self.on_slm_infra_adaptor_vim_list_test3, 'infrastructure.management.compute.list') #STEP2: Spy the topic on which the SLM will contact the infrastructure adaptor the first time, to request the resource availability. self.manoconn_spy.subscribe(self.on_slm_infra_adaptor_service_deploy_request_test3, 'infrastructure.service.deploy') #STEP3: Send a correctly formatted service request message (from the gk) to the SLM self.manoconn_gk.call_async(self.dummy, 'service.instances.create', msg=self.createGkNewServiceRequestMessage(correctlyFormatted=True), content_type='application/yaml', correlation_id=self.corr_id) #STEP4: Start waiting for the messages that are triggered by this request self.waitForFirstEvent(timeout=10, msg='Wait for message from SLM to IA to request resources timed out.') ############################################################### #TEST4: Test Reaction when SLM receives an empty list of VIMs. ############################################################### def on_slm_infra_adaptor_vim_list_test4(self, ch, method, properties, message): """ This method replies to a request of the SLM to the IA to get the VIM-list. """ if properties.app_id == 'son-plugin.ServiceLifecycleManager': VIM_list = [] self.manoconn_ia.notify('infrastructure.management.compute.list', yaml.dump(VIM_list), correlation_id=properties.correlation_id) def on_slm_response_to_gk_with_empty_vim_list(self, ch, method, properties, message): """ This method checks the content of the message send from SLM to the GK to indicate that there are no vims available. """ msg = yaml.load(message) #We don't want to trigger on the first response (the async_call), butonly on the second(the notify) and we don't want to trigger on our outgoing message. if properties.app_id == 'son-plugin.ServiceLifecycleManager': if msg['status'] != 'INSTANTIATING': self.assertTrue(isinstance(msg, dict), msg='message is not a dictionary.') self.assertEqual(msg['status'], 'ERROR', msg='status is not correct.') self.assertEqual(msg['error'], 'No VIM.', msg='error message is not correct.') self.assertTrue(isinstance(msg['timestamp'], float), msg='timestamp is not a float.') self.firstEventFinished() def testReactionToWronglyFormattedVimList(self): """ This method tests the response of the SLM when it receives an empty VIM list. The SLM should report back to the gk with an error. """ self.wait_for_first_event.clear() #STEP1: Spy the topic on which the SLM will contact the infrastructure adaptor self.manoconn_spy.subscribe(self.on_slm_infra_adaptor_vim_list_test4, 'infrastructure.management.compute.list') #STEP2: Spy the topic on which the SLM will contact the GK, to indicate that the deployment is stopped due to lack of resources. self.manoconn_spy.subscribe(self.on_slm_response_to_gk_with_empty_vim_list, 'service.instances.create') #STEP3: Send a correctly formatted service request message (from the gk) to the SLM self.manoconn_gk.call_async(self.on_slm_response_to_gk_with_empty_vim_list, 'service.instances.create', msg=self.createGkNewServiceRequestMessage(correctlyFormatted=True), content_type='application/yaml', correlation_id=self.corr_id) #STEP4: Start waiting for the messages that are triggered by this request self.waitForFirstEvent(timeout=10, msg='Wait for message from SLM to IA to request resources timed out.') ############################################################################### #TEST7: Test reaction to negative response on deployment message to/from IA ############################################################################### def on_slm_infra_adaptor_vim_list_test7(self, ch, method, properties, message): """ This method replies to a request of the SLM to the IA to get the VIM-list. """ if properties.app_id == 'son-plugin.ServiceLifecycleManager': VIM_list = [{'vim_uuid':uuid.uuid4().hex}] self.manoconn_ia.notify('infrastructure.management.compute.list', yaml.dump(VIM_list), correlation_id=properties.correlation_id) def on_slm_infra_adaptor_service_deploy_request_test7(self, ch, method, properties, message): """ This method fakes a message from the IA to the SLM that indicates that the deployment has failed. """ if properties.app_id == 'son-plugin.ServiceLifecycleManager': reply_message = {'request_status':'failed'} self.manoconn_ia.notify('infrastructure.service.deploy', yaml.dump(reply_message), correlation_id=properties.correlation_id) def on_slm_gk_service_deploy_request_failed(self, ch, method, properties, message): """ This method checks whether the message from the SLM to the GK to indicate that the deployment failed is correctly formatted. """ msg = yaml.load(message) #We don't want to trigger on the first response (the async_call), but only on the second(the notify) and we don't want to trigger on our outgoing message. if properties.app_id == 'son-plugin.ServiceLifecycleManager': if msg['status'] != 'INSTANTIATING': self.assertTrue(isinstance(msg, dict), msg='message is not a dictionary.') self.assertEqual(msg['status'], "ERROR", msg='status is not correct.') self.assertEqual(msg['error'], 'Deployment result: failed', msg='error message is not correct.') self.assertTrue(isinstance(msg['timestamp'], float), msg='timestamp is not a float.') self.firstEventFinished() def testReactionToNegativeReplyOnDeploymentFromIA(self): """ When the SLM contacts the IA to request whether enough resources are available, it gets a response from the IA. If this response indicates that the resources are available, the SLM should requestthe deployment of the service to the IA. """ self.wait_for_first_event.clear() #STEP1: Spy the topic on which the SLM will contact the infrastructure adaptor self.manoconn_spy.subscribe(self.on_slm_infra_adaptor_vim_list_test7, 'infrastructure.management.compute.list') #STEP2: Spy the topic on which the SLM will contact the IA the second time, to request the deployment of the service self.manoconn_ia.subscribe(self.on_slm_infra_adaptor_service_deploy_request_test7, 'infrastructure.service.deploy') #STEP3: Spy the topic on which the SLM will contact the GK to respond that the deployment has failed. self.manoconn_gk.subscribe(self.on_slm_gk_service_deploy_request_failed, 'service.instances.create') #STEP4: Send a correctly formatted service request message (from the gk) to the SLM self.manoconn_gk.call_async(self.dummy, 'service.instances.create', msg=self.createGkNewServiceRequestMessage(correctlyFormatted=True), content_type='application/yaml', correlation_id=self.corr_id) #STEP5: Start waiting for the messages that are triggered by this request self.waitForFirstEvent(timeout=15, msg='Wait for message from SLM to IA to request deployment timed out.') ############################################################################### #TEST8: Test Monitoring message creation. ############################################################################### def testMonitoringMessageGeneration(self): """ SLM should generate a message for the monitoring module in order to start the monitoring process to the deployed network service. This message is generated from the information existing in NSD, VNFDs, NSRs and VNFs. The test checks that, given the sonata-demo network service, SLM correctly generates the expected message for the monitoring module. """ #STEP1: create NSD and VNFD by reading test descriptors. gk_request = yaml.load(self.createGkNewServiceRequestMessage()) #STEP2: add ids to NSD and VNFDs (those used in the expected message) gk_request['NSD']['uuid'] = '005606ed-be7d-4ce3-983c-847039e3a5a2' gk_request['VNFD1']['uuid'] = '6a15313f-cb0a-4540-baa2-77cc6b3f5b68' gk_request['VNFD2']['uuid'] = '645db4fa-a714-4cba-9617-4001477d1281' gk_request['VNFD3']['uuid'] = '8a0aa837-ec1c-44e5-9907-898f6401c3ae' #STEP3: load nsr_file, containing both NSR and the list of VNFRs message_from_ia = yaml.load(open('/plugins/son-mano-service-lifecycle-management/test/test_records/ia-nsr.yml', 'r')) nsr_file = yaml.load(open('/plugins/son-mano-service-lifecycle-management/test/test_records/sonata-demo-nsr.yml', 'r')) vnfrs_file = yaml.load(open('/plugins/son-mano-service-lifecycle-management/test/test_records/sonata-demo-vnfrs.yml', 'r')) #STEP4: call real method message = tools.build_monitoring_message(gk_request, message_from_ia, nsr_file, vnfrs_file) #STEP5: read expected message from descriptor file expected_message = json.load(open('/plugins/son-mano-service-lifecycle-management/test/test_descriptors/monitoring-message.json', 'r')) #STEP6: compare that generated message is equals to the expected one self.assertEqual(message, expected_message, "messages are not equals") ############################################################################### #TEST9: Test creation of the message addressed to the Monitoring Repository ############################################################################### def testNsrCreation(self): """ Once the Infrastructure Adapter has deployed the network service, it would build the entire NSR from the information provided by the Infrastructure Adapter. This test checks that, given the sonata-demo network service, the IA is able to build the correct NSR. """ #STEP1: create NSD and VNFD by reading test descriptors. gk_request = yaml.load(self.createGkNewServiceRequestMessage()) #STEP2: read IA response and the expected NSR ia_nsr = yaml.load(open('/plugins/son-mano-service-lifecycle-management/test/test_records/ia-nsr.yml', 'r')) expected_nsr = yaml.load(open('/plugins/son-mano-service-lifecycle-management/test/test_records/sonata-demo-nsr.yml', 'r')) #STEP3: call real method message = tools.build_nsr(gk_request, ia_nsr) #STEP4: comprare the generated message is equals to the expected one self.assertEqual(message, expected_nsr, "Built NSR is not equal to the expected one") ############################################################################### #TEST10: Test creation of the NSR ############################################################################### def testVnfrsCreation(self): #STEP1: create NSD and VNFD by reading test descriptors. gk_request = yaml.load(self.createGkNewServiceRequestMessage()) #STEP2: read IA response and the expected NSR ia_nsr = yaml.load(open('/plugins/son-mano-service-lifecycle-management/test/test_records/ia-nsr.yml', 'r')) expected_vnfrs = yaml.load(open('/plugins/son-mano-service-lifecycle-management/test/test_records/sonata-demo-vnfrs.yml', 'r')) message = tools.build_vnfrs(gk_request, ia_nsr['vnfrs']) self.assertEqual(message, expected_vnfrs, "Built VNFRs are not equals to the expected ones")
class testSlmFunctionality(unittest.TestCase): """ Tests the tasks that the SLM should perform in the service life cycle of the network services. """ slm_proc = None manoconn_pm = None uuid = '1' @classmethod def setUpClass(cls): """ Starts the SLM instance and takes care if its registration. """ def on_register_trigger(ch, method, properties, message): return json.dumps({'status':'OK','uuid':cls.uuid}) #Some threading events that can be used during the tests cls.wait_for_event = threading.Event() cls.wait_for_event.clear() #Deploy SLM and a connection to the broker cls.slm_proc = Process(target=ServiceLifecycleManager) cls.slm_proc.daemon = True cls.manoconn_pm = ManoBrokerRequestResponseConnection('Son-plugin.SonPluginManager') cls.manoconn_pm.subscribe(on_register_trigger,'platform.management.plugin.register') cls.slm_proc.start() #wait until registration process finishes if not cls.wait_for_event.wait(timeout=5): pass @classmethod def tearDownClass(cls): if cls.slm_proc is not None: cls.slm_proc.terminate() del cls.slm_proc # cls.manoconn_pm.stop_connection() def setUp(self): #We make a spy connection to listen to the different topics on the broker self.manoconn_spy = ManoBrokerRequestResponseConnection('Son-plugin.SonSpy') #we need a connection to simulate messages from the gatekeeper self.manoconn_gk = ManoBrokerRequestResponseConnection('Son-plugin.SonGateKeeper') #we need a connection to simulate messages from the infrastructure adapter self.manoconn_ia = ManoBrokerRequestResponseConnection('Son-plugin.SonInfrastructureAdapter') #def tearDown(self): #self.manoconn_spy.stop_connection() #self.manoconn_gk.stop_connection() #self.manoconn_ia.stop_connection() def createGkNewServiceRequestMessage(self): """ This method helps creating messages for the service request packets. """ path_descriptors = '/plugins/son-mano-service-lifecycle-management/test/test_descriptors/' #import the nsd and vnfds that form the service nsd_descriptor = open(path_descriptors + 'sonata-demo.yml','r') vnfd1_descriptor = open(path_descriptors + 'firewall-vnfd.yml','r') vnfd2_descriptor = open(path_descriptors + 'iperf-vnfd.yml','r') vnfd3_descriptor = open(path_descriptors + 'tcpdump-vnfd.yml','r') service_request = {'NSD': yaml.load(nsd_descriptor), 'VNFD1': yaml.load(vnfd1_descriptor), 'VNFD2': yaml.load(vnfd2_descriptor), 'VNFD3': yaml.load(vnfd3_descriptor)} return yaml.dump(service_request) #Method that terminates the timer that waits for an event def eventFinished(self): self.wait_for_event.set() #Method that starts a timer, waiting for an event def waitForEvent(self, timeout=5, msg="Event timed out."): if not self.wait_for_event.wait(timeout): self.assertEqual(True, False, msg=msg) def on_slm_infra_adaptor_instantiation(self, ch, method, properties, message): msg = yaml.load(message) self.assertIn('forwarding_graph', msg.keys(), msg='forwarding_graph is not a key.') self.assertIn('vnf_images', msg.keys(), msg='vnf_images is not a key.') for vnf in msg['vnf_images']: self.assertIn('vnf_id', vnf.keys(), msg='vnf_id is not a key.') self.assertIn('url', vnf.keys(), msg='url is not a key.') self.eventFinished() def on_slm_gk_response(self, ch, method, properties, message): self.eventFinished() def on_gk_response_service_request(self, ch, method, properties, message): #TODO return def on_service_deployment_response(self, ch, method, properties, message): msg = yaml.load(message) self.assertIn('request_status', msg.keys(), msg='request_status is not a key') return def do_nothing(self, ch, method, properties, message): return @unittest.skip("trueee") def testResponseToGkNewServiceRequest(self): """ This method tests the reaction of the SLM when it receives a message from the gk, targetted to the infrastructure adaptor. """ #STEP1: Spy the topic on which the SLM will contact the infrastructure adaptor self.manoconn_spy.subscribe(self.on_slm_infra_adaptor_instantiation, 'infrastructure.service.deploy') #STEP2: Send a service request message (from the gk) to the SLM self.manoconn_gk.call_async(self.on_gk_response_service_request, 'service.instances.create', msg=self.createGkNewServiceRequestMessage(), content_type='application/yaml', correlation_id='sr1') #STEP3: Start waiting for the messages that are triggered by this request self.waitForEvent(timeout=10) def createInfrastructureAdapterResponseMessage(self): path_descriptors = '/plugins/son-mano-service-lifecycle-management/test/test_descriptors/' ia_nsr = open(path_descriptors + 'infrastructure-adapter-nsr.yml','r') return str(yaml.load(ia_nsr)) def test_on_infra_adaptor_service_deploy_reply(self): #STEP1: Spy the topic on which the SLM will contact the GK self.manoconn_spy.subscribe(self.on_service_deployment_response, 'service.instances.create') #STEP2: Send a service deployment response from Inrastructure Adapter to the SLM self.manoconn_ia.call_async(self.do_nothing, "infrastructure.service.deploy", msg=self.createInfrastructureAdapterResponseMessage(), content_type='application/yaml') #STEP3: Start waiting for the messages that are triggered by this request self.waitForEvent(timeout=10)
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")