class testPLEXRegistration(unittest.TestCase):
    """
    Tests the registration process of the Scaling Executive to the broker
    and the plugin manager, and the heartbeat process.
    """

    def setUp(self):
        #a new Scaling Executive in another process for each test
        self.plex_proc = Process(target=ScalingExecutive)
        self.plex_proc.daemon = True

        if 'broker_man_host' in os.environ:
            self.man_host = os.environ['broker_man_host']
        else:
            self.man_host = 'http://localhost:15672'

        if 'sm_broker_host' in os.environ:
            self.sm_host = os.environ['sm_broker_host']
        else:
            self.sm_host = 'http://localhost:15672'
        url_user = "******".format(self.man_host)
        url_create = '{0}/api/vhosts/fsm-1234'.format(self.man_host)
        url_permission = '{0}/api/permissions/fsm-1234/specific-management'.format(self.man_host)
        self.headers = {'content-type': 'application/json'}
        data1 = '{"password":"******","tags":"son-sm"}'
        data2 = '{"configure":".*","write":".*","read":".*"}'
        res = requests.put(url=url_user, headers=self.headers, data=data1, auth=('guest', 'guest'))
        LOG.info(res.content)
        res1 = requests.put(url=url_create, headers=self.headers, auth=('guest', 'guest'))
        LOG.info(res1.content)
        res2= requests.put(url=url_permission, headers=self.headers, data=data2, auth=('guest', 'guest'))
        LOG.info(res2.content)

        #make a new connection with the broker before each test
        url = "{0}/fsm-1234".format(self.sm_host)
        self.manoconn = ManoBrokerRequestResponseConnection('son-plugin.SonPluginManager')
        self.sm_connection = ManoBrokerRequestResponseConnection('son-plugin.FSM', url=url)

        #Some threading events that can be used during the tests
        self.wait_for_event1 = threading.Event()
        self.wait_for_event1.clear()

        self.wait_for_event2 = threading.Event()
        self.wait_for_event2.clear()

    def tearDown(self):
        #Killing the scaling Executive
        if self.plex_proc is not None:
            self.plex_proc.terminate()
        del self.plex_proc

        #Killing the connection with the broker
        try:
            self.manoconn.stop_connection()
            self.sm_connection.stop_connection()
        except Exception as e:
            LOG.exception("Stop connection exception.")

        #Clearing the threading helpers
        del self.wait_for_event1
        del self.wait_for_event2

        url_user = "******".format(self.man_host)
        url_vhost = "{0}/api/vhosts/fsm-1234".format(self.man_host)
        requests.delete(url=url_user, headers=self.headers, auth=('guest', 'guest'))
        requests.delete(url=url_vhost, headers=self.headers, auth=('guest', 'guest'))

    #Method that terminates the timer that waits for an event
    def eventFinished1(self):
        self.wait_for_event1.set()

    def eventFinished2(self):
        self.wait_for_event2.set()

    #Method that starts a timer, waiting for an event
    def waitForEvent1(self, timeout=5, msg="Event timed out."):
        if not self.wait_for_event1.wait(timeout):
            self.assertEqual(True, False, msg=msg)

    def waitForEvent2(self, timeout=5, msg="Event timed out."):
        if not self.wait_for_event2.wait(timeout):
            self.assertEqual(True, False, msg=msg)


    def test_1_SCEX_Registration(self):
        """
        TEST: This test verifies whether the Scaling Executive is sending out a message,
        and whether it contains all the needed info on the
        platform.management.plugin.register topic to register to the plugin
        manager.
        """

        #STEP3a: When receiving the message, we need to check whether all fields present.
        def on_register_receive(ch, method, properties, message):

            msg = yaml.load(message)
            #CHECK: The message should be a dictionary.
            self.assertTrue(isinstance(msg, dict), msg='message is not a dictionary')
            #CHECK: The dictionary should have a key 'name'.
            self.assertIn('name', msg.keys(), msg='No name provided in message.')
            if isinstance(msg['name'], str):
                #CHECK: The value of 'name' should not be an empty string.
                self.assertTrue(len(msg['name']) > 0, msg='empty name provided.')
            else:
                #CHECK: The value of 'name' should be a string
                self.assertEqual(True, False, msg='name is not a string')
            #CHECK: The dictionary should have a key 'version'.
            self.assertIn('version', msg.keys(), msg='No version provided in message.')
            if isinstance(msg['version'], str):
                #CHECK: The value of 'version' should not be an empty string.
                self.assertTrue(len(msg['version']) > 0, msg='empty version provided.')
            else:
                #CHECK: The value of 'version' should be a string
                self.assertEqual(True, False, msg='version is not a string')
            #CHECK: The dictionary should have a key 'description'
            self.assertIn('description', msg.keys(), msg='No description provided in message.')
            if isinstance(msg['description'], str):
                #CHECK: The value of 'description' should not be an empty string.
                self.assertTrue(len(msg['description']) > 0, msg='empty description provided.')
            else:
                #CHECK: The value of 'description' should be a string
                self.assertEqual(True, False, msg='description is not a string')

            # stop waiting
            self.eventFinished1()

        #STEP1: Listen to the platform.management.plugin.register topic
        self.manoconn.subscribe(on_register_receive, 'platform.management.plugin.register')

        #STEP2: Start the Scaling Executive
        self.plex_proc.start()

        #STEP3b: When not receiving the message, the test failed
        self.waitForEvent1(timeout=5, msg="message not received.")

    def test_2_SCEX_request_response(self):

        def on_request_send(ch, method, properties, message):

            if properties.app_id == "son-plugin.ScalingExecutive":
                msg = yaml.load(message)

                self.assertTrue(isinstance(msg, dict), msg='message is not a dictionary')

                self.assertIn('uuid', msg.keys(), msg='No uuid provided in message.')
                if isinstance(msg['uuid'], str):
                    self.assertTrue(msg['uuid'] == '1234', msg='empty uuid provided.')

                self.assertNotIn('scale', msg.keys(), msg='wrong message!')

                res_payload = yaml.dump({'uuid': '1234', 'scale': '2'})

                self.eventFinished1()
                return res_payload

        def on_response_send(ch, method, properties, message):
            if properties.app_id == "son-plugin.ScalingExecutive":
                msg = yaml.load(message)

                self.assertTrue(isinstance(msg, dict), msg='message is not a dictionary')

                self.assertIn('uuid', msg.keys(), msg='No uuid provided in message.')
                if isinstance(msg['uuid'], str):
                    self.assertTrue(msg['uuid'] == '1234', msg='empty uuid provided.')

                self.assertIn('scale', msg.keys(), msg='No scale provided in message.')
                if isinstance(msg['scale'], str):
                    self.assertTrue(msg['scale'] == '2', msg='empty uuid provided.')

                self.eventFinished2()

        self.plex_proc.start()

        time.sleep(2)

        self.manoconn.subscribe(on_response_send, 'scaling.executive.request')
        self.sm_connection.register_async_endpoint(on_request_send, 'scaling.fsm.1234')

        req_payload = yaml.dump({'uuid': '1234'})
        self.manoconn.publish("scaling.executive.request", message=req_payload)

        self.waitForEvent1(timeout=5, msg="response message not received.")
        self.waitForEvent2(timeout=5, msg="request message not received.")
class test_SMR_functionalities(unittest.TestCase):

    @classmethod
    def setUpClass(self):

        self.smr_proc = Process(target=SpecificManagerRegistry)

        self.smr_proc.daemon = True

        self.manoconn = ManoBrokerRequestResponseConnection('son-plugin.SpecificManagerRegistry')


        self.wait_for_ssm_event = threading.Event()
        self.wait_for_ssm_event.clear()

        self.wait_for_fsm_event = threading.Event()
        self.wait_for_fsm_event.clear()

        self.event1 = False
        self.event2 = False

        self.smr_proc.start()
        time.sleep(4)

    @classmethod
    def tearDownClass(self):

        if self.smr_proc is not None:
            self.smr_proc.terminate()
        del self.smr_proc

        try:
            self.manoconn.stop_connection()
        except Exception as e:
            LOG.exception("Stop connection exception.")

        del self.wait_for_fsm_event
        del self.wait_for_ssm_event

    def ssm_eventFinished(self):
        self.wait_for_ssm_event.set()


    def waitForSSMEvent(self, timeout=5, msg="Event timed out."):
        if not self.wait_for_ssm_event.wait(timeout):
            self.assertEqual(True, False, msg=msg)


    def fsm_eventFinished(self):
        self.wait_for_fsm_event.set()


    def waitForFSMEvent(self, timeout=5, msg="Event timed out."):
        if not self.wait_for_fsm_event.wait(timeout):
            self.assertEqual(True, False, msg=msg)

    def test_1_SMR_onboard(self):

        self.event1 = False
        self.event2 = False

        def on_ssm_onboarding_result(ch, method, properties, message):

            if properties.app_id == 'son-plugin.SpecificManagerRegistry':
                result = yaml.load(message)

                self.assertTrue(list(result.keys()) == ['sonssmservice1dumb1','sonssmservice1placement1'] or
                                list(result.keys()) == ['sonssmservice1placement1', 'sonssmservice1dumb1'],
                                msg='not all SSMs results received')

                self.assertTrue(result['sonssmservice1dumb1']['status'] == 'On-boarded',
                                msg='error in onbording sonssmservice1dumb1')

                self.assertTrue(result['sonssmservice1dumb1']['error'] == 'None',
                                msg='error in onbording sonssmservice1dumb1')

                self.assertTrue(result['sonssmservice1placement1']['status'] == 'On-boarded',
                                msg='error in onbording sonssmservice1dumb1')

                self.assertTrue(result['sonssmservice1placement1']['error'] == 'None',
                                msg='error in onbording sonssmservice1placement1')

                self.ssm_eventFinished()

        def on_fsm_onboarding_result(ch, method, properties, message):

            if properties.app_id == 'son-plugin.SpecificManagerRegistry':

                result = yaml.load(message)
                if list(result.keys()) == ['sonfsmservice1function1dumb1']:

                    self.assertTrue(list(result.keys()) == ['sonfsmservice1function1dumb1'],
                                    msg='not all FSMs results in VNFD1 received')

                    self.assertTrue(result['sonfsmservice1function1dumb1']['status'] == 'On-boarded',
                                    msg='error in onbording sonssmservice1dumb1')

                    self.assertTrue(result['sonfsmservice1function1dumb1']['error'] == 'None',
                                    msg='error in onbording sonfsmservice1function1dumb1')

                    self.event1 = True
                else:
                    self.assertTrue(list(result.keys()) ==
                                    ['sonfsmservice1function1monitoring1', 'sonfsmservice1firewallconfiguration1']or
                                    list(result.keys()) ==
                                    ['sonfsmservice1firewallconfiguration1','sonfsmservice1function1monitoring1']
                                    , msg='not all FSMs results in VNFD2 received')

                    self.assertTrue(result['sonfsmservice1function1monitoring1']['status'] == 'On-boarded',
                                    msg='error in onbording sonssmservice1dumb1')

                    self.assertTrue(result['sonfsmservice1function1monitoring1']['error'] == 'None',
                                    msg='error in onbording sonfsmservice1function1monitoring1')

                    self.assertTrue(result['sonfsmservice1firewallconfiguration1']['status'] == 'On-boarded',
                                    msg='error in onbording sonssmservice1dumb1')

                    self.assertTrue(result['sonfsmservice1firewallconfiguration1']['error'] == 'None',
                                    msg='error in onbording sonfsmservice1firewallconfiguration1')

                    self.event2 = True

                if self.event1 and self.event2 == True:
                    self.fsm_eventFinished()



        self.manoconn.subscribe(on_ssm_onboarding_result, 'specific.manager.registry.ssm.on-board')
        self.manoconn.subscribe(on_fsm_onboarding_result, 'specific.manager.registry.fsm.on-board')

        onboaring_proc = Process(target=fakeslm_onboarding)
        onboaring_proc.daemon = True

        onboaring_proc.start()

        self.waitForSSMEvent(timeout=70 , msg='SSM Onboarding request not received.')
        self.waitForFSMEvent(timeout=70, msg='FSM Onboarding request not received.')

        self.wait_for_fsm_event.clear()
        self.wait_for_ssm_event.clear()

        onboaring_proc.terminate()
        del onboaring_proc


    def test_2_SMR_instantiation(self):

        self.event1 = False
        self.event2 = False

        def on_ssm_instantiation_result(ch, method, properties, message):

            if properties.app_id == 'son-plugin.SpecificManagerRegistry':
                result = yaml.load(message)
                self.assertTrue(list(result.keys()) == ['sonssmservice1dumb1', 'sonssmservice1placement1'] or
                                list(result.keys()) == ['sonssmservice1placement1', 'sonssmservice1dumb1'],
                                msg='not all SSMs results received')

                self.assertTrue(result['sonssmservice1dumb1']['status'] == 'Instantiated',
                                msg='error in instantiation sonssmservice1dumb1')

                self.assertTrue(result['sonssmservice1dumb1']['error'] == 'None',
                                msg='error in instantiation sonssmservice1dumb1')

                self.assertTrue(result['sonssmservice1placement1']['status'] == 'Instantiated',
                                msg='error in instantiation sonssmservice1placement1')

                self.assertTrue(result['sonssmservice1placement1']['error'] == 'None',
                                msg='error in instantiation sonssmservice1placement1')

                self.ssm_eventFinished()

        def on_fsm_instantiation_result(ch, method, properties, message):

            if properties.app_id == 'son-plugin.SpecificManagerRegistry':

                result = yaml.load(message)
                if list(result.keys()) == ['sonfsmservice1function1dumb1']:

                    self.assertTrue(list(result.keys()) == ['sonfsmservice1function1dumb1'],
                                    msg='not all FSMs instantiation results in VNFD1 received')

                    self.assertTrue(result['sonfsmservice1function1dumb1']['status'] == 'Instantiated',
                                    msg='error in instantiation sonfsmservice1function1dumb1')

                    self.assertTrue(result['sonfsmservice1function1dumb1']['error'] == 'None',
                                    msg='error in instantiation sonfsmservice1function1dumb1')

                    self.event1 = True
                else:
                    self.assertTrue(list(result.keys()) ==
                                    ['sonfsmservice1function1monitoring1', 'sonfsmservice1firewallconfiguration1'] or
                                    list(result.keys()) ==
                                    ['sonfsmservice1firewallconfiguration1', 'sonfsmservice1function1monitoring1']
                                    , msg='not all FSMs instantiation results in VNFD2 received')

                    self.assertTrue(result['sonfsmservice1function1monitoring1']['status'] == 'Instantiated',
                                    msg='error in instantiation sonfsmservice1function1monitoring1')

                    self.assertTrue(result['sonfsmservice1function1monitoring1']['error'] == 'None',
                                    msg='error in instantiation sonfsmservice1function1monitoring1')

                    self.assertTrue(result['sonfsmservice1firewallconfiguration1']['status'] == 'Instantiated',
                                    msg='error in instantiation sonfsmservice1firewallconfiguration1')

                    self.assertTrue(result['sonfsmservice1firewallconfiguration1']['error'] == 'None',
                                    msg='error in instantiation sonfsmservice1firewallconfiguration1')

                    self.event2 = True

                if self.event1 and self.event2:
                    self.fsm_eventFinished()

        self.manoconn.subscribe(on_ssm_instantiation_result, 'specific.manager.registry.ssm.instantiate')
        self.manoconn.subscribe(on_fsm_instantiation_result, 'specific.manager.registry.fsm.instantiate')

        instantiation_proc = Process(target=fakeslm_instantiation)
        instantiation_proc.daemon = True

        instantiation_proc.start()

        self.waitForSSMEvent(timeout=70, msg='SSM instantiation request not received.')
        self.waitForFSMEvent(timeout=70, msg='FSM instantiation request not received.')

        self.wait_for_ssm_event.clear()
        self.wait_for_fsm_event.clear()

        instantiation_proc.terminate()
        del instantiation_proc


    def test_3_SMR_update(self):

        def on_ssm_updating_result(ch, method, properties, message):

            if properties.app_id == 'son-plugin.SpecificManagerRegistry':
                result = yaml.load(message)
                self.assertTrue(list(result.keys()) == ['sonssmservice1dumb1'],
                                msg='not all SSMs results received')

                self.assertTrue(result['sonssmservice1dumb1']['status'] == 'Updated',
                                msg='error in updating status filed sonssmservice1dumb1')

                self.assertTrue(result['sonssmservice1dumb1']['error'] == 'None',
                                msg='error in updating error filed sonssmservice1dumb1')

                self.ssm_eventFinished()

        def on_fsm_updating_result(ch, method, properties, message):

            if properties.app_id == 'son-plugin.SpecificManagerRegistry':

                result = yaml.load(message)
                self.assertTrue(list(result.keys()) ==
                                ['sonfsmservice1function1updateddumb1']
                                , msg='not all FSMs updating results in VNFD2 received')

                self.assertTrue(result['sonfsmservice1function1updateddumb1']['status'] == 'Updated',
                                msg='error in updating sonfsmservice1function1monitoring1')

                self.assertTrue(result['sonfsmservice1function1updateddumb1']['error'] == 'None',
                                msg='error in updating sonfsmservice1function1monitoring1')

                self.fsm_eventFinished()

        self.manoconn.subscribe(on_ssm_updating_result, 'specific.manager.registry.ssm.update')
        self.manoconn.subscribe(on_fsm_updating_result, 'specific.manager.registry.fsm.update')

        updating_proc = Process(target=fakeslm_updating)
        updating_proc.daemon = True
        updating_proc.start()

        self.waitForSSMEvent(timeout=70, msg='SSM updating request not received.')
        self.waitForFSMEvent(timeout=70, msg='FSM updating request not received.')

        self.wait_for_fsm_event.clear()
        self.wait_for_ssm_event.clear()

        updating_proc.terminate()
        del updating_proc

    def test_4_SMR_terminate(self):

        self.event1 = False
        self.event2 = False

        def on_ssm_termination_result(ch, method, properties, message):

            if properties.app_id == 'son-plugin.SpecificManagerRegistry':
                result = yaml.load(message)
                self.assertTrue(list(result.keys()) == ['sonssmservice1dumb1','sonssmservice1placement1'] or
                                ['sonssmservice1placement1','sonssmservice1dumb1'],
                                msg='not all SSMs results received')

                self.assertTrue(result['sonssmservice1dumb1']['status'] == 'Terminated',
                                msg='error in termination status field sonssmservice1dumb1')

                self.assertTrue(result['sonssmservice1dumb1']['error'] == 'None',
                                msg='error in termination error field sonssmservice1dumb1')

                self.assertTrue(result['sonssmservice1placement1']['status'] == 'Terminated',
                                msg='error in termination status field sonssmservice1placement1')

                self.assertTrue(result['sonssmservice1placement1']['error'] == 'None',
                            msg='error in termination error field sonssmservice1placement1')

                self.ssm_eventFinished()

        def on_fsm_termination_result(ch, method, properties, message):

            if properties.app_id == 'son-plugin.SpecificManagerRegistry':

                result = yaml.load(message)

                if list(result.keys()) == ['sonfsmservice1function1dumb1']:

                    self.assertTrue(result['sonfsmservice1function1dumb1']['status'] == 'Terminated',
                                    msg='error in termination status field sonfsmservice1function1dumb1')

                    self.assertTrue(result['sonfsmservice1function1dumb1']['error'] == 'None',
                                msg='error in termination error field sonfsmservice1function1dumb1')

                    self.event1 = True

                else:
                    self.assertTrue(list(result.keys()) ==
                                    ['sonfsmservice1function1monitoring1', 'sonfsmservice1function1updateddumb1'] or
                                    list(result.keys()) ==
                                    ['sonfsmservice1function1updateddumb1', 'sonfsmservice1function1monitoring1']
                                    , msg='not all FSMs Termination results in vnfdt2 received')

                    self.assertTrue(result['sonfsmservice1function1monitoring1']['status'] == 'Terminated',
                                    msg='error in termination status field sonfsmservice1function1monitoring1')

                    self.assertTrue(result['sonfsmservice1function1monitoring1']['error'] == 'None',
                                msg='error in termination error field sonfsmservice1function1monitoring1')

                    self.assertTrue(result['sonfsmservice1function1updateddumb1']['status'] == 'Terminated',
                                    msg='error in termination status field sonfsmservice1function1updateddumb1')

                    self.assertTrue(result['sonfsmservice1function1updateddumb1']['error'] == 'None',
                                msg='error in termination error field sonfsmservice1function1updateddumb1')

                    self.event2 = True

                self.fsm_eventFinished()

            if self.event1 and self.event2:
                self.fsm_eventFinished()

        self.manoconn.subscribe(on_ssm_termination_result, 'specific.manager.registry.ssm.terminate')
        self.manoconn.subscribe(on_fsm_termination_result, 'specific.manager.registry.fsm.terminate')

        termination_proc = Process(target=fakeslm_termination)
        termination_proc.daemon = True
        termination_proc.start()

        self.waitForSSMEvent(timeout=70, msg='SSM termination request not received.')
        self.waitForFSMEvent(timeout=70, msg='FSM termination request not received.')

        self.wait_for_fsm_event.clear()
        self.wait_for_ssm_event.clear()

        termination_proc.terminate()
        del termination_proc
class testSMRRegistration(unittest.TestCase):

    def setUp(self):
        #a new SMR in another process for each test
        self.smr_proc = Process(target=SpecificManagerRegistry)
        self.smr_proc.daemon = True
        #make a new connection with the broker before each test
        self.manoconn = ManoBrokerRequestResponseConnection('son-plugin.SonPluginManager')

        #Some threading events that can be used during the tests
        self.wait_for_event = threading.Event()
        self.wait_for_event.clear()

        #The uuid that can be assigned to the plugin
        self.uuid = '1'

    def tearDown(self):
        #Killing SMR
        if self.smr_proc is not None:
            self.smr_proc.terminate()
        del self.smr_proc

        #Killing the connection with the broker
        try:
            self.manoconn.stop_connection()
        except Exception as e:
            LOG.exception("Stop connection exception.")

        #Clearing the threading helpers
        del self.wait_for_event

    #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 testSMRRegistration(self):
        """
        TEST: This test verifies whether SMR is sending out a message,
        and whether it contains all the needed info on the
        platform.management.plugin.register topic to register to the plugin
        manager.
        """

        #STEP3a: When receiving the message, we need to check whether all fields present.
        def on_register_receive(ch, method, properties, message):

            msg = yaml.load(message)
            #CHECK: The message should be a dictionary.
            self.assertTrue(isinstance(msg, dict), msg='message is not a dictionary')
            #CHECK: The dictionary should have a key 'name'.
            self.assertIn('name', msg.keys(), msg='No name provided in message.')
            if isinstance(msg['name'], str):
                #CHECK: The value of 'name' should not be an empty string.
                self.assertTrue(len(msg['name']) > 0, msg='empty name provided.')
            else:
                #CHECK: The value of 'name' should be a string
                self.assertEqual(True, False, msg='name is not a string')
            #CHECK: The dictionary should have a key 'version'.
            self.assertIn('version', msg.keys(), msg='No version provided in message.')
            if isinstance(msg['version'], str):
                #CHECK: The value of 'version' should not be an empty string.
                self.assertTrue(len(msg['version']) > 0, msg='empty version provided.')
            else:
                #CHECK: The value of 'version' should be a string
                self.assertEqual(True, False, msg='version is not a string')
            #CHECK: The dictionary should have a key 'description'
            self.assertIn('description', msg.keys(), msg='No description provided in message.')
            if isinstance(msg['description'], str):
                #CHECK: The value of 'description' should not be an empty string.
                self.assertTrue(len(msg['description']) > 0, msg='empty description provided.')
            else:
                #CHECK: The value of 'description' should be a string
                self.assertEqual(True, False, msg='description is not a string')

            # stop waiting
            self.eventFinished()

        #STEP1: Listen to the platform.management.plugin.register topic
        self.manoconn.subscribe(on_register_receive, 'platform.management.plugin.register')

        #STEP2: Start the Scaling Executive
        self.smr_proc.start()

        #STEP3b: When not receiving the message, the test failed
        self.waitForEvent(timeout=5, msg="message not received.")
Exemple #4
0
class testSMRRegistration(unittest.TestCase):

    def setUp(self):
        #a new SMR in another process for each test
        self.smr_proc = Process(target=SpecificManagerRegistry)
        self.smr_proc.daemon = True
        #make a new connection with the broker before each test
        self.manoconn = ManoBrokerRequestResponseConnection('son-plugin.SonPluginManager')

        #Some threading events that can be used during the tests
        self.wait_for_event = threading.Event()
        self.wait_for_event.clear()

        #The uuid that can be assigned to the plugin
        self.uuid = '1'

    def tearDown(self):
        #Killing SMR
        if self.smr_proc is not None:
            self.smr_proc.terminate()
        del self.smr_proc

        #Killing the connection with the broker
        try:
            self.manoconn.stop_connection()
        except Exception as e:
            LOG.exception("Stop connection exception.")

        #Clearing the threading helpers
        del self.wait_for_event

    #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 testSMRRegistration(self):
        """
        TEST: This test verifies whether SMR is sending out a message,
        and whether it contains all the needed info on the
        platform.management.plugin.register topic to register to the plugin
        manager.
        """

        #STEP3a: When receiving the message, we need to check whether all fields present.
        def on_register_receive(ch, method, properties, message):

            msg = yaml.load(message)
            #CHECK: The message should be a dictionary.
            self.assertTrue(isinstance(msg, dict), msg='message is not a dictionary')
            #CHECK: The dictionary should have a key 'name'.
            self.assertIn('name', msg.keys(), msg='No name provided in message.')
            if isinstance(msg['name'], str):
                #CHECK: The value of 'name' should not be an empty string.
                self.assertTrue(len(msg['name']) > 0, msg='empty name provided.')
            else:
                #CHECK: The value of 'name' should be a string
                self.assertEqual(True, False, msg='name is not a string')
            #CHECK: The dictionary should have a key 'version'.
            self.assertIn('version', msg.keys(), msg='No version provided in message.')
            if isinstance(msg['version'], str):
                #CHECK: The value of 'version' should not be an empty string.
                self.assertTrue(len(msg['version']) > 0, msg='empty version provided.')
            else:
                #CHECK: The value of 'version' should be a string
                self.assertEqual(True, False, msg='version is not a string')
            #CHECK: The dictionary should have a key 'description'
            self.assertIn('description', msg.keys(), msg='No description provided in message.')
            if isinstance(msg['description'], str):
                #CHECK: The value of 'description' should not be an empty string.
                self.assertTrue(len(msg['description']) > 0, msg='empty description provided.')
            else:
                #CHECK: The value of 'description' should be a string
                self.assertEqual(True, False, msg='description is not a string')

            # stop waiting
            self.eventFinished()

        #STEP1: Listen to the platform.management.plugin.register topic
        self.manoconn.subscribe(on_register_receive, 'platform.management.plugin.register')

        #STEP2: Start the Scaling Executive
        self.smr_proc.start()

        #STEP3b: When not receiving the message, the test failed
        self.waitForEvent(timeout=5, msg="message not received.")
class test_SMR_functionalities(unittest.TestCase):
    @classmethod
    def setUpClass(self):

        self.smr_proc = Process(target=SpecificManagerRegistry)

        self.smr_proc.daemon = True

        self.manoconn = ManoBrokerRequestResponseConnection(
            'son-plugin.SpecificManagerRegistry')

        self.wait_for_ssm_event = threading.Event()
        self.wait_for_ssm_event.clear()

        self.wait_for_fsm_event = threading.Event()
        self.wait_for_fsm_event.clear()

        self.event1 = False
        self.event2 = False

        self.smr_proc.start()
        time.sleep(4)

    @classmethod
    def tearDownClass(self):

        if self.smr_proc is not None:
            self.smr_proc.terminate()
        del self.smr_proc

        try:
            self.manoconn.stop_connection()
        except Exception as e:
            LOG.exception("Stop connection exception.")

        del self.wait_for_fsm_event
        del self.wait_for_ssm_event

    def ssm_eventFinished(self):
        self.wait_for_ssm_event.set()

    def waitForSSMEvent(self, timeout=5, msg="Event timed out."):
        if not self.wait_for_ssm_event.wait(timeout):
            self.assertEqual(True, False, msg=msg)

    def fsm_eventFinished(self):
        self.wait_for_fsm_event.set()

    def waitForFSMEvent(self, timeout=5, msg="Event timed out."):
        if not self.wait_for_fsm_event.wait(timeout):
            self.assertEqual(True, False, msg=msg)

    def test_1_SMR_onboard(self):

        self.event1 = False
        self.event2 = False

        def on_ssm_onboarding_result(ch, method, properties, message):

            if properties.app_id == 'son-plugin.SpecificManagerRegistry':
                result = yaml.load(message)

                self.assertTrue(
                    list(result.keys())
                    == ['sonssmservice1dumb1', 'sonssmservice1placement1']
                    or list(result.keys())
                    == ['sonssmservice1placement1', 'sonssmservice1dumb1'],
                    msg='not all SSMs results received')

                self.assertTrue(
                    result['sonssmservice1dumb1']['status'] == 'On-boarded',
                    msg='error in onbording sonssmservice1dumb1')

                self.assertTrue(
                    result['sonssmservice1dumb1']['error'] == 'None',
                    msg='error in onbording sonssmservice1dumb1')

                self.assertTrue(result['sonssmservice1placement1']['status'] ==
                                'On-boarded',
                                msg='error in onbording sonssmservice1dumb1')

                self.assertTrue(
                    result['sonssmservice1placement1']['error'] == 'None',
                    msg='error in onbording sonssmservice1placement1')

                self.ssm_eventFinished()

        def on_fsm_onboarding_result(ch, method, properties, message):

            if properties.app_id == 'son-plugin.SpecificManagerRegistry':

                result = yaml.load(message)
                if list(result.keys()) == ['sonfsmservice1function1dumb1']:

                    self.assertTrue(
                        list(
                            result.keys()) == ['sonfsmservice1function1dumb1'],
                        msg='not all FSMs results in VNFD1 received')

                    self.assertTrue(
                        result['sonfsmservice1function1dumb1']['status'] ==
                        'On-boarded',
                        msg='error in onbording sonssmservice1dumb1')

                    self.assertTrue(
                        result['sonfsmservice1function1dumb1']['error'] ==
                        'None',
                        msg='error in onbording sonfsmservice1function1dumb1')

                    self.event1 = True
                else:
                    self.assertTrue(
                        list(result.keys()) == [
                            'sonfsmservice1function1monitoring1',
                            'sonfsmservice1firewallconfiguration1'
                        ] or list(result.keys()) == [
                            'sonfsmservice1firewallconfiguration1',
                            'sonfsmservice1function1monitoring1'
                        ],
                        msg='not all FSMs results in VNFD2 received')

                    self.assertTrue(
                        result['sonfsmservice1function1monitoring1']['status']
                        == 'On-boarded',
                        msg='error in onbording sonssmservice1dumb1')

                    self.assertTrue(
                        result['sonfsmservice1function1monitoring1']['error']
                        == 'None',
                        msg=
                        'error in onbording sonfsmservice1function1monitoring1'
                    )

                    self.assertTrue(
                        result['sonfsmservice1firewallconfiguration1']
                        ['status'] == 'On-boarded',
                        msg='error in onbording sonssmservice1dumb1')

                    self.assertTrue(
                        result['sonfsmservice1firewallconfiguration1']['error']
                        == 'None',
                        msg=
                        'error in onbording sonfsmservice1firewallconfiguration1'
                    )

                    self.event2 = True

                if self.event1 and self.event2 == True:
                    self.fsm_eventFinished()

        self.manoconn.subscribe(on_ssm_onboarding_result,
                                'specific.manager.registry.ssm.on-board')
        self.manoconn.subscribe(on_fsm_onboarding_result,
                                'specific.manager.registry.fsm.on-board')

        onboaring_proc = Process(target=fakeslm_onboarding)
        onboaring_proc.daemon = True

        onboaring_proc.start()

        self.waitForSSMEvent(timeout=70,
                             msg='SSM Onboarding request not received.')
        self.waitForFSMEvent(timeout=70,
                             msg='FSM Onboarding request not received.')

        self.wait_for_fsm_event.clear()
        self.wait_for_ssm_event.clear()

        onboaring_proc.terminate()
        del onboaring_proc

    def test_2_SMR_instantiation(self):

        self.event1 = False
        self.event2 = False

        def on_ssm_instantiation_result(ch, method, properties, message):

            if properties.app_id == 'son-plugin.SpecificManagerRegistry':
                result = yaml.load(message)
                self.assertTrue(
                    list(result.keys())
                    == ['sonssmservice1dumb1', 'sonssmservice1placement1']
                    or list(result.keys())
                    == ['sonssmservice1placement1', 'sonssmservice1dumb1'],
                    msg='not all SSMs results received')

                self.assertTrue(
                    result['sonssmservice1dumb1']['status'] == 'Instantiated',
                    msg='error in instantiation sonssmservice1dumb1')

                self.assertTrue(
                    result['sonssmservice1dumb1']['error'] == 'None',
                    msg='error in instantiation sonssmservice1dumb1')

                self.assertTrue(
                    result['sonssmservice1placement1']['status'] ==
                    'Instantiated',
                    msg='error in instantiation sonssmservice1placement1')

                self.assertTrue(
                    result['sonssmservice1placement1']['error'] == 'None',
                    msg='error in instantiation sonssmservice1placement1')

                self.ssm_eventFinished()

        def on_fsm_instantiation_result(ch, method, properties, message):

            if properties.app_id == 'son-plugin.SpecificManagerRegistry':

                result = yaml.load(message)
                if list(result.keys()) == ['sonfsmservice1function1dumb1']:

                    self.assertTrue(
                        list(
                            result.keys()) == ['sonfsmservice1function1dumb1'],
                        msg=
                        'not all FSMs instantiation results in VNFD1 received')

                    self.assertTrue(
                        result['sonfsmservice1function1dumb1']['status'] ==
                        'Instantiated',
                        msg=
                        'error in instantiation sonfsmservice1function1dumb1')

                    self.assertTrue(
                        result['sonfsmservice1function1dumb1']['error'] ==
                        'None',
                        msg=
                        'error in instantiation sonfsmservice1function1dumb1')

                    self.event1 = True
                else:
                    self.assertTrue(
                        list(result.keys()) == [
                            'sonfsmservice1function1monitoring1',
                            'sonfsmservice1firewallconfiguration1'
                        ] or list(result.keys()) == [
                            'sonfsmservice1firewallconfiguration1',
                            'sonfsmservice1function1monitoring1'
                        ],
                        msg=
                        'not all FSMs instantiation results in VNFD2 received')

                    self.assertTrue(
                        result['sonfsmservice1function1monitoring1']['status']
                        == 'Instantiated',
                        msg=
                        'error in instantiation sonfsmservice1function1monitoring1'
                    )

                    self.assertTrue(
                        result['sonfsmservice1function1monitoring1']['error']
                        == 'None',
                        msg=
                        'error in instantiation sonfsmservice1function1monitoring1'
                    )

                    self.assertTrue(
                        result['sonfsmservice1firewallconfiguration1']
                        ['status'] == 'Instantiated',
                        msg=
                        'error in instantiation sonfsmservice1firewallconfiguration1'
                    )

                    self.assertTrue(
                        result['sonfsmservice1firewallconfiguration1']['error']
                        == 'None',
                        msg=
                        'error in instantiation sonfsmservice1firewallconfiguration1'
                    )

                    self.event2 = True

                if self.event1 and self.event2:
                    self.fsm_eventFinished()

        self.manoconn.subscribe(on_ssm_instantiation_result,
                                'specific.manager.registry.ssm.instantiate')
        self.manoconn.subscribe(on_fsm_instantiation_result,
                                'specific.manager.registry.fsm.instantiate')

        instantiation_proc = Process(target=fakeslm_instantiation)
        instantiation_proc.daemon = True

        instantiation_proc.start()

        self.waitForSSMEvent(timeout=70,
                             msg='SSM instantiation request not received.')
        self.waitForFSMEvent(timeout=70,
                             msg='FSM instantiation request not received.')

        self.wait_for_ssm_event.clear()
        self.wait_for_fsm_event.clear()

        instantiation_proc.terminate()
        del instantiation_proc

    def test_3_SMR_update(self):
        def on_ssm_updating_result(ch, method, properties, message):

            if properties.app_id == 'son-plugin.SpecificManagerRegistry':
                result = yaml.load(message)
                self.assertTrue(list(result.keys()) == ['sonssmservice1dumb1'],
                                msg='not all SSMs results received')

                self.assertTrue(
                    result['sonssmservice1dumb1']['status'] == 'Updated',
                    msg='error in updating status filed sonssmservice1dumb1')

                self.assertTrue(
                    result['sonssmservice1dumb1']['error'] == 'None',
                    msg='error in updating error filed sonssmservice1dumb1')

                self.ssm_eventFinished()

        def on_fsm_updating_result(ch, method, properties, message):

            if properties.app_id == 'son-plugin.SpecificManagerRegistry':

                result = yaml.load(message)
                self.assertTrue(
                    list(result.keys()) == [
                        'sonfsmservice1function1updateddumb1'
                    ],
                    msg='not all FSMs updating results in VNFD2 received')

                self.assertTrue(
                    result['sonfsmservice1function1updateddumb1']['status'] ==
                    'Updated',
                    msg='error in updating sonfsmservice1function1monitoring1')

                self.assertTrue(
                    result['sonfsmservice1function1updateddumb1']['error'] ==
                    'None',
                    msg='error in updating sonfsmservice1function1monitoring1')

                self.fsm_eventFinished()

        self.manoconn.subscribe(on_ssm_updating_result,
                                'specific.manager.registry.ssm.update')
        self.manoconn.subscribe(on_fsm_updating_result,
                                'specific.manager.registry.fsm.update')

        updating_proc = Process(target=fakeslm_updating)
        updating_proc.daemon = True
        updating_proc.start()

        self.waitForSSMEvent(timeout=70,
                             msg='SSM updating request not received.')
        self.waitForFSMEvent(timeout=70,
                             msg='FSM updating request not received.')

        self.wait_for_fsm_event.clear()
        self.wait_for_ssm_event.clear()

        updating_proc.terminate()
        del updating_proc

    def test_4_SMR_terminate(self):

        self.event1 = False
        self.event2 = False

        def on_ssm_termination_result(ch, method, properties, message):

            if properties.app_id == 'son-plugin.SpecificManagerRegistry':
                result = yaml.load(message)
                self.assertTrue(
                    list(result.keys())
                    == ['sonssmservice1dumb1', 'sonssmservice1placement1']
                    or ['sonssmservice1placement1', 'sonssmservice1dumb1'],
                    msg='not all SSMs results received')

                self.assertTrue(
                    result['sonssmservice1dumb1']['status'] == 'Terminated',
                    msg='error in termination status field sonssmservice1dumb1'
                )

                self.assertTrue(
                    result['sonssmservice1dumb1']['error'] == 'None',
                    msg='error in termination error field sonssmservice1dumb1')

                self.assertTrue(
                    result['sonssmservice1placement1']['status'] ==
                    'Terminated',
                    msg=
                    'error in termination status field sonssmservice1placement1'
                )

                self.assertTrue(
                    result['sonssmservice1placement1']['error'] == 'None',
                    msg=
                    'error in termination error field sonssmservice1placement1'
                )

                self.ssm_eventFinished()

        def on_fsm_termination_result(ch, method, properties, message):

            if properties.app_id == 'son-plugin.SpecificManagerRegistry':

                result = yaml.load(message)

                if list(result.keys()) == ['sonfsmservice1function1dumb1']:

                    self.assertTrue(
                        result['sonfsmservice1function1dumb1']['status'] ==
                        'Terminated',
                        msg=
                        'error in termination status field sonfsmservice1function1dumb1'
                    )

                    self.assertTrue(
                        result['sonfsmservice1function1dumb1']['error'] ==
                        'None',
                        msg=
                        'error in termination error field sonfsmservice1function1dumb1'
                    )

                    self.event1 = True

                else:
                    self.assertTrue(
                        list(result.keys()) == [
                            'sonfsmservice1function1monitoring1',
                            'sonfsmservice1function1updateddumb1'
                        ] or list(result.keys()) == [
                            'sonfsmservice1function1updateddumb1',
                            'sonfsmservice1function1monitoring1'
                        ],
                        msg=
                        'not all FSMs Termination results in vnfdt2 received')

                    self.assertTrue(
                        result['sonfsmservice1function1monitoring1']['status']
                        == 'Terminated',
                        msg=
                        'error in termination status field sonfsmservice1function1monitoring1'
                    )

                    self.assertTrue(
                        result['sonfsmservice1function1monitoring1']['error']
                        == 'None',
                        msg=
                        'error in termination error field sonfsmservice1function1monitoring1'
                    )

                    self.assertTrue(
                        result['sonfsmservice1function1updateddumb1']['status']
                        == 'Terminated',
                        msg=
                        'error in termination status field sonfsmservice1function1updateddumb1'
                    )

                    self.assertTrue(
                        result['sonfsmservice1function1updateddumb1']['error']
                        == 'None',
                        msg=
                        'error in termination error field sonfsmservice1function1updateddumb1'
                    )

                    self.event2 = True

                self.fsm_eventFinished()

            if self.event1 and self.event2:
                self.fsm_eventFinished()

        self.manoconn.subscribe(on_ssm_termination_result,
                                'specific.manager.registry.ssm.terminate')
        self.manoconn.subscribe(on_fsm_termination_result,
                                'specific.manager.registry.fsm.terminate')

        termination_proc = Process(target=fakeslm_termination)
        termination_proc.daemon = True
        termination_proc.start()

        self.waitForSSMEvent(timeout=70,
                             msg='SSM termination request not received.')
        self.waitForFSMEvent(timeout=70,
                             msg='FSM termination request not received.')

        self.wait_for_fsm_event.clear()
        self.wait_for_ssm_event.clear()

        termination_proc.terminate()
        del termination_proc
class testSlmRegistrationAndHeartbeat(unittest.TestCase):
    """
    Tests the registration process of the SLM to the broker
    and the plugin manager, and the heartbeat process.
    """
    def setUp(self):
        #a new SLM in another process for each test
        self.slm_proc = Process(target=ServiceLifecycleManager)
        self.slm_proc.daemon = True
        #make a new connection with the broker before each test
        self.manoconn = ManoBrokerRequestResponseConnection(
            'son-plugin.SonPluginManager')

        #Some threading events that can be used during the tests
        self.wait_for_event = threading.Event()
        self.wait_for_event.clear()

        #The uuid that can be assigned to the plugin
        self.uuid = '1'

    def tearDown(self):
        #Killing the slm
        if self.slm_proc is not None:
            self.slm_proc.terminate()
        del self.slm_proc

        #Killing the connection with the broker
        try:
            self.manoconn.stop_connection()
        except Exception as e:
            LOG.exception("Stop connection exception.")

        #Clearing the threading helpers
        del self.wait_for_event

    #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 testSlmHeartbeat(self):
        """
        TEST: This test verifies whether the SLM sends out a heartbeat
        as intended, once it is registered and whether this heartbeat
        message is correctly formatted.
        """
        def on_registration_trigger(ch, method, properties, message):
            """
            When the registration request from the plugin is received,
            this method replies as if it were the plugin manager
            """
            self.eventFinished()
            return json.dumps({'status': 'OK', 'uuid': self.uuid})

        def on_heartbeat_receive(ch, method, properties, message):
            """
            When the heartbeat message is received, this
            method checks if it is formatted correctly
            """
            msg = json.loads(str(message))
            #CHECK: The message should be a dictionary.
            self.assertTrue(isinstance(msg, dict),
                            msg="Message is not a dictionary.")
            #CHECK: The dictionary should have a key 'uuid'.
            self.assertTrue("uuid" in msg.keys(), msg="uuid is not a key.")
            #CHECK: The value of 'uuid' should be a string.
            self.assertTrue(isinstance(msg["uuid"], str),
                            msg="uuid is not a string.")
            #CHECK: The uuid in the message should be the same as the assigned uuid.
            self.assertEqual(self.uuid, msg["uuid"], msg="uuid not correct.")
            #CHECK: The dictionary should have a key 'state'.
            self.assertTrue("state" in msg.keys(), msg="state is not a key.")
            #CHECK: The value of 'state' should be a 'READY', 'RUNNING', 'PAUSED' or 'FAILED'.
            self.assertTrue(msg["state"]
                            in ["READY", "RUNNING", "PAUSED", "FAILED"],
                            msg="Not a valid state.")

            #Stop the wait
            self.eventFinished()

        #STEP1: subscribe to the correct topics
        self.manoconn.register_async_endpoint(
            on_registration_trigger, 'platform.management.plugin.register')
        self.manoconn.subscribe(
            on_heartbeat_receive,
            'platform.management.plugin.' + self.uuid + '.heartbeat')

        #STEP2: Start the SLM
        self.slm_proc.start()

        #STEP3: Wait until the registration request has been answered
        self.waitForEvent(msg="No registration request received")

        self.wait_for_event.clear()

        #STEP4: Wait until the heartbeat message is received.

    def testSlmRegistration(self):
        """
        TEST: This test verifies whether the SLM is sending out a message,
        and whether it contains all the needed info on the
        platform.management.plugin.register topic to register to the plugin
        manager.
        """

        #STEP3a: When receiving the message, we need to check whether all fields present. TODO: check properties
        def on_register_receive(ch, method, properties, message):

            msg = json.loads(str(message))
            #CHECK: The message should be a dictionary.
            self.assertTrue(isinstance(msg, dict),
                            msg='message is not a dictionary')
            #CHECK: The dictionary should have a key 'name'.
            self.assertIn('name',
                          msg.keys(),
                          msg='No name provided in message.')
            if isinstance(msg['name'], str):
                #CHECK: The value of 'name' should not be an empty string.
                self.assertTrue(len(msg['name']) > 0,
                                msg='empty name provided.')
            else:
                #CHECK: The value of 'name' should be a string
                self.assertEqual(True, False, msg='name is not a string')
            #CHECK: The dictionary should have a key 'version'.
            self.assertIn('version',
                          msg.keys(),
                          msg='No version provided in message.')
            if isinstance(msg['version'], str):
                #CHECK: The value of 'version' should not be an empty string.
                self.assertTrue(len(msg['version']) > 0,
                                msg='empty version provided.')
            else:
                #CHECK: The value of 'version' should be a string
                self.assertEqual(True, False, msg='version is not a string')
            #CHECK: The dictionary should have a key 'description'
            self.assertIn('description',
                          msg.keys(),
                          msg='No description provided in message.')
            if isinstance(msg['description'], str):
                #CHECK: The value of 'description' should not be an empty string.
                self.assertTrue(len(msg['description']) > 0,
                                msg='empty description provided.')
            else:
                #CHECK: The value of 'description' should be a string
                self.assertEqual(True,
                                 False,
                                 msg='description is not a string')

            # stop waiting
            self.eventFinished()

        #STEP1: Listen to the platform.management.plugin.register topic
        self.manoconn.subscribe(on_register_receive,
                                'platform.management.plugin.register')

        #STEP2: Start the SLM
        self.slm_proc.start()

        #STEP3b: When not receiving the message, the test failed
        self.waitForEvent(timeout=5, msg="message not received.")
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()
Exemple #8
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
    uuid = '1'
    corr_id = '1ba347d6-6210-4de7-9ca3-a383e50d0330'

    ########################
    #SETUP
    ########################
    def setUp(self):
        def on_register_trigger(ch, method, properties, message):
            return json.dumps({'status': 'OK', 'uuid': self.uuid})

        #vnfcounter for when needed
        self.vnfcounter = 0

        #Generate a new corr_id for every test
        self.corr_id = str(uuid.uuid4())

        #a new SLM in another process for each test
        self.slm_proc = ServiceLifecycleManager(auto_register=False,
                                                start_running=False)

        #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')

        #Some threading events that can be used during the tests
        self.wait_for_first_event = threading.Event()
        self.wait_for_first_event.clear()

        #The uuid that can be assigned to the plugin
        self.uuid = '1'

    def tearDown(self):
        #Killing the slm
        self.slm_proc.manoconn.stop_connection()
        self.slm_proc.manoconn.stop_threads()

        try:
            del self.slm_proc
        except:
            pass

        #Killing the connection with the broker
        self.manoconn_spy.stop_connection()
        self.manoconn_gk.stop_connection()
        self.manoconn_ia.stop_connection()

        self.manoconn_spy.stop_threads()
        self.manoconn_gk.stop_threads()
        self.manoconn_ia.stop_threads()

        del self.manoconn_spy
        del self.manoconn_gk
        del self.manoconn_ia

        del self.wait_for_first_event

########################
#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()

    #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 dummy(self, ch, method, properties, message):
        """
        Sometimes, we need a cbf for a async_call, without actually using it.
        """

        return

#############################################################
#TEST1: test validate_deploy_request
#############################################################

    def test_validate_deploy_request(self):
        """
        The method validate_deploy_request is used to check whether the
        received message that requests the deployment of a new service is
        correctly formatted.
        """

        #Setup
        service_dict = {}
        service_id = str(uuid.uuid4())
        corr_id = str(uuid.uuid4())
        service_dict[service_id] = {'original_corr_id': corr_id}

        #SUBTEST1: Check a correctly formatted message
        message = self.createGkNewServiceRequestMessage()
        service_dict[service_id]['payload'] = yaml.load(message)

        self.slm_proc.set_services(service_dict)
        self.slm_proc.validate_deploy_request(service_id)
        result = self.slm_proc.get_services()

        self.assertEqual(
            {
                'status': result[service_id]['status'],
                'error': result[service_id]['error']
            }, {
                'status': 'INSTANTIATING',
                'error': None
            },
            msg="outcome and expected result not equal SUBTEST1.")

        #SUBTEST2: Check a message that is not a dictionary
        message = "test message"
        service_dict[service_id]['payload'] = message

        self.slm_proc.set_services(service_dict)
        self.slm_proc.validate_deploy_request(service_id)
        result = self.slm_proc.get_services()

        expected_message = "Request " + corr_id + ": payload is not a dict."
        expected_response = {'status': 'ERROR', 'error': expected_message}

        self.assertEqual(
            {
                'status': result[service_id]['status'],
                'error': result[service_id]['error']
            },
            expected_response,
            msg="outcome and expected result not equal SUBTEST2.")

        #SUBTEST3: Check a message that contains no NSD
        message = self.createGkNewServiceRequestMessage()
        loaded_message = yaml.load(message)
        del loaded_message['NSD']
        service_dict[service_id]['payload'] = loaded_message

        self.slm_proc.set_services(service_dict)
        self.slm_proc.validate_deploy_request(service_id)
        result = self.slm_proc.get_services()

        expected_message = "Request " + corr_id + ": NSD is not a dict."
        expected_response = {'status': 'ERROR', 'error': expected_message}

        self.assertEqual(
            {
                'status': result[service_id]['status'],
                'error': result[service_id]['error']
            },
            expected_response,
            msg="outcome and expected result not equal SUBTEST3.")

        #SUBTEST4: The number of VNFDs must be the same as listed in the NSD
        message = self.createGkNewServiceRequestMessage()
        loaded_message = yaml.load(message)
        loaded_message['NSD']['network_functions'].append({})
        service_dict[service_id]['payload'] = loaded_message

        self.slm_proc.set_services(service_dict)
        self.slm_proc.validate_deploy_request(service_id)
        result = self.slm_proc.get_services()

        expected_message = "Request " + corr_id + ": # of VNFDs doesn't match NSD."
        expected_response = {'status': 'ERROR', 'error': expected_message}

        self.assertEqual(
            {
                'status': result[service_id]['status'],
                'error': result[service_id]['error']
            },
            expected_response,
            msg="outcome and expected result not equal SUBTEST4.")

        #SUBTEST5: VNFDs can not be empty
        message = self.createGkNewServiceRequestMessage()
        loaded_message = yaml.load(message)
        loaded_message['VNFD1'] = None
        service_dict[service_id]['payload'] = loaded_message

        self.slm_proc.set_services(service_dict)
        self.slm_proc.validate_deploy_request(service_id)
        result = self.slm_proc.get_services()

        expected_message = "Request " + corr_id + ": empty VNFD."
        expected_response = {'status': 'ERROR', 'error': expected_message}

        self.assertEqual(
            {
                'status': result[service_id]['status'],
                'error': result[service_id]['error']
            },
            expected_response,
            msg="outcome and expected result not equal SUBTEST5.")

###########################################################
#TEST2: Test start_next_task
###########################################################

    def test_start_next_task(self):
        """
        This method tests the start_next_task method
        """

        #Setup
        service_dict = {}
        service_id = str(uuid.uuid4())
        corr_id = str(uuid.uuid4())
        orig_corr_id = str(uuid.uuid4())
        service_dict[service_id] = {
            'corr_id': corr_id,
            'original_corr_id': orig_corr_id,
            'pause_chain': True,
            'kill_chain': False
        }

        #SUBTEST1: Check if next task is correctly called
        message = self.createGkNewServiceRequestMessage()

        #Add a task to the list
        task_list = ['validate_deploy_request']

        #Create the ledger
        service_dict[service_id]['schedule'] = task_list
        service_dict[service_id]['payload'] = yaml.load(message)

        #Run the method
        self.slm_proc.set_services(service_dict)
        self.slm_proc.start_next_task(service_id)

        #wait for the task to finish
        time.sleep(0.1)
        result = self.slm_proc.get_services()

        #Check result
        generated_response = {
            'status': result[service_id]['status'],
            'error': result[service_id]['error']
        }
        expected_response = {'status': 'INSTANTIATING', 'error': None}

        self.assertEqual(generated_response,
                         expected_response,
                         msg="outcome and expected result not equal SUBTEST1.")

        #Setup
        service_dict = {}
        service_id = str(uuid.uuid4())
        corr_id = str(uuid.uuid4())
        orig_corr_id = str(uuid.uuid4())
        service_dict[service_id] = {
            'corr_id': corr_id,
            'original_corr_id': orig_corr_id,
            'pause_chain': False,
            'kill_chain': False
        }

        #SUBTEST2: Check behavior if there is no next task
        message = self.createGkNewServiceRequestMessage()

        #Add a task to the list
        task_list = []

        #Create the ledger
        service_dict[service_id]['schedule'] = task_list
        service_dict[service_id]['payload'] = yaml.load(message)

        #Run the method
        self.slm_proc.set_services(service_dict)
        self.slm_proc.start_next_task(service_id)

        #wait for the task to finish
        time.sleep(0.1)
        result = self.slm_proc.get_services()

        #Check result: if successful, service_id will not be a key in result

        self.assertFalse(service_id in result.keys(),
                         msg="key is part of ledger in SUBTEST2.")

# ###############################################################
# #TEST3: Test service_instance_create
# ###############################################################
#     def test_service_instance_create(self):
#         """
#         This method tests the service_instance_create method of the SLM
#         """

#         #Setup
#         message = self.createGkNewServiceRequestMessage()
#         corr_id = str(uuid.uuid4())
#         topic = "service.instances.create"
#         prop_dict = {'reply_to': topic,
#                      'correlation_id': corr_id,
#                      'app_id': "Gatekeeper"}

#         properties = namedtuple('properties', prop_dict.keys())(*prop_dict.values())

#         schedule = self.slm_proc.service_instance_create('foo',
#                                                          'bar',
#                                                          properties,
#                                                          message)

#         #Check result: since we don't know how many of the tasks
#         #were completed by the time we got the result, we only check
#         #the final elements in the tasklist

#         #The last 7 elements from the generated result
#         generated_result = schedule[-7:]

#         #The expected last 7 elements in the list
#         expected_result = ['SLM_mapping', 'ia_prepare', 'vnf_deploy',
#                            'vnf_chain', 'wan_configure',
#                            'instruct_monitoring', 'inform_gk']

#         self.assertEqual(generated_result,
#                          expected_result,
#                          msg='lists are not equal')

###############################################################
#TEST4: Test resp_topo
###############################################################

    def test_resp_topo(self):
        """
        This method tests the resp_topo method.
        """

        #Setup
        #Create topology message
        first = {
            'vim_uuid': str(uuid.uuid4()),
            'memory_used': 5,
            'memory_total': 12,
            'core_used': 4,
            'core_total': 6
        }
        second = {
            'vim_uuid': str(uuid.uuid4()),
            'memory_used': 3,
            'memory_total': 5,
            'core_used': 4,
            'core_total': 5
        }
        third = {
            'vim_uuid': str(uuid.uuid4()),
            'memory_used': 6,
            'memory_total': 7,
            'core_used': 2,
            'core_total': 12
        }
        topology_message = [first, second, third]
        payload = yaml.dump(topology_message)

        #Create ledger
        service_dict = {}
        service_id = str(uuid.uuid4())
        corr_id = str(uuid.uuid4())
        service_dict[service_id] = {
            'act_corr_id': corr_id,
            'infrastructure': {
                'topology': None
            },
            'schedule': ['get_ledger'],
            'original_corr_id': corr_id,
            'pause_chain': True,
            'kill_chain': False
        }

        self.slm_proc.set_services(service_dict)

        #Create properties
        topic = "infrastructure.management.compute.list"
        prop_dict = {
            'reply_to': topic,
            'correlation_id': corr_id,
            'app_id': 'InfrastructureAdaptor'
        }

        properties = namedtuple('properties',
                                prop_dict.keys())(*prop_dict.values())

        #Run method
        self.slm_proc.resp_topo('foo', 'bar', properties, payload)

        #Check result
        result = self.slm_proc.get_services()

        self.assertEqual(topology_message,
                         result[service_id]['infrastructure']['topology'],
                         msg="Dictionaries are not equal")

###############################################################
#TEST5: Test resp_vnf_depl
###############################################################

    def test_resp_vnf_depl(self):
        """
        This method tests the resp_vnf_depl method.
        """

        #SUBTEST1: Only one VNFD in the service
        #Setup
        #Create the message
        vnfr = yaml.load(
            open(
                '/plugins/son-mano-service-lifecycle-management/test/test_records/expected_vnfr_iperf.yml',
                'r'))
        message = {'status': 'DEPLOYED', 'error': None, 'vnfr': vnfr}

        payload = yaml.dump(message)

        #Create ledger
        service_dict = {}
        service_id = str(uuid.uuid4())
        corr_id = str(uuid.uuid4())
        service_dict[service_id] = {
            'act_corr_id': corr_id,
            'function': [{
                'id': vnfr['id']
            }],
            'vnfs_to_deploy': 1,
            'schedule': ['get_ledger'],
            'original_corr_id': corr_id,
            'pause_chain': True,
            'kill_chain': False
        }

        self.slm_proc.set_services(service_dict)

        #Create properties
        topic = "mano.function.deploy"
        prop_dict = {
            'reply_to': topic,
            'correlation_id': corr_id,
            'app_id': 'FunctionLifecycleManager'
        }

        properties = namedtuple('props', prop_dict.keys())(*prop_dict.values())

        #Run method
        self.slm_proc.resp_vnf_depl('foo', 'bar', properties, payload)

        #Check result
        result = self.slm_proc.get_services()

        self.assertEqual(vnfr,
                         result[service_id]['function'][0]['vnfr'],
                         msg="Dictionaries are not equal SUBTEST 1")

        self.assertEqual(result[service_id]['vnfs_to_deploy'],
                         0,
                         msg="Values not equal SUBTEST 1")

        #SUBTEST2: Two VNFDs in the service
        #Setup
        #Create the message
        vnfr = yaml.load(
            open(
                '/plugins/son-mano-service-lifecycle-management/test/test_records/expected_vnfr_iperf.yml',
                'r'))
        message = {'status': 'DEPLOYED', 'error': None, 'vnfr': vnfr}

        payload = yaml.dump(message)

        #Create ledger
        service_dict = {}
        service_id = str(uuid.uuid4())
        corr_id = str(uuid.uuid4())
        service_dict[service_id] = {
            'act_corr_id': corr_id,
            'function': [{
                'id': vnfr['id']
            }],
            'vnfs_to_deploy': 2,
            'schedule': ['get_ledger'],
            'original_corr_id': corr_id,
            'pause_chain': True,
            'kill_chain': False
        }

        self.slm_proc.set_services(service_dict)

        #Create properties
        topic = "mano.function.deploy"
        prop_dict = {
            'reply_to': topic,
            'correlation_id': corr_id,
            'app_id': 'FunctionLifecycleManager'
        }

        properties = namedtuple('props', prop_dict.keys())(*prop_dict.values())

        #Run method
        self.slm_proc.resp_vnf_depl('foo', 'bar', properties, payload)

        #Check result
        result = self.slm_proc.get_services()

        self.assertEqual(vnfr,
                         result[service_id]['function'][0]['vnfr'],
                         msg="Dictionaries are not equal SUBTEST 2")

        self.assertEqual(result[service_id]['vnfs_to_deploy'],
                         1,
                         msg="Values not equal SUBTEST 2")

        self.assertEqual(result[service_id]['schedule'], ['get_ledger'],
                         msg="Lists not equal SUBTEST 2")

###############################################################
#TEST6: Test resp_prepare
###############################################################

    def test_resp_prepare(self):
        """
        This method tests the resp_prepare method.
        """

        #SUBTEST 1: Successful response message
        #Setup
        #Create the message
        message = {
            'request_status': 'COMPLETED',
            'error': None,
        }

        payload = yaml.dump(message)

        #Create ledger
        service_dict = {}
        service_id = str(uuid.uuid4())
        corr_id = str(uuid.uuid4())
        service_dict[service_id] = {
            'act_corr_id': corr_id,
            'schedule': ['get_ledger'],
            'original_corr_id': corr_id,
            'pause_chain': True,
            'kill_chain': False
        }

        self.slm_proc.set_services(service_dict)

        #Create properties
        topic = "infrastructure.service.prepare"
        prop_dict = {
            'reply_to': topic,
            'correlation_id': corr_id,
            'app_id': 'InfrastructureAdaptor'
        }

        properties = namedtuple('props', prop_dict.keys())(*prop_dict.values())

        #Run method
        self.slm_proc.resp_prepare('foo', 'bar', properties, payload)

        #Check result
        result = self.slm_proc.get_services()

        self.assertFalse('status' in result[service_id].keys(),
                         msg="Key in dictionary SUBTEST 1")

        self.assertFalse('error' in result[service_id].keys(),
                         msg="Key in dictionary SUBTEST 1")

        #SUBTEST 2: Failed response message

        def on_test_resp_prepare_subtest2(ch, mthd, prop, payload):

            message = yaml.load(payload)

            self.assertEqual(message['status'],
                             'ERROR',
                             msg="Status not correct in SUBTEST 1")

            self.assertEqual(message['error'],
                             'BAR',
                             msg="Error not correct in SUBTEST 1")

            self.assertTrue('timestamp' in message.keys(),
                            msg="Timestamp missing in SUBTEST 1")

            self.assertEqual(len(message.keys()),
                             3,
                             msg="Number of keys not correct in SUBTEST1")
            self.firstEventFinished()

        #Setup
        #Create the message

        message = {
            'request_status': 'FOO',
            'message': 'BAR',
        }

        payload = yaml.dump(message)

        #Listen on feedback topic
        self.manoconn_gk.subscribe(on_test_resp_prepare_subtest2,
                                   'service.instances.create')

        #Create ledger
        service_dict = {}
        service_id = str(uuid.uuid4())
        corr_id = str(uuid.uuid4())
        service_dict[service_id] = {
            'act_corr_id': corr_id,
            'schedule': ['get_ledger'],
            'original_corr_id': corr_id,
            'pause_chain': True,
            'kill_chain': False
        }

        self.slm_proc.set_services(service_dict)

        #Create properties
        topic = "infrastructure.service.prepare"
        prop_dict = {
            'reply_to': topic,
            'correlation_id': corr_id,
            'app_id': 'InfrastructureAdaptor'
        }

        properties = namedtuple('props', prop_dict.keys())(*prop_dict.values())

        #Run method
        self.slm_proc.resp_prepare('foo', 'bar', properties, payload)

        #Wait for the test to finish
        self.waitForFirstEvent(timeout=5)

###############################################################
#TEST7: test contact_gk
###############################################################

    def test_contact_gk(self):
        """
        This method tests the contact_gk method.
        """

        #Check result SUBTEST 1
        def on_contact_gk_subtest1(ch, mthd, prop, payload):
            message = yaml.load(payload)

            self.assertEqual(message['status'],
                             'FOO',
                             msg="Status not correct in SUBTEST 1")

            self.assertEqual(message['error'],
                             'BAR',
                             msg="Error not correct in SUBTEST 1")

            self.assertTrue('timestamp' in message.keys(),
                            msg="Timestamp missing in SUBTEST 1")

            self.assertEqual(len(message.keys()),
                             3,
                             msg="Number of keys not correct in SUBTEST1")
            self.firstEventFinished()

        #Check result SUBTEST2
        def on_contact_gk_subtest2(ch, mthd, prop, payload):
            self.firstEventFinished()

            message = yaml.load(payload)

            self.assertEqual(message['status'],
                             'FOO',
                             msg="Status not correct in SUBTEST 2")

            self.assertEqual(message['error'],
                             'BAR',
                             msg="Error not correct in SUBTEST 2")

            self.assertEqual(message['FOO'],
                             'BAR',
                             msg="Error not correct in SUBTEST 2")

            self.assertTrue('timestamp' in message.keys(),
                            msg="Timestamp missing in SUBTEST 2")

            self.assertEqual(len(message.keys()),
                             4,
                             msg="Number of keys not correct in SUBTEST2")

        #SUBTEST1: Without additional content
        #Setup
        #Create the ledger
        self.wait_for_first_event.clear()
        service_dict = {}
        service_id = str(uuid.uuid4())
        corr_id = str(uuid.uuid4())
        service_dict[service_id] = {
            'schedule': ['get_ledger'],
            'original_corr_id': corr_id,
            'pause_chain': True,
            'status': 'FOO',
            'error': 'BAR',
            'kill_chain': False
        }

        #Set the ledger
        self.slm_proc.set_services(service_dict)

        #Spy the message bus
        self.manoconn_spy.subscribe(on_contact_gk_subtest1,
                                    'service.instances.create')

        #Wait until subscription is completed
        time.sleep(0.1)

        #Run the method
        self.slm_proc.contact_gk(service_id)

        #Wait for the test to finish
        self.waitForFirstEvent(timeout=5)

        #SUBTEST2: With additional content
        #Setup
        self.wait_for_first_event.clear()
        #Create the ledger
        service_dict = {}
        service_id = str(uuid.uuid4())
        corr_id = str(uuid.uuid4())
        add_content = {'FOO': 'BAR'}
        service_dict[service_id] = {
            'schedule': ['get_ledger'],
            'original_corr_id': corr_id,
            'pause_chain': True,
            'status': 'FOO',
            'error': 'BAR',
            'add_content': add_content
        }

        self.slm_proc.set_services(service_dict)

        #Spy the message bus
        self.manoconn_gk.subscribe(on_contact_gk_subtest2,
                                   'service.instances.create')

        #Wait until subscription is completed
        time.sleep(0.1)

        #Run the method
        self.slm_proc.contact_gk(service_id)

        #Wait for the test to finish
        self.waitForFirstEvent(timeout=5)

###############################################################
#TEST8: test request_topology
###############################################################

    def test_request_topology(self):
        """
        This method tests the request_topology method.
        """

        #Check result SUBTEST 1
        def on_request_topology_subtest1(ch, mthd, prop, payload):

            self.assertEqual(payload, "{}", msg="Payload is not empty")

            self.firstEventFinished()

        #SUBTEST1: Trigger request_topology
        #Setup
        #Create the ledger
        self.wait_for_first_event.clear()
        service_dict = {}
        service_id = str(uuid.uuid4())
        corr_id = str(uuid.uuid4())
        service_dict[service_id] = {
            'schedule': ['get_ledger'],
            'original_corr_id': corr_id,
            'pause_chain': True,
            'kill_chain': False,
            'status': 'FOO',
            'error': 'BAR',
            'infrastructure': {}
        }

        #Set the ledger
        self.slm_proc.set_services(service_dict)

        #Spy the message bus
        self.manoconn_spy.subscribe(on_request_topology_subtest1,
                                    'infrastructure.management.compute.list')

        #Wait until subscription is completed
        time.sleep(0.1)

        #Run the method
        self.slm_proc.request_topology(service_id)

        #Wait for the test to finish
        self.waitForFirstEvent(timeout=5)

###############################################################
#TEST9: test ia_prepare
###############################################################
# def test_ia_prepare(self):
#     """
#     This method tests the request_topology method.
#     """

#     #Check result SUBTEST 1
#     def on_ia_prepare_subtest1(ch, mthd, prop, payload):

#         message = yaml.load(payload)

#         for func in service_dict[service_id]['function']:
#             self.assertIn(func['vim_uuid'],
#                           message.keys(),
#                           msg="VIM uuid missing from keys")

#             image = func['vnfd']['virtual_deployment_units'][0]['vm_image']

#             self.assertIn(image,
#                           message[func['vim_uuid']]['vm_images'],
#                           msg="image not on correct Vim")

#         self.firstEventFinished()

#     #SUBTEST1: Check ia_prepare message if functions are mapped on
#     # different VIMs.
#     #Setup
#     #Create the ledger
#     self.wait_for_first_event.clear()
#     service_dict = {}
#     service_id = str(uuid.uuid4())
#     corr_id = str(uuid.uuid4())
#     service_dict[service_id] = {'schedule': ['get_ledger'],
#                                 'original_corr_id':corr_id,
#                                 'pause_chain': True,
#                                 'kill_chain': False,
#                                 'function': []}

#     path = '/plugins/son-mano-service-lifecycle-management/test/'

#     message = {}
#     message['instance_id'] = service_id
#     vnfd1 = open(path + 'test_descriptors/firewall-vnfd.yml', 'r')
#     vnfd2 = open(path + 'test_descriptors/iperf-vnfd.yml', 'r')
#     vnfd3 = open(path + 'test_descriptors/tcpdump-vnfd.yml', 'r')

#     service_dict[service_id]['function'].append({'vnfd': yaml.load(vnfd1)})
#     service_dict[service_id]['function'].append({'vnfd': yaml.load(vnfd2)})
#     service_dict[service_id]['function'].append({'vnfd': yaml.load(vnfd3)})

#     for vnfd in service_dict[service_id]['function']:
#         vim_uuid = str(uuid.uuid4())
#         vnfd['vim_uuid'] = vim_uuid

#     #Set the ledger
#     self.slm_proc.set_services(service_dict)

#     #Spy the message bus
#     self.manoconn_spy.subscribe(on_ia_prepare_subtest1,
#                                 'infrastructure.service.prepare')

#     #Wait until subscription is completed
#     time.sleep(0.1)

#     #Run the method
#     self.slm_proc.ia_prepare(service_id)

#     #Wait for the test to finish
#     self.waitForFirstEvent(timeout=5)

#     #SUBTEST2: Check ia_prepare message if functions are mapped on
#     # same VIMs.
#     #Setup
#     #Create the ledger
#     self.wait_for_first_event.clear()
#     service_dict = {}
#     service_id = str(uuid.uuid4())
#     corr_id = str(uuid.uuid4())
#     service_dict[service_id] = {'schedule': ['get_ledger'],
#                                 'original_corr_id':corr_id,
#                                 'pause_chain': True,
#                                 'kill_chain': False,
#                                 'function': []}

#     path = '/plugins/son-mano-service-lifecycle-management/test/'

#     vnfd1 = open(path + 'test_descriptors/firewall-vnfd.yml', 'r')
#     vnfd2 = open(path + 'test_descriptors/iperf-vnfd.yml', 'r')
#     vnfd3 = open(path + 'test_descriptors/tcpdump-vnfd.yml', 'r')

#     service_dict[service_id]['function'].append({'vnfd': yaml.load(vnfd1)})
#     service_dict[service_id]['function'].append({'vnfd': yaml.load(vnfd2)})
#     service_dict[service_id]['function'].append({'vnfd': yaml.load(vnfd3)})

#     vim_uuid = str(uuid.uuid4())
#     for vnfd in service_dict[service_id]['function']:
#         vnfd['vim_uuid'] = vim_uuid

#     #Set the ledger
#     self.slm_proc.set_services(service_dict)

#     #Run the method
#     self.slm_proc.ia_prepare(service_id)

#     #Wait for the test to finish
#     self.waitForFirstEvent(timeout=5)

###############################################################
#TEST10: test vnf_deploy
###############################################################

    def test_vnf_deploy(self):
        """
        This method tests the request_topology method.
        """

        #Check result SUBTEST 1
        def on_vnf_deploy_subtest1(ch, mthd, prop, payload):
            message = yaml.load(payload)

            self.assertIn(message,
                          service_dict[service_id]['function'],
                          msg="Payload is not correct")

            self.vnfcounter = self.vnfcounter + 1

            if self.vnfcounter == len(service_dict[service_id]['function']):
                self.firstEventFinished()

        #SUBTEST1: Run test
        #Setup
        #Create the ledger
        self.wait_for_first_event.clear()
        service_dict = {}
        self.vnfcounter = 0
        service_id = str(uuid.uuid4())
        corr_id = str(uuid.uuid4())
        service_dict[service_id] = {
            'schedule': ['get_ledger'],
            'original_corr_id': corr_id,
            'pause_chain': True,
            'kill_chain': False,
            'function': []
        }

        path = '/plugins/son-mano-service-lifecycle-management/test/'

        vnfd1 = open(path + 'test_descriptors/firewall-vnfd.yml', 'r')
        vnfd2 = open(path + 'test_descriptors/iperf-vnfd.yml', 'r')
        vnfd3 = open(path + 'test_descriptors/tcpdump-vnfd.yml', 'r')

        service_dict[service_id]['function'].append({
            'vnfd':
            yaml.load(vnfd1),
            'id':
            str(uuid.uuid4()),
            'vim_uuid':
            str(uuid.uuid4())
        })
        service_dict[service_id]['function'].append({
            'vnfd':
            yaml.load(vnfd2),
            'id':
            str(uuid.uuid4()),
            'vim_uuid':
            str(uuid.uuid4())
        })
        service_dict[service_id]['function'].append({
            'vnfd':
            yaml.load(vnfd3),
            'id':
            str(uuid.uuid4()),
            'vim_uuid':
            str(uuid.uuid4())
        })

        #Set the ledger
        self.slm_proc.set_services(service_dict)

        #Spy the message bus
        self.manoconn_spy.subscribe(on_vnf_deploy_subtest1,
                                    'mano.function.deploy')

        #Wait until subscription is completed
        time.sleep(0.1)

        #Run the method
        self.slm_proc.vnf_deploy(service_id)

        #Wait for the test to finish
        self.waitForFirstEvent(timeout=5)

        #SUBTEST2: TODO: test that only one message is sent per vnf

###############################################################################
#TEST11: Test build_monitoring_message
###############################################################################

    def test_build_monitoring_message(self):
        """
        This method tests the build_monitoring_message method
        """

        #Setup
        gk_request = yaml.load(self.createGkNewServiceRequestMessage())

        #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'

        #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'))

        vnfd_firewall = gk_request['VNFD1']
        vnfd_iperf = gk_request['VNFD2']
        vnfd_tcpdump = gk_request['VNFD3']

        vnfr_firewall = vnfrs_file[1]
        vnfr_iperf = vnfrs_file[0]
        vnfr_tcpdump = vnfrs_file[2]

        service = {
            'nsd': gk_request['NSD'],
            'nsr': nsr_file,
            'vim_uuid': message_from_ia['instanceVimUuid']
        }
        functions = []
        functions.append({
            'vnfr': vnfr_iperf,
            'vnfd': vnfd_iperf,
            'id': vnfr_iperf['id']
        })
        functions.append({
            'vnfr': vnfr_firewall,
            'vnfd': vnfd_firewall,
            'id': vnfr_firewall['id']
        })
        functions.append({
            'vnfr': vnfr_tcpdump,
            'vnfd': vnfd_tcpdump,
            'id': vnfr_tcpdump['id']
        })

        #Call the method
        message = tools.build_monitoring_message(service, functions)

        #Load expected results
        expected_message = json.load(
            open(
                '/plugins/son-mano-service-lifecycle-management/test/test_descriptors/monitoring-message.json',
                'r'))

        #Check result
        self.assertEqual(message, expected_message, "messages are not equals")
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 testSlmRegistrationAndHeartbeat(unittest.TestCase):
    """
    Tests the registration process of the SLM to the broker
    and the plugin manager, and the heartbeat process.
    """

    def setUp(self):
        #a new SLM in another process for each test
        self.slm_proc = Process(target=ServiceLifecycleManager)
        self.slm_proc.daemon = True
        #make a new connection with the broker before each test
        self.manoconn = ManoBrokerRequestResponseConnection('son-plugin.SonPluginManager')

        #Some threading events that can be used during the tests
        self.wait_for_event = threading.Event()
        self.wait_for_event.clear()

        #The uuid that can be assigned to the plugin
        self.uuid = '1'

    def tearDown(self):
        #Killing the slm
        if self.slm_proc is not None:
            self.slm_proc.terminate()
        del self.slm_proc

        #Killing the connection with the broker
        try:
            self.manoconn.stop_connection()
        except Exception as e:
            LOG.exception("Stop connection exception.")

        #Clearing the threading helpers
        del self.wait_for_event

    #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 testSlmHeartbeat(self):
        """
        TEST: This test verifies whether the SLM sends out a heartbeat
        as intended, once it is registered and whether this heartbeat
        message is correctly formatted.
        """

        def on_registration_trigger(ch, method, properties, message):
            """
            When the registration request from the plugin is received,
            this method replies as if it were the plugin manager
            """
            self.eventFinished()
            return json.dumps({'status': 'OK', 'uuid': self.uuid})

        def on_heartbeat_receive(ch, method, properties, message):
            """
            When the heartbeat message is received, this
            method checks if it is formatted correctly
            """
            msg = json.loads(str(message))
            #CHECK: The message should be a dictionary.
            self.assertTrue(isinstance(msg, dict), msg="Message is not a dictionary.")
            #CHECK: The dictionary should have a key 'uuid'.
            self.assertTrue("uuid" in msg.keys(), msg="uuid is not a key.")
            #CHECK: The value of 'uuid' should be a string.
            self.assertTrue(isinstance(msg["uuid"], str), msg="uuid is not a string.")
            #CHECK: The uuid in the message should be the same as the assigned uuid.
            self.assertEqual(self.uuid, msg["uuid"], msg="uuid not correct.")
            #CHECK: The dictionary should have a key 'state'.
            self.assertTrue("state" in msg.keys(), msg="state is not a key.")
            #CHECK: The value of 'state' should be a 'READY', 'RUNNING', 'PAUSED' or 'FAILED'.
            self.assertTrue(msg["state"] in ["READY", "RUNNING", "PAUSED", "FAILED"], msg="Not a valid state.")

            #Stop the wait
            self.eventFinished()

        #STEP1: subscribe to the correct topics
        self.manoconn.register_async_endpoint(on_registration_trigger, 'platform.management.plugin.register')
        self.manoconn.subscribe(on_heartbeat_receive, 'platform.management.plugin.' + self.uuid + '.heartbeat')

        #STEP2: Start the SLM
        self.slm_proc.start()

        #STEP3: Wait until the registration request has been answered
        self.waitForEvent(msg="No registration request received")

        self.wait_for_event.clear()

        #STEP4: Wait until the heartbeat message is received.

    def testSlmRegistration(self):
        """
        TEST: This test verifies whether the SLM is sending out a message,
        and whether it contains all the needed info on the
        platform.management.plugin.register topic to register to the plugin
        manager.
        """

        #STEP3a: When receiving the message, we need to check whether all fields present. TODO: check properties
        def on_register_receive(ch, method, properties, message):

            msg = json.loads(str(message))
            #CHECK: The message should be a dictionary.
            self.assertTrue(isinstance(msg, dict), msg='message is not a dictionary')
            #CHECK: The dictionary should have a key 'name'.
            self.assertIn('name', msg.keys(), msg='No name provided in message.')
            if isinstance(msg['name'], str):
                #CHECK: The value of 'name' should not be an empty string.
                self.assertTrue(len(msg['name']) > 0, msg='empty name provided.')
            else:
                #CHECK: The value of 'name' should be a string
                self.assertEqual(True, False, msg='name is not a string')
            #CHECK: The dictionary should have a key 'version'.
            self.assertIn('version', msg.keys(), msg='No version provided in message.')
            if isinstance(msg['version'], str):
                #CHECK: The value of 'version' should not be an empty string.
                self.assertTrue(len(msg['version']) > 0, msg='empty version provided.')
            else:
                #CHECK: The value of 'version' should be a string
                self.assertEqual(True, False, msg='version is not a string')
            #CHECK: The dictionary should have a key 'description'
            self.assertIn('description', msg.keys(), msg='No description provided in message.')
            if isinstance(msg['description'], str):
                #CHECK: The value of 'description' should not be an empty string.
                self.assertTrue(len(msg['description']) > 0, msg='empty description provided.')
            else:
                #CHECK: The value of 'description' should be a string
                self.assertEqual(True, False, msg='description is not a string')

            # stop waiting
            self.eventFinished()

        #STEP1: Listen to the platform.management.plugin.register topic
        self.manoconn.subscribe(on_register_receive, 'platform.management.plugin.register')

        #STEP2: Start the SLM
        self.slm_proc.start()

        #STEP3b: When not receiving the message, the test failed 
        self.waitForEvent(timeout=5, msg="message not received.")
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 testPLEXRegistration(unittest.TestCase):
    """
    Tests the registration process of the Scaling Executive to the broker
    and the plugin manager, and the heartbeat process.
    """
    def setUp(self):
        #a new Scaling Executive in another process for each test
        self.plex_proc = Process(target=ScalingExecutive)
        self.plex_proc.daemon = True

        if 'broker_man_host' in os.environ:
            self.man_host = os.environ['broker_man_host']
        else:
            self.man_host = 'http://localhost:15672'

        if 'sm_broker_host' in os.environ:
            self.sm_host = os.environ['sm_broker_host']
        else:
            self.sm_host = 'http://localhost:15672'
        url_user = "******".format(self.man_host)
        url_create = '{0}/api/vhosts/fsm-1234'.format(self.man_host)
        url_permission = '{0}/api/permissions/fsm-1234/specific-management'.format(
            self.man_host)
        self.headers = {'content-type': 'application/json'}
        data1 = '{"password":"******","tags":"son-sm"}'
        data2 = '{"configure":".*","write":".*","read":".*"}'
        res = requests.put(url=url_user,
                           headers=self.headers,
                           data=data1,
                           auth=('guest', 'guest'))
        LOG.info(res.content)
        res1 = requests.put(url=url_create,
                            headers=self.headers,
                            auth=('guest', 'guest'))
        LOG.info(res1.content)
        res2 = requests.put(url=url_permission,
                            headers=self.headers,
                            data=data2,
                            auth=('guest', 'guest'))
        LOG.info(res2.content)

        #make a new connection with the broker before each test
        url = "{0}/fsm-1234".format(self.sm_host)
        self.manoconn = ManoBrokerRequestResponseConnection(
            'son-plugin.SonPluginManager')
        self.sm_connection = ManoBrokerRequestResponseConnection(
            'son-plugin.FSM', url=url)

        #Some threading events that can be used during the tests
        self.wait_for_event1 = threading.Event()
        self.wait_for_event1.clear()

        self.wait_for_event2 = threading.Event()
        self.wait_for_event2.clear()

    def tearDown(self):
        #Killing the scaling Executive
        if self.plex_proc is not None:
            self.plex_proc.terminate()
        del self.plex_proc

        #Killing the connection with the broker
        try:
            self.manoconn.stop_connection()
            self.sm_connection.stop_connection()
        except Exception as e:
            LOG.exception("Stop connection exception.")

        #Clearing the threading helpers
        del self.wait_for_event1
        del self.wait_for_event2

        url_user = "******".format(self.man_host)
        url_vhost = "{0}/api/vhosts/fsm-1234".format(self.man_host)
        requests.delete(url=url_user,
                        headers=self.headers,
                        auth=('guest', 'guest'))
        requests.delete(url=url_vhost,
                        headers=self.headers,
                        auth=('guest', 'guest'))

    #Method that terminates the timer that waits for an event
    def eventFinished1(self):
        self.wait_for_event1.set()

    def eventFinished2(self):
        self.wait_for_event2.set()

    #Method that starts a timer, waiting for an event
    def waitForEvent1(self, timeout=5, msg="Event timed out."):
        if not self.wait_for_event1.wait(timeout):
            self.assertEqual(True, False, msg=msg)

    def waitForEvent2(self, timeout=5, msg="Event timed out."):
        if not self.wait_for_event2.wait(timeout):
            self.assertEqual(True, False, msg=msg)

    def test_1_SCEX_Registration(self):
        """
        TEST: This test verifies whether the Scaling Executive is sending out a message,
        and whether it contains all the needed info on the
        platform.management.plugin.register topic to register to the plugin
        manager.
        """

        #STEP3a: When receiving the message, we need to check whether all fields present.
        def on_register_receive(ch, method, properties, message):

            msg = yaml.load(message)
            #CHECK: The message should be a dictionary.
            self.assertTrue(isinstance(msg, dict),
                            msg='message is not a dictionary')
            #CHECK: The dictionary should have a key 'name'.
            self.assertIn('name',
                          msg.keys(),
                          msg='No name provided in message.')
            if isinstance(msg['name'], str):
                #CHECK: The value of 'name' should not be an empty string.
                self.assertTrue(len(msg['name']) > 0,
                                msg='empty name provided.')
            else:
                #CHECK: The value of 'name' should be a string
                self.assertEqual(True, False, msg='name is not a string')
            #CHECK: The dictionary should have a key 'version'.
            self.assertIn('version',
                          msg.keys(),
                          msg='No version provided in message.')
            if isinstance(msg['version'], str):
                #CHECK: The value of 'version' should not be an empty string.
                self.assertTrue(len(msg['version']) > 0,
                                msg='empty version provided.')
            else:
                #CHECK: The value of 'version' should be a string
                self.assertEqual(True, False, msg='version is not a string')
            #CHECK: The dictionary should have a key 'description'
            self.assertIn('description',
                          msg.keys(),
                          msg='No description provided in message.')
            if isinstance(msg['description'], str):
                #CHECK: The value of 'description' should not be an empty string.
                self.assertTrue(len(msg['description']) > 0,
                                msg='empty description provided.')
            else:
                #CHECK: The value of 'description' should be a string
                self.assertEqual(True,
                                 False,
                                 msg='description is not a string')

            # stop waiting
            self.eventFinished1()

        #STEP1: Listen to the platform.management.plugin.register topic
        self.manoconn.subscribe(on_register_receive,
                                'platform.management.plugin.register')

        #STEP2: Start the Scaling Executive
        self.plex_proc.start()

        #STEP3b: When not receiving the message, the test failed
        self.waitForEvent1(timeout=5, msg="message not received.")

    def test_2_SCEX_request_response(self):
        def on_request_send(ch, method, properties, message):

            if properties.app_id == "son-plugin.ScalingExecutive":
                msg = yaml.load(message)

                self.assertTrue(isinstance(msg, dict),
                                msg='message is not a dictionary')

                self.assertIn('uuid',
                              msg.keys(),
                              msg='No uuid provided in message.')
                if isinstance(msg['uuid'], str):
                    self.assertTrue(msg['uuid'] == '1234',
                                    msg='empty uuid provided.')

                self.assertNotIn('scale', msg.keys(), msg='wrong message!')

                res_payload = yaml.dump({'uuid': '1234', 'scale': '2'})

                self.eventFinished1()
                return res_payload

        def on_response_send(ch, method, properties, message):
            if properties.app_id == "son-plugin.ScalingExecutive":
                msg = yaml.load(message)

                self.assertTrue(isinstance(msg, dict),
                                msg='message is not a dictionary')

                self.assertIn('uuid',
                              msg.keys(),
                              msg='No uuid provided in message.')
                if isinstance(msg['uuid'], str):
                    self.assertTrue(msg['uuid'] == '1234',
                                    msg='empty uuid provided.')

                self.assertIn('scale',
                              msg.keys(),
                              msg='No scale provided in message.')
                if isinstance(msg['scale'], str):
                    self.assertTrue(msg['scale'] == '2',
                                    msg='empty uuid provided.')

                self.eventFinished2()

        self.plex_proc.start()

        time.sleep(2)

        self.manoconn.subscribe(on_response_send, 'scaling.executive.request')
        self.sm_connection.register_async_endpoint(on_request_send,
                                                   'scaling.fsm.1234')

        req_payload = yaml.dump({'uuid': '1234'})
        self.manoconn.publish("scaling.executive.request", message=req_payload)

        self.waitForEvent1(timeout=5, msg="response message not received.")
        self.waitForEvent2(timeout=5, msg="request message not received.")
Exemple #14
0
class test_SMR_functionalities(unittest.TestCase):

    @classmethod
    def setUpClass(self):

        def wait_for_smr(ch, method, properties, message):

            LOG.info("PM status message received")
            status = json.loads(message)
            plugin_dict = status['plugin_dict']
            for uuid in plugin_dict.keys():
                if plugin_dict[uuid]['name'] == 'son-plugin.SpecificManagerRegistry':
                    LOG.info("SMR detected")
                    self.smr_active = True

        print("SetUpClass triggered")

        self.smr_active = False
        self.manoconn = ManoBrokerRequestResponseConnection('smr-unittest')
        self.manoconn.subscribe(wait_for_smr, 'platform.management.plugin.status')

        self.smr_proc = Process(target=SpecificManagerRegistry)
        self.smr_proc.daemon = True
        self.smr_proc.start()

        self.wait_for_ssm_event = threading.Event()
        self.wait_for_ssm_event.clear()

        self.wait_for_fsm_event = threading.Event()
        self.wait_for_fsm_event.clear()

        self.event1 = False
        self.event2 = False

        while not self.smr_active:
            LOG.info("SMR not active yet, sleeping...")
            time.sleep(1)

        LOG.info('SMR is active')

    @classmethod
    def tearDownClass(self):

        if self.smr_proc is not None:
            self.smr_proc.terminate()
        del self.smr_proc

        try:
            self.manoconn.stop_connection()
        except Exception as e:
            LOG.exception("Stop connection exception.")

        del self.wait_for_fsm_event
        del self.wait_for_ssm_event

    def ssm_eventFinished(self):
        self.wait_for_ssm_event.set()


    def waitForSSMEvent(self, timeout=5, msg="Event timed out."):
        if not self.wait_for_ssm_event.wait(timeout):
            self.assertEqual(True, False, msg=msg)


    def fsm_eventFinished(self):
        self.wait_for_fsm_event.set()


    def waitForFSMEvent(self, timeout=5, msg="Event timed out."):
        if not self.wait_for_fsm_event.wait(timeout):
            self.assertEqual(True, False, msg=msg)

    def test_1_SMR_onboard(self):

        self.event1 = False
        self.event2 = False

        def on_ssm_onboarding_result(ch, method, properties, message):

            if properties.app_id == 'son-plugin.SpecificManagerRegistry':
                result = yaml.load(message)

                self.assertTrue(list(result.keys()) == ['sonssmservice1dumb1','sonssmservice1placement1'] or
                                list(result.keys()) == ['sonssmservice1placement1', 'sonssmservice1dumb1'],
                                msg='not all SSMs results received')

                self.assertTrue(result['sonssmservice1dumb1']['status'] == 'On-boarded',
                                msg='error in onbording sonssmservice1dumb1')

                self.assertTrue(result['sonssmservice1dumb1']['error'] == 'None',
                                msg='error in onbording sonssmservice1dumb1')

                self.assertTrue(result['sonssmservice1placement1']['status'] == 'On-boarded',
                                msg='error in onbording sonssmservice1dumb1')

                self.assertTrue(result['sonssmservice1placement1']['error'] == 'None',
                                msg='error in onbording sonssmservice1placement1')

                self.ssm_eventFinished()

        def on_fsm_onboarding_result(ch, method, properties, message):

            if properties.app_id == 'son-plugin.SpecificManagerRegistry':

                result = yaml.load(message)
                if list(result.keys()) == ['sonfsmservice1function1dumb1']:

                    self.assertTrue(list(result.keys()) == ['sonfsmservice1function1dumb1'],
                                    msg='not all FSMs results in VNFD1 received')

                    self.assertTrue(result['sonfsmservice1function1dumb1']['status'] == 'On-boarded',
                                    msg='error in onbording sonssmservice1dumb1')

                    self.assertTrue(result['sonfsmservice1function1dumb1']['error'] == 'None',
                                    msg='error in onbording sonfsmservice1function1dumb1')

                    self.event1 = True
                else:
                    self.assertTrue(list(result.keys()) ==
                                    ['sonfsmservice1function1monitoring1', 'sonfsmservice1firewallconfiguration1']or
                                    list(result.keys()) ==
                                    ['sonfsmservice1firewallconfiguration1','sonfsmservice1function1monitoring1']
                                    , msg='not all FSMs results in VNFD2 received')

                    self.assertTrue(result['sonfsmservice1function1monitoring1']['status'] == 'On-boarded',
                                    msg='error in onbording sonssmservice1dumb1')

                    self.assertTrue(result['sonfsmservice1function1monitoring1']['error'] == 'None',
                                    msg='error in onbording sonfsmservice1function1monitoring1')

                    self.assertTrue(result['sonfsmservice1firewallconfiguration1']['status'] == 'On-boarded',
                                    msg='error in onbording sonssmservice1dumb1')

                    self.assertTrue(result['sonfsmservice1firewallconfiguration1']['error'] == 'None',
                                    msg='error in onbording sonfsmservice1firewallconfiguration1')

                    self.event2 = True

                if self.event1 and self.event2 == True:
                    self.fsm_eventFinished()



        self.manoconn.subscribe(on_ssm_onboarding_result, 'specific.manager.registry.ssm.on-board')
        self.manoconn.subscribe(on_fsm_onboarding_result, 'specific.manager.registry.fsm.on-board')

        onboaring_proc = Process(target=fakeslm_onboarding)
        onboaring_proc.daemon = True

        onboaring_proc.start()

        self.waitForSSMEvent(timeout=70 , msg='SSM Onboarding request not received.')
        self.waitForFSMEvent(timeout=70, msg='FSM Onboarding request not received.')

        self.wait_for_fsm_event.clear()
        self.wait_for_ssm_event.clear()

        onboaring_proc.terminate()
        del onboaring_proc


    def test_2_SMR_instantiation(self):

        self.event1 = False
        self.event2 = False

        def on_ssm_instantiation_result(ch, method, properties, message):

            if properties.app_id == 'son-plugin.SpecificManagerRegistry':
                result = yaml.load(message)
                self.assertTrue(list(result.keys()) == ['sonssmservice1dumb1', 'sonssmservice1placement1'] or
                                list(result.keys()) == ['sonssmservice1placement1', 'sonssmservice1dumb1'],
                                msg='not all SSMs results received')

                self.assertTrue(result['sonssmservice1dumb1']['status'] == 'Instantiated',
                                msg='error in instantiation sonssmservice1dumb1')

                self.assertTrue(result['sonssmservice1dumb1']['error'] == 'None',
                                msg='error in instantiation sonssmservice1dumb1')

                self.assertTrue(result['sonssmservice1placement1']['status'] == 'Instantiated',
                                msg='error in instantiation sonssmservice1placement1')

                self.assertTrue(result['sonssmservice1placement1']['error'] == 'None',
                                msg='error in instantiation sonssmservice1placement1')

                self.ssm_eventFinished()

        def on_fsm_instantiation_result(ch, method, properties, message):

            if properties.app_id == 'son-plugin.SpecificManagerRegistry':

                result = yaml.load(message)
                if list(result.keys()) == ['sonfsmservice1function1dumb1']:

                    self.assertTrue(list(result.keys()) == ['sonfsmservice1function1dumb1'],
                                    msg='not all FSMs instantiation results in VNFD1 received')

                    self.assertTrue(result['sonfsmservice1function1dumb1']['status'] == 'Instantiated',
                                    msg='error in instantiation sonfsmservice1function1dumb1')

                    self.assertTrue(result['sonfsmservice1function1dumb1']['error'] == 'None',
                                    msg='error in instantiation sonfsmservice1function1dumb1')

                    self.event1 = True
                else:
                    self.assertTrue(list(result.keys()) ==
                                    ['sonfsmservice1function1monitoring1', 'sonfsmservice1firewallconfiguration1'] or
                                    list(result.keys()) ==
                                    ['sonfsmservice1firewallconfiguration1', 'sonfsmservice1function1monitoring1']
                                    , msg='not all FSMs instantiation results in VNFD2 received')

                    self.assertTrue(result['sonfsmservice1function1monitoring1']['status'] == 'Instantiated',
                                    msg='error in instantiation sonfsmservice1function1monitoring1')

                    self.assertTrue(result['sonfsmservice1function1monitoring1']['error'] == 'None',
                                    msg='error in instantiation sonfsmservice1function1monitoring1')

                    self.assertTrue(result['sonfsmservice1firewallconfiguration1']['status'] == 'Instantiated',
                                    msg='error in instantiation sonfsmservice1firewallconfiguration1')

                    self.assertTrue(result['sonfsmservice1firewallconfiguration1']['error'] == 'None',
                                    msg='error in instantiation sonfsmservice1firewallconfiguration1')

                    self.event2 = True

                if self.event1 and self.event2:
                    self.fsm_eventFinished()

        self.manoconn.subscribe(on_ssm_instantiation_result, 'specific.manager.registry.ssm.instantiate')
        self.manoconn.subscribe(on_fsm_instantiation_result, 'specific.manager.registry.fsm.instantiate')

        instantiation_proc = Process(target=fakeslm_instantiation)
        instantiation_proc.daemon = True

        instantiation_proc.start()

        self.waitForSSMEvent(timeout=70, msg='SSM instantiation request not received.')
        self.waitForFSMEvent(timeout=70, msg='FSM instantiation request not received.')

        self.wait_for_ssm_event.clear()
        self.wait_for_fsm_event.clear()

        instantiation_proc.terminate()
        del instantiation_proc
class testSlmFunctionality(unittest.TestCase):
    """
    Tests the tasks that the SLM should perform in the service
    life cycle of the network services.
    """

    slm_proc    = None
    uuid        = '1'
    corr_id     = '1ba347d6-6210-4de7-9ca3-a383e50d0330'

########################
#SETUP
########################
    def setUp(self):
        def on_register_trigger(ch, method, properties, message):
            return json.dumps({'status': 'OK', 'uuid': self.uuid})

        #vnfcounter for when needed
        self.vnfcounter = 0

        #Generate a new corr_id for every test
        self.corr_id = str(uuid.uuid4())

        #a new SLM in another process for each test
        self.slm_proc = ServiceLifecycleManager(auto_register=False, start_running=False)

        #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')

        #Some threading events that can be used during the tests
        self.wait_for_first_event = threading.Event()
        self.wait_for_first_event.clear()

        #The uuid that can be assigned to the plugin
        self.uuid = '1'

    def tearDown(self):
        #Killing the slm
        self.slm_proc.manoconn.stop_connection()
        self.slm_proc.manoconn.stop_threads()

        try:
            del self.slm_proc
        except:
            pass

        #Killing the connection with the broker
        self.manoconn_spy.stop_connection()
        self.manoconn_gk.stop_connection()
        self.manoconn_ia.stop_connection()

        self.manoconn_spy.stop_threads()
        self.manoconn_gk.stop_threads()
        self.manoconn_ia.stop_threads()

        del self.manoconn_spy
        del self.manoconn_gk
        del self.manoconn_ia

        del self.wait_for_first_event

########################
#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()

    #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 dummy(self, ch, method, properties, message):
        """
        Sometimes, we need a cbf for a async_call, without actually using it.
        """

        return

#############################################################
#TEST1: test validate_deploy_request
#############################################################
    def test_validate_deploy_request(self):
        """
        The method validate_deploy_request is used to check whether the
        received message that requests the deployment of a new service is
        correctly formatted.
        """

        #Setup
        service_dict = {}
        service_id = str(uuid.uuid4())
        corr_id = str(uuid.uuid4())
        service_dict[service_id] = {'original_corr_id':corr_id}

        #SUBTEST1: Check a correctly formatted message
        message = self.createGkNewServiceRequestMessage()
        service_dict[service_id]['payload'] =  yaml.load(message)

        self.slm_proc.set_services(service_dict)
        self.slm_proc.validate_deploy_request(service_id)
        result = self.slm_proc.get_services()

        self.assertEqual({'status': result[service_id]['status'],
                          'error': result[service_id]['error']},
                         {'status': 'INSTANTIATING', 'error': None},
                         msg="outcome and expected result not equal SUBTEST1.")

        #SUBTEST2: Check a message that is not a dictionary
        message = "test message"
        service_dict[service_id]['payload'] = message

        self.slm_proc.set_services(service_dict)
        self.slm_proc.validate_deploy_request(service_id)
        result = self.slm_proc.get_services()

        expected_message = "Request " + corr_id + ": payload is not a dict."
        expected_response = {'status': 'ERROR', 'error': expected_message}

        self.assertEqual({'status': result[service_id]['status'],
                          'error': result[service_id]['error']},
                         expected_response,
                         msg="outcome and expected result not equal SUBTEST2.")


        #SUBTEST3: Check a message that contains no NSD
        message = self.createGkNewServiceRequestMessage()
        loaded_message = yaml.load(message)
        del loaded_message['NSD']
        service_dict[service_id]['payload'] = loaded_message

        self.slm_proc.set_services(service_dict)
        self.slm_proc.validate_deploy_request(service_id)
        result = self.slm_proc.get_services()

        expected_message = "Request " + corr_id + ": NSD is not a dict."
        expected_response = {'status': 'ERROR', 'error': expected_message}

        self.assertEqual({'status': result[service_id]['status'],
                          'error': result[service_id]['error']},
                         expected_response,
                         msg="outcome and expected result not equal SUBTEST3.")

        #SUBTEST4: The number of VNFDs must be the same as listed in the NSD
        message = self.createGkNewServiceRequestMessage()
        loaded_message = yaml.load(message)
        loaded_message['NSD']['network_functions'].append({})
        service_dict[service_id]['payload'] = loaded_message

        self.slm_proc.set_services(service_dict)
        self.slm_proc.validate_deploy_request(service_id)
        result = self.slm_proc.get_services()

        expected_message = "Request " + corr_id + ": # of VNFDs doesn't match NSD."
        expected_response = {'status': 'ERROR', 'error': expected_message}

        self.assertEqual({'status': result[service_id]['status'],
                          'error': result[service_id]['error']},
                         expected_response,
                         msg="outcome and expected result not equal SUBTEST4.")

        #SUBTEST5: VNFDs can not be empty
        message = self.createGkNewServiceRequestMessage()
        loaded_message = yaml.load(message)
        loaded_message['VNFD1'] = None
        service_dict[service_id]['payload'] = loaded_message

        self.slm_proc.set_services(service_dict)
        self.slm_proc.validate_deploy_request(service_id)
        result = self.slm_proc.get_services()

        expected_message = "Request " + corr_id + ": empty VNFD."
        expected_response = {'status': 'ERROR', 'error': expected_message}

        self.assertEqual({'status': result[service_id]['status'],
                          'error': result[service_id]['error']},
                         expected_response,
                         msg="outcome and expected result not equal SUBTEST5.")

###########################################################
#TEST2: Test start_next_task
###########################################################
    def test_start_next_task(self):
        """
        This method tests the start_next_task method
        """

        #Setup
        service_dict = {}
        service_id = str(uuid.uuid4())
        corr_id = str(uuid.uuid4())
        orig_corr_id = str(uuid.uuid4())
        service_dict[service_id] = {'corr_id':corr_id,
                                    'original_corr_id': orig_corr_id,
                                    'pause_chain': True,
                                    'kill_chain': False}

        #SUBTEST1: Check if next task is correctly called
        message = self.createGkNewServiceRequestMessage()

        #Add a task to the list
        task_list = ['validate_deploy_request']

        #Create the ledger
        service_dict[service_id]['schedule'] = task_list
        service_dict[service_id]['payload'] = yaml.load(message)

        #Run the method
        self.slm_proc.set_services(service_dict)
        self.slm_proc.start_next_task(service_id)

        #wait for the task to finish
        time.sleep(0.1)
        result = self.slm_proc.get_services()

        #Check result
        generated_response = {'status': result[service_id]['status'],
                              'error': result[service_id]['error']}
        expected_response = {'status': 'INSTANTIATING', 'error': None}

        self.assertEqual(generated_response,
                         expected_response,
                         msg="outcome and expected result not equal SUBTEST1.")

        #Setup
        service_dict = {}
        service_id = str(uuid.uuid4())
        corr_id = str(uuid.uuid4())
        orig_corr_id = str(uuid.uuid4())
        service_dict[service_id] = {'corr_id':corr_id,
                                    'original_corr_id': orig_corr_id,
                                    'pause_chain': False,
                                    'kill_chain': False}

        #SUBTEST2: Check behavior if there is no next task
        message = self.createGkNewServiceRequestMessage()

        #Add a task to the list
        task_list = []

        #Create the ledger
        service_dict[service_id]['schedule'] = task_list
        service_dict[service_id]['payload'] = yaml.load(message)

        #Run the method
        self.slm_proc.set_services(service_dict)
        self.slm_proc.start_next_task(service_id)

        #wait for the task to finish
        time.sleep(0.1)
        result = self.slm_proc.get_services()

        #Check result: if successful, service_id will not be a key in result

        self.assertFalse(service_id in result.keys(),
                         msg="key is part of ledger in SUBTEST2.")

# ###############################################################
# #TEST3: Test service_instance_create
# ###############################################################
#     def test_service_instance_create(self):
#         """
#         This method tests the service_instance_create method of the SLM
#         """

#         #Setup
#         message = self.createGkNewServiceRequestMessage()
#         corr_id = str(uuid.uuid4())
#         topic = "service.instances.create"
#         prop_dict = {'reply_to': topic, 
#                      'correlation_id': corr_id,
#                      'app_id': "Gatekeeper"}

#         properties = namedtuple('properties', prop_dict.keys())(*prop_dict.values())

#         schedule = self.slm_proc.service_instance_create('foo',
#                                                          'bar',
#                                                          properties,
#                                                          message)

#         #Check result: since we don't know how many of the tasks
#         #were completed by the time we got the result, we only check
#         #the final elements in the tasklist

#         #The last 7 elements from the generated result
#         generated_result = schedule[-7:]

#         #The expected last 7 elements in the list
#         expected_result = ['SLM_mapping', 'ia_prepare', 'vnf_deploy',
#                            'vnf_chain', 'wan_configure',
#                            'instruct_monitoring', 'inform_gk']

#         self.assertEqual(generated_result,
#                          expected_result,
#                          msg='lists are not equal')

###############################################################
#TEST4: Test resp_topo
###############################################################
    # def test_resp_topo(self):
    #     """
    #     This method tests the resp_topo method.
    #     """

    #     #Setup
    #     #Create topology message
    #     first = {'vim_uuid':str(uuid.uuid4()), 'memory_used':5, 'memory_total':12, 'core_used':4, 'core_total':6}
    #     second = {'vim_uuid':str(uuid.uuid4()), 'memory_used':3, 'memory_total':5, 'core_used':4, 'core_total':5}
    #     third = {'vim_uuid':str(uuid.uuid4()), 'memory_used':6, 'memory_total':7, 'core_used':2, 'core_total':12}
    #     topology_message = [first, second, third]
    #     payload = yaml.dump(topology_message)

    #     #Create ledger
    #     service_dict = {}
    #     service_id = str(uuid.uuid4())
    #     corr_id = str(uuid.uuid4())
    #     service_dict[service_id] = {'act_corr_id':corr_id,
    #                                 'infrastructure': {'topology':None},
    #                                 'schedule': ['get_ledger'],
    #                                 'original_corr_id':corr_id,
    #                                 'pause_chain': True,
    #                                 'kill_chain': False}

    #     self.slm_proc.set_services(service_dict)

    #     #Create properties
    #     topic = "infrastructure.management.compute.list"
    #     prop_dict = {'reply_to': topic, 
    #                  'correlation_id': corr_id,
    #                  'app_id': 'InfrastructureAdaptor'}

    #     properties = namedtuple('properties', prop_dict.keys())(*prop_dict.values())

    #     #Run method
    #     self.slm_proc.resp_topo('foo', 'bar', properties, payload)

    #     #Check result
    #     result = self.slm_proc.get_services()

    #     self.assertEqual(topology_message,
    #                      result[service_id]['infrastructure']['topology'],
    #                      msg="Dictionaries are not equal")

###############################################################
#TEST5: Test resp_vnf_depl
###############################################################
    def test_resp_vnf_depl(self):
        """
        This method tests the resp_vnf_depl method.
        """

        #SUBTEST1: Only one VNFD in the service
        #Setup
        #Create the message
        vnfr = yaml.load(open('/plugins/son-mano-service-lifecycle-management/test/test_records/expected_vnfr_iperf.yml', 'r'))
        message = {'status': 'DEPLOYED',
                   'error': None,
                   'ip_mapping': [],
                   'vnfr': vnfr}

        payload = yaml.dump(message)

        #Create ledger
        service_dict = {}
        service_id = str(uuid.uuid4())
        corr_id = str(uuid.uuid4())
        service_dict[service_id] = {'act_corr_id':corr_id,
                                    'function': [{'id': vnfr['id']}],
                                    'vnfs_to_resp': 1,
                                    'ip_mapping': [],
                                    'schedule': ['get_ledger'],
                                    'original_corr_id':corr_id,
                                    'pause_chain': True,
                                    'kill_chain': False}

        self.slm_proc.set_services(service_dict)

        #Create properties
        topic = "mano.function.deploy"
        prop_dict = {'reply_to': topic, 
                     'correlation_id': corr_id,
                     'app_id': 'FunctionLifecycleManager'}

        properties = namedtuple('props', prop_dict.keys())(*prop_dict.values())

        #Run method
        self.slm_proc.resp_vnf_depl('foo', 'bar', properties, payload)

        #Check result
        result = self.slm_proc.get_services()

        self.assertEqual(vnfr,
                         result[service_id]['function'][0]['vnfr'],
                         msg="Dictionaries are not equal SUBTEST 1")

        self.assertEqual(result[service_id]['vnfs_to_resp'],
                         0,
                         msg="Values not equal SUBTEST 1")


        #SUBTEST2: Two VNFDs in the service
        #Setup
        #Create the message
        vnfr = yaml.load(open('/plugins/son-mano-service-lifecycle-management/test/test_records/expected_vnfr_iperf.yml', 'r'))
        message = {'status': 'DEPLOYED',
                   'error': None,
                   'ip_mapping': [],
                   'vnfr': vnfr}

        payload = yaml.dump(message)

        #Create ledger
        service_dict = {}
        service_id = str(uuid.uuid4())
        corr_id = str(uuid.uuid4())
        service_dict[service_id] = {'act_corr_id':corr_id,
                                    'function': [{'id': vnfr['id']}],
                                    'vnfs_to_resp': 2,
                                    'ip_mapping': [],
                                    'schedule': ['get_ledger'],
                                    'original_corr_id':corr_id,
                                    'pause_chain': True,
                                    'kill_chain': False}

        self.slm_proc.set_services(service_dict)

        #Create properties
        topic = "mano.function.deploy"
        prop_dict = {'reply_to': topic, 
                     'correlation_id': corr_id,
                     'app_id': 'FunctionLifecycleManager'}

        properties = namedtuple('props', prop_dict.keys())(*prop_dict.values())

        #Run method
        self.slm_proc.resp_vnf_depl('foo', 'bar', properties, payload)

        #Check result
        result = self.slm_proc.get_services()

        self.assertEqual(vnfr,
                         result[service_id]['function'][0]['vnfr'],
                         msg="Dictionaries are not equal SUBTEST 2")

        self.assertEqual(result[service_id]['vnfs_to_resp'],
                         1,
                         msg="Values not equal SUBTEST 2")

        self.assertEqual(result[service_id]['schedule'],
                         ['get_ledger'],
                         msg="Lists not equal SUBTEST 2")

###############################################################
#TEST6: Test resp_prepare
###############################################################
    def test_resp_prepare(self):
        """
        This method tests the resp_prepare method.
        """

        #SUBTEST 1: Successful response message
        #Setup
        #Create the message
        message = {'request_status': 'COMPLETED',
                   'error': None,
                   }

        payload = yaml.dump(message)

        #Create ledger
        service_dict = {}
        service_id = str(uuid.uuid4())
        corr_id = str(uuid.uuid4())
        service_dict[service_id] = {'act_corr_id':corr_id,
                                    'schedule': ['get_ledger'],
                                    'original_corr_id':corr_id,
                                    'pause_chain': True,
                                    'current_workflow': 'instantiation',
                                    'kill_chain': False}

        self.slm_proc.set_services(service_dict)

        #Create properties
        topic = "infrastructure.service.prepare"
        prop_dict = {'reply_to': topic, 
                     'correlation_id': corr_id,
                     'app_id': 'InfrastructureAdaptor'}

        properties = namedtuple('props', prop_dict.keys())(*prop_dict.values())

        #Run method
        self.slm_proc.resp_prepare('foo', 'bar', properties, payload)

        #Check result
        result = self.slm_proc.get_services()

        self.assertFalse('status' in result[service_id].keys(),
                         msg="Key in dictionary SUBTEST 1")

        self.assertFalse('error' in result[service_id].keys(),
                         msg="Key in dictionary SUBTEST 1")

        # #SUBTEST 2: Failed response message

        # def on_test_resp_prepare_subtest2(ch, mthd, prop, payload):

        #     message = yaml.load(payload)

        #     self.assertEqual(message['status'],
        #                      'ERROR',
        #                      msg="Status not correct in SUBTEST 1")

        #     self.assertEqual(message['error'],
        #                      'BAR',
        #                      msg="Error not correct in SUBTEST 1")

        #     self.assertTrue('timestamp' in message.keys(),
        #                      msg="Timestamp missing in SUBTEST 1")

        #     self.assertEqual(len(message.keys()),
        #                      3,
        #                     msg="Number of keys not correct in SUBTEST1")
        #     self.firstEventFinished()

        # #Setup
        # #Create the message

        # message = {'request_status': 'FOO',
        #            'message': 'BAR',
        #            }

        # payload = yaml.dump(message)

        # #Listen on feedback topic
        # self.manoconn_gk.subscribe(on_test_resp_prepare_subtest2,'service.instances.create')

        # #Create ledger
        # service_dict = {}
        # service_id = str(uuid.uuid4())
        # corr_id = str(uuid.uuid4())
        # service_dict[service_id] = {'act_corr_id':corr_id,
        #                             'schedule': ['get_ledger'],
        #                             'original_corr_id':corr_id,
        #                             'pause_chain': True,
        #                             'current_workflow': 'instantiation',
        #                             'kill_chain': False}

        # self.slm_proc.set_services(service_dict)

        # #Create properties
        # topic = "infrastructure.service.prepare"
        # prop_dict = {'reply_to': topic, 
        #              'correlation_id': corr_id,
        #              'app_id': 'InfrastructureAdaptor'}

        # properties = namedtuple('props', prop_dict.keys())(*prop_dict.values())

        # #Run method
        # self.slm_proc.resp_prepare('foo', 'bar', properties, payload)

        # #Wait for the test to finish
        # self.waitForFirstEvent(timeout=5)


###############################################################
#TEST7: test contact_gk
###############################################################
    def test_contact_gk(self):
        """
        This method tests the contact_gk method.
        """

        #Check result SUBTEST 1
        def on_contact_gk_subtest1(ch, mthd, prop, payload):
            message = yaml.load(payload)

            self.assertEqual(message['status'],
                             'FOO',
                             msg="Status not correct in SUBTEST 1")

            self.assertEqual(message['error'],
                             'BAR',
                             msg="Error not correct in SUBTEST 1")

            self.assertTrue('timestamp' in message.keys(),
                             msg="Timestamp missing in SUBTEST 1")

            self.assertEqual(len(message.keys()),
                             3,
                            msg="Number of keys not correct in SUBTEST1")
            self.firstEventFinished()

        #Check result SUBTEST2
        def on_contact_gk_subtest2(ch, mthd, prop, payload):
            self.firstEventFinished()

            message = yaml.load(payload)

            self.assertEqual(message['status'],
                             'FOO',
                             msg="Status not correct in SUBTEST 2")

            self.assertEqual(message['error'],
                             'BAR',
                             msg="Error not correct in SUBTEST 2")

            self.assertEqual(message['FOO'],
                             'BAR',
                             msg="Error not correct in SUBTEST 2")

            self.assertTrue('timestamp' in message.keys(),
                             msg="Timestamp missing in SUBTEST 2")

            self.assertEqual(len(message.keys()),
                             4,
                            msg="Number of keys not correct in SUBTEST2")

        #SUBTEST1: Without additional content
        #Setup
        #Create the ledger
        self.wait_for_first_event.clear()
        service_dict = {}
        service_id = str(uuid.uuid4())
        corr_id = str(uuid.uuid4())
        service_dict[service_id] = {'schedule': ['get_ledger'],
                                    'original_corr_id':corr_id,
                                    'pause_chain': True,
                                    'status': 'FOO',
                                    'error': 'BAR',
                                    'kill_chain': False,
                                    'topic': 'service.instances.create'}

        #Set the ledger
        self.slm_proc.set_services(service_dict)

        #Spy the message bus
        self.manoconn_spy.subscribe(on_contact_gk_subtest1, 'service.instances.create')

        #Wait until subscription is completed
        time.sleep(0.1)

        #Run the method
        self.slm_proc.contact_gk(service_id)

        #Wait for the test to finish
        self.waitForFirstEvent(timeout=5)

        #SUBTEST2: With additional content
        #Setup
        self.wait_for_first_event.clear()
        #Create the ledger
        service_dict = {}
        service_id = str(uuid.uuid4())
        corr_id = str(uuid.uuid4())
        add_content = {'FOO': 'BAR'}
        service_dict[service_id] = {'schedule': ['get_ledger'],
                                    'original_corr_id':corr_id,
                                    'pause_chain': True,
                                    'status': 'FOO',
                                    'error': 'BAR',
                                    'add_content': add_content,
                                    'topic': 'service.instances.create'}

        self.slm_proc.set_services(service_dict)

        #Spy the message bus
        self.manoconn_gk.subscribe(on_contact_gk_subtest2, 'service.instances.create')

        #Wait until subscription is completed
        time.sleep(0.1)

        #Run the method
        self.slm_proc.contact_gk(service_id)

        #Wait for the test to finish
        self.waitForFirstEvent(timeout=5)
class testSlmFunctionality(unittest.TestCase):
    """
    Tests the tasks that the SLM should perform in the service
    life cycle of the network services.
    """

    slm_proc = None
    uuid = '1'
    corr_id = '1ba347d6-6210-4de7-9ca3-a383e50d0330'

    ########################
    #SETUP
    ########################
    def setUp(self):
        def on_register_trigger(ch, method, properties, message):
            return json.dumps({'status': 'OK', 'uuid': self.uuid})

        #vnfcounter for when needed
        self.vnfcounter = 0

        #Generate a new corr_id for every test
        self.corr_id = str(uuid.uuid4())

        #a new SLM in another process for each test
        self.slm_proc = ServiceLifecycleManager(start_running=False)

        #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')

        #Some threading events that can be used during the tests
        self.wait_for_first_event = threading.Event()
        self.wait_for_first_event.clear()

        #The uuid that can be assigned to the plugin
        self.uuid = '1'

    def tearDown(self):
        #Killing the slm
        self.slm_proc.manoconn.stop_connection()
        self.slm_proc.manoconn.stop_threads()

        try:
            del self.slm_proc
        except:
            pass

        #Killing the connection with the broker
        self.manoconn_spy.stop_connection()
        self.manoconn_gk.stop_connection()
        self.manoconn_ia.stop_connection()

        self.manoconn_spy.stop_threads()
        self.manoconn_gk.stop_threads()
        self.manoconn_ia.stop_threads()

        del self.manoconn_spy
        del self.manoconn_gk
        del self.manoconn_ia

        del self.wait_for_first_event

########################
#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()

    #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 dummy(self, ch, method, properties, message):
        """
        Sometimes, we need a cbf for a async_call, without actually using it.
        """

        return

#############################################################
#TEST1: test validate_deploy_request
#############################################################

    def test_validate_deploy_request(self):
        """
        The method validate_deploy_request is used to check whether the
        received message that requests the deployment of a new service is
        correctly formatted.
        """

        #Setup
        service_dict = {}
        service_id = str(uuid.uuid4())
        corr_id = str(uuid.uuid4())
        service_dict[service_id] = {'original_corr_id': corr_id}

        # #SUBTEST1: Check a correctly formatted message
        # message = self.createGkNewServiceRequestMessage()
        # service_dict[service_id]['payload'] =  yaml.load(message)

        # self.slm_proc.set_services(service_dict)
        # self.slm_proc.validate_deploy_request(service_id)
        # result = self.slm_proc.get_services()

        # self.assertEqual({'status': result[service_id]['status'],
        #                   'error': result[service_id]['error']},
        #                  {'status': 'INSTANTIATING', 'error': None},
        #                  msg="outcome and expected result not equal SUBTEST1.")

        #SUBTEST2: Check a message that is not a dictionary
        message = "test message"
        service_dict[service_id]['payload'] = message

        self.slm_proc.set_services(service_dict)
        self.slm_proc.validate_deploy_request(service_id)
        result = self.slm_proc.get_services()

        expected_message = "Request " + corr_id + ": payload is not a dict."
        expected_response = {'status': 'ERROR', 'error': expected_message}

        self.assertEqual(
            {
                'status': result[service_id]['status'],
                'error': result[service_id]['error']
            },
            expected_response,
            msg="outcome and expected result not equal SUBTEST2.")

        #SUBTEST3: Check a message that contains no NSD
        message = self.createGkNewServiceRequestMessage()
        loaded_message = yaml.load(message)
        del loaded_message['NSD']
        service_dict[service_id]['payload'] = loaded_message

        self.slm_proc.set_services(service_dict)
        self.slm_proc.validate_deploy_request(service_id)
        result = self.slm_proc.get_services()

        expected_message = "Request " + corr_id + ": NSD is not a dict."
        expected_response = {'status': 'ERROR', 'error': expected_message}

        self.assertEqual(
            {
                'status': result[service_id]['status'],
                'error': result[service_id]['error']
            },
            expected_response,
            msg="outcome and expected result not equal SUBTEST3.")

        #SUBTEST4: The number of VNFDs must be the same as listed in the NSD
        message = self.createGkNewServiceRequestMessage()
        loaded_message = yaml.load(message)
        loaded_message['NSD']['network_functions'].append({})
        service_dict[service_id]['payload'] = loaded_message

        self.slm_proc.set_services(service_dict)
        self.slm_proc.validate_deploy_request(service_id)
        result = self.slm_proc.get_services()

        expected_message = "Request " + corr_id + ": # of VNFDs doesn't match NSD."
        expected_response = {'status': 'ERROR', 'error': expected_message}

        self.assertEqual(
            {
                'status': result[service_id]['status'],
                'error': result[service_id]['error']
            },
            expected_response,
            msg="outcome and expected result not equal SUBTEST4.")

        #SUBTEST5: VNFDs can not be empty
        message = self.createGkNewServiceRequestMessage()
        loaded_message = yaml.load(message)
        loaded_message['VNFD1'] = None
        service_dict[service_id]['payload'] = loaded_message

        self.slm_proc.set_services(service_dict)
        self.slm_proc.validate_deploy_request(service_id)
        result = self.slm_proc.get_services()

        expected_message = "Request " + corr_id + ": empty VNFD."
        expected_response = {'status': 'ERROR', 'error': expected_message}

        self.assertEqual(
            {
                'status': result[service_id]['status'],
                'error': result[service_id]['error']
            },
            expected_response,
            msg="outcome and expected result not equal SUBTEST5.")

###########################################################
#TEST2: Test start_next_task
###########################################################

    def test_start_next_task(self):
        """
        This method tests the start_next_task method
        """

        #Setup
        service_dict = {}
        service_id = str(uuid.uuid4())
        corr_id = str(uuid.uuid4())
        orig_corr_id = str(uuid.uuid4())
        service_dict[service_id] = {
            'corr_id': corr_id,
            'original_corr_id': orig_corr_id,
            'pause_chain': True,
            'kill_chain': False
        }

        #SUBTEST1: Check if next task is correctly called
        message = self.createGkNewServiceRequestMessage()

        #Add a task to the list
        task_list = ['validate_deploy_request']

        #Create the ledger
        service_dict[service_id]['schedule'] = task_list
        service_dict[service_id]['payload'] = yaml.load(message)

        #Run the method
        self.slm_proc.set_services(service_dict)
        self.slm_proc.start_next_task(service_id)

        #wait for the task to finish
        time.sleep(0.1)
        result = self.slm_proc.get_services()

        #Check result
        generated_response = {
            'status': result[service_id]['status'],
            'error': result[service_id]['error']
        }
        expected_response = {'status': 'INSTANTIATING', 'error': None}

        self.assertEqual(generated_response,
                         expected_response,
                         msg="outcome and expected result not equal SUBTEST1.")

        #Setup
        service_dict = {}
        service_id = str(uuid.uuid4())
        corr_id = str(uuid.uuid4())
        orig_corr_id = str(uuid.uuid4())
        service_dict[service_id] = {
            'corr_id': corr_id,
            'original_corr_id': orig_corr_id,
            'pause_chain': False,
            'kill_chain': False
        }

        #SUBTEST2: Check behavior if there is no next task
        message = self.createGkNewServiceRequestMessage()

        #Add a task to the list
        task_list = []

        #Create the ledger
        service_dict[service_id]['schedule'] = task_list
        service_dict[service_id]['payload'] = yaml.load(message)

        #Run the method
        self.slm_proc.set_services(service_dict)
        self.slm_proc.start_next_task(service_id)

        #wait for the task to finish
        time.sleep(0.1)
        result = self.slm_proc.get_services()

        #Check result: if successful, service_id will not be a key in result

        self.assertFalse(service_id in result.keys(),
                         msg="key is part of ledger in SUBTEST2.")

# ###############################################################
# #TEST3: Test service_instance_create
# ###############################################################
#     def test_service_instance_create(self):
#         """
#         This method tests the service_instance_create method of the SLM
#         """

#         #Setup
#         message = self.createGkNewServiceRequestMessage()
#         corr_id = str(uuid.uuid4())
#         topic = "service.instances.create"
#         prop_dict = {'reply_to': topic,
#                      'correlation_id': corr_id,
#                      'app_id': "Gatekeeper"}

#         properties = namedtuple('properties', prop_dict.keys())(*prop_dict.values())

#         schedule = self.slm_proc.service_instance_create('foo',
#                                                          'bar',
#                                                          properties,
#                                                          message)

#         #Check result: since we don't know how many of the tasks
#         #were completed by the time we got the result, we only check
#         #the final elements in the tasklist

#         #The last 7 elements from the generated result
#         generated_result = schedule[-7:]

#         #The expected last 7 elements in the list
#         expected_result = ['SLM_mapping', 'ia_prepare', 'vnf_deploy',
#                            'vnf_chain', 'wan_configure',
#                            'instruct_monitoring', 'inform_gk']

#         self.assertEqual(generated_result,
#                          expected_result,
#                          msg='lists are not equal')

###############################################################
#TEST4: Test resp_topo
###############################################################
# def test_resp_topo(self):
#     """
#     This method tests the resp_topo method.
#     """

#     #Setup
#     #Create topology message
#     first = {'vim_uuid':str(uuid.uuid4()), 'memory_used':5, 'memory_total':12, 'core_used':4, 'core_total':6}
#     second = {'vim_uuid':str(uuid.uuid4()), 'memory_used':3, 'memory_total':5, 'core_used':4, 'core_total':5}
#     third = {'vim_uuid':str(uuid.uuid4()), 'memory_used':6, 'memory_total':7, 'core_used':2, 'core_total':12}
#     topology_message = [first, second, third]
#     payload = yaml.dump(topology_message)

#     #Create ledger
#     service_dict = {}
#     service_id = str(uuid.uuid4())
#     corr_id = str(uuid.uuid4())
#     service_dict[service_id] = {'act_corr_id':corr_id,
#                                 'infrastructure': {'topology':None},
#                                 'schedule': ['get_ledger'],
#                                 'original_corr_id':corr_id,
#                                 'pause_chain': True,
#                                 'kill_chain': False}

#     self.slm_proc.set_services(service_dict)

#     #Create properties
#     topic = "infrastructure.management.compute.list"
#     prop_dict = {'reply_to': topic,
#                  'correlation_id': corr_id,
#                  'app_id': 'InfrastructureAdaptor'}

#     properties = namedtuple('properties', prop_dict.keys())(*prop_dict.values())

#     #Run method
#     self.slm_proc.resp_topo('foo', 'bar', properties, payload)

#     #Check result
#     result = self.slm_proc.get_services()

#     self.assertEqual(topology_message,
#                      result[service_id]['infrastructure']['topology'],
#                      msg="Dictionaries are not equal")

###############################################################
#TEST5: Test resp_vnf_depl
###############################################################

    def test_resp_vnf_depl(self):
        """
        This method tests the resp_vnf_depl method.
        """

        #SUBTEST1: Only one VNFD in the service
        #Setup
        #Create the message
        vnfr = yaml.load(
            open(
                '/plugins/son-mano-service-lifecycle-management/test/test_records/expected_vnfr_iperf.yml',
                'r'))
        message = {
            'status': 'DEPLOYED',
            'error': None,
            'ip_mapping': [],
            'vnfr': vnfr
        }

        payload = yaml.dump(message)

        #Create ledger
        service_dict = {}
        service_id = str(uuid.uuid4())
        corr_id = str(uuid.uuid4())
        service_dict[service_id] = {
            'act_corr_id': corr_id,
            'function': [{
                'id': vnfr['id']
            }],
            'vnfs_to_resp': 1,
            'ip_mapping': [],
            'schedule': ['get_ledger'],
            'original_corr_id': corr_id,
            'pause_chain': True,
            'kill_chain': False
        }

        self.slm_proc.set_services(service_dict)

        #Create properties
        topic = "mano.function.deploy"
        prop_dict = {
            'reply_to': topic,
            'correlation_id': corr_id,
            'app_id': 'FunctionLifecycleManager'
        }

        properties = namedtuple('props', prop_dict.keys())(*prop_dict.values())

        #Run method
        self.slm_proc.resp_vnf_depl('foo', 'bar', properties, payload)

        #Check result
        result = self.slm_proc.get_services()

        self.assertEqual(vnfr,
                         result[service_id]['function'][0]['vnfr'],
                         msg="Dictionaries are not equal SUBTEST 1")

        self.assertEqual(result[service_id]['vnfs_to_resp'],
                         0,
                         msg="Values not equal SUBTEST 1")

        #SUBTEST2: Two VNFDs in the service
        #Setup
        #Create the message
        vnfr = yaml.load(
            open(
                '/plugins/son-mano-service-lifecycle-management/test/test_records/expected_vnfr_iperf.yml',
                'r'))
        message = {
            'status': 'DEPLOYED',
            'error': None,
            'ip_mapping': [],
            'vnfr': vnfr
        }

        payload = yaml.dump(message)

        #Create ledger
        service_dict = {}
        service_id = str(uuid.uuid4())
        corr_id = str(uuid.uuid4())
        service_dict[service_id] = {
            'act_corr_id': corr_id,
            'function': [{
                'id': vnfr['id']
            }],
            'vnfs_to_resp': 2,
            'ip_mapping': [],
            'schedule': ['get_ledger'],
            'original_corr_id': corr_id,
            'pause_chain': True,
            'kill_chain': False
        }

        self.slm_proc.set_services(service_dict)

        #Create properties
        topic = "mano.function.deploy"
        prop_dict = {
            'reply_to': topic,
            'correlation_id': corr_id,
            'app_id': 'FunctionLifecycleManager'
        }

        properties = namedtuple('props', prop_dict.keys())(*prop_dict.values())

        #Run method
        self.slm_proc.resp_vnf_depl('foo', 'bar', properties, payload)

        #Check result
        result = self.slm_proc.get_services()

        self.assertEqual(vnfr,
                         result[service_id]['function'][0]['vnfr'],
                         msg="Dictionaries are not equal SUBTEST 2")

        self.assertEqual(result[service_id]['vnfs_to_resp'],
                         1,
                         msg="Values not equal SUBTEST 2")

        self.assertEqual(result[service_id]['schedule'], ['get_ledger'],
                         msg="Lists not equal SUBTEST 2")

###############################################################
#TEST6: Test resp_prepare
###############################################################

    def test_resp_prepare(self):
        """
        This method tests the resp_prepare method.
        """

        #SUBTEST 1: Successful response message
        #Setup
        #Create the message
        message = {
            'request_status': 'COMPLETED',
            'error': None,
        }

        payload = yaml.dump(message)

        #Create ledger
        service_dict = {}
        service_id = str(uuid.uuid4())
        corr_id = str(uuid.uuid4())
        service_dict[service_id] = {
            'act_corr_id': corr_id,
            'schedule': ['get_ledger'],
            'original_corr_id': corr_id,
            'pause_chain': True,
            'current_workflow': 'instantiation',
            'kill_chain': False
        }

        self.slm_proc.set_services(service_dict)

        #Create properties
        topic = "infrastructure.service.prepare"
        prop_dict = {
            'reply_to': topic,
            'correlation_id': corr_id,
            'app_id': 'InfrastructureAdaptor'
        }

        properties = namedtuple('props', prop_dict.keys())(*prop_dict.values())

        #Run method
        self.slm_proc.resp_prepare('foo', 'bar', properties, payload)

        #Check result
        result = self.slm_proc.get_services()

        self.assertFalse('status' in result[service_id].keys(),
                         msg="Key in dictionary SUBTEST 1")

        self.assertFalse('error' in result[service_id].keys(),
                         msg="Key in dictionary SUBTEST 1")