Skip to content

Commit

Permalink
Merge pull request #11 from kytos-ng/fix/issue_10
Browse files Browse the repository at this point in the history
[Fix] graph node `status` wasn't being considered when adding nodes
  • Loading branch information
viniarck committed Jan 27, 2022
2 parents 12cd8c1 + 9e6630b commit fd29a59
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 23 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ Fixed
Security
========

[2022.1.0] - 2022-01-25
***********************

Changed
=======
- Adapted ``update_nodes`` to only add if node.status is ``EntityStatus.UP``
- Adapted ``update_links`` to only add if link.status is ``EntityStatus.UP``


[2.4.1] - 2022-01-21
********************
Expand Down
10 changes: 7 additions & 3 deletions graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from itertools import combinations, islice

from kytos.core import log
from kytos.core.common import EntityStatus
from napps.kytos.pathfinder.utils import (filter_ge, filter_in, filter_le,
lazy_filter, nx_edge_data_delay,
nx_edge_data_priority,
Expand Down Expand Up @@ -50,11 +51,14 @@ def update_nodes(self, nodes):
"""Update all nodes inside the graph."""
for node in nodes.values():
try:
if node.status != EntityStatus.UP:
continue
self.graph.add_node(node.id)

for interface in node.interfaces.values():
self.graph.add_node(interface.id)
self.graph.add_edge(node.id, interface.id)
if interface.status == EntityStatus.UP:
self.graph.add_node(interface.id)
self.graph.add_edge(node.id, interface.id)

except AttributeError as err:
raise TypeError(
Expand All @@ -64,7 +68,7 @@ def update_nodes(self, nodes):
def update_links(self, links):
"""Update all links inside the graph."""
for link in links.values():
if link.is_active():
if link.status == EntityStatus.UP:
self.graph.add_edge(link.endpoint_a.id, link.endpoint_b.id)
self.update_link_metadata(link)

Expand Down
2 changes: 1 addition & 1 deletion kytos.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"username": "kytos",
"name": "pathfinder",
"description": "Keeps track of topology changes, and calculates the best path between two points.",
"version": "2.4.1",
"version": "2022.1.0",
"napp_dependencies": ["kytos/topology"],
"license": "MIT",
"tags": ["pathfinder", "rest", "work-in-progress"],
Expand Down
4 changes: 4 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,10 @@ def shortest_path(self):
return jsonify({"paths": paths})

@listen_to("kytos.topology.updated")
def on_topology_updated(self, event):
"""Update the graph when the network topology is updated."""
self.update_topology(event)

def update_topology(self, event):
"""Update the graph when the network topology is updated."""
if "topology" not in event.content:
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
BASE_ENV = Path(os.environ.get('VIRTUAL_ENV', '/'))

NAPP_NAME = 'pathfinder'
NAPP_VERSION = '2.4.1'
NAPP_VERSION = '2022.1.0'

# Kytos var folder
VAR_PATH = BASE_ENV / 'var' / 'lib' / 'kytos'
Expand Down
13 changes: 13 additions & 0 deletions tests/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,34 @@
from kytos.core.interface import Interface
from kytos.core.link import Link
from kytos.core.switch import Switch
from kytos.core.common import EntityStatus
from kytos.lib.helpers import (get_interface_mock, get_link_mock,
get_switch_mock)


def get_topology_mock():
"""Create a default topology."""
switch_a = get_switch_mock("00:00:00:00:00:00:00:01", 0x04)
switch_a.status = EntityStatus.UP
switch_b = get_switch_mock("00:00:00:00:00:00:00:02", 0x04)
switch_b.status = EntityStatus.UP
switch_c = get_switch_mock("00:00:00:00:00:00:00:03", 0x01)
switch_c.status = EntityStatus.UP

interface_a1 = get_interface_mock("s1-eth1", 1, switch_a)
interface_a1.status = EntityStatus.UP
interface_a2 = get_interface_mock("s1-eth2", 2, switch_a)
interface_a2.status = EntityStatus.UP

interface_b1 = get_interface_mock("s2-eth1", 1, switch_b)
interface_b1.status = EntityStatus.UP
interface_b2 = get_interface_mock("s2-eth2", 2, switch_b)
interface_b2.status = EntityStatus.UP

interface_c1 = get_interface_mock("s3-eth1", 1, switch_c)
interface_c1.status = EntityStatus.UP
interface_c2 = get_interface_mock("s3-eth2", 2, switch_c)
interface_c2.status = EntityStatus.UP

switch_a.interfaces = {
interface_a1.id: interface_a1,
Expand All @@ -39,8 +49,11 @@ def get_topology_mock():
}

link_1 = get_link_mock(interface_a1, interface_b1)
link_1.status = EntityStatus.UP
link_2 = get_link_mock(interface_a2, interface_c1)
link_2.status = EntityStatus.UP
link_3 = get_link_mock(interface_b2, interface_c2)
link_3.status = EntityStatus.UP

topology = MagicMock()
topology.links = {"1": link_1, "2": link_2, "3": link_3}
Expand Down
4 changes: 4 additions & 0 deletions tests/integration/edges_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,3 +271,7 @@ def _fill_links(links, interfaces):
links["User1:4<->User4:3"] = Link(
interfaces["User1:4"], interfaces["User4:3"]
)

for link in links.values():
link.enable()
link.activate()
11 changes: 9 additions & 2 deletions tests/integration/test_paths.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,18 @@ def generate_topology():
@staticmethod
def create_switch(name, switches):
"""Add a new switch to the list of switches"""
switches[name] = Switch(name)
switch = Switch(name)
switch.is_active = lambda: True
switches[name] = switch

@staticmethod
def add_interfaces(count, switch, interfaces):
"""Add a new interface to the list of interfaces"""
for i in range(1, count + 1):
str1 = f"{switch.dpid}:{i}"
interface = Interface(str1, i, switch)
interface.enable()
interface.activate()
interfaces[str1] = interface
switch.update_interface(interface)

Expand All @@ -52,9 +56,12 @@ def create_link(interface_a, interface_b, interfaces, links):
"""Add a new link between two interfaces into the list of links"""
compounded = f"{interface_a}|{interface_b}"
final_name = compounded
links[final_name] = Link(
link = Link(
interfaces[interface_a], interfaces[interface_b]
)
link.enable()
link.activate()
links[final_name] = link

@staticmethod
def add_metadata_to_link(interface_a, interface_b, metrics, links):
Expand Down
4 changes: 4 additions & 0 deletions tests/integration/test_paths_simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,8 @@ def generate_topology():
{"bandwidth": 49, "ownership": "blue"}
)

for link in links.values():
link.enable()
link.activate()

return switches, links
53 changes: 37 additions & 16 deletions tests/unit/test_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
from unittest import TestCase
from unittest.mock import MagicMock, call, patch

from kytos.core.common import EntityStatus
from napps.kytos.pathfinder.graph import KytosGraph

# pylint: disable=import-error
from tests.helpers import (
get_filter_links_fake,
Expand Down Expand Up @@ -53,24 +55,45 @@ def test_update_topology_links(self, *args):
_, mock_update_links, topology = self.setting_update_topology(*args)
mock_update_links.assert_called_with(topology.links)

def test_update_links(self):
"""Test update_links."""
topology = get_topology_mock()
self.kytos_graph.update_links(topology.links)
assert self.mock_graph.add_edge.call_count == len(topology.links)

def test_update_links_not_up(self):
"""Test update_links entity not up."""
topology = get_topology_mock()
keys_num = 2
for key in list(topology.links.keys())[:keys_num]:
topology.links[key].status = EntityStatus.DOWN

self.kytos_graph.update_links(topology.links)
assert self.mock_graph.add_edge.call_count == len(topology.links) - keys_num

def test_update_nodes_not_up(self):
"""Test update_nodes entity not up."""
topology = get_topology_mock()
keys_num = 2
for key in list(topology.switches.keys())[:keys_num]:
topology.switches[key].status = EntityStatus.DISABLED
for key in topology.switches.keys():
topology.switches[key].interfaces = {}

self.kytos_graph.update_nodes(topology.switches)
assert self.mock_graph.add_node.call_count == len(topology.switches) - keys_num

def test_update_nodes(self):
"""Test update nodes."""
topology = get_topology_mock()
self.kytos_graph.update_nodes(topology.switches)
switch = topology.switches["00:00:00:00:00:00:00:01"]

calls = [call(switch.id)]
calls += [
call(interface.id) for interface in switch.interfaces.values()
]
self.mock_graph.add_node.assert_has_calls(calls)

calls = [
call(switch.id, interface.id)
for interface in switch.interfaces.values()
]

self.mock_graph.add_edge.assert_has_calls(calls)
edge_count = sum(
[len(sw.interfaces.values()) for sw in topology.switches.values()]
)
node_count = len(topology.switches) + edge_count
assert self.mock_graph.add_edge.call_count == edge_count
assert self.mock_graph.add_node.call_count == node_count

def test_update_nodes_2(self):
"""Test update nodes."""
Expand Down Expand Up @@ -126,9 +149,7 @@ def test_constrained_k_shortest_paths(self, mock_combinations):
self.kytos_graph.k_shortest_paths = MagicMock(
return_value=constrained_k_shortest_paths
)
self.kytos_graph._filter_links = MagicMock(
side_effect=get_filter_links_fake
)
self.kytos_graph._filter_links = MagicMock(side_effect=get_filter_links_fake)
k_shortest_paths = self.kytos_graph.constrained_k_shortest_paths(
source,
dest,
Expand Down

0 comments on commit fd29a59

Please sign in to comment.