# Copyright 2016 - Alcatel-Lucent
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

"""
test_vitrage graph algorithms
----------------------------------

Tests for `vitrage` graph driver algorithms
"""
from testtools import matchers

from vitrage.common.constants import EdgeLabel
from vitrage.common.constants import EdgeProperties as EProps
from vitrage.datasources.heat.stack import HEAT_STACK_DATASOURCE
from vitrage.datasources.neutron.network import NEUTRON_NETWORK_DATASOURCE
from vitrage.graph.algo_driver.algorithm import Mapping
from vitrage.graph.algo_driver.sub_graph_matching import \
    NEG_CONDITION
from vitrage.graph.algo_driver.sub_graph_matching import subgraph_matching
from vitrage.graph.driver.elements import Edge
from vitrage.graph.driver.graph import Direction
from vitrage.tests.base import IsEmpty
from vitrage.tests.unit.graph.base import *  # noqa

ROOT_ID = EntityCategory.RESOURCE + ':' + OPENSTACK_CLUSTER + ':' + CLUSTER_ID


class GraphAlgorithmTest(GraphTestBase):

    # noinspection PyPep8Naming
    @classmethod
    def setUpClass(cls):
        super(GraphAlgorithmTest, cls).setUpClass()
        cls.vm_id = 10000000
        cls.vm_alarm_id = 30000000
        cls.vms = []
        cls.host_alarm_id = 20000000
        cls.host_test_id = 40000000
        cls.entity_graph = cls._create_entity_graph(
            'entity_graph',
            num_of_hosts_per_node=ENTITY_GRAPH_HOSTS_PER_CLUSTER,
            num_of_vms_per_host=ENTITY_GRAPH_VMS_PER_HOST,
            num_of_alarms_per_host=ENTITY_GRAPH_ALARMS_PER_HOST,
            num_of_alarms_per_vm=ENTITY_GRAPH_ALARMS_PER_VM,
            num_of_tests_per_host=ENTITY_GRAPH_TESTS_PER_HOST)

    def test_graph_query_vertices(self):
        ga = self.entity_graph.algo

        query = {'==': {VProps.VITRAGE_TYPE: OPENSTACK_CLUSTER}}
        subgraph = ga.graph_query_vertices(root_id=ROOT_ID, query_dict=query)
        self.assertEqual(
            1,  # For Cluster
            subgraph.num_vertices(), 'num of vertex node')

        query = {
            'or': [
                {'==': {VProps.VITRAGE_TYPE: NOVA_HOST_DATASOURCE}},
                {'==': {VProps.VITRAGE_TYPE: OPENSTACK_CLUSTER}}
            ]
        }

        subgraph = ga.graph_query_vertices(root_id=ROOT_ID, query_dict=query)
        self.assertEqual(
            ENTITY_GRAPH_HOSTS_PER_CLUSTER,
            subgraph.num_edges(), 'num of edges Host <-- NODE')

        query = {
            'or': [
                {'==': {VProps.VITRAGE_TYPE: NOVA_INSTANCE_DATASOURCE}},
                {'==': {VProps.VITRAGE_CATEGORY: ALARM}},
                {'==': {VProps.VITRAGE_TYPE: NOVA_HOST_DATASOURCE}},
                {'==': {VProps.VITRAGE_TYPE: OPENSTACK_CLUSTER}}
            ]
        }
        subgraph = ga.graph_query_vertices(root_id=ROOT_ID, query_dict=query)
        self.assertEqual(
            ENTITY_GRAPH_HOSTS_PER_CLUSTER +
            ENTITY_GRAPH_HOSTS_PER_CLUSTER * ENTITY_GRAPH_ALARMS_PER_HOST +
            ENTITY_GRAPH_HOSTS_PER_CLUSTER * ENTITY_GRAPH_VMS_PER_HOST +
            ENTITY_GRAPH_HOSTS_PER_CLUSTER * ENTITY_GRAPH_VMS_PER_HOST *
            ENTITY_GRAPH_ALARMS_PER_VM,
            subgraph.num_edges(), 'num of BOTH edges Host (depth 1)')

        # Get first host ID
        neighboring_hosts = self.entity_graph.neighbors(
            v_node.vertex_id, {VProps.VITRAGE_TYPE: NOVA_HOST_DATASOURCE})
        first_host_id = neighboring_hosts.pop().vertex_id

        query = {'!=': {'NOTHING': 'IS EVERYTHING'}}
        subgraph = ga.graph_query_vertices(
            root_id=first_host_id, query_dict=query, depth=1)
        self.assertEqual(
            1 +  # For host
            1 +  # For Cluster
            ENTITY_GRAPH_ALARMS_PER_HOST +
            ENTITY_GRAPH_TESTS_PER_HOST +
            ENTITY_GRAPH_VMS_PER_HOST,
            subgraph.num_edges(), 'num of BOTH edges Host (depth 1)')

        query = {
            'or': [
                {'==': {VProps.VITRAGE_TYPE: 'switch'}},
                {'==': {VProps.VITRAGE_TYPE: NOVA_HOST_DATASOURCE}},
            ]
        }
        subgraph = ga.graph_query_vertices(
            root_id=first_host_id, query_dict=query, depth=1)
        self.assertEqual(
            1,  # For 'switch'
            subgraph.num_edges(), 'num of BOTH edges Host (depth 1)')

        subgraph = ga.graph_query_vertices(root_id=first_host_id, depth=2)
        self.assertEqual(
            1 +  # Cluster to switch
            ENTITY_GRAPH_HOSTS_PER_CLUSTER * 2 +
            ENTITY_GRAPH_ALARMS_PER_HOST +
            ENTITY_GRAPH_TESTS_PER_HOST +
            ENTITY_GRAPH_VMS_PER_HOST +
            ENTITY_GRAPH_VMS_PER_HOST * ENTITY_GRAPH_ALARMS_PER_VM,
            subgraph.num_edges(), 'num of BOTH edges Host (depth 2)')

        subgraph = ga.graph_query_vertices(root_id=first_host_id, depth=3,
                                           direction=Direction.OUT)
        self.assertEqual(
            1 +
            ENTITY_GRAPH_VMS_PER_HOST,
            subgraph.num_edges(), 'num of BOTH edges Host (depth 3)')

        query = {
            'and': [
                {'!=': {VProps.VITRAGE_TYPE: ALARM_ON_VM}},
                {'!=': {VProps.VITRAGE_TYPE: ALARM_ON_HOST}},
                {'!=': {VProps.VITRAGE_CATEGORY: ALARM}}
            ]
        }
        subgraph = ga.graph_query_vertices(root_id=ROOT_ID,
                                           query_dict=query,
                                           depth=3)
        self.assertEqual(
            1 +  # Cluster to switch
            ENTITY_GRAPH_HOSTS_PER_CLUSTER * 2 +
            ENTITY_GRAPH_HOSTS_PER_CLUSTER * ENTITY_GRAPH_TESTS_PER_HOST +
            ENTITY_GRAPH_HOSTS_PER_CLUSTER * ENTITY_GRAPH_VMS_PER_HOST,
            subgraph.num_edges(), 'num of edges Node (depth 3)')

        query = {
            'or': [
                {'==': {VProps.VITRAGE_TYPE: OPENSTACK_CLUSTER}},
                {'==': {VProps.VITRAGE_CATEGORY: ALARM}},
            ]
        }
        subgraph = ga.graph_query_vertices(root_id=ROOT_ID,
                                           query_dict=query,
                                           depth=3)
        self.assertEqual(0, subgraph.num_edges(),
                         'num of BOTH edges Node (depth 3)')
        self.assertEqual(1, subgraph.num_vertices(),
                         'num of BOTH vertices Node (depth 3)')

        # check the edge_query_dict parameter
        query = {'!=': {'NOTHING': 'IS EVERYTHING'}}
        edge_query = {'==': {EProps.RELATIONSHIP_TYPE: EdgeLabel.CONTAINS}}
        subgraph = ga.graph_query_vertices(root_id=ROOT_ID,
                                           query_dict=query,
                                           depth=5,
                                           edge_query_dict=edge_query)
        alarms = subgraph.get_vertices(
            vertex_attr_filter={VProps.VITRAGE_CATEGORY: ALARM})
        self.assertThat(alarms, IsEmpty(), 'We filtered the ON relationship,'
                                           ' so no alarms should exist')

        # check that the vitrage_is_deleted=True edges are deleted from the
        # graph
        hosts_query = {VProps.VITRAGE_CATEGORY: RESOURCE,
                       VProps.VITRAGE_TYPE: NOVA_HOST_DATASOURCE}
        hosts = self.entity_graph.get_vertices(
            vertex_attr_filter=hosts_query)
        instances_query = {VProps.VITRAGE_CATEGORY: RESOURCE,
                           VProps.VITRAGE_TYPE: NOVA_INSTANCE_DATASOURCE}
        instances = self.entity_graph.get_vertices(
            vertex_attr_filter=instances_query)
        instance_edges = self.entity_graph.get_edges(instances[0].vertex_id)

        for edge in instance_edges:
            if NOVA_HOST_DATASOURCE in edge.source_id:
                host_instance_edge = edge
        host_instance_edge[VProps.VITRAGE_IS_DELETED] = True
        self.entity_graph.update_edge(host_instance_edge)

        edges_query = {EProps.RELATIONSHIP_TYPE: EdgeLabel.CONTAINS,
                       VProps.VITRAGE_IS_DELETED: False}
        if host_instance_edge.source_id != hosts[0].vertex_id:
            new_edge = Edge(hosts[0].vertex_id, instances[0].vertex_id,
                            EdgeLabel.CONTAINS, properties=edges_query)
            self.entity_graph.update_edge(new_edge)
        else:
            new_edge = Edge(hosts[1].vertex_id, instances[0].vertex_id,
                            EdgeLabel.CONTAINS, properties=edges_query)
            self.entity_graph.update_edge(new_edge)

        query = {'!=': {'NOTHING': 'IS EVERYTHING'}}
        edge_query = {'==': {EProps.VITRAGE_IS_DELETED: False}}
        subgraph = ga.graph_query_vertices(root_id=ROOT_ID,
                                           query_dict=query,
                                           depth=5,
                                           edge_query_dict=edge_query)
        self.assertEqual(self.entity_graph.num_edges() - 1,
                         subgraph.num_edges(),
                         'We filtered the ON relationship, so no alarms '
                         'should exist')

        # Undo changes made by this test
        host_instance_edge[VProps.VITRAGE_IS_DELETED] = False
        self.entity_graph.update_edge(host_instance_edge)
        self.entity_graph.remove_edge(new_edge)

    def test_no_match_graph_query_vertices(self):
        query = {'==': {VProps.VITRAGE_TYPE: 'test'}}
        subgraph = self.entity_graph.algo.graph_query_vertices(
            root_id=ROOT_ID,
            query_dict=query)
        self.assertEqual(
            0,
            subgraph.num_vertices(), 'num of vertex node')

    def test_template_matching(self):
        """Test the template matching algorithm

        Using the entity graph (created above) as a big graph we search
        for a sub graph match
        """
        ga = self.entity_graph.algo

        # Get ids of some of the elements in the entity graph:
        vm_alarm = self.entity_graph.get_vertex(
            ALARM_ON_VM + str(self.vm_alarm_id - 1))
        host_alarm = self.entity_graph.get_vertex(
            ALARM_ON_HOST + str(self.host_alarm_id - 1))

        # Create a template for template matching
        template_graph = NXGraph('template_graph')
        t_v_host_alarm = graph_utils.create_vertex(
            vitrage_id='1', vitrage_category=ALARM, vitrage_type=ALARM_ON_HOST)
        t_v_alarm_fail = graph_utils.create_vertex(
            vitrage_id='1', vitrage_category=ALARM, vitrage_type='fail')
        t_v_host = graph_utils.create_vertex(
            vitrage_id='2',
            vitrage_category=RESOURCE,
            vitrage_type=NOVA_HOST_DATASOURCE)
        t_v_vm = graph_utils.create_vertex(
            vitrage_id='3',
            vitrage_category=RESOURCE,
            vitrage_type=NOVA_INSTANCE_DATASOURCE)
        t_v_vm_alarm = graph_utils.create_vertex(
            vitrage_id='4', vitrage_category=ALARM, vitrage_type=ALARM_ON_VM)
        t_v_switch = graph_utils.create_vertex(
            vitrage_id='5', vitrage_category=RESOURCE, vitrage_type='switch')
        t_v_node = graph_utils.create_vertex(
            vitrage_id='6',
            vitrage_category=RESOURCE,
            vitrage_type=OPENSTACK_CLUSTER)
        t_v_node_not_in_graph = graph_utils.create_vertex(
            vitrage_id='7',
            vitrage_category=RESOURCE,
            vitrage_type=OPENSTACK_CLUSTER + ' not in graph')

        e_alarm_on_host = graph_utils.create_edge(
            t_v_host_alarm.vertex_id, t_v_host.vertex_id, ELabel.ON)
        e_host_contains_vm = graph_utils.create_edge(
            t_v_host.vertex_id, t_v_vm.vertex_id, ELabel.CONTAINS)
        e_alarm_on_vm = graph_utils.create_edge(
            t_v_vm_alarm.vertex_id, t_v_vm.vertex_id, ELabel.ON)
        e_host_uses_switch = graph_utils.create_edge(
            t_v_host.vertex_id, t_v_switch.vertex_id, 'USES')
        e_node_contains_host = graph_utils.create_edge(
            t_v_node.vertex_id, t_v_host.vertex_id, ELabel.CONTAINS)
        e_node_contains_switch = graph_utils.create_edge(
            t_v_node.vertex_id, t_v_switch.vertex_id, ELabel.CONTAINS)
        e_node_contains_switch_fail = graph_utils.create_edge(
            t_v_node.vertex_id, t_v_switch.vertex_id, ELabel.CONTAINS + 'fail')
        e_host_to_node_not_in_graph = graph_utils.create_edge(
            t_v_node_not_in_graph.vertex_id, t_v_host.vertex_id, ELabel.ON)

        for v in [t_v_host_alarm, t_v_host, t_v_vm, t_v_vm_alarm,
                  t_v_switch, t_v_switch, t_v_node]:
            del(v[VProps.VITRAGE_ID])

        template_graph.add_vertex(t_v_alarm_fail)
        mappings = ga.sub_graph_matching(template_graph,
                                         Mapping(t_v_host_alarm,
                                                 host_alarm,
                                                 is_vertex=True),
                                         validate=True)
        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - Single vertex alarm not in graph '
            'Template_root is a specific host alarm ')
        template_graph.remove_vertex(t_v_alarm_fail)

        template_graph.add_vertex(t_v_host_alarm)
        mappings = ga.sub_graph_matching(template_graph,
                                         Mapping(t_v_host_alarm,
                                                 host_alarm,
                                                 is_vertex=True))
        self.assertThat(
            mappings,
            matchers.HasLength(1),
            'Template - Single vertex (host alarm) '
            'Template_root is a specific host alarm ')

        template_graph.add_vertex(t_v_host)
        mappings = ga.sub_graph_matching(template_graph,
                                         Mapping(t_v_host_alarm,
                                                 host_alarm,
                                                 is_vertex=True))
        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - Two disconnected vertices (host alarm , host)'
            'Template_root is a specific host alarm ')

        template_graph.add_edge(e_alarm_on_host)
        mappings = ga.sub_graph_matching(template_graph,
                                         Mapping(t_v_host_alarm,
                                                 host_alarm,
                                                 is_vertex=True))
        self.assertThat(
            mappings,
            matchers.HasLength(1),
            'Template - Two connected vertices (host alarm -ON-> host)'
            ' template_root is a specific host alarm ')

        host = mappings[0][t_v_host.vertex_id]
        host_vertex = self.entity_graph.get_vertex(host.vertex_id)
        mappings = ga.sub_graph_matching(template_graph,
                                         Mapping(t_v_host,
                                                 host_vertex,
                                                 is_vertex=True))
        self.assertThat(
            mappings,
            matchers.HasLength(ENTITY_GRAPH_ALARMS_PER_HOST),
            'Template - Two connected vertices (host alarm -ON-> host)'
            ' template_root is a specific host ')

        template_graph.add_vertex(t_v_vm)
        mappings = ga.sub_graph_matching(template_graph,
                                         Mapping(t_v_host_alarm,
                                                 host_alarm,
                                                 is_vertex=True))
        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - Two connected vertices and a disconnected vertex'
            '(host alarm -ON-> host, instance)'
            ' template_root is a specific host alarm ')

        template_graph.add_vertex(t_v_vm_alarm)
        mappings = ga.sub_graph_matching(template_graph,
                                         Mapping(t_v_vm_alarm,
                                                 vm_alarm,
                                                 is_vertex=True))
        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - Two connected vertices and two disconnected vertices'
            '(host alarm -ON-> host, instance, instance alarm)'
            ' template_root is a specific instance alarm ')

        template_graph.add_edge(e_alarm_on_vm)
        mappings = ga.sub_graph_matching(template_graph,
                                         Mapping(t_v_vm_alarm,
                                                 vm_alarm,
                                                 is_vertex=True))
        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - Two connected vertices and two more connected vertices'
            '(host alarm -ON-> host, instance alarm -ON-> instance)'
            ' template_root is a specific instance alarm ')

        template_graph.add_edge(e_host_contains_vm)
        mappings = ga.sub_graph_matching(template_graph,
                                         Mapping(t_v_vm_alarm,
                                                 vm_alarm,
                                                 is_vertex=True))
        self.assertThat(
            mappings,
            matchers.HasLength(ENTITY_GRAPH_ALARMS_PER_HOST),
            'Template - Four connected vertices'
            '(host alarm -ON-> host -CONTAINS-> instance <-ON- instance alarm)'
            ' template_root is a specific instance alarm ')

        mappings = ga.sub_graph_matching(template_graph,
                                         Mapping(t_v_host_alarm,
                                                 host_alarm,
                                                 is_vertex=True))
        self.assertThat(
            mappings,
            matchers.HasLength(ENTITY_GRAPH_VMS_PER_HOST *
                               ENTITY_GRAPH_ALARMS_PER_VM),
            'Template - Four connected vertices'
            '(host alarm -ON-> host -CONTAINS-> instance <-ON- instance alarm)'
            ' template_root is a specific host alarm ')

        mappings = ga.sub_graph_matching(template_graph,
                                         Mapping(t_v_host,
                                                 host_vertex,
                                                 is_vertex=True))
        self.assertThat(
            mappings,
            matchers.HasLength(ENTITY_GRAPH_VMS_PER_HOST *
                               ENTITY_GRAPH_ALARMS_PER_VM *
                               ENTITY_GRAPH_ALARMS_PER_HOST),
            'Template - Four connected vertices'
            '(host alarm -ON-> host -CONTAINS-> instance <-ON- instance alarm)'
            ' template_root is a specific host ')

        template_graph.add_vertex(t_v_switch)
        mappings = ga.sub_graph_matching(template_graph,
                                         Mapping(t_v_vm_alarm,
                                                 vm_alarm,
                                                 is_vertex=True))
        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - Four connected vertices and a disconnected vertex'
            '(host alarm -ON-> host -CONTAINS-> instance <-ON- instance alarm'
            ',switch) template_root is an instance alarm ')

        template_graph.add_edge(e_host_uses_switch)
        mappings = ga.sub_graph_matching(template_graph,
                                         Mapping(t_v_vm_alarm,
                                                 vm_alarm,
                                                 is_vertex=True))
        self.assertThat(
            mappings,
            matchers.HasLength(ENTITY_GRAPH_ALARMS_PER_HOST),
            'Template - Five connected vertices'
            '(host alarm -ON-> host -CONTAINS-> instance <-ON- instance alarm'
            ',host -USES-> switch) template_root '
            'is a specific instance alarm ')

        mappings = ga.sub_graph_matching(template_graph,
                                         Mapping(t_v_host,
                                                 host_vertex,
                                                 is_vertex=True))
        self.assertThat(
            mappings,
            matchers.HasLength(ENTITY_GRAPH_VMS_PER_HOST *
                               ENTITY_GRAPH_ALARMS_PER_VM *
                               ENTITY_GRAPH_ALARMS_PER_HOST),
            'Template - Five connected vertices'
            '(host alarm -ON-> host -CONTAINS-> instance <-ON- instance alarm'
            ',host -USES-> switch) template_root is a specific host ')

        mappings = subgraph_matching(self.entity_graph, template_graph, [
            Mapping(t_v_switch, v_switch, is_vertex=True),
            Mapping(t_v_vm_alarm, vm_alarm, is_vertex=True)],
            validate=False)
        self.assertThat(
            mappings,
            matchers.HasLength(ENTITY_GRAPH_ALARMS_PER_HOST),
            'Template - Five connected vertices, two mappings given'
            '(host alarm -ON-> host -CONTAINS-> instance <-ON- instance alarm'
            ',host -USES-> switch) 7template_root is a specific host ')

        template_graph.add_vertex(t_v_node_not_in_graph)
        template_graph.add_edge(e_host_to_node_not_in_graph)
        mappings = ga.sub_graph_matching(template_graph,
                                         Mapping(t_v_vm_alarm,
                                                 vm_alarm,
                                                 is_vertex=True))
        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - Five connected vertices and an invalid edge'
            '(host alarm -ON-> host -CONTAINS-> instance <-ON- instance alarm'
            ',host -USES-> switch) template_root is an instance alarm ')
        template_graph.remove_vertex(t_v_node_not_in_graph)

        template_graph.remove_vertex(t_v_host_alarm)
        template_graph.add_vertex(t_v_node)
        template_graph.add_edge(e_node_contains_host)
        template_graph.add_edge(e_node_contains_switch)
        mappings = ga.sub_graph_matching(template_graph,
                                         Mapping(t_v_vm_alarm,
                                                 vm_alarm,
                                                 is_vertex=True))
        self.assertThat(
            mappings,
            matchers.HasLength(1),
            'Template - FIVE connected vertices'
            '(host -CONTAINS-> instance <-ON- instance alarm'
            ',node -CONTAINS-> host -USES-> switch, node-CONTAINS->switch)'
            ' template_root is an instance alarm ')

        mappings = subgraph_matching(self.entity_graph, template_graph, [
            Mapping(e_node_contains_switch, e_node_to_switch, is_vertex=False),
            Mapping(t_v_vm_alarm, vm_alarm, is_vertex=True)])
        self.assertThat(
            mappings,
            matchers.HasLength(1),
            'Template - FIVE connected vertices'
            '(host -CONTAINS-> instance <-ON- instance alarm'
            ',node -CONTAINS-> host -USES-> switch, node-CONTAINS->switch)'
            ' 3 Known Mappings[switch, node, vm alarm] ')

        template_graph.add_edge(e_node_contains_switch_fail)
        mappings = subgraph_matching(self.entity_graph, template_graph, [
            Mapping(t_v_node, v_node, is_vertex=True),
            Mapping(t_v_switch, v_switch, is_vertex=True)], validate=True)
        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - FIVE connected vertices - 2 Known Mapping[node,switch]'
            ' Check that ALL edges between the 2 known mappings are checked'
            ' we now have node-CONTAINS fail->switch AND node-CONTAINS->switch'
            ' ')

        mappings = ga.sub_graph_matching(template_graph,
                                         Mapping(e_node_contains_switch,
                                                 e_node_to_switch,
                                                 is_vertex=False),
                                         validate=True)
        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - FIVE connected vertices - 2 Known Mapping[node,switch]'
            ' Check that ALL edges between the 2 known mappings are checked'
            ' we now have node-CONTAINS fail->switch AND node-CONTAINS->switch'
            ' ')

        template_graph.remove_edge(e_node_contains_switch)
        mappings = subgraph_matching(self.entity_graph, template_graph, [
            Mapping(t_v_node, v_node, is_vertex=True),
            Mapping(t_v_switch, v_switch, is_vertex=True)])
        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - FIVE connected vertices - 2 Known Mapping[node,switch]'
            ' But the edge between these 2 is not same as the graph '
            '(host -CONTAINS-> instance <-ON- instance alarm'
            ',node -CONTAINS-> host -USES-> switch, node-CONTAINS '
            'fail->switch)'
            ' ')

        mappings = ga.sub_graph_matching(template_graph,
                                         Mapping(t_v_vm_alarm,
                                                 vm_alarm,
                                                 is_vertex=True))
        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - FIVE connected vertices'
            '(host -CONTAINS-> instance <-ON- instance alarm'
            ',node -CONTAINS-> host -USES-> switch, node-CONTAINS '
            'fail->switch)'
            ' template_root is an instance alarm')

    def test_template_matching_with_not_operator_of_complicated_subgraph(self):
        """Test the template matching algorithm with 'not' operator

        Using the entity graph (created above) as a big graph we search
        for a sub graph matches that has simple 'not' operator in the template
        """
        ga = self.entity_graph.algo

        # Get ids of some of the elements in the entity graph:
        host = self.entity_graph.get_vertex(
            NOVA_HOST_DATASOURCE + str(ENTITY_GRAPH_HOSTS_PER_CLUSTER - 1))

        # Create a template for template matching
        template_graph = NXGraph('template_graph')
        t_v_alarm_fail = graph_utils.create_vertex(
            vitrage_id='1', vitrage_category=ALARM, vitrage_type='fail')
        t_v_host = graph_utils.create_vertex(
            vitrage_id='2',
            vitrage_category=RESOURCE,
            vitrage_type=NOVA_HOST_DATASOURCE)
        t_v_vm = graph_utils.create_vertex(
            vitrage_id='3',
            vitrage_category=RESOURCE,
            vitrage_type=NOVA_INSTANCE_DATASOURCE)
        t_v_vm_alarm = graph_utils.create_vertex(
            vitrage_id='4', vitrage_category=ALARM, vitrage_type=ALARM_ON_VM)

        e_host_contains_vm = graph_utils.create_edge(
            t_v_host.vertex_id, t_v_vm.vertex_id, ELabel.CONTAINS)
        e_alarm_not_on_vm = graph_utils.create_edge(
            t_v_vm_alarm.vertex_id, t_v_vm.vertex_id, ELabel.ON)
        e_alarm_not_on_vm[NEG_CONDITION] = True
        e_alarm_not_on_vm[EProps.VITRAGE_IS_DELETED] = True
        e_alarm_not_on_host = graph_utils.create_edge(
            t_v_alarm_fail.vertex_id, t_v_host.vertex_id, ELabel.ON)
        e_alarm_not_on_host[NEG_CONDITION] = True
        e_alarm_not_on_host[EProps.VITRAGE_IS_DELETED] = True

        for v in [t_v_alarm_fail, t_v_host, t_v_vm, t_v_vm_alarm]:
            del(v[VProps.VITRAGE_ID])

        # add host vertex to subgraph
        template_graph.add_vertex(t_v_host)
        mappings = ga.sub_graph_matching(template_graph,
                                         Mapping(t_v_host, host, True),
                                         validate=True)
        self.assertThat(
            mappings,
            matchers.HasLength(1),
            'Template - Single vertex alarm not in graph '
            'Template_root is a specific host ' + str(mappings))

        # add vm vertex to subgraph
        template_graph.add_vertex(t_v_vm)
        template_graph.add_edge(e_host_contains_vm)
        mappings = ga.sub_graph_matching(template_graph,
                                         Mapping(t_v_host, host, True))
        self.assertThat(
            mappings, matchers.HasLength(ENTITY_GRAPH_VMS_PER_HOST),
            'Template - Two connected vertices (host -> vm)'
            ' template_root is a specific host ' + str(mappings))

        # add not alarm to subgraph
        template_graph.add_vertex(t_v_vm_alarm)
        template_graph.add_edge(e_alarm_not_on_vm)
        mappings = ga.sub_graph_matching(template_graph,
                                         Mapping(t_v_host, host, True))
        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - Three connected vertices (host -> vm <- NOT alarm)'
            ' template_root is a specific host ' + str(mappings))

        # create temporary entity graph
        temp_entity_graph = self.entity_graph.copy()
        temp_ga = temp_entity_graph.algo
        vms = temp_entity_graph.neighbors(
            host.vertex_id,
            vertex_attr_filter={
                VProps.VITRAGE_CATEGORY: EntityCategory.RESOURCE,
                VProps.VITRAGE_TYPE: NOVA_INSTANCE_DATASOURCE})

        ###################################################################
        # Use case 1: remove alarms of specific vm
        ###################################################################
        alarms = temp_entity_graph.neighbors(
            vms[0].vertex_id,
            vertex_attr_filter={VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
                                VProps.VITRAGE_TYPE: ALARM_ON_VM})
        for alarm in alarms:
            temp_entity_graph.remove_vertex(alarm)

        mappings = temp_ga.sub_graph_matching(template_graph,
                                              Mapping(t_v_host, host, True))
        self.assertThat(
            mappings,
            matchers.HasLength(1),
            'Template - Three connected vertices (host -> vm <- NOT alarm)'
            'Template_root is a specific host ' + str(mappings))

        # add another not alarm to subgraph
        template_graph.add_vertex(t_v_alarm_fail)
        template_graph.add_edge(e_alarm_not_on_host)
        mappings = temp_ga.sub_graph_matching(template_graph,
                                              Mapping(t_v_host, host, True))
        self.assertThat(
            mappings,
            matchers.HasLength(1),
            'Template - Four connected vertices '
            '(NOT alarm -> host -> vm <- NOT alarm)'
            ' template_root is a specific host alarm ' + str(mappings))

        ###################################################################
        # Use case 2: mark alarms and their edges as deleted
        ###################################################################
        vms = temp_entity_graph.neighbors(
            host.vertex_id,
            vertex_attr_filter={
                VProps.VITRAGE_CATEGORY: EntityCategory.RESOURCE,
                VProps.VITRAGE_TYPE: NOVA_INSTANCE_DATASOURCE})
        alarms = temp_entity_graph.neighbors(
            vms[1].vertex_id,
            vertex_attr_filter={VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
                                VProps.VITRAGE_TYPE: ALARM_ON_VM})
        for alarm in alarms:
            alarm[VProps.VITRAGE_IS_DELETED] = True
            temp_entity_graph.update_vertex(alarm)
            edges = temp_entity_graph.get_edges(alarm.vertex_id)
            for edge in edges:
                edge[EProps.VITRAGE_IS_DELETED] = True
                temp_entity_graph.update_edge(edge)

        mappings = temp_ga.sub_graph_matching(template_graph,
                                              Mapping(t_v_host, host, True))
        self.assertThat(
            mappings,
            matchers.HasLength(2),
            'Template - Three connected vertices (host -> vm <- NOT alarm)'
            'Template_root is a specific host ' + str(mappings))

        ###################################################################
        # Use case 3: mark alarm edges as deleted with event on the host
        ###################################################################
        alarms = temp_entity_graph.neighbors(
            vms[2].vertex_id,
            vertex_attr_filter={VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
                                VProps.VITRAGE_TYPE: ALARM_ON_VM})
        for alarm in alarms:
            edges = temp_entity_graph.get_edges(alarm.vertex_id)
            for edge in edges:
                edge[EProps.VITRAGE_IS_DELETED] = True
                temp_entity_graph.update_edge(edge)

        mappings = temp_ga.sub_graph_matching(template_graph,
                                              Mapping(t_v_host, host, True))
        self.assertThat(
            mappings,
            matchers.HasLength(3),
            'Template - Three connected vertices (host -> vm <- NOT alarm)'
            'Template_root is a specific host ' + str(mappings))

        ###################################################################
        # Use case 4: event arrived on deleted alarm vertex on vm, that
        #             has other alarms on it
        ###################################################################
        alarms = temp_entity_graph.neighbors(
            vms[3].vertex_id,
            vertex_attr_filter={VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
                                VProps.VITRAGE_TYPE: ALARM_ON_VM})
        deleted_vertex = alarms[0]
        deleted_vertex[VProps.VITRAGE_IS_DELETED] = True
        temp_entity_graph.update_vertex(deleted_vertex)
        mappings = temp_ga.sub_graph_matching(template_graph,
                                              Mapping(t_v_vm_alarm,
                                                      deleted_vertex,
                                                      True))
        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - Four connected vertices '
            '(NOT alarm -> host -> vm <- NOT alarm)'
            ' template_root is a specific host ' + str(mappings))

        ###################################################################
        # Use case 5: event arrived on deleted alarm edge on vm, that has
        #             other alarms on it
        ###################################################################
        alarms = temp_entity_graph.neighbors(
            vms[4].vertex_id,
            vertex_attr_filter={VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
                                VProps.VITRAGE_TYPE: ALARM_ON_VM})
        edges = list(temp_entity_graph.get_edges(alarms[0].vertex_id))
        deleted_edge = edges[0]
        deleted_edge[EProps.VITRAGE_IS_DELETED] = True
        temp_entity_graph.update_edge(deleted_edge)
        mappings = temp_ga.sub_graph_matching(template_graph,
                                              Mapping(e_alarm_not_on_vm,
                                                      deleted_edge,
                                                      False))
        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - Four connected vertices '
            '(NOT alarm -> host -> vm <- NOT alarm)'
            ' template_root is a specific host ' + str(mappings))

        ###################################################################
        # Use case 6: event arrived on deleted alarm edge on vm, that has
        #             other vitrage_is_deleted alarms on it
        ###################################################################
        alarms = temp_entity_graph.neighbors(
            vms[5].vertex_id,
            vertex_attr_filter={VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
                                VProps.VITRAGE_TYPE: ALARM_ON_VM})
        for alarm in alarms:
            edges = temp_entity_graph.get_edges(alarm.vertex_id)
            for edge in edges:
                edge[EProps.VITRAGE_IS_DELETED] = True
                temp_entity_graph.update_edge(edge)
        deleted_edge = \
            list(temp_entity_graph.get_edges(alarms[0].vertex_id))[0]
        mappings = temp_ga.sub_graph_matching(template_graph,
                                              Mapping(e_alarm_not_on_vm,
                                                      deleted_edge,
                                                      False))
        self.assertThat(
            mappings,
            matchers.HasLength(1),
            'Template - Four connected vertices '
            '(NOT alarm -> host -> vm <- NOT alarm)'
            ' template_root is a specific host ' + str(mappings))

    def test_template_matching_with_not_operator_of_simple_subgraph(self):
        """Test the template matching algorithm with 'not' operator

        Using the entity graph (created above) as a big graph we search
        for a sub graph matches that has simple 'not' operator in the template
        """
        # Get ids of some of the elements in the entity graph:
        graph_host = self.entity_graph.get_vertex(
            NOVA_HOST_DATASOURCE + str(ENTITY_GRAPH_HOSTS_PER_CLUSTER - 1))

        # Create a template for template matching
        template_graph = NXGraph('template_graph')
        t_v_vm = graph_utils.create_vertex(
            vitrage_id='1',
            vitrage_category=RESOURCE,
            vitrage_type=NOVA_INSTANCE_DATASOURCE)
        t_v_vm_alarm = graph_utils.create_vertex(
            vitrage_id='2', vitrage_category=ALARM, vitrage_type=ALARM_ON_VM)

        e_alarm_not_on_vm = graph_utils.create_edge(
            t_v_vm_alarm.vertex_id, t_v_vm.vertex_id, ELabel.ON)
        e_alarm_not_on_vm[NEG_CONDITION] = True
        e_alarm_not_on_vm[EProps.VITRAGE_IS_DELETED] = True

        for v in [t_v_vm, t_v_vm_alarm]:
            del(v[VProps.VITRAGE_ID])

        # add instance vertex to subgraph
        template_graph.add_vertex(t_v_vm)

        # add not alarm on vm vertex to subgraph
        template_graph.add_vertex(t_v_vm_alarm)
        template_graph.add_edge(e_alarm_not_on_vm)

        # create copy of the entity graph
        temp_entity_graph = self.entity_graph.copy()
        temp_ga = temp_entity_graph.algo
        vms = temp_entity_graph.neighbors(
            graph_host.vertex_id,
            vertex_attr_filter={
                VProps.VITRAGE_CATEGORY: EntityCategory.RESOURCE,
                VProps.VITRAGE_TYPE: NOVA_INSTANCE_DATASOURCE})

        ###################################################################
        # Use case 1: find subgraphs (when edges are deleted) with event on
        #             the edge
        ###################################################################
        alarms = temp_entity_graph.neighbors(
            vms[0].vertex_id,
            vertex_attr_filter={VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
                                VProps.VITRAGE_TYPE: ALARM_ON_VM})
        for alarm in alarms:
            edges = temp_entity_graph.get_edges(alarm.vertex_id)
            for edge in edges:
                edge[EProps.VITRAGE_IS_DELETED] = True
                temp_entity_graph.update_edge(edge)

        graph_alarm_edge = \
            list(temp_entity_graph.get_edges(alarms[0].vertex_id))[0]

        mappings = temp_ga.sub_graph_matching(
            template_graph,
            Mapping(e_alarm_not_on_vm, graph_alarm_edge, False))
        self.assertThat(
            mappings,
            matchers.HasLength(1),
            'Template - Two not connected vertices (vm <- alarm)')

        # find subgraphs (when edges are deleted) with event on the alarm
        mappings = temp_ga.sub_graph_matching(
            template_graph,
            Mapping(t_v_vm_alarm, alarms[0], True))
        self.assertThat(
            mappings,
            matchers.HasLength(1),
            'Template - Two not connected vertices (vm <- alarm)')

        ###################################################################
        # Use case 2: find subgraphs (when vertices are deleted) with event
        #             on the edge
        ###################################################################
        alarms = temp_entity_graph.neighbors(
            vms[1].vertex_id,
            vertex_attr_filter={VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
                                VProps.VITRAGE_TYPE: ALARM_ON_VM})
        for alarm in alarms:
            alarm[VProps.VITRAGE_IS_DELETED] = True
            temp_entity_graph.update_vertex(alarm)

        graph_alarm_edge = \
            list(temp_entity_graph.get_edges(alarms[0].vertex_id))[0]

        mappings = temp_ga.sub_graph_matching(
            template_graph,
            Mapping(e_alarm_not_on_vm, graph_alarm_edge, False))
        self.assertThat(
            mappings,
            matchers.HasLength(1),
            'Template - Two not connected vertices (vm <- alarm)')

        # find subgraphs (when vertices are deleted) with event on the alarm
        mappings = temp_ga.sub_graph_matching(
            template_graph,
            Mapping(t_v_vm_alarm, alarms[0], True))
        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - Two not connected vertices (vm <- alarm)')

        ###################################################################
        # Use case 3: find subgraphs (when vertices and edges are deleted)
        #             with event on the edge
        ###################################################################
        alarms = temp_entity_graph.neighbors(
            vms[2].vertex_id,
            vertex_attr_filter={VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
                                VProps.VITRAGE_TYPE: ALARM_ON_VM})
        for alarm in alarms:
            alarm[VProps.VITRAGE_IS_DELETED] = True
            temp_entity_graph.update_vertex(alarm)
            edges = temp_entity_graph.get_edges(alarm.vertex_id)
            for edge in edges:
                edge[EProps.VITRAGE_IS_DELETED] = True
                temp_entity_graph.update_edge(edge)

        graph_alarm_edge = \
            list(temp_entity_graph.get_edges(alarms[0].vertex_id))[0]

        mappings = temp_ga.sub_graph_matching(
            template_graph,
            Mapping(e_alarm_not_on_vm, graph_alarm_edge, False))

        self.assertThat(
            mappings,
            matchers.HasLength(1),
            'Template - Two not connected vertices (vm <- alarm)')

        # find subgraphs (when vertices and edges are deleted) with event
        # on the alarm
        mappings = temp_ga.sub_graph_matching(
            template_graph,
            Mapping(t_v_vm_alarm, alarms[0], True))

        self.assertThat(
            mappings,
            matchers.HasLength(1),
            'Template - Two not connected vertices (vm <- alarm)')

        ###################################################################
        # Use case 4: find subgraphs (when one alarm of many is deleted)
        #             with event on the edge
        ###################################################################
        alarms = temp_entity_graph.neighbors(
            vms[3].vertex_id,
            vertex_attr_filter={VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
                                VProps.VITRAGE_TYPE: ALARM_ON_VM})
        graph_alarm = alarms[0]
        graph_alarm[VProps.VITRAGE_IS_DELETED] = True

        graph_alarm_edge = \
            list(temp_entity_graph.get_edges(alarms[0].vertex_id))[0]

        mappings = temp_ga.sub_graph_matching(
            template_graph,
            Mapping(e_alarm_not_on_vm, graph_alarm_edge, False))
        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - Two not connected vertices (vm <- alarm)')

        # find subgraphs (when one alarm of many is deleted) with event
        # on the alarm
        mappings = temp_ga.sub_graph_matching(
            template_graph,
            Mapping(t_v_vm_alarm, alarms[0], True))
        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - Two not connected vertices (vm <- alarm)')

        ###################################################################
        # Use case 5: find subgraphs (when one edge of alarm of many is
        #             deleted) with event on the edge
        ###################################################################
        alarms = temp_entity_graph.neighbors(
            vms[4].vertex_id,
            vertex_attr_filter={VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
                                VProps.VITRAGE_TYPE: ALARM_ON_VM})

        graph_alarm_edge = \
            list(temp_entity_graph.get_edges(alarms[0].vertex_id))[0]
        graph_alarm_edge[EProps.VITRAGE_IS_DELETED] = True
        temp_entity_graph.update_edge(graph_alarm_edge)

        mappings = temp_ga.sub_graph_matching(
            template_graph,
            Mapping(e_alarm_not_on_vm, graph_alarm_edge, False))

        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - Two not connected vertices (vm <- alarm)')

        ###################################################################
        # Use case 6: find subgraphs (when one alarm its edge are deleted
        #             from many alarms) with event on the edge
        ###################################################################
        alarms = temp_entity_graph.neighbors(
            vms[5].vertex_id,
            vertex_attr_filter={VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
                                VProps.VITRAGE_TYPE: ALARM_ON_VM})

        alarms[0][VProps.VITRAGE_IS_DELETED] = True
        temp_entity_graph.update_vertex(alarms[0])
        graph_alarm_edge = \
            list(temp_entity_graph.get_edges(alarms[0].vertex_id))[0]
        graph_alarm_edge[EProps.VITRAGE_IS_DELETED] = True
        temp_entity_graph.update_edge(graph_alarm_edge)

        mappings = temp_ga.sub_graph_matching(
            template_graph,
            Mapping(e_alarm_not_on_vm, graph_alarm_edge, False))

        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - Two not connected vertices (vm <- alarm)')

    def test_template_matching_with_not_operator_of_problematic_subgraph(self):
        """Test the template matching algorithm with 'not' operator

        Checking the following use case:
        network -> vm <--- alarm -> stack -> network
        """

        # Get ids of some of the elements in the entity graph:
        graph_host = self.entity_graph.get_vertex(
            NOVA_HOST_DATASOURCE + str(ENTITY_GRAPH_HOSTS_PER_CLUSTER - 1))

        # Create a template for template matching
        template_graph = NXGraph('template_graph')
        t_v_network = graph_utils.create_vertex(
            vitrage_id='1',
            vitrage_category=RESOURCE,
            vitrage_type=NEUTRON_NETWORK_DATASOURCE)
        t_v_vm = graph_utils.create_vertex(
            vitrage_id='2',
            vitrage_category=RESOURCE,
            vitrage_type=NOVA_INSTANCE_DATASOURCE)
        t_v_alarm = graph_utils.create_vertex(
            vitrage_id='3', vitrage_category=ALARM, vitrage_type=ALARM_ON_VM)
        t_v_stack = graph_utils.create_vertex(
            vitrage_id='4',
            vitrage_category=RESOURCE,
            vitrage_type=HEAT_STACK_DATASOURCE)

        e_network_connect_vm = graph_utils.create_edge(
            t_v_network.vertex_id, t_v_vm.vertex_id, ELabel.CONNECT)
        e_alarm_not_on_vm = graph_utils.create_edge(
            t_v_alarm.vertex_id, t_v_vm.vertex_id, ELabel.ON)
        e_alarm_not_on_vm[NEG_CONDITION] = True
        e_alarm_not_on_vm[EProps.VITRAGE_IS_DELETED] = True
        e_alarm_on_stack = graph_utils.create_edge(
            t_v_alarm.vertex_id, t_v_stack.vertex_id, ELabel.ON)
        e_stack_connect_network = graph_utils.create_edge(
            t_v_network.vertex_id, t_v_stack.vertex_id, ELabel.CONNECT)

        for v in [t_v_vm, t_v_alarm, t_v_network, t_v_stack]:
            del(v[VProps.VITRAGE_ID])

        # add network vertex to subgraph
        template_graph.add_vertex(t_v_network)

        # add vm vertex and connect it to host
        template_graph.add_vertex(t_v_vm)
        template_graph.add_edge(e_network_connect_vm)

        # add not alarm and connect it to vm
        template_graph.add_vertex(t_v_alarm)
        template_graph.add_edge(e_alarm_not_on_vm)

        # add stack vertex and connect it to alarm
        template_graph.add_vertex(t_v_stack)
        template_graph.add_edge(e_alarm_on_stack)

        # connect stack to network
        template_graph.add_edge(e_stack_connect_network)

        # create copy of the entity graph
        temp_entity_graph = self.entity_graph.copy()
        temp_ga = temp_entity_graph.algo
        vms = temp_entity_graph.neighbors(
            graph_host.vertex_id,
            vertex_attr_filter={
                VProps.VITRAGE_CATEGORY: EntityCategory.RESOURCE,
                VProps.VITRAGE_TYPE: NOVA_INSTANCE_DATASOURCE})

        ###################################################################
        # Use case 1: alarm connected to vm
        ###################################################################
        alarms = temp_entity_graph.neighbors(
            vms[0].vertex_id,
            vertex_attr_filter={VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
                                VProps.VITRAGE_TYPE: ALARM_ON_VM})

        # Action
        for alarm in alarms[1:len(alarms)]:
            alarm[VProps.VITRAGE_IS_DELETED] = True
            temp_entity_graph.update_vertex(alarm)
            edges = temp_entity_graph.get_edges(alarm.vertex_id)
            for edge in edges:
                edge[EProps.VITRAGE_IS_DELETED] = True
                temp_entity_graph.update_edge(edge)

        # build problematic subgraph in entity graph
        specific_alarm = alarms[0]
        self._build_problematic_subgraph_in_entity_graph(specific_alarm,
                                                         vms[0],
                                                         temp_entity_graph,
                                                         0)

        # trigger on edge between vm and alarm
        graph_alarm_edges = \
            temp_entity_graph.get_edges(specific_alarm.vertex_id)
        for edge in graph_alarm_edges:
            if 'instance' in edge.target_id:
                graph_alarm_edge = edge

        mappings = temp_ga.sub_graph_matching(
            template_graph,
            Mapping(e_alarm_not_on_vm, graph_alarm_edge, False))
        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - Two not connected vertices (vm <- alarm)')

        # trigger on alarm
        mappings = temp_ga.sub_graph_matching(
            template_graph,
            Mapping(t_v_alarm, specific_alarm, True))
        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - Two not connected vertices (vm <- alarm)')

        ###################################################################
        # Use case 2: alarm not connected to vm (with edge
        #             vitrage_is_deleted=True)
        ###################################################################
        alarms = temp_entity_graph.neighbors(
            vms[1].vertex_id,
            vertex_attr_filter={VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
                                VProps.VITRAGE_TYPE: ALARM_ON_VM})

        # Action
        for alarm in alarms:
            edges = temp_entity_graph.get_edges(alarm.vertex_id)
            for edge in edges:
                edge[EProps.VITRAGE_IS_DELETED] = True
                temp_entity_graph.update_edge(edge)

        # build problematic subgraph in entity graph
        specific_alarm = alarms[0]
        self._build_problematic_subgraph_in_entity_graph(specific_alarm,
                                                         vms[1],
                                                         temp_entity_graph,
                                                         1)

        # trigger on edge between vm and alarm
        graph_alarm_edges = \
            temp_entity_graph.get_edges(specific_alarm.vertex_id)
        for edge in graph_alarm_edges:
            if 'instance' in edge.target_id:
                graph_alarm_edge = edge

        mappings = temp_ga.sub_graph_matching(
            template_graph,
            Mapping(e_alarm_not_on_vm, graph_alarm_edge, False))
        self.assertThat(
            mappings,
            matchers.HasLength(1),
            'Template - Two not connected vertices (vm <- alarm)')

        # trigger on alarm
        mappings = temp_ga.sub_graph_matching(
            template_graph,
            Mapping(t_v_alarm, specific_alarm, True))
        self.assertThat(
            mappings,
            matchers.HasLength(1),
            'Template - Two not connected vertices (vm <- alarm)')

        ###################################################################
        # Use case 3: alarm not connected to vm (without any edge)
        ###################################################################
        alarms = temp_entity_graph.neighbors(
            vms[2].vertex_id,
            vertex_attr_filter={VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
                                VProps.VITRAGE_TYPE: ALARM_ON_VM})

        # Action
        for alarm in alarms:
            edges = temp_entity_graph.get_edges(alarm.vertex_id)
            for edge in edges:
                temp_entity_graph.remove_edge(edge)

        # build problematic subgraph in entity graph
        specific_alarm = alarms[0]
        self._build_problematic_subgraph_in_entity_graph(specific_alarm,
                                                         vms[2],
                                                         temp_entity_graph,
                                                         2)

        # trigger on edge between vm and alarm
        graph_alarm_edges = \
            temp_entity_graph.get_edges(specific_alarm.vertex_id)
        for edge in graph_alarm_edges:
            if 'instance' in edge.target_id:
                graph_alarm_edge = edge

        mappings = temp_ga.sub_graph_matching(
            template_graph,
            Mapping(e_alarm_not_on_vm, graph_alarm_edge, False))
        self.assertThat(
            mappings,
            matchers.HasLength(1),
            'Template - Two not connected vertices (vm <- alarm)')

        # trigger on alarm
        mappings = temp_ga.sub_graph_matching(
            template_graph,
            Mapping(t_v_alarm, specific_alarm, True))
        self.assertThat(
            mappings,
            matchers.HasLength(1),
            'Template - Two not connected vertices (vm <- alarm)')

        ###################################################################
        # Use case 4: alarm not connected to vm (with edge
        #             vitrage_is_deleted=True) and other connected alarms exist
        ###################################################################
        alarms = temp_entity_graph.neighbors(
            vms[3].vertex_id,
            vertex_attr_filter={VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
                                VProps.VITRAGE_TYPE: ALARM_ON_VM})

        # Action
        edges = [e for e in temp_entity_graph.get_edges(alarms[0].vertex_id)]
        edges[0][EProps.VITRAGE_IS_DELETED] = True
        temp_entity_graph.update_edge(edge)

        # build problematic subgraph in entity graph
        for alarm in alarms:
            self._build_problematic_subgraph_in_entity_graph(alarm,
                                                             vms[3],
                                                             temp_entity_graph,
                                                             3)

        # trigger on edge (that was deleted) between vm and alarm
        specific_alarm = alarms[0]
        graph_alarm_edges = \
            temp_entity_graph.get_edges(specific_alarm.vertex_id)
        for edge in graph_alarm_edges:
            if 'instance' in edge.target_id:
                graph_alarm_edge = edge

        mappings = temp_ga.sub_graph_matching(
            template_graph,
            Mapping(e_alarm_not_on_vm, graph_alarm_edge, False))
        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - Two not connected vertices (vm <- alarm)')

        # trigger on edge (that wasn't deleted) between vm and alarm
        specific_alarm = alarms[1]
        graph_alarm_edges = \
            temp_entity_graph.get_edges(specific_alarm.vertex_id)
        for edge in graph_alarm_edges:
            if 'instance' in edge.target_id:
                graph_alarm_edge = edge

        mappings = temp_ga.sub_graph_matching(
            template_graph,
            Mapping(e_alarm_not_on_vm, graph_alarm_edge, False))
        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - Two not connected vertices (vm <- alarm)')

        # trigger on alarm
        mappings = temp_ga.sub_graph_matching(
            template_graph,
            Mapping(t_v_alarm, specific_alarm, True))
        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - Two not connected vertices (vm <- alarm)')

        # trigger on instance
        mappings = temp_ga.sub_graph_matching(
            template_graph,
            Mapping(t_v_vm, vms[3], True))
        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - Two not connected vertices (vm <- alarm)')

        ###################################################################
        # Use case 5: alarm not connected to vm (without any edge) and
        #             other connected alarms exist
        ###################################################################
        alarms = temp_entity_graph.neighbors(
            vms[4].vertex_id,
            vertex_attr_filter={VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
                                VProps.VITRAGE_TYPE: ALARM_ON_VM})

        # Action
        edges = [e for e in temp_entity_graph.get_edges(alarms[0].vertex_id)]
        temp_entity_graph.remove_edge(edges[0])

        # build problematic subgraph in entity graph
        for alarm in alarms:
            self._build_problematic_subgraph_in_entity_graph(alarm,
                                                             vms[4],
                                                             temp_entity_graph,
                                                             4)

        # trigger on edge (that was deleted) between vm and alarm
        specific_alarm = alarms[0]
        graph_alarm_edges = \
            temp_entity_graph.get_edges(specific_alarm.vertex_id)
        for edge in graph_alarm_edges:
            if 'instance' in edge.target_id:
                graph_alarm_edge = edge

        mappings = temp_ga.sub_graph_matching(
            template_graph,
            Mapping(e_alarm_not_on_vm, graph_alarm_edge, False))
        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - Two not connected vertices (vm <- alarm)')

        # trigger on edge (that wasn't deleted) between vm and alarm
        specific_alarm = alarms[1]
        graph_alarm_edges = \
            temp_entity_graph.get_edges(specific_alarm.vertex_id)
        for edge in graph_alarm_edges:
            if 'instance' in edge.target_id:
                graph_alarm_edge = edge

        mappings = temp_ga.sub_graph_matching(
            template_graph,
            Mapping(e_alarm_not_on_vm, graph_alarm_edge, False))
        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - Two not connected vertices (vm <- alarm)')

        # trigger on alarm
        mappings = temp_ga.sub_graph_matching(
            template_graph,
            Mapping(t_v_alarm, specific_alarm, True))
        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - Two not connected vertices (vm <- alarm)')

        # trigger on instance
        mappings = temp_ga.sub_graph_matching(
            template_graph,
            Mapping(t_v_vm, vms[4], True))
        self.assertThat(
            mappings,
            IsEmpty(),
            'Template - Two not connected vertices (vm <- alarm)')

    @staticmethod
    def _build_problematic_subgraph_in_entity_graph(alarm,
                                                    vm,
                                                    temp_entity_graph,
                                                    num):
        stack_vertex = graph_utils.create_vertex(
            vitrage_id='stack' + str(num),
            vitrage_category=RESOURCE,
            vitrage_type=HEAT_STACK_DATASOURCE)
        temp_entity_graph.update_vertex(stack_vertex)

        alarm_stack_edge = graph_utils.create_edge(
            alarm.vertex_id, stack_vertex.vertex_id, ELabel.ON)
        temp_entity_graph.update_edge(alarm_stack_edge)

        network_vertex = graph_utils.create_vertex(
            vitrage_id='network' + str(num),
            vitrage_category=RESOURCE,
            vitrage_type=NEUTRON_NETWORK_DATASOURCE)
        temp_entity_graph.update_vertex(network_vertex)

        network_stack_edge = graph_utils.create_edge(
            network_vertex.vertex_id, stack_vertex.vertex_id, ELabel.CONNECT)
        temp_entity_graph.update_edge(network_stack_edge)

        network_vm_edge = graph_utils.create_edge(
            network_vertex.vertex_id, vm.vertex_id, ELabel.CONNECT)
        temp_entity_graph.update_edge(network_vm_edge)
