示例#1
0
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))
示例#4
0
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()
示例#6
0
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")
示例#7
0
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)
示例#8
0
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")